From c653e1b90ad2724c3521fd2b58629d5f9a07385a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 11:10:50 +0000 Subject: [PATCH 1/2] fix(evolution): align desktop workspace scoping Co-authored-by: EXboy --- .../src-tauri/src/skilllite_bridge/chat.rs | 3 +- .../src/skilllite_bridge/evolution_cli.rs | 12 +++- .../integrations/evolution_ui/authorize.rs | 39 +++++++++-- .../src-tauri/src/skilllite_bridge/paths.rs | 41 ++++++++++++ crates/skilllite-commands/src/evolution.rs | 37 ++++++++++- .../CONTEXT.md | 41 ++++++++++++ .../PRD.md | 37 +++++++++++ .../REVIEW.md | 29 +++++++++ .../STATUS.md | 17 +++++ .../TASK.md | 65 +++++++++++++++++++ tasks/board.md | 4 +- 11 files changed, 312 insertions(+), 13 deletions(-) create mode 100644 tasks/TASK-2026-067-desktop-evolution-workspace-scope/CONTEXT.md create mode 100644 tasks/TASK-2026-067-desktop-evolution-workspace-scope/PRD.md create mode 100644 tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md create mode 100644 tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md create mode 100644 tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs index 955f59f8..7184f329 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs @@ -13,7 +13,7 @@ use tauri::{Emitter, Manager, Window}; use super::local::mcp::McpServerEntry; use super::bundled_skills_sync; -use super::paths::{find_project_root, load_dotenv_for_child}; +use super::paths::{find_project_root, load_dotenv_for_child, with_explicit_workspace_env}; use super::protocol::{ make_protocol_recovered_event, make_protocol_warning_event, parse_stream_event_line, preview_line, StreamEvent, INVALID_LINE_PREVIEW_CHARS, MAX_CONSECUTIVE_INVALID_PROTOCOL_LINES, @@ -369,6 +369,7 @@ pub fn chat_stream( load_dotenv_for_child(&raw_workspace), config_overrides.as_ref(), ); + let env_pairs = with_explicit_workspace_env(env_pairs, &workspace_root); let provenance = summarize_env_provenance(&env_sources); if !provenance.is_empty() { eprintln!( diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs index d1424a31..cd59cafa 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs @@ -11,7 +11,7 @@ use serde::Deserialize; use super::local::engine_types::{ProvisionRuntimesResult, RuntimeUiSnapshot}; use super::chat::{merge_dotenv_with_chat_overrides, ChatConfigOverrides}; -use super::paths::{find_project_root, load_dotenv_for_child}; +use super::paths::{find_project_root, load_dotenv_for_child, with_explicit_workspace_env}; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] @@ -31,7 +31,10 @@ pub fn spawn_skilllite( let mut cmd = Command::new(skilllite_path); crate::windows_spawn::hide_child_console(&mut cmd); cmd.args(args); - let env_pairs = merge_dotenv_with_chat_overrides(load_dotenv_for_child(workspace), cfg); + let env_pairs = with_explicit_workspace_env( + merge_dotenv_with_chat_overrides(load_dotenv_for_child(workspace), cfg), + &root, + ); for (k, v) in env_pairs { cmd.env(k, v); } @@ -103,7 +106,10 @@ where let mut cmd = Command::new(skilllite_path); crate::windows_spawn::hide_child_console(&mut cmd); cmd.args(&args); - let env_pairs = merge_dotenv_with_chat_overrides(load_dotenv_for_child(workspace), cfg); + let env_pairs = with_explicit_workspace_env( + merge_dotenv_with_chat_overrides(load_dotenv_for_child(workspace), cfg), + &root, + ); for (k, v) in env_pairs { cmd.env(k, v); } 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..67da7b74 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 @@ -3,7 +3,19 @@ use crate::skilllite_bridge::evolution_cli::spawn_skilllite_json; use crate::skilllite_bridge::local::engine_types::AuthorizeCapabilityResponse; use crate::skilllite_bridge::local::env_keys::evolution as evo_keys; -use crate::skilllite_bridge::paths::{find_project_root, load_dotenv_for_child}; +use crate::skilllite_bridge::paths::{ + find_project_root, load_dotenv_for_child, with_explicit_workspace_env, +}; + +fn background_run_args(workspace: &str) -> Vec { + vec![ + "evolution".to_string(), + "run".to_string(), + "--json".to_string(), + "--workspace".to_string(), + workspace.to_string(), + ] +} pub fn authorize_capability_evolution( workspace: &str, @@ -38,13 +50,11 @@ pub fn authorize_capability_evolution( let root = find_project_root(&workspace_owned); let mut cmd = std::process::Command::new(&skilllite_path_owned); crate::windows_spawn::hide_child_console(&mut cmd); - cmd.arg("evolution") - .arg("run") - .arg("--json") + cmd.args(background_run_args(&workspace_owned)) .current_dir(&root) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); - for (k, v) in load_dotenv_for_child(&workspace_owned) { + for (k, v) in with_explicit_workspace_env(load_dotenv_for_child(&workspace_owned), &root) { cmd.env(k, v); } cmd.env(evo_keys::SKILLLITE_EVO_FORCE_PROPOSAL_ID, &proposal_id_owned); @@ -52,3 +62,22 @@ pub fn authorize_capability_evolution( }); Ok(proposal_id) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn background_run_args_include_explicit_workspace() { + assert_eq!( + background_run_args("/tmp/project"), + vec![ + "evolution", + "run", + "--json", + "--workspace", + "/tmp/project" + ] + ); + } +} diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/paths.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/paths.rs index 7749d95d..959182bb 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/paths.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/paths.rs @@ -58,6 +58,21 @@ pub(crate) fn load_dotenv_for_child(workspace: &str) -> Vec<(String, String)> { crate::skilllite_bridge::local::parse_dotenv_walking_up(&base, 5) } +/// Ensure desktop-spawned CLI children use the selected project as the data root. +pub(crate) fn with_explicit_workspace_env( + mut env_pairs: Vec<(String, String)>, + workspace_root: &Path, +) -> Vec<(String, String)> { + env_pairs.retain(|(key, _)| { + key != crate::skilllite_bridge::local::env_keys::paths::SKILLLITE_WORKSPACE + }); + env_pairs.push(( + crate::skilllite_bridge::local::env_keys::paths::SKILLLITE_WORKSPACE.to_string(), + workspace_root.to_string_lossy().to_string(), + )); + env_pairs +} + pub(crate) fn skilllite_chat_root() -> PathBuf { crate::skilllite_bridge::local::chat_root() } @@ -261,6 +276,32 @@ mod tests { let _ = std::fs::remove_dir_all(&resolved); } + #[test] + fn explicit_workspace_env_overrides_dotenv_workspace() { + let workspace_root = PathBuf::from("/tmp/selected-workspace"); + let pairs = with_explicit_workspace_env( + vec![ + ( + crate::skilllite_bridge::local::env_keys::paths::SKILLLITE_WORKSPACE + .to_string(), + "/tmp/stale-workspace".to_string(), + ), + ("OPENAI_MODEL".to_string(), "dotenv-model".to_string()), + ], + &workspace_root, + ); + let map: std::collections::HashMap<_, _> = pairs.into_iter().collect(); + assert_eq!( + map.get(crate::skilllite_bridge::local::env_keys::paths::SKILLLITE_WORKSPACE) + .map(String::as_str), + Some("/tmp/selected-workspace") + ); + assert_eq!( + map.get("OPENAI_MODEL").map(String::as_str), + Some("dotenv-model") + ); + } + #[cfg(debug_assertions)] #[test] fn workspace_debug_skilllite_candidate_points_to_workspace_target_debug() { diff --git a/crates/skilllite-commands/src/evolution.rs b/crates/skilllite-commands/src/evolution.rs index d68dd95d..1b5852eb 100644 --- a/crates/skilllite-commands/src/evolution.rs +++ b/crates/skilllite-commands/src/evolution.rs @@ -28,10 +28,12 @@ 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::discovery::resolve_skills_dir_with_legacy_fallback; use skilllite_core::skill::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 the default `skills/` +/// root, falling back to legacy `.skills/` only when appropriate. fn resolve_skills_root(workspace: Option<&str>) -> Option { let ws: PathBuf = workspace .filter(|s| !s.is_empty()) @@ -47,7 +49,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)] @@ -1030,6 +1032,37 @@ mod tests { assert!(normalize_risk_filter(Some("urgent")).is_err()); } + #[test] + fn resolve_skills_root_prefers_default_skills_directory() { + let root = std::env::temp_dir().join(format!( + "skilllite-evo-skills-test-{}", + uuid::Uuid::new_v4() + )); + std::fs::create_dir_all(root.join("skills")).expect("skills dir"); + std::fs::create_dir_all(root.join(".skills")).expect("legacy skills dir"); + + let resolved = + resolve_skills_root(Some(root.to_string_lossy().as_ref())).expect("skills root"); + + assert_eq!(resolved, root.join("skills")); + let _ = std::fs::remove_dir_all(&root); + } + + #[test] + fn resolve_skills_root_keeps_legacy_fallback_when_default_missing() { + let root = std::env::temp_dir().join(format!( + "skilllite-evo-skills-test-{}", + uuid::Uuid::new_v4() + )); + std::fs::create_dir_all(root.join(".skills")).expect("legacy skills dir"); + + let resolved = + resolve_skills_root(Some(root.to_string_lossy().as_ref())).expect("skills root"); + + assert_eq!(resolved, root.join(".skills")); + let _ = std::fs::remove_dir_all(&root); + } + #[test] fn query_backlog_rows_applies_filters() { let root = diff --git a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/CONTEXT.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/CONTEXT.md new file mode 100644 index 00000000..5df17369 --- /dev/null +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/CONTEXT.md @@ -0,0 +1,41 @@ +# Technical Context + +## Current State + +- Relevant crates/files: + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs` + - `crates/skilllite-commands/src/evolution.rs` + - `crates/skilllite-commands/src/evolution_desktop.rs` + - `crates/skilllite-core/src/paths.rs` +- Current behavior: + - Desktop chat sets subprocess cwd to the project root and sends `config.workspace`, but does not set `SKILLLITE_WORKSPACE`; `ChatSession` stores state under `skilllite_executor::chat_root()`. + - `evolution run --workspace` loads dotenv, then sets `SKILLLITE_WORKSPACE` to the resolved workspace before calling `paths::chat_root()`. + - Desktop pending/confirm commands use `resolve_skills_dir_with_legacy_fallback(root, "skills")`, while `evolution run` uses `/.skills`. + +## Architecture Fit + +- Layer boundaries involved: desktop Tauri bridge -> `skilllite` CLI entry -> `skilllite-commands` -> evolution/agent crates. +- Interfaces to preserve: existing CLI subcommands and JSON shapes remain unchanged. + +## Dependency and Compatibility + +- New dependencies: none. +- Backward compatibility notes: legacy `.skills/` remains supported when no `skills/` directory exists. + +## Design Decisions + +- Decision: Inject absolute `SKILLLITE_WORKSPACE` in desktop subprocess helpers after merging dotenv/UI overrides. + - Rationale: The desktop caller passes a workspace explicitly; env-dependent storage roots must match that explicit contract. + - Alternatives considered: Change `chat_root()` to inspect cwd or `AgentConfig.workspace`. + - Why rejected: That would affect non-desktop callers and broaden the blast radius. +- Decision: Reuse `resolve_skills_dir_with_legacy_fallback` in `evolution run`. + - Rationale: It aligns run output with pending/confirm/status and preserves legacy fallback. + - Alternatives considered: Change desktop pending/confirm to `.skills`. + - Why rejected: That would regress OpenClaw/default `skills/` workspaces. + +## Open Questions + +- [x] Is this a security bypass? No; the bug is state partitioning and wrong root selection, while gatekeeper constraints remain intact. +- [x] Are docs required? No user-facing flags or documented commands change; behavior is corrected to the existing workspace contract. diff --git a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/PRD.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/PRD.md new file mode 100644 index 00000000..d9471f2f --- /dev/null +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/PRD.md @@ -0,0 +1,37 @@ +# PRD + +## Background + +The desktop Assistant moved multiple evolution and runtime surfaces to CLI subprocesses. The CLI commands accept `--workspace`, but shared state roots still depend on `SKILLLITE_WORKSPACE`. If the desktop process only sets cwd or passes `--workspace` to some commands, the chat session, evolution backlog, manual run, and background authorization can observe different SQLite databases. + +## Objective + +All desktop-triggered chat/evolution subprocesses must treat the selected project root as the single workspace state root. Evolved skill creation and desktop pending/confirm operations must resolve the same skill root. + +## Functional Requirements + +- FR-1: Desktop child process environment must include absolute `SKILLLITE_WORKSPACE=` after dotenv/UI overrides are merged. +- FR-2: Capability authorization must run the background forced evolution against the same workspace as the enqueue command. +- FR-3: `evolution run` must select `skills/` by default and use `.skills/` only as legacy fallback when `skills/` is absent and `.skills/` exists. + +## Non-Functional Requirements + +- Security: Do not loosen sandbox or gatekeeper path checks. +- Performance: No additional long-running work in the desktop command path. +- Compatibility: Preserve existing CLI flags and keep `.skills/` fallback for legacy workspaces. + +## Constraints + +- Technical: Keep changes within existing bridge/command layers; do not introduce new crate dependencies. +- Timeline: N/A for autonomous execution. + +## Success Metrics + +- Metric: Workspace state root consistency across desktop chat and evolution subprocesses. +- Baseline: Chat can write `~/.skilllite/chat` while `evolution run --workspace` reads `/chat`. +- Target: Both paths receive the same absolute `SKILLLITE_WORKSPACE`. + +## Rollout + +- Rollout plan: Ship as a patch-level bug fix with regression tests. +- Rollback plan: Revert the bridge env injection and skill-root resolver change if unexpected compatibility regressions appear. diff --git a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md new file mode 100644 index 00000000..e5fd29ef --- /dev/null +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/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-067-desktop-evolution-workspace-scope/STATUS.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md new file mode 100644 index 00000000..cf7d404b --- /dev/null +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md @@ -0,0 +1,17 @@ +# Status Journal + +## Timeline + +- 2026-06-02: + - Progress: Confirmed recent desktop L2 CLI bridge can split workspace-backed evolution state between ambient/default roots and the explicit project workspace. Drafted task baseline before implementation. + - Blockers: None. + - Next step: Implement minimal workspace env injection and skill-root resolver alignment, then add 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-067-desktop-evolution-workspace-scope/TASK.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md new file mode 100644 index 00000000..a7da449d --- /dev/null +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md @@ -0,0 +1,65 @@ +# TASK Card + +## Metadata + +- Task ID: `TASK-2026-067` +- Title: Fix desktop evolution workspace scoping +- Status: `in_progress` +- Priority: `P0` +- Owner: `agent` +- Contributors: Cursor automation +- Created: `2026-06-02` +- Target milestone: next patch release + +## Problem + +Recent desktop L2 CLI bridge changes can run chat, evolution status/backlog, manual evolution runs, and capability authorization with different effective `SKILLLITE_WORKSPACE` values. Because `chat_root()` uses `SKILLLITE_WORKSPACE` rather than process cwd, this can split SQLite evolution state between `~/.skilllite/chat` and `/chat`, making manual evolution report "nothing to evolve" despite active chat state and making user-authorized proposals fail in the background. `evolution run` also writes pending evolved skills under `.skills` while the desktop pending/confirm paths use the `skills` resolver. + +## Scope + +- In scope: + - Ensure desktop-spawned `skilllite` subprocesses receive an absolute `SKILLLITE_WORKSPACE` matching the resolved project root. + - Ensure capability authorization background runs carry the same workspace scope. + - Align `evolution run` skill root resolution with the desktop pending/confirm resolver. + - Add regression tests that prove the environment merge and skill-root selection behavior. +- Out of scope: + - Redesigning the assistant bridge or restoring in-process fallbacks. + - Changing evolution scoring, LLM behavior, or sandbox policy. + - Changing user-facing CLI flags. + +## Acceptance Criteria + +- [ ] Agent chat and desktop evolution CLI subprocesses use the same absolute workspace root for `SKILLLITE_WORKSPACE`. +- [ ] `evolution authorize-capability` background execution includes the workspace passed by the desktop caller. +- [ ] `evolution run` writes/reads evolved skills through `skills/` by default, falling back to `.skills/` only when appropriate. +- [ ] Regression tests cover workspace env injection and `skills` vs `.skills` selection. +- [ ] Required Rust formatting, lint, tests, and task validation pass. + +## Risks + +- Risk: Overriding a deliberately configured `SKILLLITE_WORKSPACE` in desktop child processes. + - Impact: Users with custom desktop state roots could see state move to the selected project. + - Mitigation: Desktop commands already pass an explicit workspace and `evolution run` already rebinds to it; make child env match that explicit caller contract instead of stale ambient env. + +## Validation Plan + +- Required tests: focused unit/regression tests plus CLI/commands test targets. +- Commands to run: + - `cargo fmt --check` + - `cargo clippy --all-targets -- -D warnings` + - `cargo test` + - `cargo test -p skilllite` + - `cargo test -p skilllite-commands` + - `python3 scripts/validate_tasks.py` +- Manual checks: terminal-driven command inspection is sufficient because this fix is subprocess environment/routing behavior, not visual UI rendering. + +## Regression Scope + +- Areas likely affected: desktop Assistant chat subprocesses, desktop evolution CLI bridge, `skilllite evolution run`, pending skill handling. +- Explicit non-goals: runtime provisioning progress streaming and skills-list fallback policy are not changed in this task. + +## Links + +- Source TODO section: N/A; critical bug-finding automation. +- Related PRs/issues: recent PRs #79, #80, #81. +- Related docs: `docs/en/ASSISTANT-SPLIT-ARCHITECTURE.md`, `docs/zh/ASSISTANT-SPLIT-ARCHITECTURE.md`. diff --git a/tasks/board.md b/tasks/board.md index 43428f7b..ebd80e9c 100644 --- a/tasks/board.md +++ b/tasks/board.md @@ -1,10 +1,10 @@ # Task Board -Last updated: 2026-05-29 (TASK-2026-066 utf8 evolution log truncate done) +Last updated: 2026-06-02 (TASK-2026-067 desktop evolution workspace scoping in progress) ## In Progress -- None. +- `TASK-2026-067-desktop-evolution-workspace-scope` - Status: `in_progress` - Owner: `agent` ## Ready From 045f43a30847e1d84149b890b14dc472472b1e88 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 11:16:55 +0000 Subject: [PATCH 2/2] docs(task): record desktop evolution validation Co-authored-by: EXboy --- .../REVIEW.md | 41 +++++++++++++++---- .../STATUS.md | 16 ++++++-- .../TASK.md | 12 +++--- tasks/board.md | 5 ++- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md index e5fd29ef..803b383a 100644 --- a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/REVIEW.md @@ -3,27 +3,50 @@ ## Scope Reviewed - Files/modules: + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/chat.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/evolution_cli.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs` + - `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/paths.rs` + - `crates/skilllite-commands/src/evolution.rs` - Commits/changes: + - Fixed desktop child process workspace env scoping. + - Fixed background capability authorization run arguments. + - Aligned `evolution run` skill root selection with desktop pending/confirm. ## Findings -- Critical: -- Major: -- Minor: +- Critical: Real bug found and fixed. Desktop Assistant could split evolution state across different chat roots, causing manual evolution to report no work despite active chat state and causing user-authorized capability proposals to be forced from the wrong database. +- Major: `evolution run` used `.skills/` unconditionally while desktop pending/confirm used `skills/` with `.skills/` fallback, orphaning generated pending skills in default `skills/` workspaces. +- Minor: Runtime provisioning progress streaming and skills-list fallback behavior were reviewed but left out of this PR because they are not crashes/data-loss/security-class issues. ## 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` ## Test Evidence - Commands run: + - `rustup update stable && rustup default stable` + - `npm ci && npm run build` in `crates/skilllite-assistant` + - `cargo fmt --check` + - `cargo clippy --all-targets -- -D warnings` + - `cargo test` + - `cargo test -p skilllite` + - `cargo test -p skilllite-commands` + - `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml explicit_workspace_env_overrides_dotenv_workspace` + - `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml background_run_args_include_explicit_workspace` + - `python3 scripts/validate_tasks.py` - Key outputs: + - `cargo test -p skilllite-commands`: `23 passed; 0 failed`. + - `cargo test -p skilllite`: CLI unit/integration suites passed, including `e2e_minimal`. + - `cargo clippy --all-targets -- -D warnings`: finished successfully. + - `cargo test`: workspace tests and doctests completed successfully. + - Assistant focused tests: each filtered test passed after installing Linux Tauri build dependencies and generating `dist`. ## Decision -- Merge readiness: `ready | not ready` -- Follow-up actions: +- Merge readiness: `ready` +- Follow-up actions: Consider a separate non-critical PR for runtime provisioning progress streaming and silent skills-list fallback behavior. diff --git a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md index cf7d404b..1882da4d 100644 --- a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/STATUS.md @@ -6,12 +6,20 @@ - Progress: Confirmed recent desktop L2 CLI bridge can split workspace-backed evolution state between ambient/default roots and the explicit project workspace. Drafted task baseline before implementation. - Blockers: None. - Next step: Implement minimal workspace env injection and skill-root resolver alignment, then add regression tests. +- 2026-06-02: + - Progress: Implemented explicit desktop child `SKILLLITE_WORKSPACE` injection, background authorize `--workspace` propagation, and `evolution run` `skills/`-first resolver alignment. + - Blockers: None. Environment remediation was required before assistant Tauri tests: upgraded Rust stable, installed GTK/WebKitGTK development packages, and generated `crates/skilllite-assistant/dist`. + - Next step: Commit final task metadata and open PR. +- 2026-06-02: + - Progress: Validation passed with `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test`, `cargo test -p skilllite`, `cargo test -p skilllite-commands`, two focused assistant Tauri tests, `npm ci && npm run build`, and task validation. + - Blockers: None. + - Next step: Ready for review. ## 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-067-desktop-evolution-workspace-scope/TASK.md b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md index a7da449d..8012aee8 100644 --- a/tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md +++ b/tasks/TASK-2026-067-desktop-evolution-workspace-scope/TASK.md @@ -4,7 +4,7 @@ - Task ID: `TASK-2026-067` - Title: Fix desktop evolution workspace scoping -- Status: `in_progress` +- Status: `done` - Priority: `P0` - Owner: `agent` - Contributors: Cursor automation @@ -29,11 +29,11 @@ Recent desktop L2 CLI bridge changes can run chat, evolution status/backlog, man ## Acceptance Criteria -- [ ] Agent chat and desktop evolution CLI subprocesses use the same absolute workspace root for `SKILLLITE_WORKSPACE`. -- [ ] `evolution authorize-capability` background execution includes the workspace passed by the desktop caller. -- [ ] `evolution run` writes/reads evolved skills through `skills/` by default, falling back to `.skills/` only when appropriate. -- [ ] Regression tests cover workspace env injection and `skills` vs `.skills` selection. -- [ ] Required Rust formatting, lint, tests, and task validation pass. +- [x] Agent chat and desktop evolution CLI subprocesses use the same absolute workspace root for `SKILLLITE_WORKSPACE`. +- [x] `evolution authorize-capability` background execution includes the workspace passed by the desktop caller. +- [x] `evolution run` writes/reads evolved skills through `skills/` by default, falling back to `.skills/` only when appropriate. +- [x] Regression tests cover workspace env injection and `skills` vs `.skills` selection. +- [x] Required Rust formatting, lint, tests, and task validation pass. ## Risks diff --git a/tasks/board.md b/tasks/board.md index ebd80e9c..99db1fe1 100644 --- a/tasks/board.md +++ b/tasks/board.md @@ -1,10 +1,10 @@ # Task Board -Last updated: 2026-06-02 (TASK-2026-067 desktop evolution workspace scoping in progress) +Last updated: 2026-06-02 (TASK-2026-067 desktop evolution workspace scoping done) ## In Progress -- `TASK-2026-067-desktop-evolution-workspace-scope` - Status: `in_progress` - Owner: `agent` +- None. ## Ready @@ -17,6 +17,7 @@ Last updated: 2026-06-02 (TASK-2026-067 desktop evolution workspace scoping in p ## Done +- `TASK-2026-067-desktop-evolution-workspace-scope` - Status: `done` - Owner: `agent` - `TASK-2026-066-utf8-evolution-log-truncate` - Status: `done` - Owner: `agent` - `TASK-2026-064-env-keys-single-source` - Status: `done` - Owner: `agent` - `TASK-2026-063-extension-tool-metadata-dispatch` - Status: `done` - Owner: `agent`