From 369b21840dee73c35e316bd666f790f70457f171 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 12 Jun 2026 11:09:39 +0000 Subject: [PATCH 1/2] fix(evolution): prevent critical run path regressions Co-authored-by: EXboy --- crates/skilllite-agent/src/chat_session.rs | 55 +++++++++---- .../src-tauri/src/life_pulse.rs | 35 ++++++++- .../integrations/evolution_ui/authorize.rs | 4 + .../src-tauri/src/skilllite_bridge/mod.rs | 2 +- crates/skilllite-commands/src/evolution.rs | 34 +++++++- .../src/evolution_status.rs | 35 +++++++-- .../CONTEXT.md | 48 ++++++++++++ .../PRD.md | 51 ++++++++++++ .../REVIEW.md | 29 +++++++ .../STATUS.md | 19 +++++ .../TASK.md | 77 +++++++++++++++++++ tasks/board.md | 4 +- 12 files changed, 367 insertions(+), 26 deletions(-) create mode 100644 tasks/TASK-2026-069-critical-evolution-run-fixes/CONTEXT.md create mode 100644 tasks/TASK-2026-069-critical-evolution-run-fixes/PRD.md create mode 100644 tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md create mode 100644 tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md create mode 100644 tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md diff --git a/crates/skilllite-agent/src/chat_session.rs b/crates/skilllite-agent/src/chat_session.rs index a3e248e2..d8ca881b 100644 --- a/crates/skilllite-agent/src/chat_session.rs +++ b/crates/skilllite-agent/src/chat_session.rs @@ -14,6 +14,7 @@ use std::path::{Path, PathBuf}; use skilllite_executor::{memory as executor_memory, session, transcript}; use skilllite_core::config::env_keys::evolution as evo_env_keys; +use skilllite_core::skill::discovery::resolve_skills_dir_with_legacy_fallback; use super::agent_loop; use super::evolution; @@ -1161,6 +1162,22 @@ fn apply_message_window_to_cache(cache: &mut TranscriptCache, paths: &[PathBuf], // ─── A9: evolution triggers (periodic + decision-count) ───────────────────── +fn resolve_workspace_skills_root(workspace: &str) -> Option { + if workspace.is_empty() { + return None; + } + + let ws = Path::new(workspace); + let workspace_root = if ws.is_absolute() { + ws.to_path_buf() + } else { + std::env::current_dir() + .unwrap_or_else(|_| PathBuf::from(".")) + .join(ws) + }; + Some(resolve_skills_dir_with_legacy_fallback(&workspace_root, "skills").effective_path) +} + async fn run_evolution_and_emit_summary( data_root: &Path, workspace: &str, @@ -1168,20 +1185,7 @@ async fn run_evolution_and_emit_summary( api_key: &str, model: &str, ) { - let skills_root = if workspace.is_empty() { - None - } else { - let ws = std::path::Path::new(workspace); - let sr = if ws.is_absolute() { - ws.join(".skills") - } else { - std::env::current_dir() - .unwrap_or_else(|_| std::path::PathBuf::from(".")) - .join(workspace) - .join(".skills") - }; - Some(sr) - }; + let skills_root = resolve_workspace_skills_root(workspace); let llm = match LlmClient::new(api_base, api_key) { Ok(c) => c, Err(e) => { @@ -1376,6 +1380,29 @@ fn transcript_entry_to_message(entry: &transcript::TranscriptEntry) -> Option transcript::TranscriptEntry { transcript::TranscriptEntry::Message { id: uuid::Uuid::new_v4().to_string(), diff --git a/crates/skilllite-assistant/src-tauri/src/life_pulse.rs b/crates/skilllite-assistant/src-tauri/src/life_pulse.rs index 94f945d8..75055973 100644 --- a/crates/skilllite-assistant/src-tauri/src/life_pulse.rs +++ b/crates/skilllite-assistant/src-tauri/src/life_pulse.rs @@ -141,6 +141,15 @@ fn emit(app: &tauri::AppHandle, kind: &str, detail: Option) { let _ = app.emit("life-pulse", &evt); } +fn growth_command_args(workspace: &str) -> Vec { + vec![ + "evolution".into(), + "run".into(), + "--workspace".into(), + workspace.into(), + ] +} + // ─── Rhythm check (in-process, no LLM) ───────────────────────────────────── fn check_schedule_due(workspace: &std::path::Path) -> bool { @@ -163,18 +172,23 @@ fn check_schedule_due(workspace: &std::path::Path) -> bool { fn spawn_growth( skilllite_path: &std::path::Path, + workspace: &str, env_pairs: &[(String, String)], running: Arc, app: tauri::AppHandle, ) { let path = skilllite_path.to_path_buf(); + let workspace = workspace.to_string(); + let root = skilllite_bridge::find_project_root(&workspace); + let args = growth_command_args(&workspace); let env: Vec<(String, String)> = env_pairs.to_vec(); std::thread::spawn(move || { emit(&app, "growth-started", None); let mut growth_cmd = Command::new(&path); crate::windows_spawn::hide_child_console(&mut growth_cmd); let result = growth_cmd - .args(["evolution", "run"]) + .args(args.iter().map(String::as_str)) + .current_dir(&root) .envs(env.iter().map(|(k, v)| (k.as_str(), v.as_str()))) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) @@ -281,6 +295,7 @@ pub fn start(state: LifePulseState, skilllite_path: PathBuf, app: tauri::AppHand s.growth_running.store(true, Ordering::SeqCst); spawn_growth( &skilllite_path, + &workspace, &child_env, s.growth_running.clone(), app.clone(), @@ -326,3 +341,21 @@ pub fn start(state: LifePulseState, skilllite_path: PathBuf, app: tauri::AppHand pub fn stop(state: &LifePulseState) { state.alive.store(false, Ordering::SeqCst); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn growth_command_args_include_workspace() { + assert_eq!( + growth_command_args("/tmp/workspace"), + vec![ + "evolution".to_string(), + "run".to_string(), + "--workspace".to_string(), + "/tmp/workspace".to_string(), + ] + ); + } +} diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs index dd768382..ba97ed58 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs @@ -41,6 +41,10 @@ pub fn authorize_capability_evolution( cmd.arg("evolution") .arg("run") .arg("--json") + .arg("--workspace") + .arg(&workspace_owned) + .arg("--proposal-id") + .arg(&proposal_id_owned) .current_dir(&root) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/mod.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/mod.rs index e6ab1d9f..2948e3bd 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/mod.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/mod.rs @@ -25,7 +25,7 @@ pub use chat::{ pub use followup_suggestions::followup_chat_suggestions; pub use integrations::*; pub use llm_routing_error::{classify_llm_routing_error_message, LlmInvokeResult}; -pub(crate) use paths::load_dotenv_for_child; +pub(crate) use paths::{find_project_root, load_dotenv_for_child}; pub use paths::{ default_writable_workspace_dir, ensure_skilllite_version, resolve_skilllite_path_app, MIN_SKILLLITE_VERSION, diff --git a/crates/skilllite-commands/src/evolution.rs b/crates/skilllite-commands/src/evolution.rs index ee12525c..034b76e5 100644 --- a/crates/skilllite-commands/src/evolution.rs +++ b/crates/skilllite-commands/src/evolution.rs @@ -28,10 +28,10 @@ use crate::Result; use skilllite_core::config::env_keys::paths as env_paths; use skilllite_core::paths; use skilllite_core::protocol::{NewSkill, NodeResult}; -use skilllite_core::skill::manifest; +use skilllite_core::skill::{discovery::resolve_skills_dir_with_legacy_fallback, manifest}; /// Resolve workspace for project-level skill evolution. -/// Uses SKILLLITE_WORKSPACE env or current_dir. Returns workspace/.skills. +/// Uses SKILLLITE_WORKSPACE env or current_dir. Returns `skills/` with legacy `.skills/` fallback. fn resolve_skills_root(workspace: Option<&str>) -> Option { let ws: PathBuf = workspace .filter(|s| !s.is_empty()) @@ -47,7 +47,7 @@ fn resolve_skills_root(workspace: Option<&str>) -> Option { } else { std::env::current_dir().ok()?.join(ws) }; - Some(ws.join(".skills")) + Some(resolve_skills_dir_with_legacy_fallback(&ws, "skills").effective_path) } #[derive(Debug)] @@ -731,6 +731,34 @@ fn build_new_skill(skills_root: &Path, skill_name: &str, txn_id: &str) -> Option }) } +#[cfg(test)] +mod evolution_run_path_tests { + use super::*; + + #[test] + fn resolve_skills_root_prefers_primary_skills_dir() { + let tmp = tempfile::tempdir().expect("temp workspace"); + std::fs::create_dir_all(tmp.path().join("skills")).expect("create skills"); + std::fs::create_dir_all(tmp.path().join(".skills")).expect("create legacy skills"); + + let resolved = resolve_skills_root(Some(tmp.path().to_string_lossy().as_ref())) + .expect("resolve skills root"); + + assert_eq!(resolved, tmp.path().join("skills")); + } + + #[test] + fn resolve_skills_root_uses_legacy_fallback_when_primary_missing() { + let tmp = tempfile::tempdir().expect("temp workspace"); + std::fs::create_dir_all(tmp.path().join(".skills")).expect("create legacy skills"); + + let resolved = resolve_skills_root(Some(tmp.path().to_string_lossy().as_ref())) + .expect("resolve skills root"); + + assert_eq!(resolved, tmp.path().join(".skills")); + } +} + /// 判断 source 是否为远程(非本地路径),用于区分「下载的技能」与本地/进化技能 fn is_remote_source(source: &str) -> bool { let s = source.trim(); diff --git a/crates/skilllite-commands/src/evolution_status.rs b/crates/skilllite-commands/src/evolution_status.rs index e5b31aa2..2c32480a 100644 --- a/crates/skilllite-commands/src/evolution_status.rs +++ b/crates/skilllite-commands/src/evolution_status.rs @@ -299,6 +299,21 @@ pub fn cmd_status(json: bool, workspace: &str, periodic_anchor_unix: Option cmd_status_human(workspace) } +fn reason_preview(reason: &str) -> String { + const DISPLAY_LIMIT_BYTES: usize = 50; + const PREFIX_LIMIT_BYTES: usize = 47; + + if reason.len() <= DISPLAY_LIMIT_BYTES { + return reason.to_string(); + } + + let mut end = PREFIX_LIMIT_BYTES.min(reason.len()); + while end > 0 && !reason.is_char_boundary(end) { + end -= 1; + } + format!("{}...", &reason[..end]) +} + fn cmd_status_human(workspace: &str) -> Result<()> { let workspace_root = resolve_workspace_root(workspace); skilllite_core::config::load_dotenv_from_dir(&workspace_root); @@ -405,11 +420,7 @@ fn cmd_status_human(workspace: &str) -> Result<()> { t if t.contains("rolled_back") => "🔙", _ => " ", }; - let reason_short = if reason.len() > 50 { - format!("{}...", &reason[..47]) - } else { - reason - }; + let reason_short = reason_preview(&reason); println!(" {} {} {} {}", icon, date, etype, reason_short); if !target.is_empty() { println!(" └─ target: {}", target); @@ -503,6 +514,20 @@ mod workspace_scope_tests { mod tests { use super::*; + #[test] + fn reason_preview_truncates_on_utf8_boundary() { + let reason = "界".repeat(17); + + let preview = reason_preview(&reason); + + assert_eq!(preview, format!("{}...", "界".repeat(15))); + } + + #[test] + fn reason_preview_keeps_short_text_unchanged() { + assert_eq!(reason_preview("short reason"), "short reason"); + } + #[test] fn evolution_status_snapshot_serializes_required_fields() { let snap = EvolutionStatusSnapshot { diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/CONTEXT.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/CONTEXT.md new file mode 100644 index 00000000..469f15eb --- /dev/null +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/CONTEXT.md @@ -0,0 +1,48 @@ +# Technical Context + +## Current State + +- Relevant crates/files: + - `crates/skilllite-commands/src/evolution_status.rs` + - `crates/skilllite-commands/src/evolution.rs` + - `crates/skilllite-commands/src/evolution_desktop.rs` + - `crates/skilllite-assistant/src-tauri/src/life_pulse.rs` + - `crates/skilllite-core/src/skill/discovery.rs` +- Current behavior: + - Human status display truncates event `reason` with byte slicing. + - `evolution run` resolves evolved skill output under `.skills`. + - Desktop pending-skill paths resolve `skills/` with `.skills` fallback. + - Life Pulse growth due checks use the selected workspace, but the growth run + subprocess omits `--workspace`. + +## Architecture Fit + +- Layer boundaries involved: + - `skilllite-commands` may depend on `skilllite-core` discovery helpers. + - Desktop bridge invokes CLI behavior through subprocess arguments. +- Interfaces to preserve: + - Existing CLI flags and JSON contracts. + - Existing `resolve_skills_dir_with_legacy_fallback` behavior. + +## Dependency and Compatibility + +- New dependencies: None. +- Backward compatibility notes: + - Workspaces with only `.skills/` must continue to receive evolved skills there. + - Workspaces with `skills/` should receive evolved skills under `skills/`. + +## Design Decisions + +- Decision: Introduce small local helpers instead of new abstractions. + - Rationale: The fix is narrow and can reuse existing core path resolution. + - Alternatives considered: Refactor all evolution workspace/path handling. + - Why rejected: Too broad for a critical bug-fix PR and higher regression risk. +- Decision: Pass `--workspace` from Life Pulse growth execution. + - Rationale: The due check and run should operate on the same workspace. + - Alternatives considered: Rely on `SKILLLITE_WORKSPACE` env only. + - Why rejected: Explicit CLI arguments already define the scoped desktop pattern. + +## Open Questions + +- [x] Are docs required? No CLI contract or user-facing flag semantics change. +- [x] Are security specs required? No sandbox, auth, or policy gates change. diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/PRD.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/PRD.md new file mode 100644 index 00000000..63073711 --- /dev/null +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/PRD.md @@ -0,0 +1,51 @@ +# PRD + +## Background + +The daily critical-bug investigation found concrete failure modes in recent +evolution behavior. The affected paths are visible to desktop and CLI users: +status inspection can crash on Unicode log content, and background evolution can +write generated skills outside the root used by pending-skill UI actions. + +## Objective + +Evolution status and run paths should be consistent, panic-free, and scoped to +the workspace selected by the user. + +## Functional Requirements + +- FR-1: Human evolution status output must truncate event reasons without slicing + through UTF-8 code points. +- FR-2: Evolution run skill output must resolve the same `skills/` or legacy + `.skills/` root as desktop pending-skill operations. +- FR-3: Life Pulse growth runs must pass the selected workspace to the child + `skilllite evolution run` command. + +## Non-Functional Requirements + +- Security: No sandbox or permission policy changes. +- Performance: Path and string handling changes must be constant or linear in + small display strings only. +- Compatibility: Preserve legacy `.skills` fallback when `skills/` does not + exist. + +## Constraints + +- Technical: Keep crate dependency direction unchanged and reuse existing core + skill discovery helpers. +- Timeline: N/A. + +## Success Metrics + +- Metric: Unicode evolution status preview does not panic. +- Baseline: Byte slicing `reason[..47]` panics when byte 47 is not a char boundary. +- Target: Regression test passes with multibyte input. +- Metric: Evolved skills root matches desktop pending-skill root. +- Baseline: `evolution run` uses `.skills` while desktop uses `skills/` with + legacy fallback. +- Target: Regression tests pass for primary `skills/` and legacy `.skills`. + +## Rollout + +- Rollout plan: Ship as a small bug-fix PR. +- Rollback plan: Revert this task's commit if unexpected path behavior appears. diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md new file mode 100644 index 00000000..e5fd29ef --- /dev/null +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md @@ -0,0 +1,29 @@ +# Review Report + +## Scope Reviewed + +- Files/modules: +- Commits/changes: + +## Findings + +- Critical: +- Major: +- Minor: + +## Quality Gates + +- Architecture boundary checks: `pass | fail` +- Security invariants: `pass | fail` +- Required tests executed: `pass | fail` +- Docs sync (EN/ZH): `pass | fail` + +## Test Evidence + +- Commands run: +- Key outputs: + +## Decision + +- Merge readiness: `ready | not ready` +- Follow-up actions: diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md new file mode 100644 index 00000000..08f05edb --- /dev/null +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md @@ -0,0 +1,19 @@ +# Status Journal + +## Timeline + +- 2026-06-12: + - Progress: Daily critical investigation identified concrete evolution status + panic and workspace/skills-root mismatch bugs. PRD and technical context + drafted before implementation. + - Blockers: None. + - Next step: Implement minimal fixes and focused regression tests. + +## Checkpoints + +- [x] PRD drafted before implementation (or `N/A` recorded) +- [x] Context drafted before implementation (or `N/A` recorded) +- [ ] Implementation complete +- [ ] Tests passed +- [ ] Review complete +- [ ] Board updated diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md new file mode 100644 index 00000000..e02dc25a --- /dev/null +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md @@ -0,0 +1,77 @@ +# TASK Card + +## Metadata + +- Task ID: `TASK-2026-069` +- Title: Fix critical evolution run correctness bugs +- Status: `in_progress` +- Priority: `P0` +- Owner: `agent` +- Contributors: +- Created: `2026-06-12` +- Target milestone: + +## Problem + +Recent evolution changes left critical correctness gaps in user-facing paths: +human `skilllite evolution status` can panic when displaying multibyte event +reasons, and evolution skill generation can target a different skills root or +workspace than desktop status/listing paths. + +## Scope + +- In scope: + - Make human evolution status reason previews UTF-8 boundary safe. + - Align `evolution run` skill root resolution with desktop pending-skill paths. + - Ensure Life Pulse growth subprocesses pass the selected workspace to `evolution run`. + - Add focused regression tests where feasible. +- Out of scope: + - Broad evolution architecture refactors. + - Changing CLI flags or user-facing command contracts. + - Fixing pre-existing reset/disable/explain workspace inconsistencies. + +## Acceptance Criteria + +- [ ] `skilllite evolution status` no longer panics on long CJK/emoji event reasons. +- [ ] `evolution run` writes evolved skills to the same effective `skills/` root that desktop pending-skill list/confirm uses. +- [ ] Life Pulse growth execution scopes the child `evolution run` to the selected workspace. +- [ ] Regression tests cover UTF-8 preview safety and skills-root alignment. + +## Risks + +- Risk: changing path resolution for evolved skills could affect legacy `.skills` workspaces. + - Impact: evolved skill output may move if fallback behavior is wrong. + - Mitigation: use existing `resolve_skills_dir_with_legacy_fallback` helper and test both primary and legacy cases. + +## Validation Plan + +- Required tests: + - Focused Rust tests for `skilllite-commands`. + - Task artifact validation. + - Workspace Rust format, lint, and test baseline as feasible. +- Commands to run: + - `cargo test -p skilllite-commands` + - `cargo fmt --check` + - `cargo clippy --all-targets -- -D warnings` + - `cargo test` + - `python3 scripts/validate_tasks.py` +- Manual checks: + - Re-read modified files. + - Inspect `tasks/board.md` after final update. + +## Regression Scope + +- Areas likely affected: + - Evolution CLI status rendering. + - Evolution run skill output paths. + - Desktop Life Pulse growth subprocess invocation. +- Explicit non-goals: + - API/provider credential behavior. + - Sandbox policy behavior. + - Python SDK behavior. + +## Links + +- Source TODO section: N/A, daily critical bug investigation. +- Related PRs/issues: recent evolution workspace scoping and UTF-8 truncation fixes. +- Related docs: `spec/verification-integrity.md`, `spec/rust-conventions.md`, `spec/testing-policy.md` diff --git a/tasks/board.md b/tasks/board.md index df732725..1e00c0f8 100644 --- a/tasks/board.md +++ b/tasks/board.md @@ -1,10 +1,10 @@ # Task Board -Last updated: 2026-06-10 (TASK-2026-068 evolution workspace db scope done) +Last updated: 2026-06-12 (TASK-2026-069 critical evolution run fixes in progress) ## In Progress -- None. +- `TASK-2026-069-critical-evolution-run-fixes` - Status: `in_progress` - Owner: `agent` ## Ready From 9e3dc25b5d4d44406ce618bab0c98c132c1c2963 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 12 Jun 2026 11:16:46 +0000 Subject: [PATCH 2/2] docs(task): record evolution run fix validation Co-authored-by: EXboy --- .../REVIEW.md | 42 +++++++++++++++---- .../STATUS.md | 18 ++++++-- .../TASK.md | 14 ++++--- tasks/board.md | 5 ++- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md index e5fd29ef..cdbef51f 100644 --- a/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/REVIEW.md @@ -3,27 +3,53 @@ ## Scope Reviewed - Files/modules: + - `crates/skilllite-commands/src/evolution_status.rs` + - `crates/skilllite-commands/src/evolution.rs` + - `crates/skilllite-agent/src/chat_session.rs` + - `crates/skilllite-assistant/src-tauri/src/life_pulse.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs` + - `tasks/TASK-2026-069-critical-evolution-run-fixes/*` - Commits/changes: + - `369b218` initial critical evolution run fixes. ## Findings - Critical: -- Major: -- Minor: + - Fixed: human `skilllite evolution status` could panic on multibyte event reasons because it sliced `reason[..47]`. + - Fixed: `evolution run` and agent A9 wrote evolved skills under `.skills` while desktop pending-skill paths used `skills/` with `.skills` fallback. + - Fixed: Life Pulse and post-authorize background `evolution run` calls could omit the selected workspace. +- Major: None remaining in scope. +- Minor: Existing Tauri crate warnings remain pre-existing and unrelated. ## Quality Gates -- Architecture boundary checks: `pass | fail` -- Security invariants: `pass | fail` -- Required tests executed: `pass | fail` -- Docs sync (EN/ZH): `pass | fail` +- Architecture boundary checks: `pass` +- Security invariants: `pass` +- Required tests executed: `pass` +- Docs sync (EN/ZH): `pass` (not needed; no CLI contract, flag, env, or docs semantics changed) ## Test Evidence - Commands run: + - `rustup update stable && rustup default stable` + - `cargo test -p skilllite-commands --features agent` + - `cargo test -p skilllite-agent` + - `cd crates/skilllite-assistant/src-tauri && cargo test` + - `cargo fmt --check` + - `cargo clippy --all-targets -- -D warnings` + - `cargo test` + - `python3 scripts/validate_tasks.py` - Key outputs: + - Rust/Cargo updated from 1.83 to 1.96 after edition 2024 dependency parse failure. + - `skilllite-commands`: 43 passed; includes UTF-8 reason preview and skills-root fallback tests. + - `skilllite-agent`: 247 passed; includes A9 skills-root fallback tests. + - `skilllite-assistant` `src-tauri`: 51 passed; includes Life Pulse workspace argument test. + - `cargo fmt --check`: passed. + - `cargo clippy --all-targets -- -D warnings`: passed. + - `cargo test`: passed for root workspace. + - `python3 scripts/validate_tasks.py`: `Task validation passed (69 task directories checked).` ## Decision -- Merge readiness: `ready | not ready` -- Follow-up actions: +- Merge readiness: ready +- Follow-up actions: Consider a separate follow-up to thread UI LLM overrides into post-authorize background evolution diagnostics; out of scope for this minimal correctness fix. diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md index 08f05edb..74f83991 100644 --- a/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/STATUS.md @@ -8,12 +8,22 @@ drafted before implementation. - Blockers: None. - Next step: Implement minimal fixes and focused regression tests. +- 2026-06-12: + - Progress: Implemented UTF-8-safe status previews, aligned evolution run + skills-root resolution with desktop fallback behavior, scoped Life Pulse and + post-authorize background runs with explicit `--workspace`, and added + focused regression tests. + - Blockers: Initial Rust 1.83 toolchain could not parse edition 2024 + dependencies; updated stable toolchain to Rust/Cargo 1.96. `src-tauri` + tests also required installing Linux GTK/WebKit Tauri build dependencies and + a temporary `dist/` directory for `tauri::generate_context!`. + - Next step: Open PR. ## Checkpoints - [x] PRD drafted before implementation (or `N/A` recorded) - [x] Context drafted before implementation (or `N/A` recorded) -- [ ] Implementation complete -- [ ] Tests passed -- [ ] Review complete -- [ ] Board updated +- [x] Implementation complete +- [x] Tests passed +- [x] Review complete +- [x] Board updated diff --git a/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md b/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md index e02dc25a..78cc48ee 100644 --- a/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md +++ b/tasks/TASK-2026-069-critical-evolution-run-fixes/TASK.md @@ -4,7 +4,7 @@ - Task ID: `TASK-2026-069` - Title: Fix critical evolution run correctness bugs -- Status: `in_progress` +- Status: `done` - Priority: `P0` - Owner: `agent` - Contributors: @@ -32,10 +32,10 @@ workspace than desktop status/listing paths. ## Acceptance Criteria -- [ ] `skilllite evolution status` no longer panics on long CJK/emoji event reasons. -- [ ] `evolution run` writes evolved skills to the same effective `skills/` root that desktop pending-skill list/confirm uses. -- [ ] Life Pulse growth execution scopes the child `evolution run` to the selected workspace. -- [ ] Regression tests cover UTF-8 preview safety and skills-root alignment. +- [x] `skilllite evolution status` no longer panics on long CJK/emoji event reasons. +- [x] `evolution run` writes evolved skills to the same effective `skills/` root that desktop pending-skill list/confirm uses. +- [x] Life Pulse growth execution scopes the child `evolution run` to the selected workspace. +- [x] Regression tests cover UTF-8 preview safety and skills-root alignment. ## Risks @@ -50,7 +50,9 @@ workspace than desktop status/listing paths. - Task artifact validation. - Workspace Rust format, lint, and test baseline as feasible. - Commands to run: - - `cargo test -p skilllite-commands` + - `cargo test -p skilllite-commands --features agent` + - `cargo test -p skilllite-agent` + - `cd crates/skilllite-assistant/src-tauri && cargo test` - `cargo fmt --check` - `cargo clippy --all-targets -- -D warnings` - `cargo test` diff --git a/tasks/board.md b/tasks/board.md index 1e00c0f8..8ab3780c 100644 --- a/tasks/board.md +++ b/tasks/board.md @@ -1,10 +1,10 @@ # Task Board -Last updated: 2026-06-12 (TASK-2026-069 critical evolution run fixes in progress) +Last updated: 2026-06-12 (TASK-2026-069 critical evolution run fixes done) ## In Progress -- `TASK-2026-069-critical-evolution-run-fixes` - Status: `in_progress` - Owner: `agent` +- None. ## Ready @@ -17,6 +17,7 @@ Last updated: 2026-06-12 (TASK-2026-069 critical evolution run fixes in progress ## Done +- `TASK-2026-069-critical-evolution-run-fixes` - Status: `done` - Owner: `agent` - `TASK-2026-068-evolution-workspace-db-scope` - Status: `done` - Owner: `agent` - `TASK-2026-067-utf8-llm-error-truncate` - Status: `done` - Owner: `agent` - `TASK-2026-066-utf8-evolution-log-truncate` - Status: `done` - Owner: `agent`