mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-05-30 03:35:20 +08:00
fix(#769): claw session <arg> now returns interactive_only instead of falling to credential check
This commit is contained in:
parent
b778d4e3d4
commit
9e1be05634
@ -7703,3 +7703,5 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
|
|||||||
767. **`claw session bogus --output-format json` ignores JSON flag and falls through to credential check** — dogfooded 2026-05-27 on `d29a8e21`. `claw --output-format json session bogus` dispatches to the full interactive REPL runtime instead of rejecting `bogus` as an unknown session subcommand. Output is `error_kind:"missing_credentials"` rather than `error_kind:"unknown_session_subcommand"`. Root cause: `session` arg parser has no unknown-subcommand guard before dispatch; `bogus` is silently accepted as a session ID / switch target and reaches the credential-check gate. Fix needed: validate known session subcommands (`list`, `exists`, `switch`, `fork`, `delete`) before dispatch, return structured `unknown_session_subcommand` error for unrecognized tokens. [SCOPE: claw-code] Source: Jobdori probe on `d29a8e21`, 2026-05-27.
|
767. **`claw session bogus --output-format json` ignores JSON flag and falls through to credential check** — dogfooded 2026-05-27 on `d29a8e21`. `claw --output-format json session bogus` dispatches to the full interactive REPL runtime instead of rejecting `bogus` as an unknown session subcommand. Output is `error_kind:"missing_credentials"` rather than `error_kind:"unknown_session_subcommand"`. Root cause: `session` arg parser has no unknown-subcommand guard before dispatch; `bogus` is silently accepted as a session ID / switch target and reaches the credential-check gate. Fix needed: validate known session subcommands (`list`, `exists`, `switch`, `fork`, `delete`) before dispatch, return structured `unknown_session_subcommand` error for unrecognized tokens. [SCOPE: claw-code] Source: Jobdori probe on `d29a8e21`, 2026-05-27.
|
||||||
|
|
||||||
768. **`claw --resume latest compact` returned `error_kind:"unknown"` + `hint:null`** — dogfooded 2026-05-27 on `89735dbd` (gaebal-gajae pinpoint against `d29a8e21`, revised ID after #766/#767 landed). Resume trailing-arg validator emitted single-line `"--resume trailing arguments must be slash commands"` with no typed prefix and no `\n` hint. Fix: (1) changed error to `"invalid_resume_argument: \`{token}\` is not a slash command.\nUsage: claw --resume <session-id|latest> /<slash-command>"` so `split_error_hint()` extracts the hint; (2) added `invalid_resume_argument` classifier arm; (3) unit test assertion + integration test `resume_non_slash_trailing_arg_has_typed_error_kind_and_hint_768` added. 34 CLI contract tests pass. [SCOPE: claw-code] Source: Gaebal-gajae + Jobdori probe on `89735dbd`, 2026-05-27.
|
768. **`claw --resume latest compact` returned `error_kind:"unknown"` + `hint:null`** — dogfooded 2026-05-27 on `89735dbd` (gaebal-gajae pinpoint against `d29a8e21`, revised ID after #766/#767 landed). Resume trailing-arg validator emitted single-line `"--resume trailing arguments must be slash commands"` with no typed prefix and no `\n` hint. Fix: (1) changed error to `"invalid_resume_argument: \`{token}\` is not a slash command.\nUsage: claw --resume <session-id|latest> /<slash-command>"` so `split_error_hint()` extracts the hint; (2) added `invalid_resume_argument` classifier arm; (3) unit test assertion + integration test `resume_non_slash_trailing_arg_has_typed_error_kind_and_hint_768` added. 34 CLI contract tests pass. [SCOPE: claw-code] Source: Gaebal-gajae + Jobdori probe on `89735dbd`, 2026-05-27.
|
||||||
|
|
||||||
|
769. **`claw session bogus` fell through to credential check instead of interactive-only guidance** — dogfooded 2026-05-27 on `b778d4e3` (tracked as #767). `claw session <anything>` with more than one token bypassed `parse_single_word_command_alias` (which only fires for `rest.len()==1`) and had no match arm in `parse_args`, so `rest.join(" ")` became a prompt literal dispatched to `CliAction::Prompt`, hitting `missing_credentials` at the gate. Fix: added `"session"` match arm that emits `interactive_only:` error with `\n`-delimited hint referencing `--resume SESSION.jsonl /session` and REPL usage. Integration test `session_with_unknown_subcommand_returns_interactive_only_not_credentials_767` asserts `error_kind:interactive_only` + non-null hint for `bogus`, `nuke`, `delete-all`. 35 CLI contract tests pass. [SCOPE: claw-code] Source: Jobdori probe on `b778d4e3`, 2026-05-27.
|
||||||
|
|||||||
@ -1166,6 +1166,15 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
|
|||||||
"`claw permissions` is a slash command. Start `claw` and run `/permissions` inside the REPL.\n Usage /permissions [read-only|workspace-write|danger-full-access]"
|
"`claw permissions` is a slash command. Start `claw` and run `/permissions` inside the REPL.\n Usage /permissions [read-only|workspace-write|danger-full-access]"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
|
// #767: `claw session bogus` bypassed parse_single_word_command_alias (rest.len()>1),
|
||||||
|
// had no match arm, and fell to CliAction::Prompt — reaching the credential gate
|
||||||
|
// instead of a structured error. Mirror the guard on `permissions`.
|
||||||
|
"session" => {
|
||||||
|
let action_hint = rest.get(1).map_or(String::new(), |a| format!(" (got: `{a}`)" ));
|
||||||
|
Err(format!(
|
||||||
|
"interactive_only: `claw session` is a slash command{action_hint}.\nUse `claw --resume SESSION.jsonl /session <action>` or start `claw` and run `/session [list|exists|switch|fork|delete]`."
|
||||||
|
))
|
||||||
|
}
|
||||||
"skills" => {
|
"skills" => {
|
||||||
let args = join_optional_args(&rest[1..]);
|
let args = join_optional_args(&rest[1..]);
|
||||||
if let Some(action) = args.as_deref() {
|
if let Some(action) = args.as_deref() {
|
||||||
|
|||||||
@ -1980,3 +1980,42 @@ fn resume_non_slash_trailing_arg_has_typed_error_kind_and_hint_768() {
|
|||||||
"hint must reference slash-command usage, got: {hint:?}"
|
"hint must reference slash-command usage, got: {hint:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn session_with_unknown_subcommand_returns_interactive_only_not_credentials_767() {
|
||||||
|
// #767: `claw session bogus` bypassed all guards and fell through to
|
||||||
|
// CliAction::Prompt, reaching the credential-check gate and returning
|
||||||
|
// error_kind:"missing_credentials" instead of a structured routing error.
|
||||||
|
// Fix: explicit "session" match arm returns interactive_only guidance.
|
||||||
|
let root = unique_temp_dir("session-unknown-767");
|
||||||
|
fs::create_dir_all(&root).expect("temp dir should exist");
|
||||||
|
|
||||||
|
for sub in &["bogus", "nuke", "delete-all"] {
|
||||||
|
let output = run_claw(&root, &["--output-format", "json", "session", sub], &[]);
|
||||||
|
assert!(
|
||||||
|
!output.status.success(),
|
||||||
|
"claw session {sub} should exit non-zero"
|
||||||
|
);
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let json_line = stderr
|
||||||
|
.lines()
|
||||||
|
.find(|l| l.trim_start().starts_with('{'))
|
||||||
|
.unwrap_or_else(|| panic!("claw session {sub} stderr should contain JSON"));
|
||||||
|
let parsed: serde_json::Value =
|
||||||
|
serde_json::from_str(json_line).expect("error envelope should be valid JSON");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parsed["error_kind"], "interactive_only",
|
||||||
|
"claw session {sub} must return error_kind:interactive_only (#767), not missing_credentials"
|
||||||
|
);
|
||||||
|
let hint = parsed["hint"].as_str().unwrap_or("");
|
||||||
|
assert!(
|
||||||
|
!hint.is_empty(),
|
||||||
|
"claw session {sub} must return non-null hint (#767)"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
hint.contains("/session") || hint.contains("--resume"),
|
||||||
|
"hint must reference /session usage, got: {hint:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user