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
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { safePath, copyRecursive } from '../utils/safePath.js';
|
|
3
|
+
import { safePath, copyRecursive, projectRootOf, mutablePath } from '../utils/safePath.js';
|
|
4
4
|
import { loadIgnoredNames } from '../utils/ignorePaths.js';
|
|
5
|
+
// the largest file sent to the app in one read
|
|
6
|
+
export const MAX_READ_BYTES = 5 * 1024 * 1024;
|
|
7
|
+
// how many folder entries one search may look at before giving up
|
|
8
|
+
export const MAX_SEARCH_VISITS = 50_000;
|
|
5
9
|
// translate any thrown error into a string message
|
|
6
10
|
function errMsg(e) {
|
|
7
11
|
return e instanceof Error ? e.message : String(e);
|
|
@@ -15,10 +19,19 @@ function guard(fn) {
|
|
|
15
19
|
return { ok: false, error: errMsg(e) };
|
|
16
20
|
}
|
|
17
21
|
}
|
|
22
|
+
// size of a file, 0 when it cannot be read (a broken link, no permission)
|
|
23
|
+
function sizeOf(file) {
|
|
24
|
+
try {
|
|
25
|
+
return fs.statSync(file).size;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
18
31
|
// list directory entries (non-hidden) sorted dirs first
|
|
19
32
|
export function list(requestedPath, cwd) {
|
|
20
33
|
return guard(() => {
|
|
21
|
-
const projectRoot =
|
|
34
|
+
const projectRoot = projectRootOf(cwd);
|
|
22
35
|
const resolved = requestedPath
|
|
23
36
|
? safePath(requestedPath, projectRoot)
|
|
24
37
|
: projectRoot;
|
|
@@ -28,24 +41,33 @@ export function list(requestedPath, cwd) {
|
|
|
28
41
|
name: e.name,
|
|
29
42
|
path: path.relative(projectRoot, path.resolve(resolved, e.name)).replace(/\\/g, '/'),
|
|
30
43
|
isDirectory: e.isDirectory(),
|
|
31
|
-
size: e.isDirectory() ? 0 :
|
|
44
|
+
size: e.isDirectory() ? 0 : sizeOf(path.resolve(resolved, e.name)),
|
|
32
45
|
}))
|
|
33
46
|
.sort((a, b) => a.isDirectory !== b.isDirectory ? (a.isDirectory ? -1 : 1) : a.name.localeCompare(b.name));
|
|
34
47
|
return { entries, projectName: path.basename(projectRoot) };
|
|
35
48
|
});
|
|
36
49
|
}
|
|
37
50
|
export function read(filePath, cwd) {
|
|
38
|
-
return guard(() =>
|
|
51
|
+
return guard(() => {
|
|
52
|
+
const resolved = safePath(filePath, projectRootOf(cwd));
|
|
53
|
+
const stat = fs.statSync(resolved);
|
|
54
|
+
if (!stat.isFile())
|
|
55
|
+
throw new Error('not a file');
|
|
56
|
+
if (stat.size > MAX_READ_BYTES)
|
|
57
|
+
throw new Error(`file too large (${stat.size} bytes, max ${MAX_READ_BYTES})`);
|
|
58
|
+
return fs.readFileSync(resolved, 'utf-8');
|
|
59
|
+
});
|
|
39
60
|
}
|
|
40
61
|
export function write(filePath, content, cwd) {
|
|
41
62
|
return guard(() => {
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
if (typeof content !== 'string')
|
|
64
|
+
throw new Error('content is required');
|
|
65
|
+
fs.writeFileSync(mutablePath(filePath, projectRootOf(cwd)), content, 'utf-8');
|
|
44
66
|
});
|
|
45
67
|
}
|
|
46
68
|
export function create(targetPath, isDir, cwd) {
|
|
47
69
|
return guard(() => {
|
|
48
|
-
const resolved =
|
|
70
|
+
const resolved = mutablePath(targetPath, projectRootOf(cwd));
|
|
49
71
|
if (isDir)
|
|
50
72
|
fs.mkdirSync(resolved, { recursive: true });
|
|
51
73
|
else {
|
|
@@ -55,25 +77,33 @@ export function create(targetPath, isDir, cwd) {
|
|
|
55
77
|
});
|
|
56
78
|
}
|
|
57
79
|
export function remove(targetPath, cwd) {
|
|
58
|
-
return guard(() => fs.rmSync(
|
|
80
|
+
return guard(() => fs.rmSync(mutablePath(targetPath, projectRootOf(cwd)), { recursive: true, force: false }));
|
|
59
81
|
}
|
|
60
82
|
export function rename(oldPath, newName, cwd) {
|
|
61
83
|
return guard(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
if (typeof newName !== 'string' || !newName || newName === '.' || newName === '..' || /[\\/]/.test(newName)) {
|
|
85
|
+
throw new Error('invalid name');
|
|
86
|
+
}
|
|
87
|
+
const projectRoot = projectRootOf(cwd);
|
|
88
|
+
const resolvedOld = mutablePath(oldPath, projectRoot);
|
|
89
|
+
const resolvedNew = safePath(path.join(path.dirname(resolvedOld), newName), projectRoot);
|
|
66
90
|
fs.renameSync(resolvedOld, resolvedNew);
|
|
67
91
|
return { newPath: path.relative(projectRoot, resolvedNew).replace(/\\/g, '/') };
|
|
68
92
|
});
|
|
69
93
|
}
|
|
70
94
|
export function copy(src, dest, cwd) {
|
|
71
|
-
return guard(() =>
|
|
95
|
+
return guard(() => {
|
|
96
|
+
const projectRoot = projectRootOf(cwd);
|
|
97
|
+
copyRecursive(mutablePath(src, projectRoot), mutablePath(dest, projectRoot));
|
|
98
|
+
});
|
|
72
99
|
}
|
|
73
100
|
export function move(src, dest, cwd) {
|
|
74
|
-
return guard(() =>
|
|
101
|
+
return guard(() => {
|
|
102
|
+
const projectRoot = projectRootOf(cwd);
|
|
103
|
+
fs.renameSync(mutablePath(src, projectRoot), mutablePath(dest, projectRoot));
|
|
104
|
+
});
|
|
75
105
|
}
|
|
76
|
-
// recursive case-insensitive name search, bounded by limit
|
|
106
|
+
// recursive case-insensitive name search, bounded by limit and by how many entries it looks at
|
|
77
107
|
export function search(query, basePath, limit) {
|
|
78
108
|
return guard(() => {
|
|
79
109
|
const q = query.trim().toLowerCase();
|
|
@@ -84,7 +114,8 @@ export function search(query, basePath, limit) {
|
|
|
84
114
|
const ignored = loadIgnoredNames(projectRoot);
|
|
85
115
|
const results = [];
|
|
86
116
|
const stack = [baseResolved];
|
|
87
|
-
|
|
117
|
+
let visits = 0;
|
|
118
|
+
while (stack.length > 0 && results.length < limit && visits < MAX_SEARCH_VISITS) {
|
|
88
119
|
const dir = stack.pop();
|
|
89
120
|
let dirEntries;
|
|
90
121
|
try {
|
|
@@ -94,22 +125,17 @@ export function search(query, basePath, limit) {
|
|
|
94
125
|
continue;
|
|
95
126
|
}
|
|
96
127
|
for (const e of dirEntries) {
|
|
128
|
+
if (++visits >= MAX_SEARCH_VISITS)
|
|
129
|
+
break;
|
|
97
130
|
if (e.name.startsWith('.') || ignored.has(e.name))
|
|
98
131
|
continue;
|
|
99
132
|
const full = path.resolve(dir, e.name);
|
|
100
133
|
if (e.name.toLowerCase().includes(q)) {
|
|
101
|
-
let size = 0;
|
|
102
|
-
if (!e.isDirectory()) {
|
|
103
|
-
try {
|
|
104
|
-
size = fs.statSync(full).size;
|
|
105
|
-
}
|
|
106
|
-
catch { }
|
|
107
|
-
}
|
|
108
134
|
results.push({
|
|
109
135
|
name: e.name,
|
|
110
136
|
path: path.relative(projectRoot, full).replace(/\\/g, '/'),
|
|
111
137
|
isDirectory: e.isDirectory(),
|
|
112
|
-
size,
|
|
138
|
+
size: e.isDirectory() ? 0 : sizeOf(full),
|
|
113
139
|
});
|
|
114
140
|
if (results.length >= limit)
|
|
115
141
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileService.js","sourceRoot":"","sources":["../../src/services/fileService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"fileService.js","sourceRoot":"","sources":["../../src/services/fileService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { findSessionJsonl } from './sessionService.js';
|
|
6
|
+
import { str } from '../utils/json.js';
|
|
7
|
+
function promptText(entry) {
|
|
8
|
+
const content = entry['message']?.['content'];
|
|
9
|
+
if (typeof content === 'string')
|
|
10
|
+
return content;
|
|
11
|
+
if (!Array.isArray(content))
|
|
12
|
+
return '';
|
|
13
|
+
return content
|
|
14
|
+
.filter((b) => !!b && typeof b === 'object' && b['type'] === 'text')
|
|
15
|
+
.map((b) => str(b['text']))
|
|
16
|
+
.join('');
|
|
17
|
+
}
|
|
18
|
+
function readEntries(file) {
|
|
19
|
+
return fs.readFileSync(file, 'utf-8').split('\n').flatMap((line) => {
|
|
20
|
+
if (!line.trim())
|
|
21
|
+
return [];
|
|
22
|
+
try {
|
|
23
|
+
return [JSON.parse(line)];
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// the user's rename, else claude's title, of the source session
|
|
31
|
+
function titleOf(entries) {
|
|
32
|
+
let custom = '';
|
|
33
|
+
let ai = '';
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (entry['type'] === 'custom-title')
|
|
36
|
+
custom = str(entry['customTitle']) || custom;
|
|
37
|
+
if (entry['type'] === 'ai-title')
|
|
38
|
+
ai = str(entry['aiTitle']) || ai;
|
|
39
|
+
}
|
|
40
|
+
return custom || ai;
|
|
41
|
+
}
|
|
42
|
+
// checkpoints of the kept messages stay usable in the fork: hard-link their backups
|
|
43
|
+
function linkBackups(sourceId, forkId, backups) {
|
|
44
|
+
if (!backups || typeof backups !== 'object')
|
|
45
|
+
return;
|
|
46
|
+
const root = path.join(os.homedir(), '.claude', 'file-history');
|
|
47
|
+
for (const backup of Object.values(backups)) {
|
|
48
|
+
const name = str(backup?.['backupFileName']);
|
|
49
|
+
if (!name || name !== path.basename(name))
|
|
50
|
+
continue;
|
|
51
|
+
const from = path.join(root, sourceId, name);
|
|
52
|
+
const to = path.join(root, forkId, name);
|
|
53
|
+
if (!fs.existsSync(from) || fs.existsSync(to))
|
|
54
|
+
continue;
|
|
55
|
+
fs.mkdirSync(path.dirname(to), { recursive: true });
|
|
56
|
+
try {
|
|
57
|
+
fs.linkSync(from, to);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
fs.copyFileSync(from, to);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// fork a conversation right before one of its prompts, as the VS Code extension does: the
|
|
65
|
+
// chain up to that prompt's parent is copied under fresh uuids into a new transcript next to
|
|
66
|
+
// the source, its file-history checkpoints follow along, and the copy is titled "(fork)"
|
|
67
|
+
export function forkSession(sourceId, userMessageId) {
|
|
68
|
+
const file = findSessionJsonl(sourceId);
|
|
69
|
+
if (!file)
|
|
70
|
+
throw new Error('Session transcript not found');
|
|
71
|
+
const entries = readEntries(file);
|
|
72
|
+
const byUuid = new Map();
|
|
73
|
+
for (const entry of entries)
|
|
74
|
+
if (str(entry['uuid']))
|
|
75
|
+
byUuid.set(str(entry['uuid']), entry);
|
|
76
|
+
const chosen = byUuid.get(userMessageId);
|
|
77
|
+
if (!chosen || chosen['type'] !== 'user')
|
|
78
|
+
throw new Error('That message is not in this session');
|
|
79
|
+
const prompt = promptText(chosen);
|
|
80
|
+
const resumeAt = str(chosen['parentUuid']);
|
|
81
|
+
if (!resumeAt)
|
|
82
|
+
return { sessionId: null, prompt };
|
|
83
|
+
// walk back from the kept tail to the root; progress entries drop out of the copy
|
|
84
|
+
const chain = [];
|
|
85
|
+
const visited = new Set();
|
|
86
|
+
for (let entry = byUuid.get(resumeAt); entry && !visited.has(str(entry['uuid'])); entry = byUuid.get(str(entry['parentUuid']))) {
|
|
87
|
+
visited.add(str(entry['uuid']));
|
|
88
|
+
if (entry['type'] !== 'progress')
|
|
89
|
+
chain.unshift(entry);
|
|
90
|
+
}
|
|
91
|
+
if (chain.length === 0)
|
|
92
|
+
return { sessionId: null, prompt };
|
|
93
|
+
const forkId = randomUUID();
|
|
94
|
+
const ids = new Map(chain.map((entry) => [str(entry['uuid']), randomUUID()]));
|
|
95
|
+
const out = chain.map((entry, i) => {
|
|
96
|
+
const { logicalParentUuid: _logical, ...rest } = entry;
|
|
97
|
+
return {
|
|
98
|
+
...rest,
|
|
99
|
+
uuid: ids.get(str(entry['uuid'])),
|
|
100
|
+
parentUuid: i === 0 ? null : ids.get(str(chain[i - 1]['uuid'])),
|
|
101
|
+
sessionId: forkId,
|
|
102
|
+
...(i === chain.length - 1 ? { timestamp: new Date().toISOString() } : {}),
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
for (const entry of entries) {
|
|
106
|
+
if (entry['type'] !== 'file-history-snapshot')
|
|
107
|
+
continue;
|
|
108
|
+
const messageId = ids.get(str(entry['messageId']));
|
|
109
|
+
if (!messageId)
|
|
110
|
+
continue;
|
|
111
|
+
const snapshot = { ...entry['snapshot'], messageId };
|
|
112
|
+
out.push({ ...entry, messageId, snapshot });
|
|
113
|
+
linkBackups(sourceId, forkId, snapshot['trackedFileBackups']);
|
|
114
|
+
}
|
|
115
|
+
const title = titleOf(entries) || prompt.split('\n')[0].slice(0, 60);
|
|
116
|
+
out.push({ type: 'custom-title', customTitle: `${title} (fork)`, sessionId: forkId });
|
|
117
|
+
fs.writeFileSync(path.join(path.dirname(file), `${forkId}.jsonl`), `${out.map((e) => JSON.stringify(e)).join('\n')}\n`, 'utf-8');
|
|
118
|
+
return { sessionId: forkId, prompt };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=forkService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forkService.js","sourceRoot":"","sources":["../../src/services/forkService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,89 +1,102 @@
|
|
|
1
1
|
import { httpRequest } from '../http/httpClient.js';
|
|
2
2
|
import { SERVER_HTTP } from '../core/config.js';
|
|
3
3
|
import { ClaudeAdapterProxy } from './claudeAdapterProxy.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
import { isLocalHost } from '../utils/localHost.js';
|
|
5
|
+
// distinct provider configs kept running; above the live-session cap so live sessions keep theirs
|
|
6
|
+
const MAX_ADAPTER_PROXIES = 8;
|
|
7
|
+
// parse a backend model payload: object = explicit model, null = claude's own default, otherwise device default
|
|
8
|
+
export function parseModelPayload(payload) {
|
|
9
|
+
if (payload === null)
|
|
10
|
+
return null;
|
|
11
|
+
if (!payload || typeof payload !== 'object')
|
|
12
|
+
return undefined;
|
|
13
|
+
const p = payload;
|
|
14
|
+
const model = {
|
|
15
|
+
model: typeof p['model'] === 'string' ? p['model'].trim() : '',
|
|
16
|
+
baseURL: typeof p['baseURL'] === 'string' && p['baseURL'] ? p['baseURL'] : undefined,
|
|
17
|
+
apiKey: typeof p['apiKey'] === 'string' && p['apiKey'] ? p['apiKey'] : undefined,
|
|
18
|
+
};
|
|
19
|
+
const contextWindow = p['contextWindow'];
|
|
20
|
+
if (typeof contextWindow === 'number' && Number.isInteger(contextWindow) && contextWindow > 0)
|
|
21
|
+
model.contextWindow = contextWindow;
|
|
22
|
+
return model.model || model.baseURL || model.apiKey ? model : undefined;
|
|
23
|
+
}
|
|
24
|
+
// a provider url must be https, or http on a local host
|
|
25
|
+
export function assertProviderURL(baseURL) {
|
|
26
|
+
let url;
|
|
27
|
+
try {
|
|
28
|
+
url = new URL(baseURL);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error(`invalid provider url: ${baseURL}`);
|
|
16
32
|
}
|
|
17
|
-
|
|
33
|
+
if (url.protocol === 'https:')
|
|
34
|
+
return;
|
|
35
|
+
if (url.protocol === 'http:' && isLocalHost(url.hostname))
|
|
36
|
+
return;
|
|
37
|
+
throw new Error(`provider url must use https: ${url.origin}`);
|
|
18
38
|
}
|
|
19
|
-
//
|
|
39
|
+
// provider connection for claude processes: env overrides, adapter proxies and the device default model
|
|
20
40
|
export class ModelService {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
getCurrent() { return this.current; }
|
|
25
|
-
// cache incoming connection settings and rebuild the runtime model args
|
|
26
|
-
apply(payload, args) {
|
|
27
|
-
const cleaned = removeModelArgs(args);
|
|
28
|
-
if (payload && typeof payload === 'object') {
|
|
29
|
-
const p = payload;
|
|
30
|
-
const current = {
|
|
31
|
-
model: typeof p['model'] === 'string' && p['model'].trim()
|
|
32
|
-
? p['model'].trim()
|
|
33
|
-
: this.current?.model ?? '',
|
|
34
|
-
baseURL: typeof p['baseURL'] === 'string' ? p['baseURL'] : undefined,
|
|
35
|
-
apiKey: typeof p['apiKey'] === 'string' ? p['apiKey'] : undefined,
|
|
36
|
-
};
|
|
37
|
-
if (current.model || current.baseURL || current.apiKey) {
|
|
38
|
-
this.current = current;
|
|
39
|
-
this.suppressDefaultFallback = false;
|
|
40
|
-
if (current.model)
|
|
41
|
-
cleaned.push('--model', current.model);
|
|
42
|
-
return cleaned;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
this.current = null;
|
|
46
|
-
this.suppressDefaultFallback = payload === null;
|
|
47
|
-
return cleaned;
|
|
48
|
-
}
|
|
49
|
-
// build env overrides for claude pty based on current model
|
|
50
|
-
async buildEnv() {
|
|
41
|
+
adapterProxies = new Map();
|
|
42
|
+
// build env overrides for a claude process running the given model
|
|
43
|
+
async buildEnv(model) {
|
|
51
44
|
const env = {
|
|
52
45
|
ANTHROPIC_BASE_URL: undefined,
|
|
53
46
|
ANTHROPIC_API_KEY: undefined,
|
|
54
47
|
ANTHROPIC_AUTH_TOKEN: undefined,
|
|
55
48
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
let proxyToken;
|
|
50
|
+
if (model?.baseURL) {
|
|
51
|
+
assertProviderURL(model.baseURL.trim());
|
|
52
|
+
const endpoint = await this.resolveEndpoint(model);
|
|
53
|
+
env.ANTHROPIC_BASE_URL = endpoint.url;
|
|
54
|
+
proxyToken = endpoint.token;
|
|
55
|
+
// the local adapter holds the provider key and takes its own token; without a key of its
|
|
56
|
+
// own claude would send its claude.ai login to that host
|
|
57
|
+
if (proxyToken)
|
|
58
|
+
env.ANTHROPIC_AUTH_TOKEN = proxyToken;
|
|
59
|
+
else if (!model.apiKey)
|
|
60
|
+
env.ANTHROPIC_AUTH_TOKEN = 'none';
|
|
61
|
+
// claude turns tool search off for hosts that are not anthropic's, then sends every mcp
|
|
62
|
+
// tool's schema each turn and can outgrow a provider's input limit; on unless the user
|
|
63
|
+
// set it themselves
|
|
64
|
+
if (process.env['ENABLE_TOOL_SEARCH'] === undefined)
|
|
65
|
+
env.ENABLE_TOOL_SEARCH = 'true';
|
|
59
66
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
env.ANTHROPIC_API_KEY = this.current.apiKey;
|
|
65
|
-
if (env.ANTHROPIC_BASE_URL?.startsWith('http://127.0.0.1:'))
|
|
66
|
-
env.ANTHROPIC_AUTH_TOKEN = 'default';
|
|
67
|
+
if (model?.apiKey && !proxyToken)
|
|
68
|
+
env.ANTHROPIC_API_KEY = model.apiKey;
|
|
69
|
+
if (model?.contextWindow)
|
|
70
|
+
env.CLAUDE_CODE_AUTO_COMPACT_WINDOW = String(model.contextWindow);
|
|
67
71
|
return env;
|
|
68
72
|
}
|
|
69
73
|
// normalize provider endpoints into Claude-compatible base urls
|
|
70
74
|
async resolveClaudeBaseURL(model) {
|
|
75
|
+
return (await this.resolveEndpoint(model)).url;
|
|
76
|
+
}
|
|
77
|
+
// the claude-compatible url of a provider, with the token of the adapter proxy started for it;
|
|
78
|
+
// one proxy per provider config, the least recently used closed past MAX_ADAPTER_PROXIES
|
|
79
|
+
async resolveEndpoint(model) {
|
|
71
80
|
const baseURL = (model.baseURL ?? '').trim().replace(/\/+$/, '');
|
|
72
81
|
if (!baseURL)
|
|
73
|
-
return baseURL;
|
|
74
|
-
if (/\/v1\/messages$/i.test(baseURL))
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
return { url: baseURL };
|
|
83
|
+
if (/\/v1\/messages$/i.test(baseURL))
|
|
84
|
+
return { url: baseURL.replace(/\/v1\/messages$/i, '') };
|
|
85
|
+
if (!/\/v1\/chat\/completions$/i.test(baseURL))
|
|
86
|
+
return { url: baseURL };
|
|
87
|
+
const config = { baseURL, apiKey: model.apiKey ?? '', model: model.model };
|
|
88
|
+
const key = JSON.stringify(config);
|
|
89
|
+
const proxy = this.adapterProxies.get(key) ?? new ClaudeAdapterProxy();
|
|
90
|
+
this.adapterProxies.delete(key);
|
|
91
|
+
this.adapterProxies.set(key, proxy);
|
|
92
|
+
for (const [oldKey, old] of this.adapterProxies) {
|
|
93
|
+
if (this.adapterProxies.size <= MAX_ADAPTER_PROXIES)
|
|
94
|
+
break;
|
|
95
|
+
this.adapterProxies.delete(oldKey);
|
|
96
|
+
void old.stop();
|
|
84
97
|
}
|
|
85
|
-
await
|
|
86
|
-
return
|
|
98
|
+
const url = await proxy.start(config);
|
|
99
|
+
return { url, token: proxy.token ?? undefined };
|
|
87
100
|
}
|
|
88
101
|
// fetch the user's current default model from backend using deviceToken
|
|
89
102
|
async fetchDefault(deviceToken) {
|
|
@@ -91,36 +104,20 @@ export class ModelService {
|
|
|
91
104
|
return null;
|
|
92
105
|
try {
|
|
93
106
|
const res = await httpRequest('GET', `${SERVER_HTTP()}/api/cli/default-model`, { token: deviceToken });
|
|
94
|
-
if (res.status !== 200
|
|
107
|
+
if (res.status !== 200)
|
|
95
108
|
return null;
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
if (!model)
|
|
99
|
-
return null;
|
|
100
|
-
return {
|
|
101
|
-
model,
|
|
102
|
-
baseURL: typeof d['baseURL'] === 'string' ? d['baseURL'] : undefined,
|
|
103
|
-
apiKey: typeof d['apiKey'] === 'string' ? d['apiKey'] : undefined,
|
|
104
|
-
};
|
|
109
|
+
const model = parseModelPayload(res.data);
|
|
110
|
+
return model?.model ? model : null;
|
|
105
111
|
}
|
|
106
112
|
catch {
|
|
107
113
|
return null;
|
|
108
114
|
}
|
|
109
115
|
}
|
|
110
|
-
// refresh from backend when no current model is set; returns new args list
|
|
111
|
-
async ensureBeforeSpawn(args, deviceToken) {
|
|
112
|
-
if (this.current)
|
|
113
|
-
return args;
|
|
114
|
-
if (this.suppressDefaultFallback)
|
|
115
|
-
return args;
|
|
116
|
-
const def = await this.fetchDefault(deviceToken);
|
|
117
|
-
if (def)
|
|
118
|
-
return this.apply({ model: def.model, baseURL: def.baseURL, apiKey: def.apiKey }, args);
|
|
119
|
-
return args;
|
|
120
|
-
}
|
|
121
116
|
// release local adapter resources
|
|
122
117
|
async dispose() {
|
|
123
|
-
|
|
118
|
+
const proxies = [...this.adapterProxies.values()];
|
|
119
|
+
this.adapterProxies.clear();
|
|
120
|
+
await Promise.all(proxies.map((proxy) => proxy.stop()));
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
123
|
//# sourceMappingURL=modelService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelService.js","sourceRoot":"","sources":["../../src/services/modelService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"modelService.js","sourceRoot":"","sources":["../../src/services/modelService.ts"],"names":[],"mappings":"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"}
|