@lucascouts/claude-agent-tui 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,16 @@ An [ACP](https://agentclientprotocol.com)-compatible agent that drives the **Cla
6
6
 
7
7
  > **Fork** of [`@agentclientprotocol/claude-agent-acp`](https://github.com/agentclientprotocol/claude-agent-acp) v0.39.0. Where the upstream adapter calls the Claude Agent **SDK**, this fork spawns the `claude` **subscription CLI** in a pseudo-terminal and translates its JSONL transcript into ACP `session/update` notifications. See [`.fork-provenance.json`](.fork-provenance.json) for the exact fork point.
8
8
 
9
+ ## Why this exists
10
+
11
+ On **June 15, 2026**, [Anthropic split Claude subscription billing](https://zed.dev/blog/anthropic-subscription-changes) into two pools: Anthropic's **first-party tools** (chat and the official **Claude Code CLI**) keep using your **Pro/Max subscription**, while **third-party agents and SDK usage** are billed separately at **API rates** — roughly **15–30× more expensive** (separate monthly credits: $20 Pro / $100 Max 5x / $200 Max 20x).
12
+
13
+ In practice, Zed's built-in Claude integration now draws from those expensive third-party credits instead of your subscription. The official `claude` CLI/TUI, however, **still runs on your subscription**.
14
+
15
+ This project bridges the two: it drives the **official Claude Code TUI** over a PTY and exposes it through the **ACP** protocol, so Zed renders it as a native agent panel — giving you the full Claude Code experience inside Zed **on your existing subscription**, not API credits.
16
+
17
+ > Not affiliated with or endorsed by Anthropic or Zed Industries. Use of the `claude` CLI remains subject to Anthropic's terms.
18
+
9
19
  ## Requirements
10
20
 
11
21
  - The **`claude` CLI** (Claude Code subscription) available on your `PATH`.
@@ -45,6 +55,22 @@ npm test
45
55
  - Token-usage updates
46
56
  - Prompt input, cancellation, and session load/replay
47
57
 
58
+ ## Supply-chain notes
59
+
60
+ [Socket](https://socket.dev/npm/package/@lucascouts/claude-agent-tui) flags some
61
+ dependency alerts (`Native code`, `Install scripts`, `Shell access`, plus
62
+ heuristic flags on the Anthropic SDK tree). **None are CVEs or malware** — they
63
+ are expected capability flags:
64
+
65
+ - `node-pty` (the same PTY that powers VS Code) needs `Native code` /
66
+ `Install scripts` / `Shell access` — driving the `claude` TUI in a real PTY is
67
+ the whole point of this bridge.
68
+ - The remaining flags come from the minified bundles inside
69
+ `@anthropic-ai/claude-agent-sdk`, of which this fork uses only two pure,
70
+ billing-free functions (`getSessionMessages`, `resolveSettings`).
71
+
72
+ All direct dependencies are first-party publishers (Microsoft, Anthropic, Zed).
73
+
48
74
  ## License
49
75
 
50
76
  [Apache-2.0](LICENSE). This is a derivative work; original copyright belongs to Zed Industries and the Agent Client Protocol authors.
@@ -97,6 +97,28 @@ type Session = {
97
97
  * once and a prior turn's terminal boundary is never re-observed.
98
98
  */
99
99
  detectorCursor?: number;
100
+ /**
101
+ * Story 046 (R1.3, design §5/§9) — a model-switch (`/model <alias>`) requested WHILE a turn is in
102
+ * flight is deferred here (last-write-wins, §9 coalescing) and flushed as a side-channel PTY write
103
+ * once the turn settles (prompt()'s finally → {@link flushPendingControlInjections}). Undefined when
104
+ * nothing is queued.
105
+ */
106
+ pendingModelInjection?: string;
107
+ /**
108
+ * Story 046 (R3.8) — true WHILE an in-place re-spawn (R3.4 dontAsk/bypass switch) is between the old
109
+ * PTY teardown and the new PTY being ready. Selector changes arriving in this window are rejected
110
+ * rather than written to a dead PTY.
111
+ */
112
+ respawning?: boolean;
113
+ /**
114
+ * Story 046 (R3.4 LIVE FIX) — true once the session's transcript has materialised (the watcher armed
115
+ * and pumped at least once, i.e. the FIRST interaction happened). An in-place re-spawn reattaches via
116
+ * `claude --resume <id>`, which needs that transcript to exist; before it, --resume falls back
117
+ * (buildResumeArgv `|| claude`) to a NEW untracked id and stalls. {@link respawnSession} refuses while
118
+ * this is falsy — a boot-time default_config_options dontAsk/bypass stays at the fresh spawn's mode
119
+ * until the user sends the first prompt.
120
+ */
121
+ interacted?: boolean;
100
122
  /**
101
123
  * Story 034 (§9 / R3.3) — the per-session HYBRID permission-gate runtime: loopback `PreToolUse`
102
124
  * hook server + scratch `--settings` backup + `tool_use.id` correlator. Present only when the
@@ -186,6 +208,28 @@ export interface StartEngineArgs {
186
208
  * (`buildResumeArgv`) is NOT extended here; the replay-only load path spawns nothing.
187
209
  */
188
210
  settingsFile?: string;
211
+ /**
212
+ * Story 046 (R3.2, choose-before-start): the seeded permission mode, forwarded to the spawn as
213
+ * `--permission-mode <mode>` (non-"default" only). Threaded to BOTH the fresh ({@link
214
+ * createSessionEngine}) and resume ({@link spawnResumePty}) paths so the R3.4 re-spawn carries it too.
215
+ */
216
+ permissionMode?: string;
217
+ /**
218
+ * Story 046 (R2.2): the seeded/re-spawn reasoning effort, forwarded to the spawn as `--effort
219
+ * <level>` (non-"default" only). Threaded to BOTH the fresh and resume spawn paths.
220
+ */
221
+ effortLevel?: string;
222
+ /**
223
+ * Story 046 (R3.4 LIVE FIX): this resume is an IN-PLACE re-spawn ({@link respawnSession} for a
224
+ * dontAsk/bypass mode or an effort change), NOT a fork/resume of an already-lived session. An
225
+ * in-place re-spawn can fire BEFORE the first interaction (e.g. a boot-time `bypassPermissions`
226
+ * switch driven by Zed's `default_config_options`), when the re-spawned `claude` has NOT written its
227
+ * transcript yet. So this branch DEFERS discovery like the fresh path (`watchdogMs: Infinity`,
228
+ * arm-on-appearance) instead of the resume default's 2000ms FATAL watchdog — which would otherwise
229
+ * throw not-found and stall the next turn until the 120s turn watchdog. The fork/resume path (flag
230
+ * absent) keeps its blocking 2000ms watchdog (R2.1, resume-discovery-unchanged.test.ts).
231
+ */
232
+ inPlaceRespawn?: boolean;
189
233
  }
190
234
  /** The createSession injection seam: spawn the PTY engine + JSONL watcher + locate the transcript. */
191
235
  export type StartEngine = (args: StartEngineArgs) => Promise<StartedEngine> | StartedEngine;
@@ -446,7 +490,89 @@ export declare class ClaudeAcpAgent implements Agent {
446
490
  unstable_deleteSession(params: DeleteSessionRequest): Promise<DeleteSessionResponse>;
447
491
  setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse>;
448
492
  setSessionConfigOption(params: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse>;
493
+ /**
494
+ * Story 046 (R3, Bug A fix) — drive a permission-mode change INTO the claude TUI (the load-bearing
495
+ * half). Cyclable modes (default/acceptEdits/plan/auto) drive via closed-loop Shift+Tab; dontAsk/
496
+ * bypassPermissions re-spawn with `--permission-mode`. Idle-guarded (R3.8); a no-op change applies
497
+ * nothing. SHARED by setSessionMode AND setSessionConfigOption(configId:"mode") — Zed sends mode
498
+ * changes via the latter, so the driving MUST live on both paths (it previously lived only on
499
+ * setSessionMode, while the config-option path was read-only → claude stuck on its spawn mode). The
500
+ * caller has already validated `target` via {@link applySessionMode}.
501
+ */
502
+ private driveModeIntoTui;
449
503
  private applySessionMode;
504
+ /**
505
+ * Story 046 (R1.2–R1.4, design §5) — apply a live model switch by injecting `/model <alias>` into
506
+ * the PTY as a SIDE-CHANNEL write. `/model` is a local TUI command: no assistant turn, no
507
+ * stop_reason — so it is NEVER routed through prompt()/createTurnResolver (that would hang) and
508
+ * never sets turnDetector (R1.4). The write goes through sendPrompt for its Ctrl+U input-clear but
509
+ * with a SYNCHRONOUS schedule so the command + `\r` commit immediately (resolves now; it awaits no
510
+ * turn). Idle-guard: inject only when no turn is in flight; otherwise defer (last-write-wins, §9)
511
+ * and flush when the turn settles (R1.3).
512
+ */
513
+ private applyModelSwitch;
514
+ /**
515
+ * Side-channel `/model <alias>` write — synchronous, resolves immediately (never a turn). claude
516
+ * 2.1.176 (GrowthBook `tengu_immediate_model_command=false`) does NOT apply `/model` inline mid-
517
+ * conversation: it opens a blocking **"Switch model?" → 1. Yes / 2. No** dialog and leaves it OPEN.
518
+ * Unconfirmed, the dialog survives until the NEXT prompt — whose `\r` then confirms the switch AND
519
+ * discards the prompt text, so no turn is born and the story-024 stall watchdog trips (the live
520
+ * 39a93bfc hang; root cause proved headless by experiments/probe-c-model-then-prompt.mjs). So after
521
+ * the command we schedule ONE Enter to accept the default "Yes, switch" once the dialog has rendered;
522
+ * if no dialog appears (same model / flag flipped on) Enter-on-empty-input is a harmless no-op.
523
+ */
524
+ private injectModelCommand;
525
+ /**
526
+ * Story 046 (R1.3) — flush a deferred model-switch once the session is idle again (called from
527
+ * prompt()'s finally, the moment the turn settles). Last-write-wins: only the most recent queued
528
+ * alias is injected; the field is cleared so a settled session with nothing queued injects nothing.
529
+ */
530
+ private flushPendingControlInjections;
531
+ /**
532
+ * Story 046 (R3.3, design §6b) — drive the TUI to `target` with closed-loop raw Shift+Tab. Writes
533
+ * `\x1b[Z` DIRECTLY to the PTY (NOT sendPrompt — its Ctrl+U clear corrupts the escape), then awaits
534
+ * the confirming `permission-mode` transcript event (the tail-as-truth fence: mode is read from the
535
+ * transcript, NEVER from p.onData). A per-step Δt budget + a one-full-cycle safety stop guarantee the
536
+ * loop ABORTS rather than hangs/false-stalls (Probe A gated this; story-044 awareness).
537
+ */
538
+ private driveCyclableMode;
539
+ /**
540
+ * Story 046 (R3.3) — poll the transcript (the pump's getMessages seam) for a `permission-mode` event
541
+ * whose mode differs from `before`, up to MODE_CYCLE_STEP_TIMEOUT_MS. Returns the new mode, or
542
+ * undefined on the Δt timeout (the caller aborts rather than hangs). The confirming event is usually
543
+ * already present right after the TUI processes the keystroke, so this returns at once in tests.
544
+ */
545
+ private awaitModeChange;
546
+ /** Story 046 (R3.3/R4.1) — the most recent `permission-mode` event's mode from the transcript (the
547
+ * same getMessages seam the pump reads), or undefined when none is present yet. */
548
+ private readLatestPermissionMode;
549
+ /**
550
+ * Story 046 (R3.4/R3.7/R3.8, design §6c) — apply a non-cyclable mode (dontAsk/bypassPermissions) by
551
+ * re-spawning the SAME sessionId in place with a flag-carrying resume argv, preserving the transcript.
552
+ * Order is load-bearing for R3.7: re-spawn FIRST, and swap in + tear down the old PTY ONLY once the new
553
+ * one is live — so a failed re-spawn leaves the prior PTY/currentValue intact (never
554
+ * torn-down-without-replacement). Re-spawn runs only while idle, so the old PTY has no pending turn to
555
+ * double-resolve. The `respawning` latch defers concurrent selector changes (R3.8).
556
+ */
557
+ private respawnSession;
558
+ /** Story 046 — the session's current effort configOption value (undefined when no effort option). */
559
+ private currentEffort;
560
+ /**
561
+ * Story 046 (R2.2, design §7) — apply a reasoning-effort change. Probe B verdict: effort has no live
562
+ * mid-session mechanism (`--effort` is a spawn flag), so a change re-spawns in place with the flag
563
+ * (mirroring the dontAsk/bypass mode path), idle-guarded, with the R3.7 failure path and R3.8 latch.
564
+ * A no-op change applies nothing. Throwing here leaves the caller's applyConfigOptionValue unrun, so
565
+ * the prior currentValue is left unchanged on failure (R3.7).
566
+ */
567
+ private applyEffortChange;
568
+ /**
569
+ * Story 046 (R4.1/R4.2/R4.3, design §8) — reconcile the `mode` configOption from the latest
570
+ * permission-mode event in the exactly-once `messages` slice. Emits current_mode_update EXACTLY ONCE
571
+ * and only when the transcript's mode differs from the advertised currentModeId (no spurious emit when
572
+ * already in sync, or when no permission-mode event is present). Model/effort have no transcript drift
573
+ * event, so they are NOT reconciled here — optimistic-on-apply only (R4.3).
574
+ */
575
+ private reconcileModeFromTranscript;
450
576
  private replaySessionHistory;
451
577
  /**
452
578
  * Shared per-turn ACP emission used by BOTH the `session/load` replay ({@link replaySessionHistory})
@@ -1 +1 @@
1
- {"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"}
package/dist/acp-agent.js CHANGED
@@ -9,7 +9,7 @@ import { applyTaskCreate, applyTaskUpdate, parseTaskCreateOutput, planEntries, r
9
9
  import { nodeToWebReadable, nodeToWebWritable, unreachable } from "./utils.js";
10
10
  // === SEAM(011): engine boundary — inject a temporary no-op engine so the agent
11
11
  // boots without the cut SDK query() path; the real PTY engine arrives in 013–015/023.
12
- // See SEAM-MAP.md (createSession/prompt CUT→023) and src/engine.ts. ===
12
+ // See fork/SEAM-MAP.md (createSession/prompt CUT→023) and src/engine.ts. ===
13
13
  import { createStubEngine } from "./engine.js";
14
14
  import { createSessionEngine, spawnResumePty, SessionEngine } from "./engine-lifecycle.js";
15
15
  import { createJsonlWatcher } from "./engine-watcher.js";
@@ -23,6 +23,7 @@ import { guardEvent } from "./billing/entrypoint-guard.js";
23
23
  import { usageUpdatesFor } from "./usage.js";
24
24
  import { createTurnResolver } from "./end-of-turn.js";
25
25
  import { sendPrompt } from "./engine-pty.js";
26
+ import { MODEL_CATALOG, DEFAULT_MODEL_INFO } from "./model-catalog.js";
26
27
  import { setupSessionGate } from "./permissions/gate-wiring.js";
27
28
  export const CLAUDE_CONFIG_DIR = process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
28
29
  const MAX_TITLE_LENGTH = 256;
@@ -92,7 +93,55 @@ export async function defaultStartEngine(args) {
92
93
  cwd: args.cwd,
93
94
  baseEnv: args.baseEnv,
94
95
  spawn: args.spawn,
96
+ // Story 046 (R3.4/R2.2): the in-place re-spawn (dontAsk/bypass or an effort change) reattaches the
97
+ // SAME sessionId carrying its mode/effort flags through the resume argv (buildResumeArgv).
98
+ permissionMode: args.permissionMode,
99
+ effortLevel: args.effortLevel,
95
100
  });
101
+ if (args.inPlaceRespawn) {
102
+ // === SEAM(046 R3.4 LIVE FIX): DEFER discovery for an in-place re-spawn ======================
103
+ // An in-place re-spawn (respawnSession: dontAsk/bypass or effort) can fire BEFORE the first
104
+ // interaction — e.g. Zed sends set_config_option(mode:bypassPermissions) at boot from
105
+ // default_config_options, so the re-spawned `claude` has not written its transcript yet. The
106
+ // blocking 2000ms watchdog below would then throw not-found, fail the re-spawn, and the next
107
+ // turn would stall until the 120s turn watchdog. Mirror the fresh path: return as soon as the
108
+ // PTY is live and discover in the BACKGROUND under watchdogMs:Infinity (cancellable), arming the
109
+ // watcher + firing the first onEvent only when the transcript APPEARS (the first interaction).
110
+ const engine = new SessionEngine({ handle, watcher: undefined, sessions: args.sessions });
111
+ const ac = new AbortController();
112
+ engine.setPendingDiscovery(ac);
113
+ void (async () => {
114
+ try {
115
+ const { transcriptPath, cwd } = await resolveWatchTarget(args.sessionId, {
116
+ watchdogMs: Infinity,
117
+ ...args.locateOptions,
118
+ signal: ac.signal,
119
+ });
120
+ const watcher = createJsonlWatcher({
121
+ sessionId: args.sessionId,
122
+ transcriptPath,
123
+ dir: cwd ?? args.cwd,
124
+ onEvent: () => args.onEvent?.(args.sessionId),
125
+ });
126
+ engine.watcher = watcher;
127
+ args.onEvent?.(args.sessionId);
128
+ }
129
+ catch (err) {
130
+ // Swallow ONLY the abort sentinel (the session was torn down before any interaction).
131
+ // SURFACE everything else (multi-match ambiguity, IO error) — never silently drop it.
132
+ if (err?.name === "AbortError")
133
+ return;
134
+ console.error(`[acp-agent] in-place re-spawn transcript discovery failed for ${args.sessionId}:`, err);
135
+ }
136
+ })();
137
+ return {
138
+ sessionId: args.sessionId,
139
+ pty: handle.pty,
140
+ watcher: undefined,
141
+ engine,
142
+ cwd: args.cwd,
143
+ };
144
+ }
96
145
  const { transcriptPath, cwd } = await resolveWatchTarget(args.sessionId, {
97
146
  ...args.locateOptions,
98
147
  });
@@ -119,6 +168,10 @@ export async function defaultStartEngine(args) {
119
168
  baseEnv: args.baseEnv,
120
169
  sessions: args.sessions,
121
170
  spawn: args.spawn,
171
+ // Story 046 (R3.2/R2.2): the seeded permission mode + effort → `--permission-mode`/`--effort` on
172
+ // the fresh spawn (non-"default" only; "default"/undefined keep the byte-for-byte pre-046 argv).
173
+ permissionMode: args.permissionMode,
174
+ effortLevel: args.effortLevel,
122
175
  // Story 034 (§9): the per-session gate scratch settings, already on disk — claude reads them at
123
176
  // startup, so the hook gates the FIRST tool call (blocker c). Absent → ungated (pre-034) spawn.
124
177
  settingsFile: args.settingsFile,
@@ -174,13 +227,6 @@ export async function defaultStartEngine(args) {
174
227
  cwd: args.cwd,
175
228
  };
176
229
  }
177
- /** A single default Degrau-1 model entry. The TUI owns real model selection in Degrau-1; this is an
178
- * honest non-interactive default so configOptions/modes have a coherent current model to anchor on. */
179
- const DEGRAU1_DEFAULT_MODEL_INFO = {
180
- value: "default",
181
- displayName: "Default",
182
- description: "Default model (selection is owned by the interactive TUI in Degrau-1)",
183
- };
184
230
  /** Compute a stable fingerprint of the session-defining params so we can
185
231
  * detect when a loadSession/resumeSession call requires tearing down and
186
232
  * recreating the underlying Query process. MCP servers are sorted by name
@@ -194,7 +240,7 @@ function computeSessionFingerprint(params) {
194
240
  // spawns the subscription `claude` through the login shell (`bash -lc 'claude …'`), so it resolves
195
241
  // from PATH — the same E1 keystone (experiments/DEGRAU0-RESULTS.md), via the shell rather than an
196
242
  // explicit resolveClaudePath() call here. resolveClaudePath() (story 012) is retained for the
197
- // `--cli` auth spawn in index.ts. See src/claude-path.ts, SEAM-MAP.md, IMPLEMENTACAO §3/§5. ===
243
+ // `--cli` auth spawn in index.ts. See fork/src/claude-path.ts, fork/SEAM-MAP.md, IMPLEMENTACAO §3/§5. ===
198
244
  function shouldHideClaudeAuth() {
199
245
  return process.argv.includes("--hide-claude-auth");
200
246
  }
@@ -282,6 +328,25 @@ export function resolvePermissionMode(defaultMode, logger = console) {
282
328
  }
283
329
  return mapped;
284
330
  }
331
+ /**
332
+ * Story 046 (R3.3): the permission modes the TUI cycles through with Shift+Tab (`\x1b[Z`), reachable
333
+ * by the closed-loop driver by stepping. `dontAsk`/`bypassPermissions` are NOT on this cycle — they
334
+ * are applied by an in-place re-spawn instead (R3.4).
335
+ */
336
+ const CYCLABLE_MODES = new Set(["default", "acceptEdits", "plan", "auto"]);
337
+ /** Story 046 (R3.3): the raw Shift+Tab bytes that cycle the TUI permission mode. Written DIRECTLY to
338
+ * the PTY — NEVER via sendPrompt, whose leading Ctrl+U clear would corrupt the escape (design GOTCHA). */
339
+ const MODE_CYCLE_KEY = "\x1b[Z";
340
+ /** Story 046 (R3.3): per-step budget for the closed-loop to see the confirming permission-mode
341
+ * transcript event before aborting (no hang, story-044 awareness); polled every MODE_CYCLE_POLL_MS. */
342
+ const MODE_CYCLE_STEP_TIMEOUT_MS = 2000;
343
+ const MODE_CYCLE_POLL_MS = 50;
344
+ /** Story 046 (hang fix): claude 2.1.176 opens a blocking "Switch model?" confirm dialog on a mid-
345
+ * conversation `/model <alias>` (GrowthBook `tengu_immediate_model_command=false`). Delay before the
346
+ * blind confirm Enter so the dialog has rendered first; the dialog stays open until confirmed, so a
347
+ * late Enter still lands while an early (pre-render) one would be lost. 800 ms validated headless
348
+ * (experiments/probe-c-model-then-prompt.mjs: the dialog rendered + the switch applied within it). */
349
+ const MODEL_CONFIRM_DELAY_MS = 800;
285
350
  /**
286
351
  * Builds the label for the "Always Allow" permission option so the user can see
287
352
  * the exact scope they are committing to. Uses the SDK-provided suggestions
@@ -644,6 +709,8 @@ export class ClaudeAcpAgent {
644
709
  // so the in-turn sub-agent watcher dies with it (covers turn-resolve AND markCancelled paths).
645
710
  sessionRecord.subagentWatcher?.stop();
646
711
  sessionRecord.subagentWatcher = undefined;
712
+ // Story 046 (R1.3): the session is idle again — flush any model switch deferred mid-turn.
713
+ this.flushPendingControlInjections(sessionRecord);
647
714
  }
648
715
  }
649
716
  async cancel(params) {
@@ -741,10 +808,15 @@ export class ClaudeAcpAgent {
741
808
  return {};
742
809
  }
743
810
  async setSessionMode(params) {
744
- if (!this.sessions[params.sessionId]) {
811
+ const session = this.sessions[params.sessionId];
812
+ if (!session) {
745
813
  throw new Error("Session not found");
746
814
  }
815
+ // Validate the requested mode against the session's availableModes (throws on an unknown/unavailable
816
+ // mode — preserved). No state change here (Degrau-1 shim); the drive/re-spawn below applies it.
747
817
  await this.applySessionMode(params.sessionId, params.modeId);
818
+ // Drive the validated mode INTO the claude TUI (shared with the set_config_option path, Bug A fix).
819
+ await this.driveModeIntoTui(params.sessionId, session, params.modeId);
748
820
  await this.updateConfigOption(params.sessionId, "mode", params.modeId);
749
821
  return {};
750
822
  }
@@ -786,6 +858,10 @@ export class ClaudeAcpAgent {
786
858
  const resolvedValue = validValue.value;
787
859
  if (params.configId === "mode") {
788
860
  await this.applySessionMode(params.sessionId, resolvedValue);
861
+ // Bug A fix (Story 046 R3) — Zed sends mode changes via set_config_option(configId:"mode"), so
862
+ // the DRIVE must happen HERE too. This path used to only validate (read-only), leaving claude
863
+ // stuck on its spawn mode — the live permission mode never changed (bypass/acceptEdits no-op'd).
864
+ await this.driveModeIntoTui(params.sessionId, session, resolvedValue);
789
865
  await this.client.sessionUpdate({
790
866
  sessionId: params.sessionId,
791
867
  update: {
@@ -794,12 +870,51 @@ export class ClaudeAcpAgent {
794
870
  },
795
871
  });
796
872
  }
797
- // === SEAM(023) Group 1: the `model` branch's SDK `query.setModel` is dropped local config
798
- // state is updated by applyConfigOptionValue below (read-only Degrau-1 shim).
799
- // Degrau 2 (030/032): PTY-backed control. ===
873
+ // === SEAM(023→046) Group 1: the dropped SDK `query.setModel` is replaced by a PTY side-channel.
874
+ // `/model <alias>` is a LOCAL TUI command (no assistant turn, no stop_reason) — inject it as a
875
+ // write that resolves immediately; NEVER route it through prompt()/the turn-resolver (it would
876
+ // hang forever) and never set turnDetector (R1.4). Idle-guard on turnDetector === undefined
877
+ // (design §5): mid-turn, defer behind pendingModelInjection and flush when the turn settles (R1.3).
878
+ // resolvedValue is already the canonical catalog alias. ===
879
+ if (params.configId === "model") {
880
+ this.applyModelSwitch(session, resolvedValue);
881
+ }
882
+ else if (params.configId === "effort") {
883
+ // Story 046 (R2.2): Probe B verdict — effort has no live mid-session path, so an effort change
884
+ // re-spawns in place with `--effort <level>` (idle-guarded, R3.7 failure path). On throw, the
885
+ // applyConfigOptionValue below is skipped so the prior currentValue stays unchanged.
886
+ await this.applyEffortChange(params.sessionId, session, resolvedValue);
887
+ }
800
888
  await this.applyConfigOptionValue(params.sessionId, session, params.configId, resolvedValue);
801
889
  return { configOptions: session.configOptions };
802
890
  }
891
+ /**
892
+ * Story 046 (R3, Bug A fix) — drive a permission-mode change INTO the claude TUI (the load-bearing
893
+ * half). Cyclable modes (default/acceptEdits/plan/auto) drive via closed-loop Shift+Tab; dontAsk/
894
+ * bypassPermissions re-spawn with `--permission-mode`. Idle-guarded (R3.8); a no-op change applies
895
+ * nothing. SHARED by setSessionMode AND setSessionConfigOption(configId:"mode") — Zed sends mode
896
+ * changes via the latter, so the driving MUST live on both paths (it previously lived only on
897
+ * setSessionMode, while the config-option path was read-only → claude stuck on its spawn mode). The
898
+ * caller has already validated `target` via {@link applySessionMode}.
899
+ */
900
+ async driveModeIntoTui(sessionId, session, target) {
901
+ if (target === session.modes.currentModeId)
902
+ return; // no-op change applies nothing to the TUI
903
+ // Idle-guard (design §9 / R3.8): driving/re-spawning is mutually exclusive with a turn in flight
904
+ // (incl. the story-031 cancel ladder, observed as a live turnDetector) and with a re-spawn already
905
+ // underway. Reject rather than write to a busy/dead PTY — the user retries when idle.
906
+ if (session.turnDetector !== undefined || session.respawning) {
907
+ throw new Error("Cannot change permission mode while the session is busy (a turn is in flight or a re-spawn is underway); retry when idle");
908
+ }
909
+ if (CYCLABLE_MODES.has(target)) {
910
+ // R3.3: drive the TUI with closed-loop raw Shift+Tab until the transcript confirms `target`.
911
+ await this.driveCyclableMode(sessionId, session, target);
912
+ }
913
+ else {
914
+ // R3.4: dontAsk/bypassPermissions are not on the Shift+Tab cycle — re-spawn in place.
915
+ await this.respawnSession(sessionId, session, { permissionMode: target });
916
+ }
917
+ }
803
918
  async applySessionMode(sessionId, modeId) {
804
919
  switch (modeId) {
805
920
  case "auto":
@@ -824,6 +939,214 @@ export class ClaudeAcpAgent {
824
939
  // emitted by the caller. No SDK `query.setPermissionMode`.
825
940
  // Degrau 2 (030/032): PTY-backed control — drive the TUI to apply the permission mode. ===
826
941
  }
942
+ /**
943
+ * Story 046 (R1.2–R1.4, design §5) — apply a live model switch by injecting `/model <alias>` into
944
+ * the PTY as a SIDE-CHANNEL write. `/model` is a local TUI command: no assistant turn, no
945
+ * stop_reason — so it is NEVER routed through prompt()/createTurnResolver (that would hang) and
946
+ * never sets turnDetector (R1.4). The write goes through sendPrompt for its Ctrl+U input-clear but
947
+ * with a SYNCHRONOUS schedule so the command + `\r` commit immediately (resolves now; it awaits no
948
+ * turn). Idle-guard: inject only when no turn is in flight; otherwise defer (last-write-wins, §9)
949
+ * and flush when the turn settles (R1.3).
950
+ */
951
+ applyModelSwitch(session, alias) {
952
+ if (session.turnDetector !== undefined) {
953
+ // A turn is in flight — injecting mid-turn corrupts the PTY input. Defer (coalesce, §9).
954
+ session.pendingModelInjection = alias;
955
+ return;
956
+ }
957
+ // Re-selecting the model the session is already on is a no-op: claude shows no "Switch model?"
958
+ // dialog for it, so skip the redundant /model (and its confirm Enter) entirely.
959
+ const current = session.configOptions.find((o) => o.id === "model")?.currentValue;
960
+ if (current === alias)
961
+ return;
962
+ this.injectModelCommand(session, alias);
963
+ }
964
+ /**
965
+ * Side-channel `/model <alias>` write — synchronous, resolves immediately (never a turn). claude
966
+ * 2.1.176 (GrowthBook `tengu_immediate_model_command=false`) does NOT apply `/model` inline mid-
967
+ * conversation: it opens a blocking **"Switch model?" → 1. Yes / 2. No** dialog and leaves it OPEN.
968
+ * Unconfirmed, the dialog survives until the NEXT prompt — whose `\r` then confirms the switch AND
969
+ * discards the prompt text, so no turn is born and the story-024 stall watchdog trips (the live
970
+ * 39a93bfc hang; root cause proved headless by experiments/probe-c-model-then-prompt.mjs). So after
971
+ * the command we schedule ONE Enter to accept the default "Yes, switch" once the dialog has rendered;
972
+ * if no dialog appears (same model / flag flipped on) Enter-on-empty-input is a harmless no-op.
973
+ */
974
+ injectModelCommand(session, alias) {
975
+ sendPrompt(session.pty, `/model ${alias}`, (fn) => fn());
976
+ // Confirm the "Switch model?" dialog — blind + scheduled, like the story-031 cancel ladder's Esc.
977
+ this.schedule(() => {
978
+ if (session.engine?.isDisposed)
979
+ return; // PTY exited meanwhile → nothing to confirm
980
+ session.pty.write("\r");
981
+ }, MODEL_CONFIRM_DELAY_MS);
982
+ }
983
+ /**
984
+ * Story 046 (R1.3) — flush a deferred model-switch once the session is idle again (called from
985
+ * prompt()'s finally, the moment the turn settles). Last-write-wins: only the most recent queued
986
+ * alias is injected; the field is cleared so a settled session with nothing queued injects nothing.
987
+ */
988
+ flushPendingControlInjections(session) {
989
+ if (session.turnDetector !== undefined)
990
+ return; // still not idle (defensive)
991
+ const alias = session.pendingModelInjection;
992
+ if (alias !== undefined) {
993
+ session.pendingModelInjection = undefined;
994
+ this.injectModelCommand(session, alias);
995
+ }
996
+ }
997
+ /**
998
+ * Story 046 (R3.3, design §6b) — drive the TUI to `target` with closed-loop raw Shift+Tab. Writes
999
+ * `\x1b[Z` DIRECTLY to the PTY (NOT sendPrompt — its Ctrl+U clear corrupts the escape), then awaits
1000
+ * the confirming `permission-mode` transcript event (the tail-as-truth fence: mode is read from the
1001
+ * transcript, NEVER from p.onData). A per-step Δt budget + a one-full-cycle safety stop guarantee the
1002
+ * loop ABORTS rather than hangs/false-stalls (Probe A gated this; story-044 awareness).
1003
+ */
1004
+ async driveCyclableMode(sessionId, session, target) {
1005
+ const cyclableCount = session.modes.availableModes.filter((m) => CYCLABLE_MODES.has(m.id)).length;
1006
+ const maxSteps = Math.max(cyclableCount, 1) + 1; // one-full-cycle safety stop
1007
+ for (let step = 0; step < maxSteps; step++) {
1008
+ if (session.modes.currentModeId === target)
1009
+ return; // converged
1010
+ const before = session.modes.currentModeId;
1011
+ session.pty.write(MODE_CYCLE_KEY); // raw \x1b[Z (Shift+Tab) — never via sendPrompt
1012
+ const observed = await this.awaitModeChange(sessionId, session, before);
1013
+ if (observed === undefined)
1014
+ return; // Δt elapsed with no confirming event → abort (no hang)
1015
+ session.modes.currentModeId = observed; // reconcile local state from the transcript truth
1016
+ }
1017
+ }
1018
+ /**
1019
+ * Story 046 (R3.3) — poll the transcript (the pump's getMessages seam) for a `permission-mode` event
1020
+ * whose mode differs from `before`, up to MODE_CYCLE_STEP_TIMEOUT_MS. Returns the new mode, or
1021
+ * undefined on the Δt timeout (the caller aborts rather than hangs). The confirming event is usually
1022
+ * already present right after the TUI processes the keystroke, so this returns at once in tests.
1023
+ */
1024
+ async awaitModeChange(sessionId, session, before) {
1025
+ let waited = 0;
1026
+ for (;;) {
1027
+ const mode = await this.readLatestPermissionMode(sessionId, session);
1028
+ if (mode !== undefined && mode !== before)
1029
+ return mode;
1030
+ if (waited >= MODE_CYCLE_STEP_TIMEOUT_MS)
1031
+ return undefined;
1032
+ await new Promise((resolve) => this.schedule(() => resolve(), MODE_CYCLE_POLL_MS));
1033
+ waited += MODE_CYCLE_POLL_MS;
1034
+ }
1035
+ }
1036
+ /** Story 046 (R3.3/R4.1) — the most recent `permission-mode` event's mode from the transcript (the
1037
+ * same getMessages seam the pump reads), or undefined when none is present yet. */
1038
+ async readLatestPermissionMode(sessionId, session) {
1039
+ // Mirror the pump's seam resolution: this.getMessages is the injectable reader, defaulting to
1040
+ // defaultGetMessages when not overridden (it is optional at the constructor seam).
1041
+ const read = this.getMessages ?? defaultGetMessages;
1042
+ const messages = await read(sessionId, { dir: session.cwd });
1043
+ for (let i = messages.length - 1; i >= 0; i--) {
1044
+ const m = messages[i];
1045
+ if (m.type === "permission-mode" && typeof m.permissionMode === "string")
1046
+ return m.permissionMode;
1047
+ }
1048
+ return undefined;
1049
+ }
1050
+ /**
1051
+ * Story 046 (R3.4/R3.7/R3.8, design §6c) — apply a non-cyclable mode (dontAsk/bypassPermissions) by
1052
+ * re-spawning the SAME sessionId in place with a flag-carrying resume argv, preserving the transcript.
1053
+ * Order is load-bearing for R3.7: re-spawn FIRST, and swap in + tear down the old PTY ONLY once the new
1054
+ * one is live — so a failed re-spawn leaves the prior PTY/currentValue intact (never
1055
+ * torn-down-without-replacement). Re-spawn runs only while idle, so the old PTY has no pending turn to
1056
+ * double-resolve. The `respawning` latch defers concurrent selector changes (R3.8).
1057
+ */
1058
+ async respawnSession(sessionId, session, change) {
1059
+ // Story 046 (R3.4 LIVE FIX guard): a re-spawn reattaches via `claude --resume <id>`, which needs the
1060
+ // transcript to ALREADY exist. Before the first interaction it is absent, so --resume falls back
1061
+ // (buildResumeArgv `|| claude`) to a NEW id the fork no longer tracks — stalling the turn until the
1062
+ // 120s watchdog AND discarding the live fresh PTY. Refuse until the session has interacted at least
1063
+ // once. The user/Zed retries after the first prompt; a boot-time default_config_options dontAsk/
1064
+ // bypass therefore stays at the fresh spawn's mode (use a fresh-spawn --permission-mode seed for
1065
+ // start-in-bypass, a documented follow-up). The OTHER selector's currentValue is left unchanged.
1066
+ if (!session.interacted) {
1067
+ throw new Error("Cannot switch to a re-spawn mode/effort before the first interaction (no transcript to resume yet); send a prompt first, then switch.");
1068
+ }
1069
+ session.respawning = true;
1070
+ try {
1071
+ const oldEngine = session.engine;
1072
+ // Preserve the OTHER selector's current value so re-spawning for one (mode OR effort) does not
1073
+ // reset the other — the resume argv carries both flags.
1074
+ const permissionMode = change.permissionMode ?? session.modes.currentModeId;
1075
+ const effortLevel = change.effortLevel ?? this.currentEffort(session);
1076
+ // Re-spawn through the SAME startEngine seam createSession uses, reusing the sessionId so the
1077
+ // transcript is reattached (R3.4); the flags flow into the flag-carrying resume argv.
1078
+ const started = await this.startEngine({
1079
+ sessionId,
1080
+ cwd: session.cwd,
1081
+ resume: true,
1082
+ // Story 046 (R3.4 LIVE FIX): an in-place re-spawn may run before the first interaction (boot
1083
+ // bypass), so DEFER discovery instead of the 2000ms fatal watchdog — see defaultStartEngine.
1084
+ inPlaceRespawn: true,
1085
+ permissionMode,
1086
+ effortLevel,
1087
+ sessions: this.engines,
1088
+ onEvent: (sid) => void this.pumpUpdates(sid),
1089
+ });
1090
+ // New PTY is live — only now retire the old one (idle ⇒ no pending turn to double-resolve) and swap.
1091
+ oldEngine?.cleanup();
1092
+ oldEngine?.kill();
1093
+ session.pty = started.pty;
1094
+ session.engine = started.engine;
1095
+ session.watcher = started.watcher;
1096
+ if (change.permissionMode) {
1097
+ session.modes = { ...session.modes, currentModeId: change.permissionMode };
1098
+ }
1099
+ }
1100
+ finally {
1101
+ session.respawning = false;
1102
+ }
1103
+ }
1104
+ /** Story 046 — the session's current effort configOption value (undefined when no effort option). */
1105
+ currentEffort(session) {
1106
+ const opt = session.configOptions.find((o) => o.id === "effort");
1107
+ return typeof opt?.currentValue === "string" ? opt.currentValue : undefined;
1108
+ }
1109
+ /**
1110
+ * Story 046 (R2.2, design §7) — apply a reasoning-effort change. Probe B verdict: effort has no live
1111
+ * mid-session mechanism (`--effort` is a spawn flag), so a change re-spawns in place with the flag
1112
+ * (mirroring the dontAsk/bypass mode path), idle-guarded, with the R3.7 failure path and R3.8 latch.
1113
+ * A no-op change applies nothing. Throwing here leaves the caller's applyConfigOptionValue unrun, so
1114
+ * the prior currentValue is left unchanged on failure (R3.7).
1115
+ */
1116
+ async applyEffortChange(sessionId, session, level) {
1117
+ if (level === this.currentEffort(session))
1118
+ return; // no value change → no-op
1119
+ if (session.turnDetector !== undefined || session.respawning) {
1120
+ throw new Error("Cannot change effort while the session is busy (a turn is in flight or a re-spawn is underway); retry when idle");
1121
+ }
1122
+ await this.respawnSession(sessionId, session, { effortLevel: level });
1123
+ }
1124
+ /**
1125
+ * Story 046 (R4.1/R4.2/R4.3, design §8) — reconcile the `mode` configOption from the latest
1126
+ * permission-mode event in the exactly-once `messages` slice. Emits current_mode_update EXACTLY ONCE
1127
+ * and only when the transcript's mode differs from the advertised currentModeId (no spurious emit when
1128
+ * already in sync, or when no permission-mode event is present). Model/effort have no transcript drift
1129
+ * event, so they are NOT reconciled here — optimistic-on-apply only (R4.3).
1130
+ */
1131
+ async reconcileModeFromTranscript(sessionId, session, messages) {
1132
+ let latestMode;
1133
+ for (const m of messages) {
1134
+ const w = m;
1135
+ if (w.type === "permission-mode" && typeof w.permissionMode === "string") {
1136
+ latestMode = w.permissionMode;
1137
+ }
1138
+ }
1139
+ if (latestMode === undefined || latestMode === session.modes.currentModeId)
1140
+ return;
1141
+ session.modes = { ...session.modes, currentModeId: latestMode };
1142
+ session.configOptions = session.configOptions.map((o) => o.id === "mode" && typeof o.currentValue === "string"
1143
+ ? { ...o, currentValue: latestMode }
1144
+ : o);
1145
+ await this.client.sessionUpdate({
1146
+ sessionId,
1147
+ update: { sessionUpdate: "current_mode_update", currentModeId: latestMode },
1148
+ });
1149
+ }
827
1150
  async replaySessionHistory(sessionId) {
828
1151
  const session = this.sessions[sessionId];
829
1152
  if (!session)
@@ -1053,6 +1376,11 @@ export class ClaudeAcpAgent {
1053
1376
  const session = this.sessions[sessionId];
1054
1377
  if (!session)
1055
1378
  return; // watcher fired before the handle was registered, or after teardown
1379
+ // Story 046 (R3.4 LIVE FIX): the pump only fires once the watcher has armed against the REAL
1380
+ // transcript, so reaching here proves the transcript exists (the first interaction happened). Mark
1381
+ // it idempotently — respawnSession gates the --resume re-spawn on this (a pre-interaction re-spawn
1382
+ // would --resume a non-existent transcript and fall back to a new untracked id).
1383
+ session.interacted = true;
1056
1384
  const messages = await readOrderedMessages(sessionId, session.cwd, {
1057
1385
  getMessages: this.getMessages,
1058
1386
  });
@@ -1104,6 +1432,15 @@ export class ClaudeAcpAgent {
1104
1432
  for (const m of fed)
1105
1433
  registerGateToolUses(m, session.gate);
1106
1434
  }
1435
+ // === SEAM(046) §8 — reconcile the `mode` configOption from transcript permission-mode events.
1436
+ // `permission-mode` is lifecycle-classified (event-switch.ts) and emits no SessionUpdate of its own,
1437
+ // and there is no other transcript-driven mode consumer — so intercept it HERE, over the SAME
1438
+ // exactly-once `fed` slice the detector/gate consume. If the latest permission-mode event's mode
1439
+ // differs from the advertised currentModeId, reconcile the mode configOption currentValue and emit
1440
+ // current_mode_update EXACTLY ONCE (covers a manual Shift+Tab in a mirrored TUI, plan-approval, and
1441
+ // the R3.4 re-spawn). Model and effort have NO transcript drift event — they stay optimistic-on-apply
1442
+ // (R4.3, documented). Additive: it never blocks the emit loop below.
1443
+ await this.reconcileModeFromTranscript(sessionId, session, fed);
1107
1444
  // === SEAM(041) §sidechain — source + merge + linearize + emit (BOTH main turns and nested
1108
1445
  // sub-agent rows). Factored into the shared {@link emitLinearizedWithNested} so the `session/load`
1109
1446
  // replay path (`replaySessionHistory`) runs the IDENTICAL loop — loaded == live with no replay-only
@@ -1373,6 +1710,12 @@ export class ClaudeAcpAgent {
1373
1710
  logger: this.logger,
1374
1711
  });
1375
1712
  await settingsManager.initialize();
1713
+ // Story 046 (R3.1/R3.6, choose-before-start): seed the permission mode from
1714
+ // settings.permissions.defaultMode, normalized through resolvePermissionMode (returns "default"
1715
+ // on undefined/invalid AND strips bypassPermissions under the root guard — so R3.1 reconciles
1716
+ // with R3.6). Drives both the spawn flag (--permission-mode, fresh path) and the advertised
1717
+ // currentModeId, replacing the old hardcoded "default".
1718
+ const seededMode = resolvePermissionMode(settingsManager.getSettings().permissions?.defaultMode, this.logger);
1376
1719
  // Per-session task state — still surfaced via plan notifications by the Group 2 pump / hooks.
1377
1720
  const taskState = new Map();
1378
1721
  // === SEAM(034) §9 hybrid gate: set up the per-session permission gate BEFORE the spawn =======
@@ -1405,6 +1748,9 @@ export class ClaudeAcpAgent {
1405
1748
  replayOnly: creationOpts.replayOnly,
1406
1749
  sessions: this.engines,
1407
1750
  onEvent: (sid) => void this.pumpUpdates(sid),
1751
+ // Story 046 (R3.1/R3.2): seed the fresh spawn with the resolved permission mode (the resume
1752
+ // path's mode is carried by the R3.4 re-spawn argv, not here).
1753
+ permissionMode: seededMode,
1408
1754
  // Story 034: the gate's scratch settings file, consumed as `--settings "<file>"` (fresh path).
1409
1755
  settingsFile: gate?.settingsPath,
1410
1756
  });
@@ -1438,13 +1784,16 @@ export class ClaudeAcpAgent {
1438
1784
  boundGate.bindPty(started.pty);
1439
1785
  started.pty.onExit(() => void boundGate.teardown());
1440
1786
  }
1441
- // Static Degrau-1 model/mode/config defaults (the TUI owns real selection in Degrau-1).
1442
- const availableModes = buildAvailableModes(DEGRAU1_DEFAULT_MODEL_INFO);
1787
+ // Story 046: advertise the full curated model catalog (was a single static "Default" entry),
1788
+ // with the current model seeded to the safe `default`. Populating the catalog also unlocks the
1789
+ // effort selector via buildConfigOptions (§5/§7). The current MODE is still seeded "default" here;
1790
+ // Task 4.1 reseeds it from settings.permissions.defaultMode.
1791
+ const availableModes = buildAvailableModes(DEFAULT_MODEL_INFO);
1443
1792
  const modes = {
1444
- currentModeId: "default",
1793
+ currentModeId: seededMode,
1445
1794
  availableModes,
1446
1795
  };
1447
- const configOptions = buildConfigOptions(modes, DEGRAU1_DEFAULT_MODEL_INFO.value, [DEGRAU1_DEFAULT_MODEL_INFO], settingsManager.getSettings().effortLevel);
1796
+ const configOptions = buildConfigOptions(modes, DEFAULT_MODEL_INFO.value, MODEL_CATALOG, settingsManager.getSettings().effortLevel);
1448
1797
  // Runtime cwd is read from inside the JSONL (story 015); fall back to the requested host cwd
1449
1798
  // until the first transcript line carries `.cwd` (the seam may return cwd === undefined early).
1450
1799
  const runtimeCwd = started.cwd ?? params.cwd;
@@ -1468,9 +1817,9 @@ export class ClaudeAcpAgent {
1468
1817
  cachedWriteTokens: 0,
1469
1818
  },
1470
1819
  modes,
1471
- modelInfos: [DEGRAU1_DEFAULT_MODEL_INFO],
1820
+ modelInfos: MODEL_CATALOG,
1472
1821
  configOptions,
1473
- contextWindowSize: inferContextWindowFromModel(DEGRAU1_DEFAULT_MODEL_INFO.value) ?? DEFAULT_CONTEXT_WINDOW,
1822
+ contextWindowSize: inferContextWindowFromModel(DEFAULT_MODEL_INFO.value) ?? DEFAULT_CONTEXT_WINDOW,
1474
1823
  taskState,
1475
1824
  gate,
1476
1825
  };
@@ -1512,13 +1861,13 @@ function buildAvailableModes(modelInfo) {
1512
1861
  }, {
1513
1862
  id: "dontAsk",
1514
1863
  name: "Don't Ask",
1515
- description: "Don't prompt for permissions, deny if not pre-approved",
1864
+ description: "Don't prompt for permissions, deny if not pre-approved. Selecting this restarts the session.",
1516
1865
  });
1517
1866
  if (ALLOW_BYPASS) {
1518
1867
  modes.push({
1519
1868
  id: "bypassPermissions",
1520
1869
  name: "Bypass Permissions",
1521
- description: "Bypass all permission checks",
1870
+ description: "Bypass all permission checks. Selecting this restarts the session.",
1522
1871
  });
1523
1872
  }
1524
1873
  return modes;
@@ -2050,6 +2399,9 @@ export function toAcpNotifications(content, role, sessionId, toolUseCache, clien
2050
2399
  case "compaction_delta":
2051
2400
  case "advisor_tool_result":
2052
2401
  case "mid_conv_system":
2402
+ case "fallback":
2403
+ // `fallback`: model-routing marker (@anthropic-ai/sdk >= 0.104) — from/to
2404
+ // model hops, no renderable content. No-op like the control blocks above.
2053
2405
  break;
2054
2406
  default:
2055
2407
  unreachable(chunk, logger);
@@ -142,8 +142,13 @@ export declare class SessionEngine {
142
142
  * `|| claude` makes a FAILED `--resume` fall back to a fresh interactive session rather than
143
143
  * hanging. The id is double-quoted so it survives shell word-splitting. There is deliberately
144
144
  * NO `-p`/`--print`/`stream-json` — those select the SDK/credit non-interactive path.
145
+ *
146
+ * Story 046 (R3.4): an optional non-"default" `permissionMode` is carried into BOTH the `--resume`
147
+ * launch AND the `|| claude` fresh fallback as `--permission-mode <mode>`, so an in-place re-spawn
148
+ * (a dontAsk/bypass switch) reattaches the SAME sessionId/transcript under the new mode. Still no
149
+ * `-p`/`--print`/`stream-json` — billing stays subscription `cli`.
145
150
  */
146
- export declare function buildResumeArgv(sessionId: string): [string, string];
151
+ export declare function buildResumeArgv(sessionId: string, permissionMode?: string, effortLevel?: string): [string, string];
147
152
  /** Options for {@link spawnResumePty}. */
148
153
  export interface SpawnResumeOptions {
149
154
  /** The prior session id to reattach to (== the JSONL transcript basename). */
@@ -154,6 +159,13 @@ export interface SpawnResumeOptions {
154
159
  baseEnv?: Record<string, string | undefined>;
155
160
  /** Injectable spawn function (defaults to node-pty's `spawn`); tests pass a fake. */
156
161
  spawn?: typeof pty.spawn;
162
+ /**
163
+ * Story 046 (R3.4): carry `--permission-mode <mode>` into the resume argv for an in-place re-spawn
164
+ * (a dontAsk/bypass switch). Non-"default" only; preserves the same sessionId/transcript.
165
+ */
166
+ permissionMode?: string;
167
+ /** Story 046 (R2.2): carry `--effort <level>` into the resume argv for an effort re-spawn. */
168
+ effortLevel?: string;
157
169
  }
158
170
  /**
159
171
  * Spawn the resume PTY, reusing story 013's sanitized env (R4.2) so the resumed turn keeps the
@@ -172,6 +184,13 @@ export interface CreateSessionEngineOptions {
172
184
  baseEnv?: Record<string, string | undefined>;
173
185
  /** Injectable spawn function (defaults to node-pty's `spawn`); tests pass a fake. */
174
186
  spawn?: typeof pty.spawn;
187
+ /**
188
+ * Story 046 (R3.2): forwarded to {@link spawnClaudePty} as `--permission-mode <mode>` for a fresh
189
+ * spawn seeded to a non-"default" mode. Absent/"default" → no flag (byte-for-byte pre-046 spawn).
190
+ */
191
+ permissionMode?: string;
192
+ /** Story 046 (R2.2): forwarded to {@link spawnClaudePty} as `--effort <level>` for a non-"default" seed. */
193
+ effortLevel?: string;
175
194
  /**
176
195
  * Story 034 (§9 hybrid gate): per-session SCRATCH settings file carrying the fork's
177
196
  * `PreToolUse` hook, forwarded to {@link spawnClaudePty} as `--settings "<file>"`. The
@@ -1 +1 @@
1
- {"version":3,"file":"engine-lifecycle.d.ts","sourceRoot":"","sources":["../src/engine-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine-lifecycle.d.ts","sourceRoot":"","sources":["../src/engine-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -167,9 +167,17 @@ const RESUME_PTY_NAME = "xterm-256color";
167
167
  * `|| claude` makes a FAILED `--resume` fall back to a fresh interactive session rather than
168
168
  * hanging. The id is double-quoted so it survives shell word-splitting. There is deliberately
169
169
  * NO `-p`/`--print`/`stream-json` — those select the SDK/credit non-interactive path.
170
+ *
171
+ * Story 046 (R3.4): an optional non-"default" `permissionMode` is carried into BOTH the `--resume`
172
+ * launch AND the `|| claude` fresh fallback as `--permission-mode <mode>`, so an in-place re-spawn
173
+ * (a dontAsk/bypass switch) reattaches the SAME sessionId/transcript under the new mode. Still no
174
+ * `-p`/`--print`/`stream-json` — billing stays subscription `cli`.
170
175
  */
171
- export function buildResumeArgv(sessionId) {
172
- return ["-c", `claude --resume "${sessionId}" || claude`];
176
+ export function buildResumeArgv(sessionId, permissionMode, effortLevel) {
177
+ const pm = permissionMode && permissionMode !== "default" ? ` --permission-mode ${permissionMode}` : "";
178
+ const ef = effortLevel && effortLevel !== "default" ? ` --effort ${effortLevel}` : "";
179
+ const flags = `${pm}${ef}`;
180
+ return ["-c", `claude --resume "${sessionId}"${flags} || claude${flags}`];
173
181
  }
174
182
  /**
175
183
  * Spawn the resume PTY, reusing story 013's sanitized env (R4.2) so the resumed turn keeps the
@@ -182,7 +190,7 @@ export function buildResumeArgv(sessionId) {
182
190
  export function spawnResumePty(opts) {
183
191
  const { sessionId, cwd, baseEnv = process.env, spawn = pty.spawn } = opts;
184
192
  const shell = resolveShell(baseEnv);
185
- const argv = buildResumeArgv(sessionId);
193
+ const argv = buildResumeArgv(sessionId, opts.permissionMode, opts.effortLevel);
186
194
  const env = buildSanitizedEnv(baseEnv);
187
195
  // §10 refuse-to-spawn guard (R4.2): abort if any forbidden billing var survived sanitization,
188
196
  // rather than resume a credit-billed run. Checks the SPAWN env, not process.env.
@@ -218,6 +226,8 @@ export function createSessionEngine(opts) {
218
226
  cwd: opts.cwd,
219
227
  baseEnv: opts.baseEnv,
220
228
  spawn: opts.spawn,
229
+ permissionMode: opts.permissionMode,
230
+ effortLevel: opts.effortLevel,
221
231
  settingsFile: opts.settingsFile,
222
232
  });
223
233
  // ONE watcher, started by the story 015 factory and bound to that same PTY.
@@ -44,15 +44,20 @@ export declare function resolveShell(baseEnv?: Record<string, string | undefined
44
44
  * billing). The path is double-quoted so it survives the `-lc` shell word-splitting.
45
45
  * Like `--permission-mode plan`, this flag changes only TUI behavior — it adds no
46
46
  * `-p`/`stream-json`, so billing stays subscription `cli` (§10).
47
+ *
48
+ * Story 046 (R3.2): the `planMode` boolean seam is GENERALIZED to a `permissionMode` string. A
49
+ * non-"default" mode is emitted as `--permission-mode <mode>`; "default"/undefined emit nothing;
50
+ * `permissionMode: "plan"` reproduces the old planMode=true path. Still interactive-only — adds no
51
+ * `-p`/`stream-json`, billing stays subscription `cli`.
47
52
  */
48
- export declare function buildClaudeCmd(sessionId: string, planMode?: boolean, settingsFile?: string): string;
53
+ export declare function buildClaudeCmd(sessionId: string, permissionMode?: string, settingsFile?: string, effortLevel?: string): string;
49
54
  /**
50
55
  * Login-shell argv (§5, R1.3). The `-lc` flag is MANDATORY: node-pty's `posix_spawnp`
51
56
  * does not execute the `claude` npm launcher's `#!/usr/bin/env node` shebang, so the
52
57
  * launcher must run *through* a login shell. (The compiled native-binary is the only
53
58
  * thing that could be spawned directly — §5 / IMPLEMENTACAO-FORK-ACP.md §17.)
54
59
  */
55
- export declare function buildSpawnArgv(sessionId: string, planMode?: boolean, settingsFile?: string): [string, string];
60
+ export declare function buildSpawnArgv(sessionId: string, permissionMode?: string, settingsFile?: string, effortLevel?: string): [string, string];
56
61
  /** Options for {@link spawnClaudePty}. */
57
62
  export interface SpawnPtyOptions {
58
63
  /** Host working directory the TUI runs in; passed straight through to the PTY (§5). */
@@ -65,11 +70,16 @@ export interface SpawnPtyOptions {
65
70
  */
66
71
  spawn?: typeof pty.spawn;
67
72
  /**
68
- * When true, adds `--permission-mode plan` to the spawn command (story 029 / R4.1).
69
- * Prefer this over the interactive Shift+Tab cycle (`\x1b[Z`), which is the §5-appendix
70
- * UNTESTED fallback and is documented, not wired as primary (R4.2/R4.3).
73
+ * Story 046 (R3.2): a non-"default" permission mode adds `--permission-mode <mode>` to the spawn
74
+ * command (generalizes the story-029 planMode=plan seam). `"plan"` reproduces the old planMode
75
+ * path. Interactive-only adds no `-p`/`stream-json`; billing stays subscription `cli`.
76
+ */
77
+ permissionMode?: string;
78
+ /**
79
+ * Story 046 (R2.2): a non-"default" reasoning effort adds `--effort <level>` to the spawn command
80
+ * (Probe B verdict — effort has no live mid-session path, so it is seeded/re-spawned). Interactive-only.
71
81
  */
72
- planMode?: boolean;
82
+ effortLevel?: string;
73
83
  /**
74
84
  * Story 034 (§9 hybrid gate): absolute path of the per-session SCRATCH settings file
75
85
  * carrying the fork's `PreToolUse` hook; appended as `--settings "<file>"`. The file
@@ -1 +1 @@
1
- {"version":3,"file":"engine-pty.d.ts","sourceRoot":"","sources":["../src/engine-pty.ts"],"names":[],"mappings":"AAiBA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAQrC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,8GAKzB,CAAC;AAEX;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAWpC;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CASrF;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,MAAM,CAE9F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,OAAO,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAKR;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,OAAO,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,CAAC,MAAM,EAAE,MAAM,CAAC,CAElB;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,CAAC,KAAK,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe,CA+BrE;AA6BD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,WAAS,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CACxB,CAAC,EAAE,IAAI,EACP,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,IAAqC,GAC9E,IAAI,CAON"}
1
+ {"version":3,"file":"engine-pty.d.ts","sourceRoot":"","sources":["../src/engine-pty.ts"],"names":[],"mappings":"AAiBA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAQrC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,8GAKzB,CAAC;AAEX;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAWpC;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CASrF;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,MAAM,CAE9F;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,CAAC,MAAM,EAAE,MAAM,CAAC,CAElB;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,CAAC,KAAK,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe,CAsCrE;AA6BD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,WAAS,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CACxB,CAAC,EAAE,IAAI,EACP,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,IAAqC,GAC9E,IAAI,CAON"}
@@ -89,11 +89,20 @@ export function resolveShell(baseEnv = process.env) {
89
89
  * billing). The path is double-quoted so it survives the `-lc` shell word-splitting.
90
90
  * Like `--permission-mode plan`, this flag changes only TUI behavior — it adds no
91
91
  * `-p`/`stream-json`, so billing stays subscription `cli` (§10).
92
+ *
93
+ * Story 046 (R3.2): the `planMode` boolean seam is GENERALIZED to a `permissionMode` string. A
94
+ * non-"default" mode is emitted as `--permission-mode <mode>`; "default"/undefined emit nothing;
95
+ * `permissionMode: "plan"` reproduces the old planMode=true path. Still interactive-only — adds no
96
+ * `-p`/`stream-json`, billing stays subscription `cli`.
92
97
  */
93
- export function buildClaudeCmd(sessionId, planMode, settingsFile) {
98
+ export function buildClaudeCmd(sessionId, permissionMode, settingsFile, effortLevel) {
94
99
  let cmd = `claude --session-id ${sessionId}`;
95
- if (planMode)
96
- cmd += " --permission-mode plan";
100
+ if (permissionMode && permissionMode !== "default")
101
+ cmd += ` --permission-mode ${permissionMode}`;
102
+ // Story 046 (R2.2): effort is a spawn flag (Probe B verdict — no live mid-session path), so a
103
+ // non-"default" level is seeded/re-spawned with `--effort <level>`. Interactive-only — no credit path.
104
+ if (effortLevel && effortLevel !== "default")
105
+ cmd += ` --effort ${effortLevel}`;
97
106
  if (settingsFile)
98
107
  cmd += ` --settings "${settingsFile}"`;
99
108
  return cmd;
@@ -104,8 +113,8 @@ export function buildClaudeCmd(sessionId, planMode, settingsFile) {
104
113
  * launcher must run *through* a login shell. (The compiled native-binary is the only
105
114
  * thing that could be spawned directly — §5 / IMPLEMENTACAO-FORK-ACP.md §17.)
106
115
  */
107
- export function buildSpawnArgv(sessionId, planMode, settingsFile) {
108
- return ["-lc", buildClaudeCmd(sessionId, planMode, settingsFile)];
116
+ export function buildSpawnArgv(sessionId, permissionMode, settingsFile, effortLevel) {
117
+ return ["-lc", buildClaudeCmd(sessionId, permissionMode, settingsFile, effortLevel)];
109
118
  }
110
119
  /**
111
120
  * Spawn the interactive `claude` TUI under a real PTY with the §5 dimensions and a
@@ -124,10 +133,10 @@ export function buildSpawnArgv(sessionId, planMode, settingsFile) {
124
133
  * process-supervisor or non-PTY spawn variant is introduced.
125
134
  */
126
135
  export function spawnClaudePty(opts) {
127
- const { cwd, baseEnv = process.env, spawn = pty.spawn, planMode, settingsFile } = opts;
136
+ const { cwd, baseEnv = process.env, spawn = pty.spawn, permissionMode, settingsFile, effortLevel, } = opts;
128
137
  const sessionId = randomUUID(); // pre-generated → correlates to the JSONL transcript
129
138
  const shell = resolveShell(baseEnv);
130
- const argv = buildSpawnArgv(sessionId, planMode, settingsFile);
139
+ const argv = buildSpawnArgv(sessionId, permissionMode, settingsFile, effortLevel);
131
140
  // Sanitized, subscription-billing env (§5/§10) via the single shared definition.
132
141
  const env = buildSanitizedEnv(baseEnv);
133
142
  // §10 no-spoof contract (R3.1/R3.3): the 'cli' entrypoint label MUST be produced
@@ -0,0 +1,11 @@
1
+ import type { ModelInfo } from "@anthropic-ai/claude-agent-sdk";
2
+ /**
3
+ * The static curated catalog advertised to the Zed Agent Panel's `model` selector. Each `value` is a
4
+ * `claude` TUI alias accepted by `/model <alias>` (live) and `--model <alias>` (spawn). `default` is
5
+ * first and is the safe fallback. Effort-capable models (`sonnet`, `opus`) carry the metadata that
6
+ * surfaces the effort selector; `default`/`haiku`/`opusplan` advertise no effort levels.
7
+ */
8
+ export declare const MODEL_CATALOG: ModelInfo[];
9
+ /** The safe fallback entry, kept as a named export so callers can seed/anchor on it without a lookup. */
10
+ export declare const DEFAULT_MODEL_INFO: ModelInfo;
11
+ //# sourceMappingURL=model-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAShE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,EA8BpC,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,EAAE,SAA4B,CAAC"}
@@ -0,0 +1,45 @@
1
+ /** Effort levels offered for reasoning-capable models — the SDK's `supportedEffortLevels` vocabulary. */
2
+ const REASONING_EFFORT_LEVELS = [
3
+ "low",
4
+ "medium",
5
+ "high",
6
+ ];
7
+ /**
8
+ * The static curated catalog advertised to the Zed Agent Panel's `model` selector. Each `value` is a
9
+ * `claude` TUI alias accepted by `/model <alias>` (live) and `--model <alias>` (spawn). `default` is
10
+ * first and is the safe fallback. Effort-capable models (`sonnet`, `opus`) carry the metadata that
11
+ * surfaces the effort selector; `default`/`haiku`/`opusplan` advertise no effort levels.
12
+ */
13
+ export const MODEL_CATALOG = [
14
+ {
15
+ value: "default",
16
+ displayName: "Default",
17
+ description: "Use the model the claude TUI is configured with (safe fallback).",
18
+ },
19
+ {
20
+ value: "sonnet",
21
+ displayName: "Sonnet",
22
+ description: "Claude Sonnet — balanced speed and capability; supports reasoning effort.",
23
+ supportsEffort: true,
24
+ supportedEffortLevels: REASONING_EFFORT_LEVELS,
25
+ },
26
+ {
27
+ value: "opus",
28
+ displayName: "Opus",
29
+ description: "Claude Opus — highest capability; supports reasoning effort.",
30
+ supportsEffort: true,
31
+ supportedEffortLevels: REASONING_EFFORT_LEVELS,
32
+ },
33
+ {
34
+ value: "haiku",
35
+ displayName: "Haiku",
36
+ description: "Claude Haiku — fastest and most economical; no reasoning effort levels.",
37
+ },
38
+ {
39
+ value: "opusplan",
40
+ displayName: "Opus Plan",
41
+ description: "Opus while planning, Sonnet for execution (plan-mode workflow).",
42
+ },
43
+ ];
44
+ /** The safe fallback entry, kept as a named export so callers can seed/anchor on it without a lookup. */
45
+ export const DEFAULT_MODEL_INFO = MODEL_CATALOG[0];
@@ -1 +1 @@
1
- {"version":3,"file":"gate-wiring.d.ts","sourceRoot":"","sources":["../../src/permissions/gate-wiring.ts"],"names":[],"mappings":"AAqCA,OAAO,EAEL,iBAAiB,EACjB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAqB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,EAAE,SAAS,MAAM,EAO7D,CAAC;AAQF,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;;+EAG+E;AAC/E,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C;oGACoG;AACpG,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C;;gDAEgD;AAChD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAI7C,2FAA2F;AAC3F,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE;;0FAE0F;AAC1F,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAC;CAC1D;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,gGAAgG;IAChG,MAAM,EAAE,gBAAgB,CAAC;IACzB,gGAAgG;IAChG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,YAAY,EAAE,MAAM,CAAC;IACrB;mGAC+F;IAC/F,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACzD;oFACgF;IAChF,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B;8EAC0E;IAC1E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AA2RD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CAIrF"}
1
+ {"version":3,"file":"gate-wiring.d.ts","sourceRoot":"","sources":["../../src/permissions/gate-wiring.ts"],"names":[],"mappings":"AAqCA,OAAO,EAEL,iBAAiB,EACjB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAqB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,EAAE,SAAS,MAAM,EAO7D,CAAC;AAQF,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;;+EAG+E;AAC/E,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C;oGACoG;AACpG,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C;;gDAEgD;AAChD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAI7C,2FAA2F;AAC3F,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAMjE;;0FAE0F;AAC1F,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,CAAC;CAC1D;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,gGAAgG;IAChG,MAAM,EAAE,gBAAgB,CAAC;IACzB,gGAAgG;IAChG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,YAAY,EAAE,MAAM,CAAC;IACrB;mGAC+F;IAC/F,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACzD;oFACgF;IAChF,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B;8EAC0E;IAC1E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAqSD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CAIrF"}
@@ -83,6 +83,9 @@ export const DEFAULT_CLOSE_TIMEOUT_MS = 2000;
83
83
  const OUTPUT_TAIL_CAP = 16384;
84
84
  /** Filename prefix of the per-session scratch settings file (diagnosable in `ls /tmp`). */
85
85
  export const SCRATCH_SETTINGS_PREFIX = "fork-acp-gate-settings-";
86
+ /** Story 046 (R3) — the file-edit tools that `acceptEdits` auto-allows, mirroring claude's native
87
+ * acceptEdits semantics (edits proceed without prompting; every other tool still asks). */
88
+ const EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
86
89
  const defaultSchedule = (fn, ms) => {
87
90
  setTimeout(fn, ms);
88
91
  };
@@ -161,6 +164,17 @@ class SessionGateImpl {
161
164
  async decide(call) {
162
165
  if (this.torndown)
163
166
  return "deny"; // a hook racing teardown is never approved
167
+ // === Story 046 (R3) — honor the live permission mode BEFORE relaying to Zed. =================
168
+ // The hook payload carries the current mode (probe-d confirmed `permission_mode` matches the
169
+ // selected mode in acceptEdits/bypassPermissions). Without this branch the gate raises
170
+ // session/request_permission for EVERY tool, overriding the panel's mode selector — the user sees
171
+ // a Zed prompt in every mode, even bypass. bypassPermissions auto-allows ALL tools; acceptEdits
172
+ // auto-allows edit-class tools; default/plan/auto/dontAsk fall through to the ACP relay (ask Zed).
173
+ // No #52822 sweep on this path: these modes make claude auto-proceed, so no native prompt renders.
174
+ if (call.permissionMode === "bypassPermissions")
175
+ return "allow";
176
+ if (call.permissionMode === "acceptEdits" && EDIT_TOOLS.has(call.toolName))
177
+ return "allow";
164
178
  // Kick the pump so the freshest JSONL (carrying this call's `tool_use` line) is re-read NOW.
165
179
  try {
166
180
  this.nudge?.();
package/package.json CHANGED
@@ -3,8 +3,8 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.1",
7
- "description": "ACP agent that drives the Claude Code subscription TUI over a PTY, rendering Claude Code threads in Zed and other ACP-compatible clients.",
6
+ "version": "0.3.0",
7
+ "description": "Run the official Claude Code TUI in Zed's agent panel on your Claude Pro/Max subscription an ACP-over-PTY bridge created for Anthropic's June 2026 billing split.",
8
8
  "main": "dist/lib.js",
9
9
  "types": "dist/lib.d.ts",
10
10
  "bin": {
@@ -60,20 +60,20 @@
60
60
  "license": "Apache-2.0",
61
61
  "dependencies": {
62
62
  "@agentclientprotocol/sdk": "0.25.0",
63
- "@anthropic-ai/claude-agent-sdk": "0.3.166",
63
+ "@anthropic-ai/claude-agent-sdk": "0.3.175",
64
64
  "node-pty": "1.1.0",
65
65
  "zod": "^3.25.0 || ^4.0.0"
66
66
  },
67
67
  "devDependencies": {
68
- "@anthropic-ai/sdk": "0.101.0",
68
+ "@anthropic-ai/sdk": "0.104.1",
69
69
  "@eslint/js": "10.0.1",
70
- "@types/node": "25.9.2",
71
- "@typescript-eslint/eslint-plugin": "8.60.1",
72
- "@typescript-eslint/parser": "8.60.1",
70
+ "@types/node": "25.9.3",
71
+ "@typescript-eslint/eslint-plugin": "8.61.0",
72
+ "@typescript-eslint/parser": "8.61.0",
73
73
  "eslint": "10.4.1",
74
74
  "eslint-config-prettier": "10.1.8",
75
75
  "globals": "17.6.0",
76
- "prettier": "3.8.3",
76
+ "prettier": "3.8.4",
77
77
  "ts-node": "10.9.2",
78
78
  "typescript": "6.0.3"
79
79
  }