kumo-cli 1.0.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -13
- package/dist/auth/credentialsStore.js +20 -7
- package/dist/auth/credentialsStore.js.map +1 -1
- package/dist/claude/conversation.js +272 -0
- package/dist/claude/conversation.js.map +1 -0
- package/dist/claude/transcriptParser.js +140 -36
- package/dist/claude/transcriptParser.js.map +1 -1
- package/dist/commands/cliArgs.js +1 -0
- package/dist/commands/cliArgs.js.map +1 -1
- package/dist/core/config.js +1 -9
- package/dist/core/config.js.map +1 -1
- package/dist/core/logger.js +50 -21
- package/dist/core/logger.js.map +1 -1
- package/dist/core/projectFileWatcher.js +100 -36
- package/dist/core/projectFileWatcher.js.map +1 -1
- package/dist/engine/claudeArgs.js +106 -0
- package/dist/engine/claudeArgs.js.map +1 -0
- package/dist/engine/claudeBinary.js +94 -0
- package/dist/engine/claudeBinary.js.map +1 -0
- package/dist/engine/claudeConfig.js +127 -0
- package/dist/engine/claudeConfig.js.map +1 -0
- package/dist/engine/claudeLogin.js +76 -0
- package/dist/engine/claudeLogin.js.map +1 -0
- package/dist/engine/controlChannel.js +75 -0
- package/dist/engine/controlChannel.js.map +1 -0
- package/dist/engine/liveTranscript.js +150 -0
- package/dist/engine/liveTranscript.js.map +1 -0
- package/dist/engine/ndjson.js +48 -0
- package/dist/engine/ndjson.js.map +1 -0
- package/dist/engine/permissions.js +101 -0
- package/dist/engine/permissions.js.map +1 -0
- package/dist/engine/probePool.js +51 -0
- package/dist/engine/probePool.js.map +1 -0
- package/dist/engine/processTree.js +45 -0
- package/dist/engine/processTree.js.map +1 -0
- package/dist/engine/remoteConfig.js +17 -0
- package/dist/engine/remoteConfig.js.map +1 -0
- package/dist/engine/sessionManager.js +444 -0
- package/dist/engine/sessionManager.js.map +1 -0
- package/dist/engine/settingsCommands.js +260 -0
- package/dist/engine/settingsCommands.js.map +1 -0
- package/dist/engine/streamSession.js +502 -0
- package/dist/engine/streamSession.js.map +1 -0
- package/dist/engine/taskTracker.js +110 -0
- package/dist/engine/taskTracker.js.map +1 -0
- package/dist/engine/toolLabels.js +32 -0
- package/dist/engine/toolLabels.js.map +1 -0
- package/dist/handlers/controlRequest.js +17 -0
- package/dist/handlers/controlRequest.js.map +1 -0
- package/dist/handlers/fileHandlers.js +12 -0
- package/dist/handlers/fileHandlers.js.map +1 -1
- package/dist/handlers/messageRouter.js +8 -1
- package/dist/handlers/messageRouter.js.map +1 -1
- package/dist/handlers/promptImages.js +5 -91
- package/dist/handlers/promptImages.js.map +1 -1
- package/dist/handlers/runtimeHandlers.js +100 -32
- package/dist/handlers/runtimeHandlers.js.map +1 -1
- package/dist/handlers/sessionHandlers.js +85 -80
- package/dist/handlers/sessionHandlers.js.map +1 -1
- package/dist/handlers/terminalHandlers.js +9 -2
- package/dist/handlers/terminalHandlers.js.map +1 -1
- package/dist/http/httpClient.js +6 -0
- package/dist/http/httpClient.js.map +1 -1
- package/dist/index.js +87 -50
- package/dist/index.js.map +1 -1
- package/dist/pty/terminalManager.js +58 -11
- package/dist/pty/terminalManager.js.map +1 -1
- package/dist/services/bootstrapService.js +17 -1
- package/dist/services/bootstrapService.js.map +1 -1
- package/dist/services/claudeAdapterProxy.js +68 -21
- package/dist/services/claudeAdapterProxy.js.map +1 -1
- package/dist/services/cliRuntime.js +39 -32
- package/dist/services/cliRuntime.js.map +1 -1
- package/dist/services/effortService.js +13 -60
- package/dist/services/effortService.js.map +1 -1
- package/dist/services/fileService.js +50 -24
- package/dist/services/fileService.js.map +1 -1
- package/dist/services/forkService.js +120 -0
- package/dist/services/forkService.js.map +1 -0
- package/dist/services/modelService.js +86 -89
- package/dist/services/modelService.js.map +1 -1
- package/dist/services/pairingService.js +21 -15
- package/dist/services/pairingService.js.map +1 -1
- package/dist/services/sessionListService.js +7 -9
- package/dist/services/sessionListService.js.map +1 -1
- package/dist/services/sessionService.js +245 -106
- package/dist/services/sessionService.js.map +1 -1
- package/dist/services/tunnelHelpers.js +9 -5
- package/dist/services/tunnelHelpers.js.map +1 -1
- package/dist/services/tunnelService.js +21 -5
- package/dist/services/tunnelService.js.map +1 -1
- package/dist/transport/wsClient.js +60 -42
- package/dist/transport/wsClient.js.map +1 -1
- package/dist/utils/ignorePaths.js +3 -3
- package/dist/utils/ignorePaths.js.map +1 -1
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/localHost.js +17 -0
- package/dist/utils/localHost.js.map +1 -0
- package/dist/utils/safePath.js +51 -20
- package/dist/utils/safePath.js.map +1 -1
- package/package.json +5 -12
- package/dist/ansiCodes.js +0 -107
- package/dist/ansiCodes.js.map +0 -1
- package/dist/auth/credentialsStore.test.js +0 -60
- package/dist/auth/credentialsStore.test.js.map +0 -1
- package/dist/claude/fileHistory.js +0 -79
- package/dist/claude/fileHistory.js.map +0 -1
- package/dist/claude/generateHookSettings.js +0 -23
- package/dist/claude/generateHookSettings.js.map +0 -1
- package/dist/claude/hookServer.js +0 -33
- package/dist/claude/hookServer.js.map +0 -1
- package/dist/claude/sessionScanner.js +0 -162
- package/dist/claude/sessionScanner.js.map +0 -1
- package/dist/claude/sessionScanner.test.js +0 -24
- package/dist/claude/sessionScanner.test.js.map +0 -1
- package/dist/claude/transcriptParser.test.js +0 -78
- package/dist/claude/transcriptParser.test.js.map +0 -1
- package/dist/commands/cliArgs.test.js +0 -25
- package/dist/commands/cliArgs.test.js.map +0 -1
- package/dist/config.js +0 -40
- package/dist/config.js.map +0 -1
- package/dist/credentialsStore.js +0 -57
- package/dist/credentialsStore.js.map +0 -1
- package/dist/generateHookSettings.js +0 -30
- package/dist/generateHookSettings.js.map +0 -1
- package/dist/handlers/fileHandlerPayloads.test.js +0 -55
- package/dist/handlers/fileHandlerPayloads.test.js.map +0 -1
- package/dist/handlers/promptImages.test.js +0 -52
- package/dist/handlers/promptImages.test.js.map +0 -1
- package/dist/hookServer.js +0 -32
- package/dist/hookServer.js.map +0 -1
- package/dist/ignorePaths.js +0 -68
- package/dist/ignorePaths.js.map +0 -1
- package/dist/loadDotEnv.js +0 -79
- package/dist/loadDotEnv.js.map +0 -1
- package/dist/logger.js +0 -29
- package/dist/logger.js.map +0 -1
- package/dist/portForwardManager.js +0 -97
- package/dist/portForwardManager.js.map +0 -1
- package/dist/projectHistoryReader.js +0 -85
- package/dist/projectHistoryReader.js.map +0 -1
- package/dist/pty/ansiCodes.js +0 -14
- package/dist/pty/ansiCodes.js.map +0 -1
- package/dist/pty/notificationDetector.js +0 -29
- package/dist/pty/notificationDetector.js.map +0 -1
- package/dist/pty/notificationDetector.test.js +0 -24
- package/dist/pty/notificationDetector.test.js.map +0 -1
- package/dist/pty/ptyMenuParser.js +0 -91
- package/dist/pty/ptyMenuParser.js.map +0 -1
- package/dist/pty/ptyMenuParser.test.js +0 -26
- package/dist/pty/ptyMenuParser.test.js.map +0 -1
- package/dist/pty/ptySnapshotRenderer.js +0 -71
- package/dist/pty/ptySnapshotRenderer.js.map +0 -1
- package/dist/pty/selectionMenuDetector.js +0 -49
- package/dist/pty/selectionMenuDetector.js.map +0 -1
- package/dist/pty/selectionMenuDetector.test.js +0 -62
- package/dist/pty/selectionMenuDetector.test.js.map +0 -1
- package/dist/pty/selectionMenuMeta.js +0 -54
- package/dist/pty/selectionMenuMeta.js.map +0 -1
- package/dist/pty/selectionMenuMeta.test.js +0 -26
- package/dist/pty/selectionMenuMeta.test.js.map +0 -1
- package/dist/pty/selectionMenuParser.js +0 -83
- package/dist/pty/selectionMenuParser.js.map +0 -1
- package/dist/pty/selectionMenuParser.test.js +0 -30
- package/dist/pty/selectionMenuParser.test.js.map +0 -1
- package/dist/pty/spawn.js +0 -104
- package/dist/pty/spawn.js.map +0 -1
- package/dist/pty/spawn.test.js +0 -17
- package/dist/pty/spawn.test.js.map +0 -1
- package/dist/pty/statusSessionDetector.js +0 -28
- package/dist/pty/statusSessionDetector.js.map +0 -1
- package/dist/pty/statusSessionDetector.test.js +0 -23
- package/dist/pty/statusSessionDetector.test.js.map +0 -1
- package/dist/pty/textInputDetector.js +0 -60
- package/dist/pty/textInputDetector.js.map +0 -1
- package/dist/pty/textInputDetector.test.js +0 -32
- package/dist/pty/textInputDetector.test.js.map +0 -1
- package/dist/ptyMenuParser.js +0 -470
- package/dist/ptyMenuParser.js.map +0 -1
- package/dist/ptySnapshotRenderer.js +0 -78
- package/dist/ptySnapshotRenderer.js.map +0 -1
- package/dist/services/checkpointService.js +0 -113
- package/dist/services/checkpointService.js.map +0 -1
- package/dist/services/checkpointService.test.js +0 -61
- package/dist/services/checkpointService.test.js.map +0 -1
- package/dist/services/claudeMenuBridge.js +0 -116
- package/dist/services/claudeMenuBridge.js.map +0 -1
- package/dist/services/claudeMenuBridge.test.js +0 -90
- package/dist/services/claudeMenuBridge.test.js.map +0 -1
- package/dist/services/claudeService.js +0 -146
- package/dist/services/claudeService.js.map +0 -1
- package/dist/services/claudeService.test.js +0 -39
- package/dist/services/claudeService.test.js.map +0 -1
- package/dist/services/cliRuntime.test.js +0 -55
- package/dist/services/cliRuntime.test.js.map +0 -1
- package/dist/services/modelAdapter.test.js +0 -47
- package/dist/services/modelAdapter.test.js.map +0 -1
- package/dist/services/modelArgs.test.js +0 -64
- package/dist/services/modelArgs.test.js.map +0 -1
- package/dist/services/modelBaseUrl.test.js +0 -32
- package/dist/services/modelBaseUrl.test.js.map +0 -1
- package/dist/services/modelService.test.js +0 -136
- package/dist/services/modelService.test.js.map +0 -1
- package/dist/services/notificationDedupe.js +0 -23
- package/dist/services/notificationDedupe.js.map +0 -1
- package/dist/services/notificationDedupe.test.js +0 -20
- package/dist/services/notificationDedupe.test.js.map +0 -1
- package/dist/services/sessionListService.test.js +0 -22
- package/dist/services/sessionListService.test.js.map +0 -1
- package/dist/services/sessionRollbackService.js +0 -195
- package/dist/services/sessionRollbackService.js.map +0 -1
- package/dist/services/sessionRollbackService.test.js +0 -142
- package/dist/services/sessionRollbackService.test.js.map +0 -1
- package/dist/services/tunnelHelpers.test.js +0 -42
- package/dist/services/tunnelHelpers.test.js.map +0 -1
- package/dist/services/tunnelService.test.js +0 -91
- package/dist/services/tunnelService.test.js.map +0 -1
- package/dist/sessionScanner.js +0 -271
- package/dist/sessionScanner.js.map +0 -1
- package/dist/snapshotScanner.js +0 -154
- package/dist/snapshotScanner.js.map +0 -1
- package/dist/spawn.js +0 -79
- package/dist/spawn.js.map +0 -1
- package/dist/terminalManager.js +0 -73
- package/dist/terminalManager.js.map +0 -1
- package/dist/transport/directWsServer.js +0 -135
- package/dist/transport/directWsServer.js.map +0 -1
- package/dist/transport/webrtcTransport.js +0 -145
- package/dist/transport/webrtcTransport.js.map +0 -1
- package/dist/transport/webrtcTransport.test.js +0 -104
- package/dist/transport/webrtcTransport.test.js.map +0 -1
- package/dist/transport/webrtcTypes.js +0 -29
- package/dist/transport/webrtcTypes.js.map +0 -1
- package/dist/transport/webrtcTypes.test.js +0 -20
- package/dist/transport/webrtcTypes.test.js.map +0 -1
- package/dist/utils/ptyBuffer.js +0 -46
- package/dist/utils/ptyBuffer.js.map +0 -1
- package/scripts/claude_launcher.cjs +0 -71
- package/scripts/run-tests.mjs +0 -46
- package/scripts/session_hook_forwarder.cjs +0 -44
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isPermissionMode } from './permissions.js';
|
|
2
|
+
// flags owned by the engine; the value is consumed when the flag takes one
|
|
3
|
+
const OWNED_FLAGS = {
|
|
4
|
+
'-p': false,
|
|
5
|
+
'--print': false,
|
|
6
|
+
'-c': false,
|
|
7
|
+
'--continue': false,
|
|
8
|
+
'--replay-user-messages': false,
|
|
9
|
+
'--output-format': true,
|
|
10
|
+
'--input-format': true,
|
|
11
|
+
'--permission-prompt-tool': true,
|
|
12
|
+
'--permission-mode': true,
|
|
13
|
+
'--session-id': true,
|
|
14
|
+
'--resume': true,
|
|
15
|
+
'-r': true,
|
|
16
|
+
};
|
|
17
|
+
// strip user passthrough flags that conflict with the stream-json engine, keeping the user's intent
|
|
18
|
+
export function filterPassthroughArgs(args) {
|
|
19
|
+
const passthrough = [];
|
|
20
|
+
let permissionMode;
|
|
21
|
+
let allowBypass = false;
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
24
|
+
if (arg === '--dangerously-skip-permissions') {
|
|
25
|
+
allowBypass = true;
|
|
26
|
+
permissionMode ??= 'bypassPermissions';
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === '--allow-dangerously-skip-permissions') {
|
|
30
|
+
allowBypass = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const [flag, inlineValue] = arg.includes('=') ? [arg.slice(0, arg.indexOf('=')), arg.slice(arg.indexOf('=') + 1)] : [arg, undefined];
|
|
34
|
+
if (!(flag in OWNED_FLAGS)) {
|
|
35
|
+
passthrough.push(arg);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let value = inlineValue;
|
|
39
|
+
if (OWNED_FLAGS[flag] && value === undefined && args[i + 1] !== undefined && !args[i + 1].startsWith('-'))
|
|
40
|
+
value = args[++i];
|
|
41
|
+
if (flag === '--permission-mode' && isPermissionMode(value))
|
|
42
|
+
permissionMode = value;
|
|
43
|
+
}
|
|
44
|
+
return { passthrough, permissionMode, allowBypass };
|
|
45
|
+
}
|
|
46
|
+
// drop `flag value`, `flag=value` (and aliases) so the engine's own value wins
|
|
47
|
+
function withoutFlag(args, ...flags) {
|
|
48
|
+
const result = [];
|
|
49
|
+
for (let i = 0; i < args.length; i++) {
|
|
50
|
+
const arg = args[i];
|
|
51
|
+
if (flags.includes(arg)) {
|
|
52
|
+
i++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (flags.some((flag) => arg.startsWith(`${flag}=`)))
|
|
56
|
+
continue;
|
|
57
|
+
result.push(arg);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
// model ids as providers spell them: claude-sonnet-4-5[1m], openrouter/x/y, qwen:7b, claude@2024
|
|
62
|
+
const MODEL_ID = /^[\w.:/@[\]-]{1,200}$/;
|
|
63
|
+
// build the claude argv for one stream-json session
|
|
64
|
+
export function buildClaudeArgs(options) {
|
|
65
|
+
if (options.model && !MODEL_ID.test(options.model))
|
|
66
|
+
throw new Error(`invalid model id: ${JSON.stringify(options.model.slice(0, 80))}`);
|
|
67
|
+
const args = [
|
|
68
|
+
'--output-format', 'stream-json',
|
|
69
|
+
'--verbose',
|
|
70
|
+
'--input-format', 'stream-json',
|
|
71
|
+
'--permission-prompt-tool', 'stdio',
|
|
72
|
+
'--permission-mode', options.permissionMode,
|
|
73
|
+
'--replay-user-messages',
|
|
74
|
+
'--setting-sources=user,project,local',
|
|
75
|
+
options.resume ? `--resume=${options.sessionId}` : `--session-id=${options.sessionId}`,
|
|
76
|
+
];
|
|
77
|
+
if (options.allowBypass)
|
|
78
|
+
args.push('--allow-dangerously-skip-permissions');
|
|
79
|
+
let extra = options.passthrough ?? [];
|
|
80
|
+
if (options.model) {
|
|
81
|
+
extra = withoutFlag(extra, '--model', '-m');
|
|
82
|
+
args.push('--model', options.model);
|
|
83
|
+
}
|
|
84
|
+
if (options.effort) {
|
|
85
|
+
extra = withoutFlag(extra, '--effort');
|
|
86
|
+
args.push('--effort', options.effort);
|
|
87
|
+
}
|
|
88
|
+
return [...args, ...extra];
|
|
89
|
+
}
|
|
90
|
+
// build the child env: model overrides plus sdk entrypoint, minus vars leaking from a parent claude/node
|
|
91
|
+
export function buildClaudeEnv(base, overrides = {}) {
|
|
92
|
+
const env = { ...base };
|
|
93
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
94
|
+
if (value === undefined)
|
|
95
|
+
delete env[key];
|
|
96
|
+
else
|
|
97
|
+
env[key] = value;
|
|
98
|
+
}
|
|
99
|
+
env['CLAUDE_CODE_ENTRYPOINT'] = 'sdk-ts';
|
|
100
|
+
env['CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING'] = 'true';
|
|
101
|
+
delete env['CLAUDECODE'];
|
|
102
|
+
delete env['CLAUDE_CODE_CHILD_SESSION'];
|
|
103
|
+
delete env['NODE_OPTIONS'];
|
|
104
|
+
return env;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=claudeArgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeArgs.js","sourceRoot":"","sources":["../../src/engine/claudeArgs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { log } from '../core/logger.js';
|
|
5
|
+
const CLAUDE_PACKAGE = '@anthropic-ai/claude-code';
|
|
6
|
+
const NATIVE_EXE = ['node_modules', '@anthropic-ai', 'claude-code', 'bin', 'claude.exe'];
|
|
7
|
+
let cached = null;
|
|
8
|
+
function lookup(command) {
|
|
9
|
+
try {
|
|
10
|
+
return execSync(command, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
11
|
+
.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// prefer the native claude.exe shipped inside the npm package next to a claude.cmd shim
|
|
18
|
+
function nativeExeFor(shimPath) {
|
|
19
|
+
const candidate = path.join(path.dirname(shimPath), ...NATIVE_EXE);
|
|
20
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
21
|
+
}
|
|
22
|
+
function findOnWindows() {
|
|
23
|
+
const appData = process.env['APPDATA'] ?? '';
|
|
24
|
+
if (appData) {
|
|
25
|
+
const exe = path.join(appData, 'npm', ...NATIVE_EXE);
|
|
26
|
+
if (fs.existsSync(exe))
|
|
27
|
+
return { cmd: exe, shell: false };
|
|
28
|
+
}
|
|
29
|
+
// $PATH: keeps `where` from looking in the current folder first, where a cloned repo could plant a claude.exe
|
|
30
|
+
const cwd = path.resolve(process.cwd());
|
|
31
|
+
const found = lookup('where $PATH:claude').filter((p) => path.dirname(path.resolve(p)).toLowerCase() !== cwd.toLowerCase());
|
|
32
|
+
const exe = found.find((p) => /\.exe$/i.test(p));
|
|
33
|
+
if (exe)
|
|
34
|
+
return { cmd: exe, shell: false };
|
|
35
|
+
const shim = found.find((p) => /\.cmd$/i.test(p)) ?? (appData && fs.existsSync(path.join(appData, 'npm', 'claude.cmd')) ? path.join(appData, 'npm', 'claude.cmd') : undefined);
|
|
36
|
+
if (!shim)
|
|
37
|
+
return null;
|
|
38
|
+
const native = nativeExeFor(shim);
|
|
39
|
+
return native ? { cmd: native, shell: false } : { cmd: shim, shell: true };
|
|
40
|
+
}
|
|
41
|
+
function findOnPosix() {
|
|
42
|
+
const found = lookup('which claude')[0];
|
|
43
|
+
return found ? { cmd: found, shell: false } : null;
|
|
44
|
+
}
|
|
45
|
+
function find() {
|
|
46
|
+
return process.platform === 'win32' ? findOnWindows() : findOnPosix();
|
|
47
|
+
}
|
|
48
|
+
// install the claude cli globally when it is missing from the host machine
|
|
49
|
+
function installClaudeCli() {
|
|
50
|
+
console.log(`[kumo-cli] claude cli not found, installing ${CLAUDE_PACKAGE}...`);
|
|
51
|
+
execSync(`npm install -g --allow-scripts=${CLAUDE_PACKAGE} ${CLAUDE_PACKAGE}`, { stdio: 'inherit' });
|
|
52
|
+
}
|
|
53
|
+
// resolve the claude executable on first use (never at import); KUMO_CLAUDE_BIN overrides discovery
|
|
54
|
+
export function resolveClaudeCommand() {
|
|
55
|
+
if (cached)
|
|
56
|
+
return cached;
|
|
57
|
+
const override = process.env['KUMO_CLAUDE_BIN'];
|
|
58
|
+
if (override) {
|
|
59
|
+
cached = { cmd: override, shell: process.platform === 'win32' && /\.(cmd|bat)$/i.test(override) };
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
let found = find();
|
|
63
|
+
if (!found) {
|
|
64
|
+
try {
|
|
65
|
+
installClaudeCli();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
log(`[claude-bin] install failed: ${error}`);
|
|
69
|
+
}
|
|
70
|
+
found = find();
|
|
71
|
+
}
|
|
72
|
+
// a bare `claude` through cmd.exe would also run one from the current folder
|
|
73
|
+
if (!found)
|
|
74
|
+
throw new Error(`claude cli not found: install ${CLAUDE_PACKAGE} or set KUMO_CLAUDE_BIN`);
|
|
75
|
+
cached = found;
|
|
76
|
+
}
|
|
77
|
+
log(`[claude-bin] using ${cached.cmd} (shell=${cached.shell})`);
|
|
78
|
+
return cached;
|
|
79
|
+
}
|
|
80
|
+
// quote one argument for a cmd.exe command line. inside quotes cmd.exe still ends the quote at `"`,
|
|
81
|
+
// expands %VAR% (and !VAR!) and splits at line breaks, and no escaping is reliable for a .cmd
|
|
82
|
+
// shim, so such arguments are refused instead
|
|
83
|
+
export function quoteWindowsArg(arg) {
|
|
84
|
+
if (/["%!\r\n]/.test(arg))
|
|
85
|
+
throw new Error(`argument not safe for cmd.exe: ${JSON.stringify(arg.slice(0, 80))}`);
|
|
86
|
+
if (arg && !/[\s&|<>^()!,;=]/.test(arg))
|
|
87
|
+
return arg;
|
|
88
|
+
return `"${arg.replace(/(\\+)$/, '$1$1')}"`;
|
|
89
|
+
}
|
|
90
|
+
// build a single shell command line so node never joins unquoted args (avoids DEP0190)
|
|
91
|
+
export function buildShellCommandLine(cmd, args) {
|
|
92
|
+
return [cmd, ...args].map(quoteWindowsArg).join(' ');
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=claudeBinary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeBinary.js","sourceRoot":"","sources":["../../src/engine/claudeBinary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { list, obj, pick } from '../utils/json.js';
|
|
2
|
+
const MODEL_KEYS = ['value', 'resolvedModel', 'displayName', 'description', 'supportsEffort', 'supportedEffortLevels', 'supportsAdaptiveThinking', 'supportsFastMode', 'supportsAutoMode'];
|
|
3
|
+
const COMMAND_KEYS = ['name', 'description', 'argumentHint'];
|
|
4
|
+
export function commandsOf(value) {
|
|
5
|
+
return list(value).map((command) => pick(command, COMMAND_KEYS));
|
|
6
|
+
}
|
|
7
|
+
// app-facing claude_config payload from an initialize response
|
|
8
|
+
export function toClaudeConfig(init) {
|
|
9
|
+
return {
|
|
10
|
+
models: list(init['models']).map((model) => pick(model, MODEL_KEYS)),
|
|
11
|
+
commands: commandsOf(init['commands']),
|
|
12
|
+
account: pick(obj(init['account']), ['email', 'organization', 'subscriptionType', 'apiProvider']),
|
|
13
|
+
outputStyle: init['output_style'] ?? null,
|
|
14
|
+
availableOutputStyles: Array.isArray(init['available_output_styles']) ? init['available_output_styles'] : [],
|
|
15
|
+
version: init['claude_code_version'] ?? null,
|
|
16
|
+
fastModeState: init['fast_mode_state'] ?? null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// what a claude running another provider reports of its own: that provider's models and account,
|
|
20
|
+
// not claude's, so it never replaces those in the shared config (the app's model picker)
|
|
21
|
+
export function withoutProviderConfig(patch) {
|
|
22
|
+
const { models: _models, account: _account, fastModeState: _fastModeState, ...rest } = patch;
|
|
23
|
+
return rest;
|
|
24
|
+
}
|
|
25
|
+
// control requests the app may run through claude_control
|
|
26
|
+
export const CONTROL_WHITELIST = new Set([
|
|
27
|
+
'get_status', 'get_usage', 'get_context_usage', 'get_settings', 'export_conversation', 'side_question',
|
|
28
|
+
'mcp_status', 'mcp_toggle', 'mcp_reconnect', 'list_permission_rules', 'update_settings', 'rewind_files',
|
|
29
|
+
'stop_task', 'cancel_async_message',
|
|
30
|
+
'get_hooks_listing', 'get_sandbox_dialog', 'get_skills_dialog', 'get_memory_dialog', 'reload_plugins', 'reload_skills',
|
|
31
|
+
]);
|
|
32
|
+
const NOT_RUNNING = 'This session is no longer running.';
|
|
33
|
+
// requests about the running process itself, with the reason a stopped session can't answer;
|
|
34
|
+
// file checkpoints live in the process that ran the turns, a resumed one has none
|
|
35
|
+
export const LIVE_ONLY_CONTROLS = new Map([
|
|
36
|
+
['rewind_files', "Code checkpoints only last while this session's Claude process runs, and it has stopped. You can still fork the conversation."],
|
|
37
|
+
['stop_task', NOT_RUNNING],
|
|
38
|
+
['cancel_async_message', NOT_RUNNING],
|
|
39
|
+
]);
|
|
40
|
+
// requests answered from the target session's own context
|
|
41
|
+
export const SESSION_SCOPED_CONTROLS = new Set(['get_context_usage', 'export_conversation', 'side_question']);
|
|
42
|
+
// mcp servers live in the chat's own process: shown, switched and reconnected there, which is
|
|
43
|
+
// started when it is not running; a throwaway probe would only ever see them connecting
|
|
44
|
+
export const OWN_PROCESS_CONTROLS = new Set(['mcp_status', 'mcp_toggle', 'mcp_reconnect']);
|
|
45
|
+
// side questions run a model call (5 min like the extension), the rest are quick reads
|
|
46
|
+
export const controlTimeoutMs = (subtype) => (subtype === 'side_question' ? 300_000 : undefined);
|
|
47
|
+
const text = (source, key, max = 4000) => {
|
|
48
|
+
const value = typeof source[key] === 'string' ? source[key].trim().slice(0, max) : '';
|
|
49
|
+
if (!value)
|
|
50
|
+
throw new Error(`${key} is required`);
|
|
51
|
+
return value;
|
|
52
|
+
};
|
|
53
|
+
// the only payload fields forwarded to claude per request
|
|
54
|
+
export function controlPayload(subtype, payload) {
|
|
55
|
+
const source = obj(payload);
|
|
56
|
+
switch (subtype) {
|
|
57
|
+
case 'side_question':
|
|
58
|
+
return { question: text(source, 'question') };
|
|
59
|
+
case 'mcp_reconnect':
|
|
60
|
+
return { serverName: text(source, 'serverName', 200) };
|
|
61
|
+
case 'mcp_toggle':
|
|
62
|
+
if (typeof source['enabled'] !== 'boolean')
|
|
63
|
+
throw new Error('enabled is required');
|
|
64
|
+
return { serverName: text(source, 'serverName', 200), enabled: source['enabled'] };
|
|
65
|
+
case 'stop_task':
|
|
66
|
+
return { task_id: text(source, 'taskId', 100) };
|
|
67
|
+
case 'cancel_async_message':
|
|
68
|
+
return { message_uuid: text(source, 'uuid', 100) };
|
|
69
|
+
case 'rewind_files':
|
|
70
|
+
return { user_message_id: text(source, 'userMessageId', 100), dry_run: source['dryRun'] === true };
|
|
71
|
+
case 'update_settings':
|
|
72
|
+
// only the output style may be changed from the app, and only for this project
|
|
73
|
+
return { source: 'localSettings', settings: { outputStyle: text(source, 'outputStyle', 200) } };
|
|
74
|
+
default:
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// keep only what the app renders; get_settings.effective carries mcp env secrets and never leaves the machine
|
|
79
|
+
export function sanitizeControlResponse(subtype, response) {
|
|
80
|
+
switch (subtype) {
|
|
81
|
+
case 'get_settings': {
|
|
82
|
+
const outputStyle = obj(response['effective'])['outputStyle'];
|
|
83
|
+
return { applied: obj(response['applied']), outputStyle: typeof outputStyle === 'string' ? outputStyle : null };
|
|
84
|
+
}
|
|
85
|
+
case 'mcp_status':
|
|
86
|
+
// server configs carry urls, headers and env secrets; of the tools only names and hints
|
|
87
|
+
return {
|
|
88
|
+
mcpServers: list(response['mcpServers']).map((server) => ({
|
|
89
|
+
...pick(server, ['name', 'status', 'scope', 'error']),
|
|
90
|
+
type: obj(server['config'])['type'] ?? null,
|
|
91
|
+
tools: list(server['tools']).map((tool) => {
|
|
92
|
+
const hints = obj(tool['annotations']);
|
|
93
|
+
return {
|
|
94
|
+
name: tool['name'] ?? '',
|
|
95
|
+
...(hints['readOnly'] === true ? { readOnly: true } : {}),
|
|
96
|
+
...(hints['destructive'] === true ? { destructive: true } : {}),
|
|
97
|
+
};
|
|
98
|
+
}),
|
|
99
|
+
})),
|
|
100
|
+
};
|
|
101
|
+
case 'list_permission_rules':
|
|
102
|
+
return { rules: list(obj(response['state'])['rules']).map((rule) => pick(rule, ['rule', 'behavior', 'source'])) };
|
|
103
|
+
case 'get_context_usage': {
|
|
104
|
+
const { gridRows: _grid, ...rest } = response;
|
|
105
|
+
return rest;
|
|
106
|
+
}
|
|
107
|
+
case 'reload_plugins':
|
|
108
|
+
// the payload repeats every command, agent and mcp config; the app only needs the outcome
|
|
109
|
+
return {
|
|
110
|
+
plugins: list(response['plugins']).map((plugin) => pick(plugin, ['name', 'version', 'source'])),
|
|
111
|
+
error_count: response['error_count'] ?? 0,
|
|
112
|
+
};
|
|
113
|
+
case 'reload_skills':
|
|
114
|
+
return { count: list(response['skills']).length };
|
|
115
|
+
case 'get_usage': {
|
|
116
|
+
const limits = obj(response['rate_limits']);
|
|
117
|
+
return {
|
|
118
|
+
session: obj(response['session']),
|
|
119
|
+
subscription_type: response['subscription_type'] ?? null,
|
|
120
|
+
rate_limits: pick(limits, ['five_hour', 'seven_day', 'limits', 'model_scoped']),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
default:
|
|
124
|
+
return response;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=claudeConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeConfig.js","sourceRoot":"","sources":["../../src/engine/claudeConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { StreamSession } from './streamSession.js';
|
|
3
|
+
const LOGIN_TIMEOUT_MS = 10 * 60_000;
|
|
4
|
+
// sign claude in with its own oauth over the control channel of a throwaway process, as the
|
|
5
|
+
// extension does: the link comes back to open on the phone, the code that page shows goes to
|
|
6
|
+
// submitCode, and claude reports when it is done
|
|
7
|
+
export class ClaudeLogin {
|
|
8
|
+
options;
|
|
9
|
+
// the process running the sign-in, null when none is in progress
|
|
10
|
+
session = null;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
get running() {
|
|
15
|
+
return this.session?.alive === true;
|
|
16
|
+
}
|
|
17
|
+
async start(useConsole = false) {
|
|
18
|
+
await this.cancel();
|
|
19
|
+
const sessionId = randomUUID();
|
|
20
|
+
const session = new StreamSession({ sessionId, permissionMode: 'default', emit: () => undefined, closeGraceMs: this.options.closeGraceMs });
|
|
21
|
+
// taken before the spec is built, so a second tap meanwhile replaces this one instead of
|
|
22
|
+
// starting a process nobody closes
|
|
23
|
+
this.session = session;
|
|
24
|
+
const spec = await this.options.spawnSpec({ sessionId, resume: false, permissionMode: 'default', allowBypass: false, model: null });
|
|
25
|
+
if (this.session !== session)
|
|
26
|
+
throw new Error('Sign-in was started again');
|
|
27
|
+
session.start(spec);
|
|
28
|
+
try {
|
|
29
|
+
const response = await session.controlRequest({ subtype: 'claude_authenticate', loginWithClaudeAi: !useConsole });
|
|
30
|
+
const url = typeof response['manualUrl'] === 'string' ? response['manualUrl'] : '';
|
|
31
|
+
if (!url)
|
|
32
|
+
throw new Error('Claude did not return a sign-in link');
|
|
33
|
+
session.controlRequest({ subtype: 'claude_oauth_wait_for_completion' }, LOGIN_TIMEOUT_MS)
|
|
34
|
+
.then(() => this.finish(session, null), (error) => this.finish(session, error));
|
|
35
|
+
return url;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
await this.cancel();
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// the code the sign-in page shows, `code#state`
|
|
43
|
+
async submitCode(code) {
|
|
44
|
+
const session = this.session;
|
|
45
|
+
if (!session?.alive)
|
|
46
|
+
throw new Error('No sign-in is in progress, start it again');
|
|
47
|
+
const value = code.trim();
|
|
48
|
+
const hash = value.indexOf('#');
|
|
49
|
+
try {
|
|
50
|
+
await session.controlRequest({
|
|
51
|
+
subtype: 'claude_oauth_callback',
|
|
52
|
+
authorizationCode: hash < 0 ? value : value.slice(0, hash),
|
|
53
|
+
state: hash < 0 ? '' : value.slice(hash + 1),
|
|
54
|
+
}, 60_000);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
// the token endpoint answers a bad or stale code with a bare 4xx
|
|
58
|
+
if (/status code 4\d\d/.test(error.message))
|
|
59
|
+
throw new Error('That code did not work, copy it again from the sign-in page');
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async cancel() {
|
|
64
|
+
const session = this.session;
|
|
65
|
+
this.session = null;
|
|
66
|
+
await session?.close('login_cancelled');
|
|
67
|
+
}
|
|
68
|
+
async finish(session, error) {
|
|
69
|
+
if (this.session !== session)
|
|
70
|
+
return;
|
|
71
|
+
this.session = null;
|
|
72
|
+
await session.close('login_done');
|
|
73
|
+
await this.options.onFinish(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=claudeLogin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeLogin.js","sourceRoot":"","sources":["../../src/engine/claudeLogin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
const CONTROL_TIMEOUT_MS = 30_000;
|
|
3
|
+
export const INITIALIZE_TIMEOUT_MS = 60_000;
|
|
4
|
+
// correlate host -> cli control requests with their responses by request_id
|
|
5
|
+
export class ControlChannel {
|
|
6
|
+
write;
|
|
7
|
+
pending = new Map();
|
|
8
|
+
// write answers false when nothing could reach claude (its stdin is gone)
|
|
9
|
+
constructor(write) {
|
|
10
|
+
this.write = write;
|
|
11
|
+
}
|
|
12
|
+
// send a control request and resolve with its success payload
|
|
13
|
+
request(request, timeoutMs = CONTROL_TIMEOUT_MS) {
|
|
14
|
+
const requestId = `kumo-${randomUUID()}`;
|
|
15
|
+
const promise = new Promise((resolve, reject) => {
|
|
16
|
+
const timer = setTimeout(() => {
|
|
17
|
+
this.cancel(requestId, `control request ${request.subtype} timed out after ${timeoutMs}ms`);
|
|
18
|
+
}, timeoutMs);
|
|
19
|
+
this.pending.set(requestId, { subtype: request.subtype, resolve, reject, timer });
|
|
20
|
+
});
|
|
21
|
+
// claude is exiting: fail now instead of at the timeout (5 minutes for a side question)
|
|
22
|
+
if (this.write({ type: 'control_request', request_id: requestId, request }) === false) {
|
|
23
|
+
this.settle(requestId, new Error(`control request ${request.subtype} could not be sent: claude is not running`));
|
|
24
|
+
}
|
|
25
|
+
return promise;
|
|
26
|
+
}
|
|
27
|
+
// settle the matching pending request; unknown ids (e.g. echoed host responses) are ignored
|
|
28
|
+
handleResponse(msg) {
|
|
29
|
+
const response = msg['response'];
|
|
30
|
+
const requestId = response?.['request_id'];
|
|
31
|
+
if (typeof requestId !== 'string')
|
|
32
|
+
return false;
|
|
33
|
+
const entry = this.pending.get(requestId);
|
|
34
|
+
if (!entry)
|
|
35
|
+
return false;
|
|
36
|
+
this.pending.delete(requestId);
|
|
37
|
+
clearTimeout(entry.timer);
|
|
38
|
+
if (response?.['subtype'] === 'success')
|
|
39
|
+
entry.resolve(response['response'] ?? {});
|
|
40
|
+
else
|
|
41
|
+
entry.reject(new Error(String(response?.['error'] ?? `control request ${entry.subtype} failed`)));
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
settle(requestId, error) {
|
|
45
|
+
const entry = this.pending.get(requestId);
|
|
46
|
+
if (!entry)
|
|
47
|
+
return;
|
|
48
|
+
this.pending.delete(requestId);
|
|
49
|
+
clearTimeout(entry.timer);
|
|
50
|
+
entry.reject(error);
|
|
51
|
+
}
|
|
52
|
+
// drop a pending request locally and tell the cli to stop working on it
|
|
53
|
+
cancel(requestId, reason = 'cancelled') {
|
|
54
|
+
const entry = this.pending.get(requestId);
|
|
55
|
+
if (!entry)
|
|
56
|
+
return;
|
|
57
|
+
this.pending.delete(requestId);
|
|
58
|
+
clearTimeout(entry.timer);
|
|
59
|
+
try {
|
|
60
|
+
this.write({ type: 'control_cancel_request', request_id: requestId });
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
entry.reject(new Error(reason));
|
|
64
|
+
}
|
|
65
|
+
// fail every pending request, used when the process exits
|
|
66
|
+
rejectAll(reason) {
|
|
67
|
+
for (const [requestId, entry] of this.pending) {
|
|
68
|
+
clearTimeout(entry.timer);
|
|
69
|
+
entry.reject(new Error(reason));
|
|
70
|
+
this.pending.delete(requestId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
get size() { return this.pending.size; }
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=controlChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlChannel.js","sourceRoot":"","sources":["../../src/engine/controlChannel.ts"],"names":[],"mappings":"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"}
|