@sumicom/quicksave 0.8.9 → 0.8.11
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/dist/ai/cardBuilder.d.ts +67 -2
- package/dist/ai/cardBuilder.d.ts.map +1 -1
- package/dist/ai/cardBuilder.js +364 -26
- package/dist/ai/cardBuilder.js.map +1 -1
- package/dist/ai/claudeCliProvider.d.ts +14 -0
- package/dist/ai/claudeCliProvider.d.ts.map +1 -1
- package/dist/ai/claudeCliProvider.js +83 -2
- package/dist/ai/claudeCliProvider.js.map +1 -1
- package/dist/ai/claudeCodeProvider.d.ts.map +1 -1
- package/dist/ai/claudeCodeProvider.js +2 -0
- package/dist/ai/claudeCodeProvider.js.map +1 -1
- package/dist/ai/claudeSdkProvider.d.ts.map +1 -1
- package/dist/ai/claudeSdkProvider.js +13 -2
- package/dist/ai/claudeSdkProvider.js.map +1 -1
- package/dist/ai/claudeTerminal/cardSynth.d.ts +63 -0
- package/dist/ai/claudeTerminal/cardSynth.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/cardSynth.js +92 -0
- package/dist/ai/claudeTerminal/cardSynth.js.map +1 -0
- package/dist/ai/claudeTerminal/hookBridge.d.ts +56 -0
- package/dist/ai/claudeTerminal/hookBridge.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/hookBridge.js +131 -0
- package/dist/ai/claudeTerminal/hookBridge.js.map +1 -0
- package/dist/ai/claudeTerminal/hookHandler.d.ts +18 -0
- package/dist/ai/claudeTerminal/hookHandler.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/hookHandler.js +124 -0
- package/dist/ai/claudeTerminal/hookHandler.js.map +1 -0
- package/dist/ai/claudeTerminal/index.d.ts +5 -0
- package/dist/ai/claudeTerminal/index.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/index.js +7 -0
- package/dist/ai/claudeTerminal/index.js.map +1 -0
- package/dist/ai/claudeTerminal/jsonlTail.d.ts +40 -0
- package/dist/ai/claudeTerminal/jsonlTail.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/jsonlTail.js +129 -0
- package/dist/ai/claudeTerminal/jsonlTail.js.map +1 -0
- package/dist/ai/claudeTerminal/provider.d.ts +106 -0
- package/dist/ai/claudeTerminal/provider.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/provider.js +579 -0
- package/dist/ai/claudeTerminal/provider.js.map +1 -0
- package/dist/ai/claudeTerminal/settingsBuilder.d.ts +44 -0
- package/dist/ai/claudeTerminal/settingsBuilder.d.ts.map +1 -0
- package/dist/ai/claudeTerminal/settingsBuilder.js +40 -0
- package/dist/ai/claudeTerminal/settingsBuilder.js.map +1 -0
- package/dist/ai/codexAppServer/cardAdapter.d.ts.map +1 -1
- package/dist/ai/codexAppServer/cardAdapter.js +13 -5
- package/dist/ai/codexAppServer/cardAdapter.js.map +1 -1
- package/dist/ai/codexAppServer/provider.d.ts +13 -2
- package/dist/ai/codexAppServer/provider.d.ts.map +1 -1
- package/dist/ai/codexAppServer/provider.js +161 -26
- package/dist/ai/codexAppServer/provider.js.map +1 -1
- package/dist/ai/profiles/project-sandbox.sb +26 -0
- package/dist/ai/provider.d.ts +29 -1
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js +1 -0
- package/dist/ai/provider.js.map +1 -1
- package/dist/ai/queuedUserPrompts.d.ts +8 -0
- package/dist/ai/queuedUserPrompts.d.ts.map +1 -0
- package/dist/ai/queuedUserPrompts.js +19 -0
- package/dist/ai/queuedUserPrompts.js.map +1 -0
- package/dist/ai/realtimeTranscription.d.ts +39 -0
- package/dist/ai/realtimeTranscription.d.ts.map +1 -0
- package/dist/ai/realtimeTranscription.js +154 -0
- package/dist/ai/realtimeTranscription.js.map +1 -0
- package/dist/ai/sandboxMcp.d.ts +7 -0
- package/dist/ai/sandboxMcp.d.ts.map +1 -1
- package/dist/ai/sandboxMcp.js +4 -0
- package/dist/ai/sandboxMcp.js.map +1 -1
- package/dist/ai/sandboxMcpStdio.d.ts +1 -1
- package/dist/ai/sandboxMcpStdio.js +120 -47
- package/dist/ai/sandboxMcpStdio.js.map +1 -1
- package/dist/ai/sessionManager.d.ts +14 -0
- package/dist/ai/sessionManager.d.ts.map +1 -1
- package/dist/ai/sessionManager.js +147 -3
- package/dist/ai/sessionManager.js.map +1 -1
- package/dist/ai/sessionRegistry.d.ts +6 -0
- package/dist/ai/sessionRegistry.d.ts.map +1 -1
- package/dist/ai/sessionRegistry.js +13 -0
- package/dist/ai/sessionRegistry.js.map +1 -1
- package/dist/ai/sessionRegistryLocator.d.ts +14 -0
- package/dist/ai/sessionRegistryLocator.d.ts.map +1 -0
- package/dist/ai/sessionRegistryLocator.js +44 -0
- package/dist/ai/sessionRegistryLocator.js.map +1 -0
- package/dist/ai/systemPrompt.d.ts.map +1 -1
- package/dist/ai/systemPrompt.js +1 -0
- package/dist/ai/systemPrompt.js.map +1 -1
- package/dist/ai/voiceStream.d.ts +74 -0
- package/dist/ai/voiceStream.d.ts.map +1 -0
- package/dist/ai/voiceStream.js +179 -0
- package/dist/ai/voiceStream.js.map +1 -0
- package/dist/ai/voiceTranscription.d.ts +33 -0
- package/dist/ai/voiceTranscription.d.ts.map +1 -0
- package/dist/ai/voiceTranscription.js +122 -0
- package/dist/ai/voiceTranscription.js.map +1 -0
- package/dist/files/fileBrowser.d.ts.map +1 -1
- package/dist/files/fileBrowser.js +3 -2
- package/dist/files/fileBrowser.js.map +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts.map +1 -1
- package/dist/handlers/legacyBusAdapter.js +6 -1
- package/dist/handlers/legacyBusAdapter.js.map +1 -1
- package/dist/handlers/messageHandler.d.ts +5 -0
- package/dist/handlers/messageHandler.d.ts.map +1 -1
- package/dist/handlers/messageHandler.js +100 -5
- package/dist/handlers/messageHandler.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/service/ipcClient.js +1 -1
- package/dist/service/ipcClient.js.map +1 -1
- package/dist/service/run.d.ts.map +1 -1
- package/dist/service/run.js +74 -3
- package/dist/service/run.js.map +1 -1
- package/dist/service/types.js +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 King Young Technology
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* ClaudeTerminalProvider — spawns `claude` in TUI mode inside the existing
|
|
5
|
+
* terminalManager PTY, intercepts turn events via hooks, tails the session
|
|
6
|
+
* JSONL for structured content, and bridges everything into the same
|
|
7
|
+
* CodingAgentProvider contract that ClaudeCliProvider satisfies.
|
|
8
|
+
*
|
|
9
|
+
* Three input channels feed cards to the PWA:
|
|
10
|
+
* - PTY screen → live terminal panel (handled by existing terminal:* verbs)
|
|
11
|
+
* - Hook events → tool_use / tool_result / turn boundary cards (low latency)
|
|
12
|
+
* - JSONL tail → assistant text + final reconciliation (per-message flush)
|
|
13
|
+
*
|
|
14
|
+
* See docs/plans/2026-05-25-claude-terminal-provider.md for the architecture
|
|
15
|
+
* rationale and probe results that justify per-message flush timing.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
18
|
+
import { dirname, join } from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { claudeProjectDir, jsonlPath } from '../cardBuilder.js';
|
|
21
|
+
import { getTerminalManager } from '../../terminal/terminalManager.js';
|
|
22
|
+
import { getClaudeBin } from '../claudeCliProvider.js';
|
|
23
|
+
import { HookBridge } from './hookBridge.js';
|
|
24
|
+
import { buildHookSettings } from './settingsBuilder.js';
|
|
25
|
+
import { JsonlTail } from './jsonlTail.js';
|
|
26
|
+
import { CardSynth } from './cardSynth.js';
|
|
27
|
+
const __ownDir = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
/**
|
|
29
|
+
* Hooks we register for M2:
|
|
30
|
+
* - UserPromptSubmit: fires when the user submits text into the TUI.
|
|
31
|
+
* - PreToolUse: fires immediately before claude executes a tool —
|
|
32
|
+
* lets us emit a tool_use card without waiting for
|
|
33
|
+
* the assistant message JSONL flush.
|
|
34
|
+
* - PostToolUse: fires immediately after the tool returns — same
|
|
35
|
+
* latency win for tool_result cards.
|
|
36
|
+
* - PermissionRequest: fires before tool execution when the tool needs
|
|
37
|
+
* user confirmation. We bridge it to
|
|
38
|
+
* `ProviderCallbacks.handlePermissionRequest` so the
|
|
39
|
+
* PWA dialog (not the TUI's y/n) decides.
|
|
40
|
+
* - Stop: fires when the assistant turn completes — anchors
|
|
41
|
+
* the stream-end CardEvent that stops the spinner.
|
|
42
|
+
*/
|
|
43
|
+
const ACTIVE_HOOKS = [
|
|
44
|
+
'UserPromptSubmit',
|
|
45
|
+
'PreToolUse',
|
|
46
|
+
'PostToolUse',
|
|
47
|
+
'PermissionRequest',
|
|
48
|
+
'Stop',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Delay before the FIRST attempt to type into a freshly spawned TUI. Claude
|
|
52
|
+
* paints the welcome screen and reads `~/.claude/projects` metadata before it
|
|
53
|
+
* accepts input. Most boxes are ready by now so the prompt lands on the first
|
|
54
|
+
* try; slower/cold boxes fall back to the re-type loop in
|
|
55
|
+
* `sendPromptUntilAccepted` instead of relying on this single guess.
|
|
56
|
+
*/
|
|
57
|
+
const TUI_INITIAL_DELAY_MS = 1000;
|
|
58
|
+
/**
|
|
59
|
+
* How long to wait for proof a typed prompt was accepted (the session JSONL
|
|
60
|
+
* appearing / growing) before re-typing it. A cold TUI that ate the first
|
|
61
|
+
* keystrokes never produces that proof, so we re-type until it does.
|
|
62
|
+
*/
|
|
63
|
+
const PROMPT_RETRY_INTERVAL_MS = 2500;
|
|
64
|
+
/** Gap between writing the prompt text and the submit CR so the TUI can paint. */
|
|
65
|
+
const PROMPT_SUBMIT_GAP_MS = 150;
|
|
66
|
+
/** Overall ceiling for discovering / starting the session JSONL. */
|
|
67
|
+
const SESSION_DISCOVER_TIMEOUT_MS = 30_000;
|
|
68
|
+
/**
|
|
69
|
+
* Pick the right interpreter + handler path so the hook command works whether
|
|
70
|
+
* the daemon runs from source (tsx, .ts file) or compiled output (node, .js).
|
|
71
|
+
*/
|
|
72
|
+
export function resolveHookCommand() {
|
|
73
|
+
// We resolve relative to this file's location. When compiled, this file is
|
|
74
|
+
// `<dist>/.../claudeTerminal/provider.js` and hookHandler.js sits next to it.
|
|
75
|
+
// When running via tsx in dev, this file is `<src>/.../claudeTerminal/provider.ts`
|
|
76
|
+
// and hookHandler.ts sits next to it; spawning a fresh `node hookHandler.ts`
|
|
77
|
+
// would fail, so we run it through `tsx`.
|
|
78
|
+
const jsHandler = join(__ownDir, 'hookHandler.js');
|
|
79
|
+
if (existsSync(jsHandler)) {
|
|
80
|
+
return { interpreter: 'node', handlerPath: jsHandler };
|
|
81
|
+
}
|
|
82
|
+
// Dev: resolve `tsx` by absolute path, NOT `npx tsx`. Claude runs the hook
|
|
83
|
+
// command with cwd = the user's project dir; in this pnpm monorepo `tsx`
|
|
84
|
+
// lives at `apps/agent/node_modules/.bin/tsx` (not hoisted to the workspace
|
|
85
|
+
// root), so `npx tsx` searches upward from the wrong cwd, falls through to a
|
|
86
|
+
// registry fetch, and dies with `sh: 1: tsx: not found` — exactly the Stop
|
|
87
|
+
// hook failure this guards against. See sandboxMcp.ts for the same fix.
|
|
88
|
+
// __ownDir is apps/agent/src/ai/claudeTerminal → three levels up is apps/agent.
|
|
89
|
+
const tsHandler = join(__ownDir, 'hookHandler.ts');
|
|
90
|
+
const tsxBin = join(__ownDir, '..', '..', '..', 'node_modules', '.bin', 'tsx');
|
|
91
|
+
return { interpreter: tsxBin, handlerPath: tsHandler };
|
|
92
|
+
}
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// TerminalProviderSession — wraps a terminalManager terminal + hookBridge
|
|
95
|
+
// ============================================================================
|
|
96
|
+
class TerminalProviderSession {
|
|
97
|
+
sessionId;
|
|
98
|
+
terminalId;
|
|
99
|
+
synth;
|
|
100
|
+
bridge;
|
|
101
|
+
tail;
|
|
102
|
+
_alive = true;
|
|
103
|
+
constructor(opts) {
|
|
104
|
+
this.sessionId = opts.sessionId;
|
|
105
|
+
this.terminalId = opts.terminalId;
|
|
106
|
+
this.bridge = opts.bridge;
|
|
107
|
+
this.tail = opts.tail;
|
|
108
|
+
this.synth = opts.synth;
|
|
109
|
+
}
|
|
110
|
+
sendUserMessage(prompt, _attachments) {
|
|
111
|
+
if (!this._alive)
|
|
112
|
+
return;
|
|
113
|
+
// TUI eats CR as submit (paste-bracketed input is handled by claude's
|
|
114
|
+
// input handler). Send the prompt followed by Enter.
|
|
115
|
+
try {
|
|
116
|
+
getTerminalManager().write(this.terminalId, prompt);
|
|
117
|
+
// Tiny delay so the TUI has time to render the prompt before the submit.
|
|
118
|
+
// 60ms picked empirically — anything < 30ms races on slow boxes.
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
if (!this._alive)
|
|
121
|
+
return;
|
|
122
|
+
try {
|
|
123
|
+
getTerminalManager().write(this.terminalId, '\r');
|
|
124
|
+
}
|
|
125
|
+
catch { /* */ }
|
|
126
|
+
}, 60);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
console.error(`[claude-terminal] sendUserMessage failed:`, err);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
interrupt() {
|
|
133
|
+
if (!this._alive)
|
|
134
|
+
return;
|
|
135
|
+
// Ctrl-C — claude TUI listens for this to abort the current turn.
|
|
136
|
+
try {
|
|
137
|
+
getTerminalManager().write(this.terminalId, '\x03');
|
|
138
|
+
}
|
|
139
|
+
catch { /* */ }
|
|
140
|
+
}
|
|
141
|
+
kill() {
|
|
142
|
+
if (!this._alive)
|
|
143
|
+
return;
|
|
144
|
+
this._alive = false;
|
|
145
|
+
try {
|
|
146
|
+
getTerminalManager().close(this.terminalId, true);
|
|
147
|
+
}
|
|
148
|
+
catch { /* */ }
|
|
149
|
+
this.tail.stop();
|
|
150
|
+
void this.bridge.stop();
|
|
151
|
+
}
|
|
152
|
+
get alive() {
|
|
153
|
+
return this._alive;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// ClaudeTerminalProvider — implements CodingAgentProvider
|
|
158
|
+
// ============================================================================
|
|
159
|
+
export class ClaudeTerminalProvider {
|
|
160
|
+
id = 'claude-terminal';
|
|
161
|
+
historyMode = 'claude-jsonl';
|
|
162
|
+
label = 'Claude (Terminal)';
|
|
163
|
+
async startSession(opts, cardBuilder, callbacks) {
|
|
164
|
+
return this.spawn(opts, cardBuilder, callbacks, undefined);
|
|
165
|
+
}
|
|
166
|
+
async resumeSession(opts, cardBuilder, callbacks) {
|
|
167
|
+
return this.spawn(opts, cardBuilder, callbacks, opts.sessionId);
|
|
168
|
+
}
|
|
169
|
+
async spawn(opts, cardBuilder, callbacks, resumeSessionId) {
|
|
170
|
+
// 1. Hook bridge — start before we spawn claude so the socket exists.
|
|
171
|
+
const bridge = new HookBridge();
|
|
172
|
+
await bridge.start();
|
|
173
|
+
// 2. Settings JSON with our hooks.
|
|
174
|
+
const { interpreter, handlerPath } = resolveHookCommand();
|
|
175
|
+
const settings = buildHookSettings({
|
|
176
|
+
handlerPath,
|
|
177
|
+
socketPath: bridge.socketPath,
|
|
178
|
+
events: ACTIVE_HOOKS,
|
|
179
|
+
nodeBin: interpreter,
|
|
180
|
+
});
|
|
181
|
+
// 3. Build claude argv. TUI mode = no -p, no --input-format.
|
|
182
|
+
const args = [];
|
|
183
|
+
if (opts.model)
|
|
184
|
+
args.push('--model', opts.model);
|
|
185
|
+
args.push('--settings', JSON.stringify(settings));
|
|
186
|
+
// Forward the user's permission preset. `bypassPermissions` skips the TUI
|
|
187
|
+
// y/n prompt AND our PermissionRequest hook — exactly what the user
|
|
188
|
+
// wants when they pick it. For `acceptEdits` / `plan` / `auto` we pass
|
|
189
|
+
// through directly; claude TUI honors them. For `default` we omit the
|
|
190
|
+
// flag and let claude use its built-in default.
|
|
191
|
+
if (opts.permissionLevel && opts.permissionLevel !== 'default') {
|
|
192
|
+
args.push('--permission-mode', opts.permissionLevel);
|
|
193
|
+
}
|
|
194
|
+
if (resumeSessionId)
|
|
195
|
+
args.push('--resume', resumeSessionId);
|
|
196
|
+
// 4. Snapshot existing JSONLs so we can detect the new one.
|
|
197
|
+
const projectDir = claudeProjectDir(opts.cwd);
|
|
198
|
+
const beforeJsonls = new Set();
|
|
199
|
+
try {
|
|
200
|
+
if (existsSync(projectDir)) {
|
|
201
|
+
for (const f of readdirSync(projectDir)) {
|
|
202
|
+
if (f.endsWith('.jsonl'))
|
|
203
|
+
beforeJsonls.add(f);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch { /* directory may not exist yet */ }
|
|
208
|
+
// 5. Spawn claude inside a terminalManager terminal.
|
|
209
|
+
const term = await getTerminalManager().create({
|
|
210
|
+
cwd: opts.cwd,
|
|
211
|
+
shell: getClaudeBin(),
|
|
212
|
+
args,
|
|
213
|
+
cols: 120,
|
|
214
|
+
rows: 30,
|
|
215
|
+
title: `Claude ${resumeSessionId ? '↻' : '✨'} ${opts.cwd.split('/').pop() ?? ''}`,
|
|
216
|
+
});
|
|
217
|
+
// 6. CRITICAL ordering note: claude TUI does NOT create the session
|
|
218
|
+
// JSONL at startup — it lazily writes it when the FIRST user message
|
|
219
|
+
// is submitted. For new sessions we must type the prompt into the PTY
|
|
220
|
+
// BEFORE polling for the JSONL, otherwise discoverSessionId() will
|
|
221
|
+
// hit its 30s timeout waiting on a file that will never appear.
|
|
222
|
+
//
|
|
223
|
+
// For resume, the file already exists and `--resume <sid>` makes
|
|
224
|
+
// claude touch it on startup, so we can poll immediately.
|
|
225
|
+
// 7. Obtain the session JSONL / sessionId.
|
|
226
|
+
let sessionId;
|
|
227
|
+
try {
|
|
228
|
+
if (!resumeSessionId && opts.prompt) {
|
|
229
|
+
// New session: claude TUI lazily creates the session JSONL only when
|
|
230
|
+
// the FIRST user message is accepted. We can't reliably guess when the
|
|
231
|
+
// TUI is ready for keystrokes — cold boxes paint the welcome screen
|
|
232
|
+
// slowly and silently eat early input, which used to leave
|
|
233
|
+
// discoverSessionId() waiting on a JSONL that never appeared (the 30s
|
|
234
|
+
// timeout seen in the field). So drive on the RESULT instead of a fixed
|
|
235
|
+
// delay: type the prompt, wait briefly for the JSONL to appear, and
|
|
236
|
+
// re-type if it didn't — the new JSONL is proof the prompt landed.
|
|
237
|
+
const prompt = opts.prompt;
|
|
238
|
+
sessionId = await sendPromptUntilAccepted({
|
|
239
|
+
send: () => this.typePrompt(term.terminalId, prompt),
|
|
240
|
+
probe: () => this.scanForNewJsonl(projectDir, beforeJsonls, undefined),
|
|
241
|
+
timeoutMs: SESSION_DISCOVER_TIMEOUT_MS,
|
|
242
|
+
initialDelayMs: TUI_INITIAL_DELAY_MS,
|
|
243
|
+
retryIntervalMs: PROMPT_RETRY_INTERVAL_MS,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
// Resume: the JSONL already exists (claude touches it on `--resume`),
|
|
248
|
+
// so just poll for it. The follow-up prompt is injected in the
|
|
249
|
+
// background at step 11 once the session is wired.
|
|
250
|
+
sessionId = await this.discoverSessionId(projectDir, beforeJsonls, resumeSessionId);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
// Don't leak the spawned PTY + socket if we never got a sessionId.
|
|
255
|
+
try {
|
|
256
|
+
getTerminalManager().close(term.terminalId, true);
|
|
257
|
+
}
|
|
258
|
+
catch { /* */ }
|
|
259
|
+
try {
|
|
260
|
+
await bridge.stop();
|
|
261
|
+
}
|
|
262
|
+
catch { /* */ }
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
cardBuilder.updateSessionId(sessionId);
|
|
266
|
+
// 8. Start tailing the JSONL.
|
|
267
|
+
const tail = new JsonlTail(jsonlPath(sessionId, opts.cwd));
|
|
268
|
+
tail.start(50);
|
|
269
|
+
const synth = new CardSynth({
|
|
270
|
+
cardBuilder,
|
|
271
|
+
emit: (evt) => callbacks.emitCardEvent(evt),
|
|
272
|
+
});
|
|
273
|
+
const session = new TerminalProviderSession({
|
|
274
|
+
sessionId,
|
|
275
|
+
terminalId: term.terminalId,
|
|
276
|
+
bridge,
|
|
277
|
+
tail,
|
|
278
|
+
synth,
|
|
279
|
+
});
|
|
280
|
+
// 9. Wire hook events → callbacks.
|
|
281
|
+
bridge.onRequest((req) => this.handleHookRequest(req, session, cardBuilder, callbacks));
|
|
282
|
+
// 10. Wire JSONL messages → cardBuilder.
|
|
283
|
+
tail.on('message', (msg) => this.handleJsonlMessage(msg, session, cardBuilder, callbacks));
|
|
284
|
+
// 11. Resume path: inject the follow-up prompt now that the session is
|
|
285
|
+
// wired. (New-session prompt was already accepted before step 7.)
|
|
286
|
+
//
|
|
287
|
+
// Unlike the new-session path, discoverSessionId returns almost
|
|
288
|
+
// immediately on resume — `--resume <sid>` makes claude touch the
|
|
289
|
+
// existing JSONL on startup — so we never block long enough for the TUI
|
|
290
|
+
// to finish painting, and an early keystroke gets eaten. Rather than
|
|
291
|
+
// guess a fixed warmup, drive on the same result signal (JSONL growth)
|
|
292
|
+
// and re-type if needed. Runs in the background: we already have the
|
|
293
|
+
// sessionId, so callers must not block on acceptance.
|
|
294
|
+
if (resumeSessionId && opts.prompt) {
|
|
295
|
+
void this.injectResumePrompt(session, tail.path, opts.prompt);
|
|
296
|
+
}
|
|
297
|
+
return { sessionId, session };
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Type a prompt into the TUI: write the text, then submit with Enter after a
|
|
301
|
+
* short render gap. Resolves once the CR has been written so callers in a
|
|
302
|
+
* re-type loop submit one prompt at a time (no overlapping setTimeout CRs).
|
|
303
|
+
* This only spaces the text from the submit — it does NOT wait for the TUI to
|
|
304
|
+
* be ready; readiness is handled by the re-type loop in sendPromptUntilAccepted.
|
|
305
|
+
*/
|
|
306
|
+
async typePrompt(terminalId, prompt) {
|
|
307
|
+
const tm = getTerminalManager();
|
|
308
|
+
try {
|
|
309
|
+
tm.write(terminalId, prompt);
|
|
310
|
+
// Tiny gap so the TUI renders the prompt before the submit CR lands.
|
|
311
|
+
await sleep(PROMPT_SUBMIT_GAP_MS);
|
|
312
|
+
tm.write(terminalId, '\r');
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
console.error('[claude-terminal] typePrompt failed:', err);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Synchronously scan the project dir for a session JSONL. For a new session,
|
|
320
|
+
* returns the basename of any .jsonl not present in `before`. For resume,
|
|
321
|
+
* returns `expectResume` once its file exists. Returns null if none match.
|
|
322
|
+
*/
|
|
323
|
+
scanForNewJsonl(projectDir, before, expectResume) {
|
|
324
|
+
try {
|
|
325
|
+
if (existsSync(projectDir)) {
|
|
326
|
+
for (const f of readdirSync(projectDir)) {
|
|
327
|
+
if (!f.endsWith('.jsonl'))
|
|
328
|
+
continue;
|
|
329
|
+
if (expectResume) {
|
|
330
|
+
if (f === `${expectResume}.jsonl`)
|
|
331
|
+
return expectResume;
|
|
332
|
+
}
|
|
333
|
+
else if (!before.has(f)) {
|
|
334
|
+
return f.slice(0, -'.jsonl'.length);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch { /* directory may not exist yet */ }
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Resume: inject the follow-up prompt into the live TUI in the background.
|
|
344
|
+
* We already have the sessionId, so this doesn't block startSession. Drives on
|
|
345
|
+
* a result signal — the existing JSONL growing past its pre-prompt size — and
|
|
346
|
+
* re-types if the TUI ate the keystrokes before it was ready.
|
|
347
|
+
*/
|
|
348
|
+
async injectResumePrompt(session, jsonlFilePath, prompt) {
|
|
349
|
+
let baseline = null;
|
|
350
|
+
try {
|
|
351
|
+
await sendPromptUntilAccepted({
|
|
352
|
+
send: () => this.typePrompt(session.terminalId, prompt),
|
|
353
|
+
probe: () => {
|
|
354
|
+
let size;
|
|
355
|
+
try {
|
|
356
|
+
size = statSync(jsonlFilePath).size;
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
// First probe (after initialDelay) anchors the baseline so claude's
|
|
362
|
+
// own resume-startup writes aren't mistaken for our prompt landing.
|
|
363
|
+
if (baseline === null) {
|
|
364
|
+
baseline = size;
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
return size > baseline ? String(size) : null;
|
|
368
|
+
},
|
|
369
|
+
abort: () => !session.alive,
|
|
370
|
+
timeoutMs: SESSION_DISCOVER_TIMEOUT_MS,
|
|
371
|
+
initialDelayMs: TUI_INITIAL_DELAY_MS,
|
|
372
|
+
retryIntervalMs: PROMPT_RETRY_INTERVAL_MS,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
if (session.alive) {
|
|
377
|
+
console.error('[claude-terminal] resume prompt injection failed:', err);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* After spawn, watch the project dir for a fresh .jsonl that's not in
|
|
383
|
+
* `before`. Returns its session id (the basename without .jsonl).
|
|
384
|
+
*
|
|
385
|
+
* For resume, the file already exists — we just wait for it to appear if it
|
|
386
|
+
* doesn't yet (claude touches it on startup).
|
|
387
|
+
*/
|
|
388
|
+
async discoverSessionId(projectDir, before, expectResume) {
|
|
389
|
+
const deadline = Date.now() + SESSION_DISCOVER_TIMEOUT_MS;
|
|
390
|
+
while (Date.now() < deadline) {
|
|
391
|
+
const sid = this.scanForNewJsonl(projectDir, before, expectResume);
|
|
392
|
+
if (sid)
|
|
393
|
+
return sid;
|
|
394
|
+
await sleep(100);
|
|
395
|
+
}
|
|
396
|
+
throw new Error('claude-terminal: session JSONL did not appear within 30s');
|
|
397
|
+
}
|
|
398
|
+
handleHookRequest(req, session, cardBuilder, callbacks) {
|
|
399
|
+
switch (req.event) {
|
|
400
|
+
case 'UserPromptSubmit':
|
|
401
|
+
// Fire-and-forget. Future: mark activeTurn = true, snapshot jsonlCutoff.
|
|
402
|
+
req.respond(null);
|
|
403
|
+
return;
|
|
404
|
+
case 'PreToolUse': {
|
|
405
|
+
const p = req.payload;
|
|
406
|
+
const tool_use_id = typeof p.tool_use_id === 'string' ? p.tool_use_id : '';
|
|
407
|
+
const tool_name = typeof p.tool_name === 'string' ? p.tool_name : 'unknown';
|
|
408
|
+
const tool_input = (p.tool_input && typeof p.tool_input === 'object')
|
|
409
|
+
? p.tool_input
|
|
410
|
+
: {};
|
|
411
|
+
if (tool_use_id)
|
|
412
|
+
session.synth.emitToolUse(tool_use_id, tool_name, tool_input);
|
|
413
|
+
callbacks.onToolUse?.(session.sessionId, tool_name, tool_input);
|
|
414
|
+
req.respond(null);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
case 'PostToolUse': {
|
|
418
|
+
const p = req.payload;
|
|
419
|
+
const tool_use_id = typeof p.tool_use_id === 'string' ? p.tool_use_id : '';
|
|
420
|
+
if (tool_use_id) {
|
|
421
|
+
const content = CardSynth.stringifyHookToolResponse(p.tool_response);
|
|
422
|
+
session.synth.emitToolResult(tool_use_id, content, !!p.is_error);
|
|
423
|
+
}
|
|
424
|
+
req.respond(null);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
case 'PermissionRequest': {
|
|
428
|
+
// ASYNC — listener returns immediately; respond is called from the
|
|
429
|
+
// PWA dialog promise resolution. HookBridge has a fallback timer
|
|
430
|
+
// (HOOK_RESPONSE_FALLBACK_MS = 30s) so a hanging dialog can't lock
|
|
431
|
+
// the TUI forever.
|
|
432
|
+
const p = req.payload;
|
|
433
|
+
const toolName = typeof p.tool_name === 'string' ? p.tool_name : 'unknown';
|
|
434
|
+
const toolInput = (p.tool_input && typeof p.tool_input === 'object')
|
|
435
|
+
? p.tool_input
|
|
436
|
+
: {};
|
|
437
|
+
const toolUseId = typeof p.tool_use_id === 'string' ? p.tool_use_id : '';
|
|
438
|
+
callbacks.handlePermissionRequest(session.sessionId, { toolName, toolInput, toolUseId })
|
|
439
|
+
.then((decision) => {
|
|
440
|
+
if (decision.action === 'deny') {
|
|
441
|
+
req.respond({
|
|
442
|
+
hookSpecificOutput: {
|
|
443
|
+
hookEventName: 'PermissionRequest',
|
|
444
|
+
decision: { behavior: 'deny', message: decision.response || 'Denied' },
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
req.respond({
|
|
450
|
+
hookSpecificOutput: {
|
|
451
|
+
hookEventName: 'PermissionRequest',
|
|
452
|
+
decision: { behavior: 'allow' },
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
})
|
|
457
|
+
.catch((err) => {
|
|
458
|
+
console.error('[claude-terminal] permission callback failed:', err);
|
|
459
|
+
req.respond(null);
|
|
460
|
+
});
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
case 'Stop': {
|
|
464
|
+
// Emit a stream-end card so the PWA spinner stops.
|
|
465
|
+
const streamEnd = {
|
|
466
|
+
sessionId: session.sessionId,
|
|
467
|
+
success: true,
|
|
468
|
+
};
|
|
469
|
+
callbacks.emitStreamEnd(streamEnd);
|
|
470
|
+
void cardBuilder.scheduleDeferredClear();
|
|
471
|
+
req.respond(null);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
default:
|
|
475
|
+
req.respond(null);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
handleJsonlMessage(msg, session, cardBuilder, callbacks) {
|
|
479
|
+
// Assistant turn: text → card, tool_use → routed through synth (deduped
|
|
480
|
+
// against PreToolUse hook).
|
|
481
|
+
if (msg.type === 'assistant' && msg.message?.content) {
|
|
482
|
+
const blocks = msg.message.content;
|
|
483
|
+
for (const block of blocks) {
|
|
484
|
+
if (block.type === 'text' && typeof block.text === 'string' && block.text) {
|
|
485
|
+
callbacks.emitCardEvent(cardBuilder.assistantText(block.text));
|
|
486
|
+
}
|
|
487
|
+
else if (block.type === 'tool_use' && typeof block.id === 'string') {
|
|
488
|
+
const name = typeof block.name === 'string' ? block.name : 'unknown';
|
|
489
|
+
const input = (block.input && typeof block.input === 'object') ? block.input : {};
|
|
490
|
+
session.synth.emitToolUse(block.id, name, input);
|
|
491
|
+
callbacks.onToolUse?.(session.sessionId, name, input);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// User turn: prompt text → card, tool_result blocks → routed through synth
|
|
496
|
+
// (deduped against PostToolUse hook).
|
|
497
|
+
if (msg.type === 'user' && msg.message?.content) {
|
|
498
|
+
const content = msg.message.content;
|
|
499
|
+
if (typeof content === 'string' && content) {
|
|
500
|
+
callbacks.emitCardEvent(cardBuilder.userMessage(content));
|
|
501
|
+
}
|
|
502
|
+
else if (Array.isArray(content)) {
|
|
503
|
+
for (const block of content) {
|
|
504
|
+
if (block.type === 'text' && typeof block.text === 'string' && block.text) {
|
|
505
|
+
callbacks.emitCardEvent(cardBuilder.userMessage(block.text));
|
|
506
|
+
}
|
|
507
|
+
else if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {
|
|
508
|
+
const text = CardSynth.stringifyHookToolResponse(block.content);
|
|
509
|
+
session.synth.emitToolResult(block.tool_use_id, text, !!block.is_error);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
// System init carries the model — surface it.
|
|
515
|
+
if (msg.type === 'system' && msg.subtype === 'init') {
|
|
516
|
+
const model = msg.model;
|
|
517
|
+
if (model)
|
|
518
|
+
callbacks.onModelDetected(model);
|
|
519
|
+
}
|
|
520
|
+
// Structured per-turn system entries. Emit live so they match what
|
|
521
|
+
// buildCardsFromHistory reconstructs on reload (same card shape + meta).
|
|
522
|
+
if (msg.type === 'system' && msg.subtype === 'turn_duration') {
|
|
523
|
+
callbacks.emitCardEvent(cardBuilder.turnDuration(msg));
|
|
524
|
+
}
|
|
525
|
+
if (msg.type === 'system' && msg.subtype === 'stop_hook_summary') {
|
|
526
|
+
callbacks.emitCardEvent(cardBuilder.stopHookSummary(msg));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function sleep(ms) {
|
|
531
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Type a prompt into a freshly spawned (or resumed) claude TUI and keep
|
|
535
|
+
* re-typing until there's proof it was accepted, or the deadline passes.
|
|
536
|
+
*
|
|
537
|
+
* The TUI eats keystrokes sent before it finishes painting, and there's no
|
|
538
|
+
* reliable readiness signal, so a single fixed delay is fragile on cold boxes.
|
|
539
|
+
* Instead we drive on the RESULT (`probe()` going non-null — e.g. the session
|
|
540
|
+
* JSONL appearing or growing): send, wait one `retryIntervalMs` window for
|
|
541
|
+
* acceptance, and re-send if it didn't land. An already-accepted prompt flushes
|
|
542
|
+
* its proof well within one window, so duplicate sends are rare in practice.
|
|
543
|
+
*
|
|
544
|
+
* @returns the token `probe()` returned on acceptance.
|
|
545
|
+
* @throws if the deadline passes without acceptance, or `abort()` fires.
|
|
546
|
+
*/
|
|
547
|
+
export async function sendPromptUntilAccepted(opts) {
|
|
548
|
+
const initialDelayMs = opts.initialDelayMs ?? 0;
|
|
549
|
+
const retryIntervalMs = opts.retryIntervalMs ?? 2500;
|
|
550
|
+
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
551
|
+
const napMs = opts.sleep ?? sleep;
|
|
552
|
+
const clock = opts.now ?? Date.now;
|
|
553
|
+
const checkAbort = () => {
|
|
554
|
+
if (opts.abort?.())
|
|
555
|
+
throw new Error('claude-terminal: prompt injection aborted');
|
|
556
|
+
};
|
|
557
|
+
const deadline = clock() + opts.timeoutMs;
|
|
558
|
+
if (initialDelayMs > 0)
|
|
559
|
+
await napMs(initialDelayMs);
|
|
560
|
+
while (clock() < deadline) {
|
|
561
|
+
checkAbort();
|
|
562
|
+
// Pre-check: on resume the prompt may already have landed from a prior
|
|
563
|
+
// attempt; avoid an unnecessary duplicate send.
|
|
564
|
+
const already = opts.probe();
|
|
565
|
+
if (already !== null)
|
|
566
|
+
return already;
|
|
567
|
+
await opts.send();
|
|
568
|
+
const windowEnd = Math.min(deadline, clock() + retryIntervalMs);
|
|
569
|
+
while (clock() < windowEnd) {
|
|
570
|
+
checkAbort();
|
|
571
|
+
const token = opts.probe();
|
|
572
|
+
if (token !== null)
|
|
573
|
+
return token;
|
|
574
|
+
await napMs(pollIntervalMs);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
throw new Error(`claude-terminal: prompt was not accepted within ${opts.timeoutMs}ms (TUI may never have become ready)`);
|
|
578
|
+
}
|
|
579
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/ai/claudeTerminal/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate the `--settings` JSON for a TUI-spawned `claude` so that selected
|
|
3
|
+
* hooks phone home to our daemon's per-session Unix socket via `hookHandler`.
|
|
4
|
+
*
|
|
5
|
+
* The hook contract (Claude Code v2.x): each hook command is a shell command
|
|
6
|
+
* invoked by claude with the hook payload as JSON on stdin. The command's
|
|
7
|
+
* stdout (if it parses as JSON with `hookSpecificOutput.hookEventName === <event>`)
|
|
8
|
+
* is interpreted as a decision; otherwise the hook is informational.
|
|
9
|
+
*
|
|
10
|
+
* We use a `node` invocation pointing at the compiled `hookHandler.js` so we
|
|
11
|
+
* don't depend on `nc -U` (which is missing from many minimal container images).
|
|
12
|
+
*/
|
|
13
|
+
import type { HookEventName } from './hookBridge.js';
|
|
14
|
+
export interface HookSettings {
|
|
15
|
+
/** Absolute path to the compiled hookHandler.js (or .ts when running under tsx). */
|
|
16
|
+
handlerPath: string;
|
|
17
|
+
/** Absolute path to the daemon's per-session Unix socket. */
|
|
18
|
+
socketPath: string;
|
|
19
|
+
/** Hooks to register. */
|
|
20
|
+
events: readonly HookEventName[];
|
|
21
|
+
/** Optional matcher per hook event (defaults to '*' = all tools). */
|
|
22
|
+
matcher?: string;
|
|
23
|
+
/** Optional node binary override (defaults to 'node' on PATH). */
|
|
24
|
+
nodeBin?: string;
|
|
25
|
+
}
|
|
26
|
+
interface HookSpec {
|
|
27
|
+
matcher: string;
|
|
28
|
+
hooks: Array<{
|
|
29
|
+
type: 'command';
|
|
30
|
+
command: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build the `{ hooks: { ... } }` block to pass via `--settings`.
|
|
35
|
+
*
|
|
36
|
+
* The same handler script handles every event — claude itself tags the payload
|
|
37
|
+
* with `hook_event_name` so the handler can route. We just need one matching
|
|
38
|
+
* spec per event so claude knows to fire it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildHookSettings(opts: HookSettings): {
|
|
41
|
+
hooks: Record<string, HookSpec[]>;
|
|
42
|
+
};
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=settingsBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settingsBuilder.d.ts","sourceRoot":"","sources":["../../../src/ai/claudeTerminal/settingsBuilder.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;CAAE,CAkB3F"}
|