mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-05-30 03:35:20 +08:00
fix(#785): add unknown_subcommand classifier arm for unknown subcommand: prose prefix
This commit is contained in:
parent
e628b4bb68
commit
87f4334728
@ -7735,3 +7735,5 @@ 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.
|
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.
|
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` (typo/near-miss for dump-manifests) returned `error_kind:"unknown"` — no classifier arm for `"unknown subcommand:"` prose prefix** — dogfooded 2026-05-27 on `e628b4bb`. Any unknown top-level subcommand that triggers the suggestion path emitted `"unknown subcommand: <x>.\nDid you mean <y>"` but `classify_error_kind` had no arm for that prefix; all fell to the `"unknown"` catch-all. The hint was non-null (the suggestion text was extracted by `split_error_hint`) but `error_kind` was undifferentiated. Fix: added `starts_with("unknown subcommand:")` → `"unknown_subcommand"` arm. Unit test assertion + integration test `unknown_subcommand_returns_typed_kind_785` using `claw dump` as the trigger. 44 CLI contract tests pass. [SCOPE: claw-code] Source: Jobdori subcommand-classifier probe on `e628b4bb`, 2026-05-27.
|
||||||
|
|||||||
@ -349,6 +349,9 @@ fn classify_error_kind(message: &str) -> &'static str {
|
|||||||
} else if message.contains("has been removed.") {
|
} else if message.contains("has been removed.") {
|
||||||
// #765: removed subcommands (login, logout) — hint contains migration guidance
|
// #765: removed subcommands (login, logout) — hint contains migration guidance
|
||||||
"removed_subcommand"
|
"removed_subcommand"
|
||||||
|
} else if message.starts_with("unknown subcommand:") {
|
||||||
|
// #785: typo/unknown top-level subcommand (e.g. `claw dump` → did you mean dump-manifests?)
|
||||||
|
"unknown_subcommand"
|
||||||
} else if message.starts_with("unexpected extra arguments")
|
} else if message.starts_with("unexpected extra arguments")
|
||||||
|| message.starts_with("unexpected_extra_args:")
|
|| message.starts_with("unexpected_extra_args:")
|
||||||
{
|
{
|
||||||
@ -13009,6 +13012,11 @@ mod tests {
|
|||||||
classify_error_kind("unrecognized argument `--foo` for subcommand `doctor`"),
|
classify_error_kind("unrecognized argument `--foo` for subcommand `doctor`"),
|
||||||
"cli_parse"
|
"cli_parse"
|
||||||
);
|
);
|
||||||
|
// #785: unknown top-level subcommand (typo or unrecognised command)
|
||||||
|
assert_eq!(
|
||||||
|
classify_error_kind("unknown subcommand: dump.\nDid you mean dump-manifests"),
|
||||||
|
"unknown_subcommand"
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
classify_error_kind("unsupported ACP invocation. Use `claw acp`."),
|
classify_error_kind("unsupported ACP invocation. Use `claw acp`."),
|
||||||
"unsupported_acp_invocation"
|
"unsupported_acp_invocation"
|
||||||
|
|||||||
@ -2502,3 +2502,38 @@ fn export_arg_errors_have_typed_kind_and_hint_784() {
|
|||||||
"hint must reference export usage, got: {h2:?}"
|
"hint must reference export usage, got: {h2:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unknown_subcommand_returns_typed_kind_785() {
|
||||||
|
// #785: `claw dump` (a near-miss for dump-manifests) returned error_kind:"unknown"
|
||||||
|
// because the classifier had no arm for "unknown subcommand:" prose prefix.
|
||||||
|
// Fix: added "unknown_subcommand" arm in classify_error_kind.
|
||||||
|
let root = unique_temp_dir("unknown-subcommand-785");
|
||||||
|
fs::create_dir_all(&root).expect("temp dir");
|
||||||
|
std::process::Command::new("git")
|
||||||
|
.args(["init", "-q"])
|
||||||
|
.current_dir(&root)
|
||||||
|
.output()
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
// "dump" is close enough to "dump-manifests" to trigger the typo suggestion path
|
||||||
|
let output = run_claw(&root, &["--output-format", "json", "dump"], &[]);
|
||||||
|
assert!(!output.status.success(), "unknown subcommand should fail");
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let j: serde_json::Value = stderr
|
||||||
|
.lines()
|
||||||
|
.find(|l| l.trim_start().starts_with('{'))
|
||||||
|
.and_then(|l| serde_json::from_str(l).ok())
|
||||||
|
.expect("unknown subcommand should emit JSON error");
|
||||||
|
assert_eq!(
|
||||||
|
j["error_kind"], "unknown_subcommand",
|
||||||
|
"unknown subcommand should return unknown_subcommand kind, got {:?}",
|
||||||
|
j["error_kind"]
|
||||||
|
);
|
||||||
|
// hint should point at the suggestion and/or --help
|
||||||
|
let hint = j["hint"].as_str().unwrap_or("");
|
||||||
|
assert!(
|
||||||
|
hint.contains("dump-manifests") || hint.contains("--help") || hint.contains("claw"),
|
||||||
|
"hint should reference the suggested subcommand or help, got: {hint:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user