@lucascouts/claude-agent-tui 0.5.2 → 0.7.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/NOTICE +1 -1
- package/README.md +1 -1
- package/dist/acp-agent.d.ts +249 -21
- package/dist/acp-agent.js +573 -73
- package/dist/agent-catalog.d.ts +95 -0
- package/dist/agent-catalog.js +287 -0
- package/dist/ansi-mirror.d.ts +0 -1
- package/dist/besteffort.d.ts +0 -1
- package/dist/billing/entrypoint-guard.d.ts +0 -1
- package/dist/claude-path.d.ts +0 -1
- package/dist/claude-path.js +6 -0
- package/dist/command-catalog.d.ts +84 -0
- package/dist/command-catalog.js +339 -0
- package/dist/diff-enriched-reader.d.ts +0 -1
- package/dist/diff-source.d.ts +0 -1
- package/dist/drift-checks.d.ts +0 -1
- package/dist/end-of-turn.d.ts +6 -1
- package/dist/end-of-turn.js +8 -1
- package/dist/engine-lifecycle.d.ts +66 -2
- package/dist/engine-lifecycle.js +43 -4
- package/dist/engine-pty.d.ts +70 -3
- package/dist/engine-pty.js +80 -6
- package/dist/engine-watcher.d.ts +0 -1
- package/dist/engine.d.ts +0 -1
- package/dist/event-switch.d.ts +0 -1
- package/dist/gate/port.d.ts +0 -1
- package/dist/gate/settings-writer.d.ts +14 -1
- package/dist/gate/settings-writer.js +49 -0
- package/dist/image-input.d.ts +30 -0
- package/dist/image-input.js +79 -0
- package/dist/image-vision-smoke.d.ts +51 -0
- package/dist/image-vision-smoke.js +111 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +6 -0
- package/dist/jsonl.d.ts +0 -1
- package/dist/lib.d.ts +0 -1
- package/dist/linearize.d.ts +1 -2
- package/dist/linearize.js +1 -1
- package/dist/live-diff-env.d.ts +0 -1
- package/dist/live-subagent-env.d.ts +0 -1
- package/dist/mcp-config-writer.d.ts +60 -0
- package/dist/mcp-config-writer.js +172 -0
- package/dist/model-catalog.d.ts +68 -3
- package/dist/model-catalog.js +123 -13
- package/dist/permissions/allow-inject.d.ts +0 -1
- package/dist/permissions/deny.d.ts +12 -1
- package/dist/permissions/deny.js +18 -0
- package/dist/permissions/elicitation-bridge.d.ts +71 -0
- package/dist/permissions/elicitation-bridge.js +146 -0
- package/dist/permissions/gate-wiring.d.ts +23 -3
- package/dist/permissions/gate-wiring.js +123 -1
- package/dist/permissions/hook-server.d.ts +11 -3
- package/dist/permissions/hook-server.js +10 -1
- package/dist/permissions/permission-mode.d.ts +0 -1
- package/dist/permissions/request-permission.d.ts +0 -1
- package/dist/settings.d.ts +0 -1
- package/dist/settings.js +9 -0
- package/dist/stop-reason-map.d.ts +0 -1
- package/dist/subagent-gate.d.ts +0 -1
- package/dist/subagent-source.d.ts +0 -1
- package/dist/subagent-watcher.d.ts +0 -1
- package/dist/tools.d.ts +0 -1
- package/dist/tools.js +5 -1
- package/dist/usage-env.d.ts +0 -1
- package/dist/usage.d.ts +3 -1
- package/dist/usage.js +3 -0
- package/dist/utils.d.ts +0 -1
- package/dist/zed-register.d.ts +0 -1
- package/package.json +12 -9
- package/dist/acp-agent.d.ts.map +0 -1
- package/dist/ansi-mirror.d.ts.map +0 -1
- package/dist/besteffort.d.ts.map +0 -1
- package/dist/billing/entrypoint-guard.d.ts.map +0 -1
- package/dist/claude-path.d.ts.map +0 -1
- package/dist/diff-enriched-reader.d.ts.map +0 -1
- package/dist/diff-source.d.ts.map +0 -1
- package/dist/drift-checks.d.ts.map +0 -1
- package/dist/end-of-turn.d.ts.map +0 -1
- package/dist/engine-lifecycle.d.ts.map +0 -1
- package/dist/engine-pty.d.ts.map +0 -1
- package/dist/engine-watcher.d.ts.map +0 -1
- package/dist/engine.d.ts.map +0 -1
- package/dist/event-switch.d.ts.map +0 -1
- package/dist/gate/port.d.ts.map +0 -1
- package/dist/gate/settings-writer.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/jsonl.d.ts.map +0 -1
- package/dist/lib.d.ts.map +0 -1
- package/dist/linearize.d.ts.map +0 -1
- package/dist/live-diff-env.d.ts.map +0 -1
- package/dist/live-subagent-env.d.ts.map +0 -1
- package/dist/model-catalog.d.ts.map +0 -1
- package/dist/permissions/allow-inject.d.ts.map +0 -1
- package/dist/permissions/deny.d.ts.map +0 -1
- package/dist/permissions/gate-wiring.d.ts.map +0 -1
- package/dist/permissions/hook-server.d.ts.map +0 -1
- package/dist/permissions/permission-mode.d.ts.map +0 -1
- package/dist/permissions/request-permission.d.ts.map +0 -1
- package/dist/settings.d.ts.map +0 -1
- package/dist/stop-reason-map.d.ts.map +0 -1
- package/dist/subagent-gate.d.ts.map +0 -1
- package/dist/subagent-source.d.ts.map +0 -1
- package/dist/subagent-watcher.d.ts.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/usage-env.d.ts.map +0 -1
- package/dist/usage.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/zed-register.d.ts.map +0 -1
package/NOTICE
CHANGED
|
@@ -10,5 +10,5 @@ This product is a derivative work of:
|
|
|
10
10
|
|
|
11
11
|
The engine was rewritten to drive the Claude Code subscription TUI over a
|
|
12
12
|
pseudo-terminal (PTY) instead of calling the Claude Agent SDK. See
|
|
13
|
-
.fork-provenance.json (fork point: v0.
|
|
13
|
+
.fork-provenance.json (fork point: v0.53.0) and CHANGELOG.md for the scope
|
|
14
14
|
of modifications.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
An [ACP](https://agentclientprotocol.com)-compatible agent that drives the **Claude Code subscription TUI** over a PTY, so your Claude Code threads render natively in [Zed](https://zed.dev) and other ACP clients.
|
|
6
6
|
|
|
7
|
-
> **Fork** of [`@agentclientprotocol/claude-agent-acp`](https://github.com/agentclientprotocol/claude-agent-acp) v0.
|
|
7
|
+
> **Fork** of [`@agentclientprotocol/claude-agent-acp`](https://github.com/agentclientprotocol/claude-agent-acp) v0.53.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
9
|
## Why this exists
|
|
10
10
|
|
package/dist/acp-agent.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Agent, AgentSideConnection, AuthenticateRequest, CancelNotification, ClientCapabilities, ForkSessionRequest, ForkSessionResponse, InitializeRequest, InitializeResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, ReadTextFileRequest, ReadTextFileResponse, ResumeSessionRequest, ResumeSessionResponse, SessionConfigOption, SessionModeState, SessionNotification, SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse, CloseSessionRequest, CloseSessionResponse, DeleteSessionRequest, DeleteSessionResponse, TerminalHandle, TerminalOutputResponse, WriteTextFileRequest, WriteTextFileResponse } from "@agentclientprotocol/sdk";
|
|
1
|
+
import { Agent, AgentSideConnection, AuthenticateRequest, CancelNotification, ClientCapabilities, ForkSessionRequest, ForkSessionResponse, InitializeRequest, InitializeResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, ReadTextFileRequest, ReadTextFileResponse, ResumeSessionRequest, ResumeSessionResponse, SessionConfigOption, SessionModeState, SessionNotification, SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse, CloseSessionRequest, CloseSessionResponse, DeleteSessionRequest, DeleteSessionResponse, LogoutRequest, LogoutResponse, TerminalHandle, TerminalOutputResponse, WriteTextFileRequest, WriteTextFileResponse, AvailableCommand } from "@agentclientprotocol/sdk";
|
|
2
2
|
import { ModelInfo, Options, PermissionMode, PermissionUpdate, SDKMessageOrigin, SDKPartialAssistantMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import { ContentBlockParam } from "@anthropic-ai/sdk/resources";
|
|
4
4
|
import { BetaContentBlock, BetaRawContentBlockDelta } from "@anthropic-ai/sdk/resources/beta.mjs";
|
|
@@ -15,6 +15,7 @@ import type { ListSubagents, GetSubagentMessages } from "./subagent-source.js";
|
|
|
15
15
|
import { type SidechainToolUse } from "./subagent-gate.js";
|
|
16
16
|
import type { SubagentWatcher } from "./subagent-watcher.js";
|
|
17
17
|
import type { DetectorSchedule, EndOfTurnDetector } from "./end-of-turn.js";
|
|
18
|
+
import { type AgentCatalogEntry } from "./agent-catalog.js";
|
|
18
19
|
import type { SessionGate, SessionGateOptions } from "./permissions/gate-wiring.js";
|
|
19
20
|
export declare const CLAUDE_CONFIG_DIR: string;
|
|
20
21
|
/**
|
|
@@ -30,6 +31,7 @@ type AccumulatedUsage = {
|
|
|
30
31
|
cachedReadTokens: number;
|
|
31
32
|
cachedWriteTokens: number;
|
|
32
33
|
};
|
|
34
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
33
35
|
type Session = {
|
|
34
36
|
/** The live PTY handle (story 013/014) running the subscription `claude` TUI for this session. */
|
|
35
37
|
pty: IPty;
|
|
@@ -49,6 +51,13 @@ type Session = {
|
|
|
49
51
|
* was surfaced in an earlier pump). Per-session — sub-agent row uuids are session-scoped.
|
|
50
52
|
*/
|
|
51
53
|
emittedNested: Set<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Story 056 (#812) — the last session title pushed to the client via `session_info_update` at the
|
|
56
|
+
* story-024 turn boundary. Used to DEDUP: `emitSessionTitleUpdate` skips the push when the freshly
|
|
57
|
+
* sanitized `getSessionInfo().summary` equals this. Undefined until the first non-empty title is
|
|
58
|
+
* pushed; per-session (titles are session-scoped).
|
|
59
|
+
*/
|
|
60
|
+
lastEmittedTitle?: string;
|
|
52
61
|
/** Story 054 — per-session dedup Set of sidechain inner tool_use ids already fed to the gate
|
|
53
62
|
* correlator (R3 exactly-once). Lazy-init on the gated pump path; absent on a no-gate session. */
|
|
54
63
|
registeredSidechain?: Set<string>;
|
|
@@ -59,19 +68,54 @@ type Session = {
|
|
|
59
68
|
engine?: SessionEngine;
|
|
60
69
|
cancelled: boolean;
|
|
61
70
|
cwd: string;
|
|
62
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Story 057 (R1.3) — the RESOLVED additional-directory list for this session (the request's
|
|
73
|
+
* `additionalDirectories`, else `_meta.additionalRoots`, else `[]`), stored so sub-task 2.3's
|
|
74
|
+
* {@link respawnSession} can re-thread the SAME `--add-dir` scope into the in-place re-spawn. This
|
|
75
|
+
* is the RAW list (per-dir sanitization is the engine's job); absent on pre-057 / replay records.
|
|
76
|
+
*/
|
|
77
|
+
additionalDirectories?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Story 057 (R2.3/R2.4, sub-task 2.3) — the CURRENT MCP scratch path ({@link writeMcpScratch})
|
|
80
|
+
* threaded into this session's spawn as `--mcp-config "<file>"`. Retained so {@link teardownSession}
|
|
81
|
+
* can REMOVE it (R2.3, no orphan/secret leak) and {@link respawnSession} can REGENERATE it (R2.4:
|
|
82
|
+
* write-new-then-remove-old, swapping this to the new path). Absent when the session declared no
|
|
83
|
+
* MCP servers (and on replay-only records, which spawn nothing).
|
|
84
|
+
*/
|
|
85
|
+
mcpConfigFile?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Story 057 (R2.4, sub-task 2.3) — the RAW ACP `mcpServers` array the client declared at create
|
|
88
|
+
* time, retained so {@link respawnSession} can RE-translate ({@link translateMcpServers}) and
|
|
89
|
+
* regenerate the scratch for the re-spawned `claude`. (The translation output is not stored —
|
|
90
|
+
* re-translating from the source keeps the regenerated scratch faithful to the original request.)
|
|
91
|
+
* Absent/empty when no MCP servers were declared.
|
|
92
|
+
*/
|
|
93
|
+
mcpServers?: NewSessionRequest["mcpServers"];
|
|
94
|
+
/** Serialized snapshot of session-defining params (cwd, mcpServers, additionalDirectories) used to
|
|
63
95
|
* detect when loadSession/resumeSession is called with changed values. */
|
|
64
96
|
sessionFingerprint: string;
|
|
65
97
|
settingsManager: SettingsManager;
|
|
66
98
|
accumulatedUsage: AccumulatedUsage;
|
|
67
99
|
modes: SessionModeState;
|
|
68
100
|
modelInfos: ModelInfo[];
|
|
101
|
+
/**
|
|
102
|
+
* Story 056 (R3.2) — the main-thread agent personas discovered for this session's cwd at
|
|
103
|
+
* create time ({@link discoverAgents}, glob-only). Stored so the model-change reconcile in
|
|
104
|
+
* {@link setSessionConfigOption} can REBUILD the `agent` configOption without re-globbing the
|
|
105
|
+
* disk. The CURRENT agent is NOT held here — it lives in the `agent` configOption's
|
|
106
|
+
* `currentValue` (mirroring `currentEffort`); `[]`/absent means no personas were discovered and
|
|
107
|
+
* the `agent` option is omitted entirely (upstream #794 `agents.length > 0` gate).
|
|
108
|
+
*/
|
|
109
|
+
agents?: AgentCatalogEntry[];
|
|
69
110
|
configOptions: SessionConfigOption[];
|
|
70
|
-
/** Context window size
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
111
|
+
/** Context window size for the session, carried across prompts so mid-stream
|
|
112
|
+
* usage_update notifications report a correct `size` before the turn's first
|
|
113
|
+
* result message arrives. Seeded by `inferContextWindowFromModel` (the static
|
|
114
|
+
* `MODEL_CONTEXT_WINDOWS` curation) and re-resolved when the user switches the
|
|
115
|
+
* session's model. NOTE (story 068): there is NO `result.modelUsage` refresh —
|
|
116
|
+
* the JSONL `usage` block carries only token counts, never a window; the window
|
|
117
|
+
* comes from static curation (the Models API `max_input_tokens` is the real
|
|
118
|
+
* authority, which this PTY/JSONL fork does not call). */
|
|
75
119
|
contextWindowSize: number;
|
|
76
120
|
/** Accumulated task list for the session, keyed by task ID. Task IDs are
|
|
77
121
|
* per-session, so this state must not be shared across sessions. */
|
|
@@ -111,6 +155,19 @@ type Session = {
|
|
|
111
155
|
* nothing is queued.
|
|
112
156
|
*/
|
|
113
157
|
pendingModelInjection?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Story 056 v4 — an effort change (`/effort <level>`) requested WHILE a turn is in flight is deferred
|
|
160
|
+
* here (last-write-wins) and flushed as a side-channel PTY write once the turn settles (mirrors
|
|
161
|
+
* {@link pendingModelInjection}). Undefined when nothing is queued.
|
|
162
|
+
*/
|
|
163
|
+
pendingEffortInjection?: string;
|
|
164
|
+
/**
|
|
165
|
+
* Story 060 (R2.1/R2.2) — true WHILE the "ultracode" effort-selector sentinel is selected for this
|
|
166
|
+
* session. The LIVE activation it drives is a keyword prefix on the OUTGOING prompt (the binary's
|
|
167
|
+
* documented per-turn Workflow opt-in) — Option A, no re-spawn. Cleared when a real effort level (or
|
|
168
|
+
* `default`) is re-selected. The declarative spawn-time complement is {@link applyUltracodeSettings}.
|
|
169
|
+
*/
|
|
170
|
+
ultracodeActive?: boolean;
|
|
114
171
|
/**
|
|
115
172
|
* Story 046 (R3.8) — true WHILE an in-place re-spawn (R3.4 dontAsk/bypass switch) is between the old
|
|
116
173
|
* PTY teardown and the new PTY being ready. Selector changes arriving in this window are rejected
|
|
@@ -148,6 +205,13 @@ type Session = {
|
|
|
148
205
|
* sourced fresh inside `emitLinearizedWithNested`; the main chain is whatever the last pump saw.
|
|
149
206
|
*/
|
|
150
207
|
lastMessages?: SessionMessage[];
|
|
208
|
+
/**
|
|
209
|
+
* Story 058 (R2.1/R2.2) — the temp image files materialized for the in-flight turn (pushed by
|
|
210
|
+
* {@link promptToClaude}'s sink when the prompt is assembled, BEFORE it is sent), unlinked at turn
|
|
211
|
+
* settle (prompt()'s catch + finally, covering resolve AND cancel) via {@link cleanupMaterializedImages}
|
|
212
|
+
* and again on teardown as an idempotent backstop. Undefined when the turn materialized no image.
|
|
213
|
+
*/
|
|
214
|
+
turnTempImagePaths?: string[];
|
|
151
215
|
};
|
|
152
216
|
/** What {@link StartEngine} returns: the authoritative session id (engine-spawn-generated for a
|
|
153
217
|
* fresh session, the resumed id otherwise), the live PTY, the started watcher, the owning engine,
|
|
@@ -226,6 +290,14 @@ export interface StartEngineArgs {
|
|
|
226
290
|
* <level>` (non-"default" only). Threaded to BOTH the fresh and resume spawn paths.
|
|
227
291
|
*/
|
|
228
292
|
effortLevel?: string;
|
|
293
|
+
/**
|
|
294
|
+
* Story 056 (R3.2): the seeded/re-spawn main-thread agent persona, forwarded to the spawn as
|
|
295
|
+
* `--agent "<name>"` (non-"default" only — the spawn layer drops the literal "default" sentinel,
|
|
296
|
+
* exactly like `--effort`/`--permission-mode`). Threaded to BOTH the fresh ({@link
|
|
297
|
+
* createSessionEngine}) and resume ({@link spawnResumePty}) paths so the agent-selecting re-spawn
|
|
298
|
+
* carries it. The persona name is allowlist-safe at the catalog boundary ({@link discoverAgents}).
|
|
299
|
+
*/
|
|
300
|
+
agent?: string;
|
|
229
301
|
/**
|
|
230
302
|
* Story 046 (R3.4 LIVE FIX): this resume is an IN-PLACE re-spawn ({@link respawnSession} for a
|
|
231
303
|
* dontAsk/bypass mode or an effort change), NOT a fork/resume of an already-lived session. An
|
|
@@ -237,6 +309,28 @@ export interface StartEngineArgs {
|
|
|
237
309
|
* absent) keeps its blocking 2000ms watchdog (R2.1, resume-discovery-unchanged.test.ts).
|
|
238
310
|
*/
|
|
239
311
|
inPlaceRespawn?: boolean;
|
|
312
|
+
/**
|
|
313
|
+
* Story 057 (R1.3/R3.1): the RESOLVED additional-directory list (session `additionalDirectories`,
|
|
314
|
+
* else `_meta.additionalRoots`), forwarded to BOTH the fresh ({@link createSessionEngine}) and
|
|
315
|
+
* resume ({@link spawnResumePty}) spawn paths so a re-spawn re-threads it. Each safe entry becomes
|
|
316
|
+
* one `--add-dir "<dir>"` on the interactive TUI argv; sanitization (per-dir drop of unsafe paths)
|
|
317
|
+
* is the ENGINE's job ({@link buildAddDirFlags}/`isSafeDir`, sub-task 1.1), so the list threaded
|
|
318
|
+
* here is RAW. ALWAYS-ON (no `FORK_*` opt-in gate, R3.1). Interactive-only — never on a `-p`/
|
|
319
|
+
* `stream-json` invocation (the fork has no headless path).
|
|
320
|
+
*/
|
|
321
|
+
additionalDirectories?: string[];
|
|
322
|
+
/**
|
|
323
|
+
* Story 057 (R2.2/R2.3, sub-task 2.3): the fork-controlled uuid-namespaced MCP scratch path
|
|
324
|
+
* ({@link writeMcpScratch}), forwarded to BOTH the fresh ({@link createSessionEngine}) and resume
|
|
325
|
+
* ({@link spawnResumePty}) spawn paths and emitted as `--mcp-config "<file>"` (never `--strict` —
|
|
326
|
+
* R2.2 MERGE: claude folds these servers IN alongside any project/user `.mcp.json` rather than
|
|
327
|
+
* replacing them). Written BEFORE the spawn — claude reads it at startup, exactly like
|
|
328
|
+
* {@link settingsFile}, so it gates the first MCP use. ALWAYS-ON (no `FORK_*` gate); present only
|
|
329
|
+
* when the session declared ≥1 MCP server. The scratch may carry MCP auth headers/env (0600 +
|
|
330
|
+
* never logged, R2.3); the caller removes it on teardown ({@link removeMcpScratch}) and regenerates
|
|
331
|
+
* it on re-spawn ({@link respawnSession}, R2.4).
|
|
332
|
+
*/
|
|
333
|
+
mcpConfigFile?: string;
|
|
240
334
|
}
|
|
241
335
|
/** The createSession injection seam: spawn the PTY engine + JSONL watcher + locate the transcript. */
|
|
242
336
|
export type StartEngine = (args: StartEngineArgs) => Promise<StartedEngine> | StartedEngine;
|
|
@@ -318,6 +412,32 @@ export interface AgentDeps {
|
|
|
318
412
|
* cannot be overridden. Tests inject short windows here; production passes nothing.
|
|
319
413
|
*/
|
|
320
414
|
gateOptions?: Omit<SessionGateOptions, "client" | "onWarn">;
|
|
415
|
+
/**
|
|
416
|
+
* Story 056 (R3.2) — override the main-thread agent-persona discovery `createSession` seeds the
|
|
417
|
+
* `agent` configOption from (default: the glob-only {@link discoverAgents}). Injected by the unit
|
|
418
|
+
* tests with an in-memory fake so the surface is exercised hermetically, never touching the real
|
|
419
|
+
* `~/.claude/agents`. Production passes nothing → the real disk glob.
|
|
420
|
+
*/
|
|
421
|
+
discoverAgents?: (cwd: string) => AgentCatalogEntry[];
|
|
422
|
+
/**
|
|
423
|
+
* Story 063 (R1/R1.1) — override the offline command discovery `sendAvailableCommandsUpdate` sources
|
|
424
|
+
* the `available_commands_update` set from (default: the disk-only {@link discoverCommands}, keyed on
|
|
425
|
+
* the session cwd). Injected by the wiring test with an in-memory fake so the surface is exercised
|
|
426
|
+
* hermetically, never touching the real `~/.claude`. Production passes nothing → the real disk scan.
|
|
427
|
+
*/
|
|
428
|
+
discoverCommands?: (cwd: string) => AvailableCommand[];
|
|
429
|
+
/**
|
|
430
|
+
* Story 056 (#812) — override the SDK session-metadata reader the end-of-turn `session_info_update`
|
|
431
|
+
* push sources the title from (default: the pure {@link getSessionInfo} from the agent SDK, which
|
|
432
|
+
* resolves the session's `summary` from its JSONL — custom title, auto-summary, or first prompt).
|
|
433
|
+
* Injected by the unit tests with an in-memory fake so the push is exercised hermetically, never
|
|
434
|
+
* touching the real `~/.claude` transcript tree. Production passes nothing → the real SDK reader.
|
|
435
|
+
*/
|
|
436
|
+
getSessionInfo?: (sessionId: string, options?: {
|
|
437
|
+
dir?: string;
|
|
438
|
+
}) => Promise<{
|
|
439
|
+
summary: string;
|
|
440
|
+
} | undefined>;
|
|
321
441
|
}
|
|
322
442
|
/**
|
|
323
443
|
* Production default for the {@link StartEngine} seam. Spawns the subscription `claude` TUI under a
|
|
@@ -451,6 +571,14 @@ export declare class ClaudeAcpAgent implements Agent {
|
|
|
451
571
|
[key: string]: BackgroundTerminal;
|
|
452
572
|
};
|
|
453
573
|
clientCapabilities?: ClientCapabilities;
|
|
574
|
+
/**
|
|
575
|
+
* Story 065 (R1/R3) — did the client advertise `clientCapabilities.elicitation.form`
|
|
576
|
+
* at initialize? Presence-based (a present `form` may legitimately be an empty `{}`,
|
|
577
|
+
* so this is derived with `!= null`, NOT property truthiness). The 065 gate (task 3.1)
|
|
578
|
+
* reads this to decide relay-via-elicitation (R1) vs the story-064 deny fallback (R3).
|
|
579
|
+
* Defaults `false` so a client that never advertised elicitation falls back safely.
|
|
580
|
+
*/
|
|
581
|
+
clientSupportsElicitationForm: boolean;
|
|
454
582
|
logger: Logger;
|
|
455
583
|
gatewayAuthRequest?: GatewayAuthRequest;
|
|
456
584
|
engine: Engine;
|
|
@@ -476,6 +604,13 @@ export declare class ClaudeAcpAgent implements Agent {
|
|
|
476
604
|
private readonly gateEnabled;
|
|
477
605
|
/** Story 034 — gate tuning knobs forwarded to setupSessionGate; see {@link AgentDeps.gateOptions}. */
|
|
478
606
|
private readonly gateOptions?;
|
|
607
|
+
/** Story 056 (R3.2) — main-thread agent-persona discovery seam; see {@link AgentDeps.discoverAgents}. */
|
|
608
|
+
private readonly discoverAgents;
|
|
609
|
+
/** Story 063 (R1/R1.1) — offline `available_commands` discovery seam; see {@link AgentDeps.discoverCommands}. */
|
|
610
|
+
private readonly discoverCommands;
|
|
611
|
+
/** Story 056 (#812) — SDK session-metadata reader for the end-of-turn title push; see
|
|
612
|
+
* {@link AgentDeps.getSessionInfo}. */
|
|
613
|
+
private readonly getSessionInfo;
|
|
479
614
|
/** Live PTY-engine registry shared with the per-session engines (story 014 cleanup map). */
|
|
480
615
|
private readonly engines;
|
|
481
616
|
constructor(client: AgentSideConnection, logger?: Logger, engine?: Engine, deps?: AgentDeps);
|
|
@@ -486,7 +621,27 @@ export declare class ClaudeAcpAgent implements Agent {
|
|
|
486
621
|
loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse>;
|
|
487
622
|
listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse>;
|
|
488
623
|
authenticate(_params: AuthenticateRequest): Promise<void>;
|
|
624
|
+
/**
|
|
625
|
+
* ACP `logout` (acp-sdk 1.0.0, acp.d.ts:1646). Under the PTY engine the bridge
|
|
626
|
+
* authenticates lazily and only tracks an in-memory `gatewayAuthRequest`; the
|
|
627
|
+
* interactive `claude` TUI owns the on-disk credential lifecycle. So `logout`
|
|
628
|
+
* here drops the in-memory auth intent and re-offers a clean handshake on the
|
|
629
|
+
* next `initialize()` (authMethods are recomputed there, unconditioned by this
|
|
630
|
+
* field). It does NOT read/write/delete `~/.claude` (billing seam — story 062
|
|
631
|
+
* R2) and never bridges `/logout` to the PTY (R3). Idempotent with no prior
|
|
632
|
+
* authenticate() (R4); active sessions are untouched (R6).
|
|
633
|
+
*/
|
|
634
|
+
logout(_params: LogoutRequest): Promise<LogoutResponse | void>;
|
|
489
635
|
prompt(params: PromptRequest): Promise<PromptResponse>;
|
|
636
|
+
/**
|
|
637
|
+
* Story 056 (#812) — push the sanitized session title to the client via `session_info_update`,
|
|
638
|
+
* fired (fire-and-forget) by the story-024 end-of-turn boundary ONLY (never on cancel/watchdog,
|
|
639
|
+
* via {@link TurnResolverOptions.onTurnResolved}). DEDUPED against {@link Session.lastEmittedTitle}
|
|
640
|
+
* so an unchanged title is not re-emitted, and silent when `getSessionInfo` finds no transcript /
|
|
641
|
+
* the title is empty. Every error is swallowed and logged — this MUST NEVER reject the turn (it is
|
|
642
|
+
* never awaited in `prompt()`), and a slow/never-resolving reader cannot delay the PromptResponse.
|
|
643
|
+
*/
|
|
644
|
+
private emitSessionTitleUpdate;
|
|
490
645
|
cancel(params: CancelNotification): Promise<void>;
|
|
491
646
|
/** Cleanly tear down a session: cancel in-flight work, dispose resources,
|
|
492
647
|
* and remove it from the session map. */
|
|
@@ -494,7 +649,7 @@ export declare class ClaudeAcpAgent implements Agent {
|
|
|
494
649
|
/** Tear down all active sessions. Called when the ACP connection closes. */
|
|
495
650
|
dispose(): Promise<void>;
|
|
496
651
|
closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse>;
|
|
497
|
-
|
|
652
|
+
deleteSession(params: DeleteSessionRequest): Promise<DeleteSessionResponse>;
|
|
498
653
|
setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse>;
|
|
499
654
|
setSessionConfigOption(params: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse>;
|
|
500
655
|
/**
|
|
@@ -559,19 +714,60 @@ export declare class ClaudeAcpAgent implements Agent {
|
|
|
559
714
|
* Order is load-bearing for R3.7: re-spawn FIRST, and swap in + tear down the old PTY ONLY once the new
|
|
560
715
|
* one is live — so a failed re-spawn leaves the prior PTY/currentValue intact (never
|
|
561
716
|
* torn-down-without-replacement). Re-spawn runs only while idle, so the old PTY has no pending turn to
|
|
562
|
-
* double-resolve. The `respawning` latch defers concurrent selector changes (R3.8).
|
|
717
|
+
* double-resolve. The `respawning` latch defers concurrent selector changes (R3.8). Re-spawning for
|
|
718
|
+
* ONE selector preserves the OTHER two (mode / effort / agent — Story 056 added agent) by reading
|
|
719
|
+
* their current values, so the resume argv always carries all three flags.
|
|
563
720
|
*/
|
|
564
721
|
private respawnSession;
|
|
565
722
|
/** Story 046 — the session's current effort configOption value (undefined when no effort option). */
|
|
566
723
|
private currentEffort;
|
|
724
|
+
/** Story 056 — the session's current agent configOption value (undefined when no agent option). */
|
|
725
|
+
private currentAgent;
|
|
567
726
|
/**
|
|
568
|
-
* Story
|
|
569
|
-
*
|
|
570
|
-
* (
|
|
571
|
-
*
|
|
572
|
-
* the
|
|
727
|
+
* Story 060 (R2/R3.2) — apply an effort-selector choice, special-casing the `ultracode` sentinel.
|
|
728
|
+
*
|
|
729
|
+
* Selecting `ultracode` (Option A — keyword + scratch, NO re-spawn): activate the session flag (which
|
|
730
|
+
* makes {@link prompt} prefix the OUTGOING prompt with the `ultracode` keyword — the binary's per-turn
|
|
731
|
+
* Workflow opt-in, the effective live mechanism), write the scratch ultracode keys via
|
|
732
|
+
* {@link applyUltracodeSettings} (the declarative spawn-time complement), and set the effort to xhigh
|
|
733
|
+
* through the SAME live `/effort` inject as every other level — NEVER `/effort ultracode` (R1.2). The
|
|
734
|
+
* `already` guard suppresses a redundant `/effort xhigh` re-inject when ultracode is re-selected while
|
|
735
|
+
* already active.
|
|
736
|
+
*
|
|
737
|
+
* Selecting a real level (or `default`) DEACTIVATES ultracode: clear the flag, remove the scratch keys,
|
|
738
|
+
* then apply that level through {@link applyEffortChange} (whose own no-op guard handles a same-level
|
|
739
|
+
* pick). `applyConfigOptionValue` (the caller, after this returns) commits the selector's currentValue,
|
|
740
|
+
* which for `ultracode` correctly stays `"ultracode"` (the {@link buildConfigOptions} `includes` guard
|
|
741
|
+
* keeps it valid across rebuilds).
|
|
742
|
+
*/
|
|
743
|
+
private applyEffortSelection;
|
|
744
|
+
/**
|
|
745
|
+
* Story 046 (R2.2) + Story 056 v4 — apply a reasoning-effort change LIVE via `/effort <level>`.
|
|
746
|
+
* SUPERSEDES the 046 Probe-B re-spawn: `claude` 2.1.195 DOES have a live `/effort <level>` local TUI
|
|
747
|
+
* command (LIVE-VERIFIED — "Set effort level to high…", applied inline, NO "Switch?" dialog unlike
|
|
748
|
+
* /model). So effort now mirrors {@link applyModelSwitch}: a side-channel write, no re-spawn, no turn —
|
|
749
|
+
* which means it ALSO works BEFORE the first interaction (the re-spawn's --resume idle-guard was why
|
|
750
|
+
* effort silently failed pre-first-prompt). Mid-turn it defers (pendingEffortInjection) and flushes
|
|
751
|
+
* when the turn settles. A no-op change applies nothing; effort stays preserved across mode/agent
|
|
752
|
+
* re-spawns (currentEffort → --effort flag), so the spawn-flag path remains as the seed/preserve route.
|
|
573
753
|
*/
|
|
574
754
|
private applyEffortChange;
|
|
755
|
+
/**
|
|
756
|
+
* Side-channel `/effort <level>` write — synchronous, resolves immediately (never a turn). Unlike
|
|
757
|
+
* `/model`, `/effort` applies INLINE with no blocking "Switch?" dialog (LIVE-VERIFIED 2.1.195), so
|
|
758
|
+
* sendPrompt's own submit `\r` is sufficient and NO confirm Enter is scheduled.
|
|
759
|
+
*/
|
|
760
|
+
private injectEffortCommand;
|
|
761
|
+
/**
|
|
762
|
+
* Story 056 (R3.3/R3.4) — apply a main-thread agent-persona change. Like effort, the persona has no
|
|
763
|
+
* live mid-session mechanism (`--agent "<name>"` is a spawn flag), so a change re-spawns in place
|
|
764
|
+
* carrying the flag (mirroring {@link applyEffortChange}), idle-guarded, with the R3.7 failure path
|
|
765
|
+
* and the R3.8 latch. A no-op change (same persona, with the "default" sentinel as the no-persona
|
|
766
|
+
* baseline) applies nothing. Throwing here leaves the caller's applyConfigOptionValue unrun, so the
|
|
767
|
+
* prior currentValue is left unchanged on failure (R3.7). Optimistic-on-apply, like effort: there is
|
|
768
|
+
* no transcript drift event for the agent persona, so it is NOT reconciled afterward (R4.3).
|
|
769
|
+
*/
|
|
770
|
+
private applyAgentChange;
|
|
575
771
|
/**
|
|
576
772
|
* Story 046 (R4.1/R4.2/R4.3, design §8) — reconcile the `mode` configOption from the latest
|
|
577
773
|
* permission-mode event in the exactly-once `messages` slice. Emits current_mode_update EXACTLY ONCE
|
|
@@ -694,13 +890,23 @@ export declare const EMBEDDED_RESOURCE_INLINE_THRESHOLD = 2048;
|
|
|
694
890
|
* anything below the threshold — or large but path-less — is
|
|
695
891
|
* inlined directly so the context is not lost.
|
|
696
892
|
*
|
|
697
|
-
*
|
|
698
|
-
* emit
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
893
|
+
* - image → materialize the base64 to a uuid-named temp file (extension from mimeType)
|
|
894
|
+
* and emit `@<temp-path>` (Story 058 / R1.1). Once at least one image is
|
|
895
|
+
* materialized, a single Read-inducing directive is appended after the loop so
|
|
896
|
+
* the TUI's Read tool fires and vision-encodes it (R1.2). Each temp path is
|
|
897
|
+
* pushed into `materializedSink` (when provided) so the caller can clean it up.
|
|
898
|
+
*
|
|
899
|
+
* `resource` (blob) / `audio` blocks are SILENT no-ops here (R4.1): they emit no PTY bytes
|
|
900
|
+
* and are NOT logged — they are expected-but-unsupported media in v1, not errors. An UNKNOWN
|
|
901
|
+
* block `type` (the `default` branch) and any block whose mapping THROWS are treated as
|
|
902
|
+
* malformed: skipped, recorded via the `logger`, and the remaining valid blocks still map —
|
|
903
|
+
* one bad block never aborts the whole prompt (R1.3). A `materializeImage` failure is caught
|
|
904
|
+
* by that same per-block isolation, so a broken image is skipped, never aborting the prompt.
|
|
905
|
+
*
|
|
906
|
+
* `materializedSink`, when passed, receives every materialized temp path (in order) so the
|
|
907
|
+
* caller owns their lifecycle (cleanup is a later task). The return type stays `string`.
|
|
702
908
|
*/
|
|
703
|
-
export declare function promptToClaude(prompt: PromptRequest, logger?: Logger): string;
|
|
909
|
+
export declare function promptToClaude(prompt: PromptRequest, logger?: Logger, materializedSink?: string[]): string;
|
|
704
910
|
/**
|
|
705
911
|
* Convert an SDKAssistantMessage (Claude) to a SessionNotification (ACP).
|
|
706
912
|
* Only handles text, image, and thinking chunks for now.
|
|
@@ -721,5 +927,27 @@ export declare function runAcp(deps?: AgentDeps): {
|
|
|
721
927
|
connection: AgentSideConnection;
|
|
722
928
|
agent: ClaudeAcpAgent;
|
|
723
929
|
};
|
|
930
|
+
/** Resolve a model alias's context window (the usage_update `size` denominator).
|
|
931
|
+
* NOTE (story 068): there is NO `result.modelUsage` window to refresh from — the
|
|
932
|
+
* JSONL `usage` carries only token counts; the window comes from static curation
|
|
933
|
+
* (the Models API `max_input_tokens` is the real authority, which this fork does
|
|
934
|
+
* not call), as detailed below.
|
|
935
|
+
*
|
|
936
|
+
* Story 068 (R1, R1.1, R1.2): consults the static {@link MODEL_CONTEXT_WINDOWS}
|
|
937
|
+
* alias→window map FIRST (an exact catalog-`value` hit — `opus`=1M, `sonnet`=200K,
|
|
938
|
+
* `sonnet[1m]`=1M, `haiku`=200K, `default`/`opusplan`=200K conservative). This
|
|
939
|
+
* fixes `opus` having wrongly reported 200K. An alias absent from the map then
|
|
940
|
+
* falls back to the legacy `\b1m\b` inference: Anthropic 1M-context variants
|
|
941
|
+
* encode "1m" as a distinct token in the SDK model ID (e.g., "claude-opus-4-6-1m"),
|
|
942
|
+
* which `\b1m\b` catches without also matching "10m" or embedded substrings.
|
|
943
|
+
* `null` (fully unknown) is intentional — the two call sites apply
|
|
944
|
+
* `?? DEFAULT_CONTEXT_WINDOW`. */
|
|
945
|
+
export declare function inferContextWindowFromModel(model: string): number | null;
|
|
946
|
+
/** Story 069 (R1) — AUTHORITATIVE context window from a turn's REAL model ID (the JSONL `model`
|
|
947
|
+
* field), used by the pump to refine the alias seed once the model is known. Exact-ID lookup first
|
|
948
|
+
* (MODEL_ID_CONTEXT_WINDOWS), then a family+version heuristic for dated snapshots / future variants
|
|
949
|
+
* (Opus is NOT uniform: 4.6 and earlier = 200K, 4.7+ = 1M; Sonnet 4.x = 200K but Sonnet 5+ = 1M;
|
|
950
|
+
* haiku = 200K; fable = 1M — story 071), then a
|
|
951
|
+
* `\b1m\b` suffix, then null (R1.3: a missing / non-string id never refines). */
|
|
952
|
+
export declare function inferContextWindowFromModelId(id: string): number | null;
|
|
724
953
|
export {};
|
|
725
|
-
//# sourceMappingURL=acp-agent.d.ts.map
|