fix: resolve 17 P2 defects and 5 P3 defects from pre-launch audit
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Batch fix covering multiple modules:
- P2-01: HandRegistry Semaphore-based max_concurrent enforcement
- P2-03: Populate toolCount/metricCount from Hand trait methods
- P2-06: heartbeat_update_config minimum interval validation
- P2-07: ReflectionResult used_fallback marker for rule-based fallback
- P2-08/09: identity_propose_change parameter naming consistency
- P2-10: ClassroomMetadata is_placeholder flag for LLM failure
- P2-11: classroomStore userDidCloseDuringGeneration intent tracking
- P2-12: workflowStore pipeline_create sends actionType
- P2-13/14: PipelineInfo step_count + PipelineStepInfo for proper step mapping
- P2-15: Pipe transform support in context.resolve (8 transforms)
- P2-16: Mustache {{...}} → \${...} auto-normalization
- P2-17: SaaSLogin password placeholder 6→8
- P2-19: serialize_skill_md + update_skill preserve tools field
- P2-22: ToolOutputGuard sensitive patterns from warn→block
- P2-23: Mutex::unwrap() → unwrap_or_else in relay/service.rs
- P3-01/03/07/08/09: Various P3 fixes
- DEFECT_LIST.md: comprehensive status sync (43/51 fixed, 8 remaining)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -238,6 +238,8 @@ impl SkillRegistry {
|
||||
tags: if updates.tags.is_empty() { existing.tags } else { updates.tags },
|
||||
category: updates.category.or(existing.category),
|
||||
triggers: if updates.triggers.is_empty() { existing.triggers } else { updates.triggers },
|
||||
// P2-19: Preserve tools field during update (was silently dropped)
|
||||
tools: if updates.tools.is_empty() { existing.tools } else { updates.tools },
|
||||
enabled: updates.enabled,
|
||||
};
|
||||
|
||||
@@ -296,6 +298,13 @@ fn serialize_skill_md(manifest: &SkillManifest) -> String {
|
||||
if !manifest.tags.is_empty() {
|
||||
parts.push(format!("tags: {}", manifest.tags.join(", ")));
|
||||
}
|
||||
// P2-19: Serialize tools field (was missing, causing tools to be lost on re-serialization)
|
||||
if !manifest.tools.is_empty() {
|
||||
parts.push("tools:".to_string());
|
||||
for tool in &manifest.tools {
|
||||
parts.push(format!(" - \"{}\"", tool));
|
||||
}
|
||||
}
|
||||
if !manifest.triggers.is_empty() {
|
||||
parts.push("triggers:".to_string());
|
||||
for trigger in &manifest.triggers {
|
||||
|
||||
@@ -9,6 +9,14 @@ use zclaw_types::Result;
|
||||
|
||||
use super::{Skill, SkillContext, SkillManifest, SkillResult};
|
||||
|
||||
/// Returns the platform-appropriate Python binary name.
|
||||
/// On Windows, the standard installer provides `python.exe`, not `python3.exe`.
|
||||
#[cfg(target_os = "windows")]
|
||||
fn python_bin() -> &'static str { "python" }
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn python_bin() -> &'static str { "python3" }
|
||||
|
||||
/// Prompt-only skill execution
|
||||
pub struct PromptOnlySkill {
|
||||
manifest: SkillManifest,
|
||||
@@ -80,7 +88,8 @@ impl Skill for PythonSkill {
|
||||
let start = Instant::now();
|
||||
let input_json = serde_json::to_string(&input).unwrap_or_default();
|
||||
|
||||
let output = Command::new("python3")
|
||||
// P2-20: Platform-aware Python binary (Windows has no python3)
|
||||
let output = Command::new(python_bin())
|
||||
.arg(&self.script_path)
|
||||
.env("SKILL_INPUT", &input_json)
|
||||
.env("AGENT_ID", &context.agent_id)
|
||||
@@ -158,14 +167,27 @@ impl Skill for ShellSkill {
|
||||
.map_err(|e| zclaw_types::ZclawError::ToolError(format!("Failed to execute shell: {}", e)))?
|
||||
};
|
||||
|
||||
let _duration_ms = start.elapsed().as_millis() as u64;
|
||||
// P3-08: Use duration_ms instead of discarding it
|
||||
let duration_ms = start.elapsed().as_millis() as u64;
|
||||
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
Ok(SkillResult::success(Value::String(stdout.to_string())))
|
||||
Ok(SkillResult {
|
||||
success: true,
|
||||
output: Value::String(stdout.to_string()),
|
||||
error: None,
|
||||
duration_ms: Some(duration_ms),
|
||||
tokens_used: None,
|
||||
})
|
||||
} else {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
Ok(SkillResult::error(stderr))
|
||||
Ok(SkillResult {
|
||||
success: false,
|
||||
output: Value::Null,
|
||||
error: Some(stderr.to_string()),
|
||||
duration_ms: Some(duration_ms),
|
||||
tokens_used: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,9 @@ pub struct SkillManifest {
|
||||
/// Trigger words for skill activation
|
||||
#[serde(default)]
|
||||
pub triggers: Vec<String>,
|
||||
/// Required tools for skill execution (e.g., "bash", "web_search")
|
||||
#[serde(default)]
|
||||
pub tools: Vec<String>,
|
||||
/// Whether the skill is enabled
|
||||
#[serde(default = "default_enabled")]
|
||||
pub enabled: bool,
|
||||
|
||||
Reference in New Issue
Block a user