diff --git a/crates/freshell-freshagent/src/terminal_tabs.rs b/crates/freshell-freshagent/src/terminal_tabs.rs index edeac17e2..a76e6ca67 100644 --- a/crates/freshell-freshagent/src/terminal_tabs.rs +++ b/crates/freshell-freshagent/src/terminal_tabs.rs @@ -1175,7 +1175,8 @@ pub(crate) async fn spawn_terminal_pane( amplifier_stub = Some(ensured); } Err(detail) => { - // Fail LOUD: spawning `amplifier resume ` without a + // Fail LOUD: spawning `amplifier session resume + // --full-history ` without a // resumable dir would hang a doomed CLI (the exact // failure mode this feature deletes). return Err(fail_json( @@ -3517,15 +3518,21 @@ mod tests { } /// A recording spec whose `resume_args` mirror the REAL amplifier - /// manifest (`extensions/amplifier/freshell.json`: `["resume", - /// "{{sessionId}}"]`, no `--resume` flag) so the recorded argv is the - /// launcher-assigned identity contract's exact `amplifier resume ` - /// shape (minus argv[0], which the recorder script does not capture). + /// manifest (`extensions/amplifier/freshell.json`: `["session", "resume", + /// "--full-history", "{{sessionId}}"]`) so the recorded argv is the + /// launcher-assigned identity contract's exact `amplifier session resume + /// --full-history ` shape (minus argv[0], which the recorder script + /// does not capture). fn amplifier_recording_cli_spec( argv_file: &std::path::Path, ) -> freshell_platform::CliCommandSpec { let mut spec = recording_cli_spec("amplifier", argv_file); - spec.resume_args = Some(vec!["resume".to_string(), "{{sessionId}}".to_string()]); + spec.resume_args = Some(vec![ + "session".to_string(), + "resume".to_string(), + "--full-history".to_string(), + "{{sessionId}}".to_string(), + ]); spec } @@ -3545,8 +3552,8 @@ mod tests { /// Task 11 (launcher-assigned identity, REST twin of the WS Task 8 /// contract): a fresh `POST /api/tabs {mode:"amplifier"}` mints the /// session UUID, pre-creates the on-disk stub BEFORE spawn, spawns - /// `amplifier resume `, and promotes the minted id into the - /// broadcast `paneContent.sessionRef` (EDEV-07). + /// `amplifier session resume --full-history `, and promotes the + /// minted id into the broadcast `paneContent.sessionRef` (EDEV-07). #[tokio::test] async fn create_amplifier_tab_fresh_mints_identity_prestubs_and_spawns_resume_argv() { let argv_file = unique_argv_file("amplifier-fresh"); @@ -3570,13 +3577,19 @@ mod tests { .unwrap() .is_running(&terminal_id)); - // 1) Recorded argv is exactly `resume ` (the recorder captures - // "$@" — everything after the program itself). + // 1) Recorded argv is exactly `session resume --full-history ` + // (the recorder captures "$@" — everything after the program itself). let argv = read_argv_file_eventually(&argv_file).await; let lines: Vec<&str> = argv.lines().collect(); - assert_eq!(lines.len(), 2, "expected `resume ` argv, got: {argv}"); - assert_eq!(lines[0], "resume", "argv: {argv}"); - let minted = Uuid::parse_str(lines[1]) + assert_eq!( + lines.len(), + 4, + "expected `session resume --full-history ` argv, got: {argv}" + ); + assert_eq!(lines[0], "session", "argv: {argv}"); + assert_eq!(lines[1], "resume", "argv: {argv}"); + assert_eq!(lines[2], "--full-history", "argv: {argv}"); + let minted = Uuid::parse_str(lines[3]) .expect("minted amplifier session id must parse as a Uuid") .to_string(); @@ -3644,7 +3657,8 @@ mod tests { } /// Same-id double-resume guard, REST rung: never spawn a second - /// `amplifier resume ` while a live terminal owns . + /// `amplifier session resume --full-history ` while a live terminal + /// owns . #[tokio::test] async fn create_amplifier_tab_rejects_duplicate_live_resume_with_409() { let argv_file = unique_argv_file("amplifier-dup"); diff --git a/crates/freshell-platform/src/cli_launch_goldens.rs b/crates/freshell-platform/src/cli_launch_goldens.rs index b701fb49d..6053b8ecd 100644 --- a/crates/freshell-platform/src/cli_launch_goldens.rs +++ b/crates/freshell-platform/src/cli_launch_goldens.rs @@ -750,7 +750,7 @@ fn amplifier_spec() -> CliCommandSpec { label: "Amplifier".into(), env_var: Some("AMPLIFIER_CMD".into()), default_cmd: "amplifier".into(), - resume_args: Some(s(&["resume", "{{sessionId}}"])), + resume_args: Some(s(&["session", "resume", "--full-history", "{{sessionId}}"])), base_env, ..Default::default() } @@ -791,8 +791,9 @@ fn g_a1_amplifier_fresh_launch_matches_manifest() { assert_eq!(launch.label, "Amplifier"); } -/// G-A2 — amplifier resume: `["resume", ""]` from the manifest's -/// `resumeArgs` template (first-occurrence substitution, rev 2.1 pin). +/// G-A2 — amplifier full-history resume: `["session", "resume", +/// "--full-history", ""]` from the manifest's `resumeArgs` +/// template (first-occurrence substitution, rev 2.1 pin). #[test] fn g_a2_amplifier_resume_appends_resume_args() { let mut all_specs = specs(); @@ -806,7 +807,12 @@ fn g_a2_amplifier_resume_appends_resume_args() { .unwrap(); assert_eq!( launch.args, - vec!["resume".to_string(), "sess-123".to_string()] + vec![ + "session".to_string(), + "resume".to_string(), + "--full-history".to_string(), + "sess-123".to_string(), + ] ); } @@ -848,9 +854,10 @@ fn resolve_amplifier_golden_with_intent( /// resumeArgs ONLY — `LaunchIntent::Start` with a preallocated session id /// is a hard StartIntentUnsupported error. The WS/REST pre-create paths /// therefore keep `LaunchIntent::Resume` for fresh amplifier panes -/// (`amplifier resume ` of the pre-created stub IS the fresh -/// launch). This golden pins that requirement so a future "make amplifier -/// look like claude" refactor fails loudly here instead of at runtime. +/// (`amplifier session resume --full-history ` of the pre-created stub +/// IS the fresh launch). This golden pins that requirement so a future "make +/// amplifier look like claude" refactor fails loudly here instead of at +/// runtime. #[test] fn g_a4_amplifier_start_intent_without_create_session_args_is_rejected() { let err = resolve_amplifier_golden_with_intent( @@ -866,7 +873,8 @@ fn g_a4_amplifier_start_intent_without_create_session_args_is_rejected() { } /// G-A4b: with Resume intent the SAME inputs resolve to -/// `amplifier resume ` (the manifest resumeArgs template). +/// `amplifier session resume --full-history ` (the manifest resumeArgs +/// template). #[test] fn g_a4b_amplifier_resume_intent_with_preallocated_id_resolves_resume_argv() { let cli = resolve_amplifier_golden_with_intent( @@ -876,7 +884,12 @@ fn g_a4b_amplifier_resume_intent_with_preallocated_id_resolves_resume_argv() { .unwrap(); assert_eq!( cli.args, - vec!["resume", "11111111-2222-3333-4444-555555555555"] + vec![ + "session", + "resume", + "--full-history", + "11111111-2222-3333-4444-555555555555", + ] ); } @@ -907,7 +920,7 @@ fn amplifier_manifest_matches_legacy_cli_block() { assert_eq!(cli["envVar"], "AMPLIFIER_CMD"); assert_eq!( cli["resumeArgs"], - serde_json::json!(["resume", "{{sessionId}}"]) + serde_json::json!(["session", "resume", "--full-history", "{{sessionId}}"]) ); assert_eq!( cli["env"], diff --git a/crates/freshell-server/src/existence_by_id.rs b/crates/freshell-server/src/existence_by_id.rs index 5b78cb6fa..ac9b9d464 100644 --- a/crates/freshell-server/src/existence_by_id.rs +++ b/crates/freshell-server/src/existence_by_id.rs @@ -20,7 +20,8 @@ pub enum ByIdAnswer { } /// Injected by-id amplifier session-dir check (kata 09v1 pattern: the probe -/// must agree with the attach arm — `amplifier resume ` finds the dir +/// must agree with the attach arm — `amplifier session resume +/// --full-history ` finds the dir /// regardless of index state). A closure keeps the probe unit-testable; /// precedent: `ClaudeTranscriptLocator`/`OpencodeSessionLocator`. pub type AmplifierSessionLocator = Arc ByIdAnswer + Send + Sync>; diff --git a/crates/freshell-sessions/src/amplifier_stub.rs b/crates/freshell-sessions/src/amplifier_stub.rs index 9f09bf997..e937109fe 100644 --- a/crates/freshell-sessions/src/amplifier_stub.rs +++ b/crates/freshell-sessions/src/amplifier_stub.rs @@ -1,5 +1,6 @@ //! Launcher-assigned amplifier session identity: pre-create ("stub") session -//! dirs on disk so the broker can spawn `amplifier resume ` with an +//! dirs on disk so the broker can spawn +//! `amplifier session resume --full-history ` with an //! identity it minted itself — no post-spawn correlation. //! //! Unlike [`crate::amplifier`] (read-only indexing; "never mutates provider @@ -79,7 +80,8 @@ pub fn resolve_amplifier_home() -> Option { /// slug DIFFERENT from slug(canonical cwd), plus that session's own /// metadata `working_dir`. On a divergent find the caller MUST override the /// spawn cwd with `working_dir_of_existing` (if it exists and is a dir) or -/// reject the create — `amplifier resume` only searches the spawn cwd's +/// reject the create — `amplifier session resume --full-history` only +/// searches the spawn cwd's /// slug, so spawning at the requested cwd would silently find nothing. #[derive(Debug, Clone)] pub struct EnsuredSession { @@ -89,7 +91,8 @@ pub struct EnsuredSession { pub working_dir_of_existing: Option, } -/// Make `amplifier resume ` guaranteed-resumable from `cwd` +/// Make `amplifier session resume --full-history ` +/// guaranteed-resumable from `cwd` /// BEFORE spawn. If the session dir already exists under ANY project slug /// (a real session, or a stub from a previous run), it is found and left /// untouched — with slug provenance reported (see [`EnsuredSession`]). diff --git a/crates/freshell-terminal/src/registry.rs b/crates/freshell-terminal/src/registry.rs index 63617802c..683c35204 100644 --- a/crates/freshell-terminal/src/registry.rs +++ b/crates/freshell-terminal/src/registry.rs @@ -1960,7 +1960,8 @@ impl TerminalRegistry { /// Same-id double-resume guard claim (see `resume_create_inflight`'s /// field doc): reserve a `"resume:{mode}:{sid}"` key for an in-flight - /// amplifier resume create. `false` means another create currently holds + /// resume-mode amplifier create (spawned as `amplifier session resume + /// --full-history `). `false` means another create currently holds /// it. Mirrors [`Self::begin_keyed_create`]; pair with /// [`Self::end_resume_create`]. fn begin_resume_create(&self, key: &str) -> bool { diff --git a/crates/freshell-ws/src/terminal.rs b/crates/freshell-ws/src/terminal.rs index f97c8228e..f39d50322 100644 --- a/crates/freshell-ws/src/terminal.rs +++ b/crates/freshell-ws/src/terminal.rs @@ -1420,7 +1420,8 @@ pub(crate) fn build_pty_exit_hook( // concurrent re-resume that has already passed `ensure_session` // (found our stub) but has NOT yet inserted its registry row is // invisible here — its dir can be GC'd in that sub-second window - // and its `amplifier resume ` then fails LOUDLY in-terminal; + // and its `amplifier session resume --full-history ` then fails + // LOUDLY in-terminal; // reopening the pane re-stubs the same id (ensure-after-GC). if freshell_terminal::registry::has_other_live_resume( &deps.registry.identity_probe_rows(), @@ -1510,7 +1511,8 @@ pub(crate) fn derive_launch_prep(create: &TerminalCreate, mode: &str) -> LaunchP // Launcher-assigned amplifier identity (kata qmpk), the fresh-claude // preallocation's sibling: a FRESH amplifier pane gets a // server-minted session id, and (below, in the pre-create block) a - // pre-created stub dir — `amplifier resume ` of that stub IS + // pre-created stub dir — `amplifier session resume --full-history + // ` of that stub IS // the fresh launch. CRITICAL: `launch_intent` STAYS `Resume` — // amplifier's manifest has resumeArgs only; `Start` without // createSessionArgs is a hard StartIntentUnsupported error @@ -2188,7 +2190,8 @@ pub(crate) async fn handle_create( let effective_shell = resolve_shell(shell, host_os, is_wsl); let windows_like = is_windows(host_os) || (is_wsl && effective_shell != ShellType::System); - // Amplifier pre-create (kata qmpk): make `amplifier resume ` + // Amplifier pre-create (kata qmpk): make + // `amplifier session resume --full-history ` // guaranteed-resumable BEFORE spawn. Fresh creates get a brand-new stub; // requested resumes whose dir is gone (e.g. a GC'd never-used stub from // a previous run) are re-stubbed under the SAME id so restore keeps @@ -2352,7 +2355,8 @@ pub(crate) async fn handle_create( amplifier_stub = Some(ensured); } Err(detail) => { - // Fail LOUD: spawning `amplifier resume ` without a + // Fail LOUD: spawning `amplifier session resume + // --full-history ` without a // resumable dir would hang a doomed CLI (the exact // failure mode this feature deletes). return send_create_error( diff --git a/crates/freshell-ws/tests/amplifier_launcher_identity.rs b/crates/freshell-ws/tests/amplifier_launcher_identity.rs index 1625e442a..ed99cefc4 100644 --- a/crates/freshell-ws/tests/amplifier_launcher_identity.rs +++ b/crates/freshell-ws/tests/amplifier_launcher_identity.rs @@ -110,7 +110,7 @@ async fn fresh_amplifier_create_carries_launcher_assigned_session_ref_and_stub() /// A requested amplifier RESUME whose session dir does not exist (e.g. a /// GC'd never-used stub from a previous run) is RE-STUBBED under the SAME /// id before spawn, so restore keeps working instead of hanging a doomed -/// `amplifier resume `. +/// `amplifier session resume --full-history `. #[tokio::test] async fn requested_amplifier_resume_with_missing_dir_is_restubbed_under_same_id() { let amp_home = isolate_amplifier_home(); @@ -219,7 +219,7 @@ async fn amplifier_create_with_vanished_cwd_is_rejected_before_spawn() { /// placeholder (the old correlation bug's poisoned persisted tab state) — /// never a resumable amplifier session. A create carrying one must be /// rejected LOUDLY before any stub is written, instead of spawning an -/// `amplifier resume terminal:...` that hangs forever. +/// `amplifier session resume --full-history terminal:...` that hangs forever. #[tokio::test] async fn amplifier_create_rejects_synthetic_terminal_placeholder_refs() { let amp_home = isolate_amplifier_home(); diff --git a/extensions/amplifier/freshell.json b/extensions/amplifier/freshell.json index 1344a8b4b..311e5e42b 100644 --- a/extensions/amplifier/freshell.json +++ b/extensions/amplifier/freshell.json @@ -7,7 +7,7 @@ "cli": { "command": "amplifier", "envVar": "AMPLIFIER_CMD", - "resumeArgs": ["resume", "{{sessionId}}"], + "resumeArgs": ["session", "resume", "--full-history", "{{sessionId}}"], "env": { "PROMPT_TOOLKIT_NO_CPR": "1" } }, "picker": { diff --git a/server/coding-cli/providers/amplifier.ts b/server/coding-cli/providers/amplifier.ts index b5fe5d232..01d23be02 100644 --- a/server/coding-cli/providers/amplifier.ts +++ b/server/coding-cli/providers/amplifier.ts @@ -267,7 +267,7 @@ export const amplifierProvider: CodingCliProvider = { }, getResumeArgs(sessionId: string) { - return ['resume', sessionId] + return ['session', 'resume', '--full-history', sessionId] }, parseEvent(line: string): NormalizedEvent[] { diff --git a/test/e2e-browser/fixtures/fake-amplifier-activity-cli.mjs b/test/e2e-browser/fixtures/fake-amplifier-activity-cli.mjs index bf13e9ca2..95aa37640 100644 --- a/test/e2e-browser/fixtures/fake-amplifier-activity-cli.mjs +++ b/test/e2e-browser/fixtures/fake-amplifier-activity-cli.mjs @@ -74,11 +74,13 @@ let eventsPath = null let sessionId = null let sessionDir = null -if (argv[0] === 'resume' && argv[1]) { +if (argv[0] === 'session' && argv[1] === 'resume' && argv.length > 2) { // LAUNCHER-ASSIGNED flow: adopt the broker's pre-created stub instead of // creating our own session dir (the events lane is already tailing the // stub's events.jsonl -- records written anywhere else are invisible). - sessionId = argv[1] + // Real launch shape: `session resume --full-history ` -- the session + // id is the argument after `--full-history` (i.e. the last element). + sessionId = argv[argv.length - 1] sessionDir = findSessionDir(sessionId) if (sessionDir) eventsPath = path.join(sessionDir, 'events.jsonl') process.stdout.write(`amplifier: resumed session ${sessionId}\r\n`) diff --git a/test/e2e-browser/fixtures/fake-amplifier-cli.mjs b/test/e2e-browser/fixtures/fake-amplifier-cli.mjs index 66ec38e1b..106c6eafa 100644 --- a/test/e2e-browser/fixtures/fake-amplifier-cli.mjs +++ b/test/e2e-browser/fixtures/fake-amplifier-cli.mjs @@ -67,8 +67,10 @@ function findSessionDir(sessionId) { return null } -if (argv[0] === 'resume') { - const sessionId = argv[1] ?? '' +if (argv[0] === 'session' && argv[1] === 'resume') { + // Real launch shape: `session resume --full-history ` -- the session + // id is the argument after `--full-history` (i.e. the last element). + const sessionId = argv[argv.length - 1] ?? '' process.stdout.write(`amplifier: resumed session ${sessionId}\r\n`) process.stdout.write('amplifier> \r\n') // Exit cleanly on EOF (Ctrl-D), like the real interactive CLI -- specs use diff --git a/test/e2e-browser/specs/amplifier-restore-rust.spec.ts b/test/e2e-browser/specs/amplifier-restore-rust.spec.ts index b14192663..99cd26b0a 100644 --- a/test/e2e-browser/specs/amplifier-restore-rust.spec.ts +++ b/test/e2e-browser/specs/amplifier-restore-rust.spec.ts @@ -377,12 +377,14 @@ test.describe('Amplifier Restore (Rust only)', () => { expect(await findStubDir(negativeSessionId)).not.toBeNull() // argv log: every amplifier spawn in this scenario was a resume, and - // both ids appear as `resume ` invocations post-restart. + // both ids appear as `session resume --full-history ` invocations + // post-restart. const entries = (await fs.readFile(argLogPath, 'utf8')).trim().split('\n').map((l) => JSON.parse(l) as { argv: string[] }) - const resumes = entries.filter((e) => e.argv[0] === 'resume') - expect(resumes.some((e) => e.argv[1] === sessionId)).toBe(true) - expect(resumes.some((e) => e.argv[1] === negativeSessionId)).toBe(true) - expect(entries.every((e) => e.argv[0] === 'resume')).toBe(true) + const isResume = (argv: string[]) => argv[0] === 'session' && argv[1] === 'resume' && argv[2] === '--full-history' + const resumes = entries.filter((e) => isResume(e.argv)) + expect(resumes.some((e) => e.argv[3] === sessionId)).toBe(true) + expect(resumes.some((e) => e.argv[3] === negativeSessionId)).toBe(true) + expect(entries.every((e) => isResume(e.argv))).toBe(true) // Invariant pins: the re-homed identity sweep never fires for these // launcher-assigned panes, and the boot layout canary stayed quiet. diff --git a/test/e2e-browser/specs/mcp-qa-smoke-rust.spec.ts b/test/e2e-browser/specs/mcp-qa-smoke-rust.spec.ts index 0b5ff1e64..294548dfa 100644 --- a/test/e2e-browser/specs/mcp-qa-smoke-rust.spec.ts +++ b/test/e2e-browser/specs/mcp-qa-smoke-rust.spec.ts @@ -216,7 +216,7 @@ test.describe('MCP QA smoke -- Rust full mode-matrix (QA-lever payoff)', () => { // At least TWO resume invocations of this id: the create-time spawn // and the explicit resume tab (every amplifier spawn is a resume now). const amplifierArgvLines = await readArgvLines(amplifierArgLog) - const amplifierResumeInvocations = amplifierArgvLines.filter((e) => e.argv[0] === 'resume' && e.argv[1] === amplifierSessionId) + const amplifierResumeInvocations = amplifierArgvLines.filter((e) => e.argv[0] === 'session' && e.argv[1] === 'resume' && e.argv[2] === '--full-history' && e.argv[3] === amplifierSessionId) expect(amplifierResumeInvocations.length).toBeGreaterThanOrEqual(2) // ----------------------------------------------------------------- diff --git a/test/e2e-browser/specs/remote-tab-linkage-rust.spec.ts b/test/e2e-browser/specs/remote-tab-linkage-rust.spec.ts index 49ccf8739..c516d21cb 100644 --- a/test/e2e-browser/specs/remote-tab-linkage-rust.spec.ts +++ b/test/e2e-browser/specs/remote-tab-linkage-rust.spec.ts @@ -220,10 +220,10 @@ test.describe('Remote tab linkage (Rust only)', () => { // restart proof below asserts a NEW one beyond this count). const resumesAfterCreate = await expect.poll(async () => { const lines = await readArgvLog(argLogPath) - return lines.filter((e) => e.argv[0] === 'resume' && e.argv[1] === SEEDED_SESSION_ID).length + return lines.filter((e) => e.argv[0] === 'session' && e.argv[1] === 'resume' && e.argv[2] === '--full-history' && e.argv[3] === SEEDED_SESSION_ID).length }, { timeout: 20_000 }).toBeGreaterThan(0).then(async () => { const lines = await readArgvLog(argLogPath) - return lines.filter((e) => e.argv[0] === 'resume' && e.argv[1] === SEEDED_SESSION_ID).length + return lines.filter((e) => e.argv[0] === 'session' && e.argv[1] === 'resume' && e.argv[2] === '--full-history' && e.argv[3] === SEEDED_SESSION_ID).length }) // ------------------------------------------------------------------ @@ -315,7 +315,7 @@ test.describe('Remote tab linkage (Rust only)', () => { // invocation beyond the create-time one(s). await expect.poll(async () => { const lines = await readArgvLog(argLogPath) - return lines.filter((e) => e.argv[0] === 'resume' && e.argv[1] === SEEDED_SESSION_ID).length + return lines.filter((e) => e.argv[0] === 'session' && e.argv[1] === 'resume' && e.argv[2] === '--full-history' && e.argv[3] === SEEDED_SESSION_ID).length }, { timeout: 30_000 }).toBeGreaterThan(resumesAfterCreate) // And the linkage itself survived: the sidebar row is OPEN again diff --git a/test/e2e-browser/specs/sidebar-click-resume.spec.ts b/test/e2e-browser/specs/sidebar-click-resume.spec.ts index 0fe2fd4cd..313e0335a 100644 --- a/test/e2e-browser/specs/sidebar-click-resume.spec.ts +++ b/test/e2e-browser/specs/sidebar-click-resume.spec.ts @@ -387,14 +387,15 @@ test.describe('Sidebar Click Resume', () => { return typeof buffer === 'string' && buffer.includes(`amplifier: resumed session ${AMPLIFIER_SESSION_ID}`) }, { timeout: 20_000 }).toBe(true) + const isAmplifierResume = (argv: string[]) => argv[0] === 'session' && argv[1] === 'resume' && argv[2] === '--full-history' const resumeInvocations = (await expect.poll(async () => { const lines = await readArgvLog(argLogPath) - return lines.filter((entry) => entry.argv[0] === 'resume') + return lines.filter((entry) => isAmplifierResume(entry.argv)) }, { timeout: 20_000 }).not.toEqual([]).then(async () => { const lines = await readArgvLog(argLogPath) - return lines.filter((entry) => entry.argv[0] === 'resume') + return lines.filter((entry) => isAmplifierResume(entry.argv)) })) - expect(resumeInvocations.some((entry) => entry.argv[1] === AMPLIFIER_SESSION_ID)).toBe(true) + expect(resumeInvocations.some((entry) => entry.argv[3] === AMPLIFIER_SESSION_ID)).toBe(true) } finally { await server.stop().catch(() => {}) } diff --git a/test/e2e-browser/specs/terminal-activity-rust.spec.ts b/test/e2e-browser/specs/terminal-activity-rust.spec.ts index 801c6d496..0b24adc88 100644 --- a/test/e2e-browser/specs/terminal-activity-rust.spec.ts +++ b/test/e2e-browser/specs/terminal-activity-rust.spec.ts @@ -448,7 +448,7 @@ test.describe('Terminal-mode CLI activity (Rust only)', () => { expect(complete.provider).toBe('amplifier') expect(complete.completionSeq).toBe(1) // The completion carries the BROKER-MINTED session id (launcher- - // assigned identity: the pane was spawned `resume ` against the + // assigned identity: the pane was spawned `session resume --full-history ` against the // pre-created stub), never a fixture-invented `fake-amp-*` id. expect(String(complete.sessionId ?? '')).toMatch(UUID_RE) diff --git a/test/integration/real/amplifier-stub-adoption-contract.test.ts b/test/integration/real/amplifier-stub-adoption-contract.test.ts index 17159c058..f3f491130 100644 --- a/test/integration/real/amplifier-stub-adoption-contract.test.ts +++ b/test/integration/real/amplifier-stub-adoption-contract.test.ts @@ -3,9 +3,10 @@ // Real Amplifier stub-adoption contract (launcher-assigned session identity). // // The Rust broker pre-creates ~/.amplifier/projects//sessions// -// stubs and spawns `amplifier resume `. This test pins the two external -// contracts that path rests on, against the REAL CLI: -// 1. STUB ADOPTION: `amplifier resume ` of a pre-created stub is +// stubs and spawns `amplifier session resume --full-history `. This test +// pins the two external contracts that path rests on, against the REAL CLI: +// 1. STUB ADOPTION: `amplifier session resume --full-history ` of a +// pre-created stub is // accepted (not rejected like an unknown id), the metadata survives in // place, and custom keys (freshell_terminal_id) are preserved. // Adoption also implicitly proves the slug: amplifier only searches the @@ -107,9 +108,9 @@ async function writeStub(home: string, resolvedCwd: string, sessionId: string): return dir } -// Spawn `amplifier resume ` (interactive), collect combined output for -// up to timeoutMs, then SIGTERM. We never make a turn — a zero-turn resume -// is the validated adoption shape. Resolves the output PLUS exit semantics: +// Spawn `amplifier session resume --full-history ` (interactive), collect +// combined output for up to timeoutMs, then SIGTERM. We never make a turn — a +// zero-turn resume is the validated adoption shape. Resolves the output PLUS exit semantics: // `exitedBeforeTimeout` distinguishes a self-exiting rejection (validated: // exit 1 in ~1-2s, before bundle/provider init) from an adoption that stays // interactive until OUR SIGTERM. timeoutMs must absorb the first run's @@ -120,7 +121,7 @@ function runResume( opts: { home: string; cwd: string; timeoutMs: number }, ): Promise<{ output: string; exitedBeforeTimeout: boolean }> { return new Promise((resolve) => { - const child = spawn(cli.command, [...cli.baseArgs, 'resume', sessionId], { + const child = spawn(cli.command, [...cli.baseArgs, 'session', 'resume', '--full-history', sessionId], { cwd: opts.cwd, // VALIDATED (V1): HOME is the isolation lever — session storage is // hardcoded to $HOME/.amplifier; AMPLIFIER_HOME would isolate nothing diff --git a/test/server/amplifier-session-association.test.ts b/test/server/amplifier-session-association.test.ts index b1ed8420d..3edf1dc5f 100644 --- a/test/server/amplifier-session-association.test.ts +++ b/test/server/amplifier-session-association.test.ts @@ -90,7 +90,7 @@ const COMMAND_SPECS: Array<[string, CodingCliCommandSpec]> = [ label: 'Amplifier', envVar: 'AMPLIFIER_CMD', defaultCommand: 'amplifier', - resumeArgs: (sessionId: string) => ['resume', sessionId], + resumeArgs: (sessionId: string) => ['session', 'resume', '--full-history', sessionId], }], ] diff --git a/test/unit/server/coding-cli/amplifier-provider.test.ts b/test/unit/server/coding-cli/amplifier-provider.test.ts index 445a41e1f..34c936678 100644 --- a/test/unit/server/coding-cli/amplifier-provider.test.ts +++ b/test/unit/server/coding-cli/amplifier-provider.test.ts @@ -117,8 +117,8 @@ describe('amplifier-provider', () => { ).toBe('abcd-1234') }) - it('getResumeArgs builds resume args', () => { - expect(amplifierProvider.getResumeArgs('abc')).toEqual(['resume', 'abc']) + it('getResumeArgs builds full-history session resume args', () => { + expect(amplifierProvider.getResumeArgs('abc')).toEqual(['session', 'resume', '--full-history', 'abc']) }) it('getStreamArgs returns a default run invocation', () => {