Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -7735,3 +7735,6 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
783. **`claw --output-format json init` success envelope was missing `hint` field; idempotent re-init was not structurally detectable** — dogfooded 2026-05-27 on `32c9276f`. The init JSON envelope had no `hint` field (absent, not null), and no field to distinguish a fresh init from a re-init without checking `created.len() == 0`. Orchestrators had to inspect `created` array length to detect idempotent behavior. Fix: (1) added `hint` field to init JSON envelope — fresh path points at `CLAUDE.md + doctor`; idempotent path says "already initialised, run doctor"; (2) added `already_initialized: bool` field — `true` when `created` and `updated` are both empty (all artifacts skipped). Both test cases (fresh + re-init) covered by `init_json_envelope_has_hint_and_already_initialized_783`. 42 CLI contract tests pass. [SCOPE: claw-code] Source: Jobdori init-envelope probe on `32c9276f`, 2026-05-27.

784. **`claw export` had two opaque arg-error paths returning `error_kind:"unknown"` + `hint:null`** — dogfooded 2026-05-27 on `81fe0ccb` (pinpoint by Gaebal-gajae). `claw export --output` (missing flag value) emitted plain `"missing value for --output"` with no typed prefix; `claw export a.md b.md` (extra positional) emitted plain `"unexpected export argument: second.md"`. Both classified as `unknown+null`. Fix: (1) `--output` missing-value error now uses `missing_flag_value:` prefix + `\n` usage hint; (2) extra positional now uses `unexpected_extra_args:` prefix + `\n` usage hint; (3) classifier `unexpected_extra_args` arm extended to match both `starts_with("unexpected extra arguments")` (prose form, #766) and `starts_with("unexpected_extra_args:")` (typed prefix form, #784). Integration test `export_arg_errors_have_typed_kind_and_hint_784` covers both paths. 43 CLI contract tests pass. [SCOPE: claw-code] Source: Gaebal-gajae pinpoint + Jobdori implementation on `81fe0ccb`, 2026-05-27.


785. **`claw dump-manifests --manifests-dir` missing-value errors were untyped/no-hint** — dogfooded 2026-05-27 on `e628b4bb`. `claw dump-manifests --manifests-dir --output-format json` and `claw dump-manifests --manifests-dir= --output-format json` emitted plain `--manifests-dir requires a path`; both classified as `error_kind:"unknown"` with `hint:null`. Manifest dumping is an automation/bootstrap surface, so callers need a stable `missing_flag_value` instead of regexing prose. Fix: changed both missing path branches to `missing_flag_value:` + newline usage hint. Regression guard: `dump_manifests_missing_dir_has_typed_kind_and_hint_785`. [SCOPE: claw-code] Source: gaebal-gajae manifest-bootstrap dogfood probe on `e628b4bb`, 2026-05-27.
4 changes: 2 additions & 2 deletions rust/crates/rusty-claude-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2156,14 +2156,14 @@ fn parse_dump_manifests_args(
if arg == "--manifests-dir" {
let value = args
.get(index + 1)
.ok_or_else(|| String::from("--manifests-dir requires a path"))?;
.ok_or_else(|| String::from("missing_flag_value: --manifests-dir requires a path.\nUsage: claw dump-manifests --manifests-dir <path>"))?;
manifests_dir = Some(PathBuf::from(value));
index += 2;
continue;
}
if let Some(value) = arg.strip_prefix("--manifests-dir=") {
if value.is_empty() {
return Err(String::from("--manifests-dir requires a path"));
return Err(String::from("missing_flag_value: --manifests-dir requires a path.\nUsage: claw dump-manifests --manifests-dir <path>"));
}
manifests_dir = Some(PathBuf::from(value));
index += 1;
Expand Down
52 changes: 52 additions & 0 deletions rust/crates/rusty-claude-cli/tests/output_format_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2216,6 +2216,58 @@ fn interactive_only_guard_batch_769_to_771() {
}
}

#[test]
fn dump_manifests_missing_dir_has_typed_kind_and_hint_785() {
// #785: dump-manifests had two stale single-line --manifests-dir errors.
// JSON callers got error_kind:"unknown" + hint:null instead of a typed
// missing_flag_value they can route without prose scraping.
let root = unique_temp_dir("dump-manifests-missing-dir-785");
fs::create_dir_all(&root).expect("temp dir should exist");

let cases: &[&[&str]] = &[
&[
"--output-format",
"json",
"dump-manifests",
"--manifests-dir",
],
&[
"--output-format",
"json",
"dump-manifests",
"--manifests-dir=",
],
];

for args in cases {
let output = run_claw(&root, args, &[]);
assert!(
!output.status.success(),
"claw {} should exit non-zero",
args.join(" ")
);
let stderr = String::from_utf8_lossy(&output.stderr);
let json_line = stderr
.lines()
.find(|l| l.trim_start().starts_with('{'))
.unwrap_or_else(|| panic!("stderr should contain JSON for {:?}, got: {stderr}", args));
let parsed: serde_json::Value = serde_json::from_str(json_line)
.expect("dump-manifests arg error envelope should be valid JSON");
assert_eq!(
parsed["error_kind"], "missing_flag_value",
"claw {:?} must return missing_flag_value (#785): {parsed}",
args
);
assert!(
parsed["hint"]
.as_str()
.map_or(false, |h| h.contains("dump-manifests")),
"claw {:?} must expose dump-manifests usage hint (#785): {parsed}",
args
);
}
}

#[test]
fn resume_plugin_mutations_are_typed_interactive_only_777() {
// #777: `/plugins install|enable|disable|uninstall|update` in resume mode returned
Expand Down