diff --git a/ROADMAP.md b/ROADMAP.md index 180df761..1472961b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7621,3 +7621,5 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed) 726. **`claw export` from a workspace with a cross-workspace legacy session emits `kind:"unknown", error_kind:"unknown"` instead of a typed error — `legacy session is missing workspace binding` error propagates through the generic error handler unclassified** — dogfooded 2026-05-26 on `d8a61090`. Reproduction: `claw export --output-format json` from a fresh `git init` workspace where the most-recent managed session was created in a different workspace root returns `{kind:"unknown", action:"abort", status:"error", error_kind:"unknown"}`. The error originates in `SessionControlError::Format(format_legacy_session_missing_workspace_root(...))` in `session_control.rs:313`; `classify_error_kind` had no branch for "legacy session is missing workspace binding" and fell through to "unknown". Fix: added `legacy_session_no_workspace_binding` branch to `classify_error_kind`. Remaining gap: `kind` still shows the error_kind value instead of `"export"` — root cause is the generic error path setting `kind = error_kind` rather than the subcommand name; this is the `#422` class and requires a separate structural fix. Source: Jobdori dogfood on `d8a61090`, 2026-05-26. 727. **`branch_freshness.fresh: null` with `upstream: null` is ambiguous — automation checking `if .workspace.branch_freshness.fresh == true` treats "no upstream configured" identically to "behind by N commits", both returning falsy null** — dogfooded 2026-05-26 on `a0c6c8ba`. Reproduction: `claw status --output-format json` from a freshly `git init`'d repo with no remote returns `{upstream: null, fresh: null, ahead: 0, behind: 0}`. An automation script that gates on `.branch_freshness.fresh == true` before proceeding sees `null == true → false` and blocks — identical to the behind-by-N case. The JSON has no discriminator between "freshness unknown because no upstream" and "freshness unknown because git unavailable". Fix: added `has_upstream: bool` to `BranchFreshness.json_value()` — automation should check `has_upstream` before branching on `fresh`. Source: Jobdori dogfood on `a0c6c8ba`, 2026-05-26. + +728. **`claw agents list` and `agents show` JSON responses had no `path` field — callers could not determine which on-disk `.toml` file backs each agent without re-walking the same discovery directories** — dogfooded 2026-05-26 on `9757fef8`. `claw agents list --output-format json` returned `{name, description, model, source: {id, label, detail_label: null}}` with no disk path. `AgentSummary` had no `path` field; the `entry.path()` from the `fs::read_dir` loop was discarded after frontmatter parsing. Fix: added `path: Option` to `AgentSummary`; populated from `entry.path()` in the discovery loop; exposed as `"path": string|null` in `agent_summary_json`. Agents now return e.g. `{path:"/Users/.../.codex/agents/codex-ultrawork-reviewer.toml"}`. Parity gap: `skills list` still lacks `path` — tracked as a follow-on (same fix needed in `SkillSummary`). Source: Jobdori dogfood on `9757fef8`, 2026-05-26. diff --git a/rust/crates/commands/src/lib.rs b/rust/crates/commands/src/lib.rs index 22b5e555..5fa34c87 100644 --- a/rust/crates/commands/src/lib.rs +++ b/rust/crates/commands/src/lib.rs @@ -2145,6 +2145,8 @@ struct AgentSummary { reasoning_effort: Option, source: DefinitionSource, shadowed_by: Option, + // #728: on-disk path so `agents show` can surface the file path + path: Option, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -3541,6 +3543,7 @@ fn load_agents_from_roots( reasoning_effort: parse_toml_string(&contents, "model_reasoning_effort"), source: *source, shadowed_by: None, + path: Some(entry.path()), }); } root_agents.sort_by(|left, right| left.name.cmp(&right.name)); @@ -4273,6 +4276,8 @@ fn agent_summary_json(agent: &AgentSummary) -> Value { "source": definition_source_json(agent.source), "active": agent.shadowed_by.is_none(), "shadowed_by": agent.shadowed_by.map(definition_source_json), + // #728: expose on-disk path so callers can inspect the agent file directly + "path": agent.path.as_ref().map(|p| p.display().to_string()), }) }