@ebowwa/coder 0.7.64 → 0.7.65
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/index.js +36168 -32
- package/dist/interfaces/ui/terminal/cli/index.js +34253 -158
- package/dist/interfaces/ui/terminal/native/README.md +53 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
- package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
- package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
- package/dist/interfaces/ui/terminal/native/index.js +43 -0
- package/dist/interfaces/ui/terminal/native/index.node +0 -0
- package/dist/interfaces/ui/terminal/native/package.json +34 -0
- package/dist/native/README.md +53 -0
- package/dist/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/native/claude_code_native.dylib +0 -0
- package/dist/native/index.d.ts +0 -480
- package/dist/native/index.darwin-arm64.node +0 -0
- package/dist/native/index.js +43 -1625
- package/dist/native/index.node +0 -0
- package/dist/native/package.json +34 -0
- package/native/index.darwin-arm64.node +0 -0
- package/native/index.js +33 -19
- package/package.json +3 -2
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +17 -14
- package/packages/src/core/agent-loop/compaction.ts +6 -2
- package/packages/src/core/agent-loop/index.ts +2 -0
- package/packages/src/core/agent-loop/loop-state.ts +1 -1
- package/packages/src/core/agent-loop/turn-executor.ts +4 -0
- package/packages/src/core/agent-loop/types.ts +4 -0
- package/packages/src/core/api-client-impl.ts +283 -173
- package/packages/src/core/cognitive-security/hooks.ts +2 -1
- package/packages/src/core/config/todo +7 -0
- package/packages/src/core/context/__tests__/integration.test.ts +334 -0
- package/packages/src/core/context/compaction.ts +170 -0
- package/packages/src/core/context/constants.ts +58 -0
- package/packages/src/core/context/extraction.ts +85 -0
- package/packages/src/core/context/index.ts +66 -0
- package/packages/src/core/context/summarization.ts +251 -0
- package/packages/src/core/context/token-estimation.ts +98 -0
- package/packages/src/core/context/types.ts +59 -0
- package/packages/src/core/models.ts +81 -4
- package/packages/src/core/normalizers/todo +5 -1
- package/packages/src/core/providers/README.md +230 -0
- package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
- package/packages/src/core/providers/index.ts +419 -0
- package/packages/src/core/providers/types.ts +132 -0
- package/packages/src/core/retry.ts +10 -0
- package/packages/src/ecosystem/tools/index.ts +174 -0
- package/packages/src/index.ts +23 -2
- package/packages/src/interfaces/ui/index.ts +17 -20
- package/packages/src/interfaces/ui/spinner.ts +2 -2
- package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
- package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
- package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
- package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
- package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
- package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
- package/packages/src/interfaces/ui/terminal/cli/index.ts +200 -13
- package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +393 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
- package/packages/src/interfaces/ui/terminal/shared/index.ts +13 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +9 -3
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +5 -1
- package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +10 -2
- package/packages/src/native/index.ts +404 -27
- package/packages/src/native/tui_v2_types.ts +39 -0
- package/packages/src/teammates/coordination.test.ts +279 -0
- package/packages/src/teammates/coordination.ts +646 -0
- package/packages/src/teammates/index.ts +95 -25
- package/packages/src/teammates/integration.test.ts +272 -0
- package/packages/src/teammates/runner.test.ts +235 -0
- package/packages/src/teammates/runner.ts +750 -0
- package/packages/src/teammates/schemas.ts +673 -0
- package/packages/src/types/index.ts +1 -0
- package/packages/src/core/context-compaction.ts +0 -578
- package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
- package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +0 -262
- package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +0 -232
- package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +0 -62
- package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +0 -537
- package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +0 -107
- package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +0 -240
- package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +0 -54
- package/packages/src/interfaces/ui/terminal/tui/commands.ts +0 -438
- package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +0 -584
- package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +0 -614
- package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +0 -333
- package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +0 -604
- package/packages/src/interfaces/ui/terminal/tui/components/index.ts +0 -118
- package/packages/src/interfaces/ui/terminal/tui/console.ts +0 -49
- package/packages/src/interfaces/ui/terminal/tui/index.ts +0 -90
- package/packages/src/interfaces/ui/terminal/tui/run.tsx +0 -42
- package/packages/src/interfaces/ui/terminal/tui/spinner.ts +0 -69
- package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +0 -390
- package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +0 -422
- package/packages/src/interfaces/ui/terminal/tui/types.ts +0 -186
- package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +0 -104
- package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +0 -239
|
@@ -6,19 +6,130 @@
|
|
|
6
6
|
* This is a thin orchestrator that:
|
|
7
7
|
* 1. Parses arguments
|
|
8
8
|
* 2. Sets up session (config, MCP, hooks)
|
|
9
|
-
* 3.
|
|
9
|
+
* 3. Initializes teammate mode if enabled
|
|
10
|
+
* 4. Dispatches to TUI or single-query mode
|
|
10
11
|
*/
|
|
11
12
|
|
|
13
|
+
// ============================================
|
|
14
|
+
// PTY WRAPPER DETECTION (must run before any other code)
|
|
15
|
+
// ============================================
|
|
16
|
+
|
|
17
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
18
|
+
import process from "node:process";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if we're running under doppler without a TTY and need a PTY wrapper
|
|
22
|
+
* This must run before any other code to properly handle the TTY requirement
|
|
23
|
+
*
|
|
24
|
+
* When successful wrapping occurs, this function NEVER returns - it exits the process
|
|
25
|
+
* when the wrapped child exits.
|
|
26
|
+
*/
|
|
27
|
+
function checkPtyWrapper(): void {
|
|
28
|
+
const isTTY = process.stdin.isTTY;
|
|
29
|
+
const isDoppler = !!process.env.DOPPLER_TOKEN;
|
|
30
|
+
const forceInteractive = process.env.CLAUDE_FORCE_INTERACTIVE === "true";
|
|
31
|
+
const hasQuery = process.argv.includes("-q") || process.argv.includes("--query");
|
|
32
|
+
const hasVersion = process.argv.includes("--version") || process.argv.includes("-v");
|
|
33
|
+
const hasHelp = process.argv.includes("--help") || process.argv.includes("-h");
|
|
34
|
+
const alreadyWrapped = process.env.CODER_PTY_WRAPPED === "1";
|
|
35
|
+
|
|
36
|
+
// Skip if we have a TTY, force interactive, have a query, version, help, or already wrapped
|
|
37
|
+
if (isTTY || forceInteractive || hasQuery || hasVersion || hasHelp || alreadyWrapped) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// If under doppler without TTY, try to wrap with unbuffer
|
|
42
|
+
if (isDoppler) {
|
|
43
|
+
const result = tryWrapWithUnbuffer();
|
|
44
|
+
if (result.wrapped && result.child) {
|
|
45
|
+
// Successfully wrapped - child is running
|
|
46
|
+
// Wait for child to exit, then exit parent with same code
|
|
47
|
+
result.child.on("exit", (code: number | null) => {
|
|
48
|
+
process.exit(code ?? 1);
|
|
49
|
+
});
|
|
50
|
+
// Prevent further execution by keeping parent alive
|
|
51
|
+
// The exit handler above will terminate this process
|
|
52
|
+
setInterval(() => {
|
|
53
|
+
/* keep alive */
|
|
54
|
+
}, 10000);
|
|
55
|
+
return; // TypeScript needs this
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Failed to wrap - show helpful error
|
|
59
|
+
console.error("Error: Interactive mode requires a TTY.");
|
|
60
|
+
console.error("");
|
|
61
|
+
console.error("When using 'doppler run', TTY is not passed through.");
|
|
62
|
+
console.error("");
|
|
63
|
+
console.error("Install 'expect' package for automatic PTY support:");
|
|
64
|
+
console.error(" macOS: brew install expect");
|
|
65
|
+
console.error(" Ubuntu: sudo apt install expect");
|
|
66
|
+
console.error(" Fedora: sudo dnf install expect");
|
|
67
|
+
console.error("");
|
|
68
|
+
console.error("Or use one of these alternatives:");
|
|
69
|
+
console.error(" 1. Single query: doppler run -- coder -q \"your question\"");
|
|
70
|
+
console.error(" 2. Export secrets: doppler secrets download --no-file && coder");
|
|
71
|
+
console.error(" 3. Force simple: CLAUDE_FORCE_INTERACTIVE=true doppler run -- coder");
|
|
72
|
+
console.error(" 4. With unbuffer: unbuffer doppler run -- coder");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Try to wrap execution with unbuffer to provide a PTY
|
|
79
|
+
* @returns Object with wrapped status and child process if successful
|
|
80
|
+
*/
|
|
81
|
+
function tryWrapWithUnbuffer(): { wrapped: boolean; child?: ReturnType<typeof spawn> } {
|
|
82
|
+
try {
|
|
83
|
+
// Check if unbuffer is available
|
|
84
|
+
const checkResult = spawnSync("which", ["unbuffer"], {
|
|
85
|
+
stdio: "ignore",
|
|
86
|
+
timeout: 1000,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (checkResult.status !== 0) {
|
|
90
|
+
return { wrapped: false };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Re-exec ourselves with unbuffer
|
|
94
|
+
const args = [process.execPath, ...process.argv.slice(1)];
|
|
95
|
+
const child = spawn("unbuffer", args, {
|
|
96
|
+
stdio: "inherit",
|
|
97
|
+
env: {
|
|
98
|
+
...process.env,
|
|
99
|
+
CODER_PTY_WRAPPED: "1",
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return { wrapped: true, child };
|
|
104
|
+
} catch {
|
|
105
|
+
return { wrapped: false };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Run PTY check before any other code
|
|
110
|
+
checkPtyWrapper();
|
|
111
|
+
|
|
112
|
+
// ============================================
|
|
113
|
+
// MAIN IMPORTS
|
|
114
|
+
// ============================================
|
|
115
|
+
|
|
12
116
|
import type { Message } from "../../../../types/index.js";
|
|
13
117
|
import type { ToolDefinition, PermissionMode } from "../../../../types/index.js";
|
|
14
118
|
import type { builtInTools } from "../../../../ecosystem/tools/index.js";
|
|
15
119
|
import type { HookManager } from "../../../../ecosystem/hooks/index.js";
|
|
16
120
|
import type { SkillManager } from "../../../../ecosystem/skills/index.js";
|
|
17
121
|
import type { MCPClientImpl } from "../../../mcp/client.js";
|
|
122
|
+
import type { TeammateMessage } from "../../../../types/index.js";
|
|
18
123
|
import { SessionStore, printSessionsList } from "../../../../core/session-store.js";
|
|
19
124
|
import { getGitStatus } from "../../../../core/git-status.js";
|
|
20
125
|
import { renderStatusLine, getContextWindow, VERSION, type StatusLineOptions } from "../shared/status-line.js";
|
|
21
|
-
import {
|
|
126
|
+
import { InteractiveRunner } from "./interactive/index.js";
|
|
127
|
+
import type { InteractiveRunnerProps } from "./interactive/types.js";
|
|
128
|
+
import {
|
|
129
|
+
TeammateModeRunner,
|
|
130
|
+
setTeammateRunner,
|
|
131
|
+
isTeammateModeActive,
|
|
132
|
+
} from "../../../../teammates/runner.js";
|
|
22
133
|
|
|
23
134
|
// Shared modules
|
|
24
135
|
import {
|
|
@@ -59,11 +170,15 @@ async function main(): Promise<void> {
|
|
|
59
170
|
// Get API key
|
|
60
171
|
const apiKey = requireApiKey();
|
|
61
172
|
|
|
173
|
+
// Determine if we'll be in interactive TUI mode (no query = interactive)
|
|
174
|
+
const isInteractiveMode = !args.query;
|
|
175
|
+
|
|
62
176
|
// Setup session (config, MCP, hooks, skills)
|
|
63
177
|
const setup = await setupSession({
|
|
64
178
|
args,
|
|
65
179
|
apiKey,
|
|
66
180
|
workingDirectory: process.cwd(),
|
|
181
|
+
isTuiMode: isInteractiveMode, // Disable console logging in TUI mode
|
|
67
182
|
});
|
|
68
183
|
|
|
69
184
|
// Get git status for system prompt
|
|
@@ -119,6 +234,64 @@ async function main(): Promise<void> {
|
|
|
119
234
|
query = process.argv.slice(2).join(" ");
|
|
120
235
|
}
|
|
121
236
|
|
|
237
|
+
// ============================================
|
|
238
|
+
// TEAMMATE MODE INITIALIZATION
|
|
239
|
+
// ============================================
|
|
240
|
+
|
|
241
|
+
let teammateRunner: TeammateModeRunner | null = null;
|
|
242
|
+
let pendingTeammateMessages: TeammateMessage[] = [];
|
|
243
|
+
|
|
244
|
+
if (args.teammateMode && args.teamName) {
|
|
245
|
+
try {
|
|
246
|
+
teammateRunner = new TeammateModeRunner({
|
|
247
|
+
teamName: args.teamName,
|
|
248
|
+
agentId: args.agentId,
|
|
249
|
+
agentName: args.agentName,
|
|
250
|
+
agentColor: args.agentColor,
|
|
251
|
+
prompt: args.systemPrompt,
|
|
252
|
+
workingDirectory: process.cwd(),
|
|
253
|
+
onMessage: (message: TeammateMessage) => {
|
|
254
|
+
// Queue message for injection into conversation
|
|
255
|
+
pendingTeammateMessages.push(message);
|
|
256
|
+
console.log(`\x1b[90m[Teammate] Message from ${message.from}: ${message.content.slice(0, 50)}...\x1b[0m`);
|
|
257
|
+
},
|
|
258
|
+
onIdle: () => {
|
|
259
|
+
console.log(`\x1b[90m[Teammate] Now idle, waiting for tasks...\x1b[0m`);
|
|
260
|
+
},
|
|
261
|
+
pollInterval: 2000,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const teammate = await teammateRunner.start();
|
|
265
|
+
|
|
266
|
+
// Set global reference for tools to access
|
|
267
|
+
setTeammateRunner(teammateRunner);
|
|
268
|
+
|
|
269
|
+
console.log(`\x1b[90m[Teammate] Joined team "${args.teamName}" as ${teammate.name} (${teammate.teammateId})\x1b[0m`);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error(`\x1b[31mError starting teammate mode: ${error}\x1b[0m`);
|
|
272
|
+
teammateRunner = null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Cleanup handler
|
|
277
|
+
const cleanup = async () => {
|
|
278
|
+
if (teammateRunner) {
|
|
279
|
+
console.log(`\x1b[90m[Teammate] Stopping teammate mode...\x1b[0m`);
|
|
280
|
+
await teammateRunner.stop();
|
|
281
|
+
setTeammateRunner(null);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
process.on("SIGINT", async () => {
|
|
286
|
+
await cleanup();
|
|
287
|
+
process.exit(0);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
process.on("SIGTERM", async () => {
|
|
291
|
+
await cleanup();
|
|
292
|
+
process.exit(0);
|
|
293
|
+
});
|
|
294
|
+
|
|
122
295
|
if (!query) {
|
|
123
296
|
// Show initial status line
|
|
124
297
|
const initialStatusOptions: StatusLineOptions = {
|
|
@@ -130,6 +303,9 @@ async function main(): Promise<void> {
|
|
|
130
303
|
};
|
|
131
304
|
console.log(`\x1b[90m${renderStatusLine(initialStatusOptions)}\x1b[0m`);
|
|
132
305
|
console.log(`\x1b[90mSession: ${sessionId}\x1b[0m`);
|
|
306
|
+
if (teammateRunner) {
|
|
307
|
+
console.log(`\x1b[90mTeammate Mode: Active | Team: ${args.teamName}\x1b[0m`);
|
|
308
|
+
}
|
|
133
309
|
console.log("\x1b[90mType your message, ? for help, or /help for commands.\x1b[0m\n");
|
|
134
310
|
|
|
135
311
|
// Interactive mode
|
|
@@ -144,7 +320,8 @@ async function main(): Promise<void> {
|
|
|
144
320
|
messages,
|
|
145
321
|
sessionId,
|
|
146
322
|
setup.mcpClients,
|
|
147
|
-
setup.permissionMode
|
|
323
|
+
setup.permissionMode,
|
|
324
|
+
teammateRunner
|
|
148
325
|
);
|
|
149
326
|
} else {
|
|
150
327
|
// Single query mode
|
|
@@ -159,6 +336,7 @@ async function main(): Promise<void> {
|
|
|
159
336
|
hookManager: setup.hookManager,
|
|
160
337
|
workingDirectory: process.cwd(),
|
|
161
338
|
gitStatus,
|
|
339
|
+
permissionMode: setup.permissionMode,
|
|
162
340
|
});
|
|
163
341
|
}
|
|
164
342
|
}
|
|
@@ -178,28 +356,29 @@ async function runInteractiveMode(
|
|
|
178
356
|
messages: Message[],
|
|
179
357
|
sessionId: string,
|
|
180
358
|
mcpClients: Map<string, MCPClientImpl>,
|
|
181
|
-
permissionMode: PermissionMode
|
|
359
|
+
permissionMode: PermissionMode,
|
|
360
|
+
teammateRunner: TeammateModeRunner | null = null
|
|
182
361
|
): Promise<void> {
|
|
183
|
-
//
|
|
362
|
+
// Note: PTY wrapper check already ran at module load time
|
|
363
|
+
// This check is for non-doppler environments without TTY
|
|
184
364
|
const isInteractive = process.stdin.isTTY;
|
|
185
|
-
|
|
186
|
-
// Allow force-interactive mode for testing
|
|
187
365
|
const forceInteractive = process.env.CLAUDE_FORCE_INTERACTIVE === "true";
|
|
188
366
|
|
|
189
367
|
if (!isInteractive && !forceInteractive) {
|
|
190
|
-
console.error("Error: Interactive mode requires a TTY.
|
|
191
|
-
console.error("
|
|
368
|
+
console.error("Error: Interactive mode requires a TTY.");
|
|
369
|
+
console.error("");
|
|
370
|
+
console.error("Use -q for single query mode, or set CLAUDE_FORCE_INTERACTIVE=true.");
|
|
192
371
|
return;
|
|
193
372
|
}
|
|
194
373
|
|
|
195
|
-
// Create a mutable session ID holder for the
|
|
374
|
+
// Create a mutable session ID holder for the interactive runner
|
|
196
375
|
let currentSessionId = sessionId;
|
|
197
376
|
const setSessionId = (newId: string) => {
|
|
198
377
|
currentSessionId = newId;
|
|
199
378
|
};
|
|
200
379
|
|
|
201
|
-
// Run the
|
|
202
|
-
|
|
380
|
+
// Run the non-React interactive CLI
|
|
381
|
+
const runner = new InteractiveRunner({
|
|
203
382
|
apiKey,
|
|
204
383
|
model: args.model,
|
|
205
384
|
permissionMode,
|
|
@@ -212,10 +391,18 @@ async function runInteractiveMode(
|
|
|
212
391
|
setSessionId,
|
|
213
392
|
initialMessages: messages,
|
|
214
393
|
workingDirectory: process.cwd(),
|
|
215
|
-
|
|
394
|
+
teammateRunner,
|
|
395
|
+
onExit: async () => {
|
|
396
|
+
// Cleanup teammate mode
|
|
397
|
+
if (teammateRunner) {
|
|
398
|
+
await teammateRunner.stop();
|
|
399
|
+
setTeammateRunner(null);
|
|
400
|
+
}
|
|
216
401
|
console.log("\n\x1b[90mGoodbye!\x1b[0m");
|
|
217
402
|
},
|
|
218
403
|
});
|
|
404
|
+
|
|
405
|
+
await runner.start();
|
|
219
406
|
}
|
|
220
407
|
|
|
221
408
|
// ============================================
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Interactive Module
|
|
3
|
+
*
|
|
4
|
+
* Non-React implementation of the interactive CLI mode.
|
|
5
|
+
* Extracts core patterns from v1 TUI without the Ink dependency.
|
|
6
|
+
*
|
|
7
|
+
* This module provides:
|
|
8
|
+
* - MessageStore: Centralized message state management
|
|
9
|
+
* - InputManager: Priority-based keyboard input handling
|
|
10
|
+
* - InteractiveRunner: Main interactive loop with agent integration
|
|
11
|
+
* - Type definitions for all components
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { InteractiveRunner, MessageStoreImpl, InputManagerImpl } from "./interactive/index.js";
|
|
16
|
+
*
|
|
17
|
+
* // Create and run interactive mode
|
|
18
|
+
* const runner = new InteractiveRunner({
|
|
19
|
+
* apiKey: process.env.API_KEY!,
|
|
20
|
+
* model: "claude-sonnet-4-6",
|
|
21
|
+
* // ... other props
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* await runner.start();
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Architecture:
|
|
28
|
+
* - MessageStore: Single source of truth for messages (non-React)
|
|
29
|
+
* - InputManager: Centralized keyboard input with priority system
|
|
30
|
+
* - InteractiveRunner: Main loop that orchestrates everything
|
|
31
|
+
*
|
|
32
|
+
* Patterns from v1 TUI:
|
|
33
|
+
* - MessageStore pattern: addMessage, addApiMessages, addSystem, clear, replace
|
|
34
|
+
* - InputContext pattern: register, focus, dispatch, blocked state
|
|
35
|
+
* - Clean separation of concerns
|
|
36
|
+
* - Well-defined TypeScript interfaces
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
// ============================================
|
|
40
|
+
// TYPES
|
|
41
|
+
// ============================================
|
|
42
|
+
|
|
43
|
+
export type {
|
|
44
|
+
// Message types
|
|
45
|
+
UIMessage,
|
|
46
|
+
MessageSubType,
|
|
47
|
+
MessageStore,
|
|
48
|
+
|
|
49
|
+
// Input types
|
|
50
|
+
InputManager,
|
|
51
|
+
InputHandler,
|
|
52
|
+
InputHandlerOptions,
|
|
53
|
+
NativeKeyEvent,
|
|
54
|
+
|
|
55
|
+
// Runner types
|
|
56
|
+
InteractiveRunnerProps,
|
|
57
|
+
InteractiveState,
|
|
58
|
+
SessionStore,
|
|
59
|
+
SessionInfo,
|
|
60
|
+
CommandContext,
|
|
61
|
+
|
|
62
|
+
// Context types
|
|
63
|
+
ContextInfo,
|
|
64
|
+
} from "./types.js";
|
|
65
|
+
|
|
66
|
+
export { InputPriority } from "./types.js";
|
|
67
|
+
|
|
68
|
+
// ============================================
|
|
69
|
+
// MESSAGE STORE
|
|
70
|
+
// ============================================
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
MessageStoreImpl,
|
|
74
|
+
getMessageStore,
|
|
75
|
+
resetMessageStore,
|
|
76
|
+
} from "./message-store.js";
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// INPUT HANDLER
|
|
80
|
+
// ============================================
|
|
81
|
+
|
|
82
|
+
export {
|
|
83
|
+
InputManagerImpl,
|
|
84
|
+
getInputManager,
|
|
85
|
+
resetInputManager,
|
|
86
|
+
KeyEvents,
|
|
87
|
+
} from "./input-handler.js";
|
|
88
|
+
|
|
89
|
+
// ============================================
|
|
90
|
+
// INTERACTIVE RUNNER
|
|
91
|
+
// ============================================
|
|
92
|
+
|
|
93
|
+
import { InteractiveRunner as _InteractiveRunner } from "./interactive-runner.js";
|
|
94
|
+
|
|
95
|
+
export { _InteractiveRunner as InteractiveRunner };
|
|
96
|
+
|
|
97
|
+
// ============================================
|
|
98
|
+
// CONVENIENCE FUNCTIONS
|
|
99
|
+
// ============================================
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Run interactive mode with the given props
|
|
103
|
+
* Convenience function that creates and starts an InteractiveRunner
|
|
104
|
+
*/
|
|
105
|
+
export async function runInteractiveMode(
|
|
106
|
+
props: import("./types.js").InteractiveRunnerProps
|
|
107
|
+
): Promise<void> {
|
|
108
|
+
const runner = new _InteractiveRunner(props);
|
|
109
|
+
await runner.start();
|
|
110
|
+
}
|