kumo-cli 1.0.6 → 1.1.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 +131 -127
- package/dist/auth/credentialsStore.js +1 -1
- package/dist/auth/credentialsStore.js.map +1 -1
- package/dist/claude/transcriptParser.js +110 -11
- package/dist/claude/transcriptParser.js.map +1 -1
- package/dist/core/config.js +1 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/logger.js +6 -18
- package/dist/core/logger.js.map +1 -1
- package/dist/engine/claudeArgs.js +102 -0
- package/dist/engine/claudeArgs.js.map +1 -0
- package/dist/engine/claudeBinary.js +85 -0
- package/dist/engine/claudeBinary.js.map +1 -0
- package/dist/engine/claudeConfig.js +113 -0
- package/dist/engine/claudeConfig.js.map +1 -0
- package/dist/engine/controlChannel.js +63 -0
- package/dist/engine/controlChannel.js.map +1 -0
- package/dist/engine/liveTranscript.js +101 -0
- package/dist/engine/liveTranscript.js.map +1 -0
- package/dist/engine/ndjson.js +43 -0
- package/dist/engine/ndjson.js.map +1 -0
- package/dist/engine/permissions.js +98 -0
- package/dist/engine/permissions.js.map +1 -0
- package/dist/engine/sessionManager.js +429 -0
- package/dist/engine/sessionManager.js.map +1 -0
- package/dist/engine/settingsCommands.js +204 -0
- package/dist/engine/settingsCommands.js.map +1 -0
- package/dist/engine/streamSession.js +509 -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/handlers/promptImages.js +8 -39
- package/dist/handlers/promptImages.js.map +1 -1
- package/dist/handlers/runtimeHandlers.js +195 -27
- package/dist/handlers/runtimeHandlers.js.map +1 -1
- package/dist/handlers/sessionHandlers.js +41 -70
- package/dist/handlers/sessionHandlers.js.map +1 -1
- package/dist/index.js +35 -40
- package/dist/index.js.map +1 -1
- package/dist/services/cliRuntime.js +37 -30
- 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/forkService.js +120 -0
- package/dist/services/forkService.js.map +1 -0
- package/dist/services/modelService.js +37 -84
- package/dist/services/modelService.js.map +1 -1
- package/dist/services/sessionListService.js +7 -9
- package/dist/services/sessionListService.js.map +1 -1
- package/dist/services/sessionService.js +77 -57
- package/dist/services/sessionService.js.map +1 -1
- package/dist/services/tunnelService.js +4 -5
- package/dist/services/tunnelService.js.map +1 -1
- package/dist/transport/wsClient.js +0 -4
- package/dist/transport/wsClient.js.map +1 -1
- package/dist/utils/ignorePaths.js +3 -3
- package/dist/utils/ignorePaths.js.map +1 -1
- package/package.json +62 -69
- 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,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
|
+
const str = (value) => (typeof value === 'string' ? value : '');
|
|
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,88 +1,57 @@
|
|
|
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
|
-
export function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return result;
|
|
4
|
+
// parse a backend model payload: object = explicit model, null = claude's own default, otherwise device default
|
|
5
|
+
export function parseModelPayload(payload) {
|
|
6
|
+
if (payload === null)
|
|
7
|
+
return null;
|
|
8
|
+
if (!payload || typeof payload !== 'object')
|
|
9
|
+
return undefined;
|
|
10
|
+
const p = payload;
|
|
11
|
+
const model = {
|
|
12
|
+
model: typeof p['model'] === 'string' ? p['model'].trim() : '',
|
|
13
|
+
baseURL: typeof p['baseURL'] === 'string' && p['baseURL'] ? p['baseURL'] : undefined,
|
|
14
|
+
apiKey: typeof p['apiKey'] === 'string' && p['apiKey'] ? p['apiKey'] : undefined,
|
|
15
|
+
};
|
|
16
|
+
return model.model || model.baseURL || model.apiKey ? model : undefined;
|
|
18
17
|
}
|
|
19
|
-
//
|
|
18
|
+
// provider connection for claude processes: env overrides, adapter proxies and the device default model
|
|
20
19
|
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() {
|
|
20
|
+
adapterProxies = new Map();
|
|
21
|
+
// build env overrides for a claude process running the given model
|
|
22
|
+
async buildEnv(model) {
|
|
51
23
|
const env = {
|
|
52
24
|
ANTHROPIC_BASE_URL: undefined,
|
|
53
25
|
ANTHROPIC_API_KEY: undefined,
|
|
54
26
|
ANTHROPIC_AUTH_TOKEN: undefined,
|
|
55
27
|
};
|
|
56
|
-
if (
|
|
57
|
-
env.ANTHROPIC_BASE_URL = await this.resolveClaudeBaseURL(
|
|
28
|
+
if (model?.baseURL) {
|
|
29
|
+
env.ANTHROPIC_BASE_URL = await this.resolveClaudeBaseURL(model);
|
|
58
30
|
env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
59
31
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
if (this.current?.apiKey)
|
|
64
|
-
env.ANTHROPIC_API_KEY = this.current.apiKey;
|
|
32
|
+
if (model?.apiKey)
|
|
33
|
+
env.ANTHROPIC_API_KEY = model.apiKey;
|
|
65
34
|
if (env.ANTHROPIC_BASE_URL?.startsWith('http://127.0.0.1:'))
|
|
66
35
|
env.ANTHROPIC_AUTH_TOKEN = 'default';
|
|
67
36
|
return env;
|
|
68
37
|
}
|
|
69
|
-
// normalize provider endpoints into Claude-compatible base urls
|
|
38
|
+
// normalize provider endpoints into Claude-compatible base urls; one adapter proxy per provider config
|
|
70
39
|
async resolveClaudeBaseURL(model) {
|
|
71
40
|
const baseURL = (model.baseURL ?? '').trim().replace(/\/+$/, '');
|
|
72
41
|
if (!baseURL)
|
|
73
42
|
return baseURL;
|
|
74
|
-
if (/\/v1\/messages$/i.test(baseURL))
|
|
75
|
-
await this.adapterProxy.stop();
|
|
43
|
+
if (/\/v1\/messages$/i.test(baseURL))
|
|
76
44
|
return baseURL.replace(/\/v1\/messages$/i, '');
|
|
77
|
-
}
|
|
78
45
|
if (/\/v1\/chat\/completions$/i.test(baseURL)) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
46
|
+
const config = { baseURL, apiKey: model.apiKey ?? '', model: model.model };
|
|
47
|
+
const key = JSON.stringify(config);
|
|
48
|
+
let proxy = this.adapterProxies.get(key);
|
|
49
|
+
if (!proxy) {
|
|
50
|
+
proxy = new ClaudeAdapterProxy();
|
|
51
|
+
this.adapterProxies.set(key, proxy);
|
|
52
|
+
}
|
|
53
|
+
return proxy.start(config);
|
|
84
54
|
}
|
|
85
|
-
await this.adapterProxy.stop();
|
|
86
55
|
return baseURL;
|
|
87
56
|
}
|
|
88
57
|
// fetch the user's current default model from backend using deviceToken
|
|
@@ -91,36 +60,20 @@ export class ModelService {
|
|
|
91
60
|
return null;
|
|
92
61
|
try {
|
|
93
62
|
const res = await httpRequest('GET', `${SERVER_HTTP()}/api/cli/default-model`, { token: deviceToken });
|
|
94
|
-
if (res.status !== 200
|
|
63
|
+
if (res.status !== 200)
|
|
95
64
|
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
|
-
};
|
|
65
|
+
const model = parseModelPayload(res.data);
|
|
66
|
+
return model?.model ? model : null;
|
|
105
67
|
}
|
|
106
68
|
catch {
|
|
107
69
|
return null;
|
|
108
70
|
}
|
|
109
71
|
}
|
|
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
72
|
// release local adapter resources
|
|
122
73
|
async dispose() {
|
|
123
|
-
|
|
74
|
+
const proxies = [...this.adapterProxies.values()];
|
|
75
|
+
this.adapterProxies.clear();
|
|
76
|
+
await Promise.all(proxies.map((proxy) => proxy.stop()));
|
|
124
77
|
}
|
|
125
78
|
}
|
|
126
79
|
//# 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;AAQ7D,
|
|
1
|
+
{"version":3,"file":"modelService.js","sourceRoot":"","sources":["../../src/services/modelService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import * as sessionService from './sessionService.js';
|
|
2
|
-
// merge persisted sessions with
|
|
3
|
-
export function mergeSessionActivity(sessions, activeIds,
|
|
4
|
-
const resolvedActiveIds = new Set(activeIds);
|
|
5
|
-
if (currentSessionId) {
|
|
6
|
-
resolvedActiveIds.add(currentSessionId);
|
|
7
|
-
}
|
|
2
|
+
// merge persisted sessions with active ids from ~/.claude/sessions and the sessions live in this runtime
|
|
3
|
+
export function mergeSessionActivity(sessions, activeIds, liveSessionIds = [], statuses = new Map()) {
|
|
4
|
+
const resolvedActiveIds = new Set([...activeIds, ...liveSessionIds]);
|
|
8
5
|
return sessions.map((session) => ({
|
|
9
6
|
...session,
|
|
10
7
|
isActive: resolvedActiveIds.has(session.sessionId),
|
|
8
|
+
...statuses.get(session.sessionId),
|
|
11
9
|
}));
|
|
12
10
|
}
|
|
13
11
|
// load the session list payload exactly once so callers do not duplicate the same merge logic
|
|
14
|
-
export async function loadSessionList(cwdArg,
|
|
12
|
+
export async function loadSessionList(cwdArg, liveSessionIds = []) {
|
|
15
13
|
const sessions = await sessionService.getSessionListForCwd(cwdArg);
|
|
16
|
-
const
|
|
17
|
-
return mergeSessionActivity(sessions,
|
|
14
|
+
const active = await sessionService.getActiveSessions();
|
|
15
|
+
return mergeSessionActivity(sessions, new Set(active.keys()), liveSessionIds, active);
|
|
18
16
|
}
|
|
19
17
|
//# sourceMappingURL=sessionListService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionListService.js","sourceRoot":"","sources":["../../src/services/sessionListService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sessionListService.js","sourceRoot":"","sources":["../../src/services/sessionListService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAOtD,yGAAyG;AACzG,MAAM,UAAU,oBAAoB,CAClC,QAA4B,EAC5B,SAAsB,EACtB,iBAAmC,EAAE,EACrC,WAAuC,IAAI,GAAG,EAAE;IAEhD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;IACrE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,GAAG,OAAO;QACV,QAAQ,EAAE,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;QAClD,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;KACnC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAe,EAAE,iBAAmC,EAAE;IAC1F,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,EAAE,CAAC;IACxD,OAAO,oBAAoB,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;AACxF,CAAC"}
|
|
@@ -3,30 +3,37 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { log } from '../core/logger.js';
|
|
5
5
|
import { cwdToProjectFolder } from '../utils/safePath.js';
|
|
6
|
-
import { parseTranscriptMessage } from '../claude/transcriptParser.js';
|
|
6
|
+
import { parseTranscriptMessage, rememberToolResults } from '../claude/transcriptParser.js';
|
|
7
7
|
import { hydratePromptImages } from '../handlers/promptImages.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
function isPidAlive(pid) {
|
|
9
|
+
if (typeof pid !== 'number')
|
|
10
|
+
return false;
|
|
11
|
+
try {
|
|
12
|
+
process.kill(pid, 0);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
// EPERM means the process exists but belongs to someone else
|
|
17
|
+
return err.code === 'EPERM';
|
|
16
18
|
}
|
|
17
|
-
return result;
|
|
18
19
|
}
|
|
19
|
-
//
|
|
20
|
-
export async function
|
|
20
|
+
// claude processes still alive, from ~/.claude/sessions, keyed by session id
|
|
21
|
+
export async function getActiveSessions() {
|
|
21
22
|
const sessionsDir = path.join(os.homedir(), '.claude', 'sessions');
|
|
22
|
-
const active = new
|
|
23
|
+
const active = new Map();
|
|
23
24
|
try {
|
|
24
25
|
const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));
|
|
25
26
|
for (const file of files) {
|
|
26
27
|
try {
|
|
27
28
|
const data = JSON.parse(fs.readFileSync(path.join(sessionsDir, file), 'utf-8'));
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
// a hard-killed claude leaves its pid file behind
|
|
30
|
+
if (!data.sessionId || !isPidAlive(data.pid))
|
|
31
|
+
continue;
|
|
32
|
+
const since = typeof data.statusUpdatedAt === 'number' ? new Date(data.statusUpdatedAt).toISOString() : undefined;
|
|
33
|
+
active.set(data.sessionId, {
|
|
34
|
+
...(typeof data.status === 'string' ? { status: data.status } : {}),
|
|
35
|
+
...(since ? { statusSince: since } : {}),
|
|
36
|
+
});
|
|
30
37
|
}
|
|
31
38
|
catch { }
|
|
32
39
|
}
|
|
@@ -34,11 +41,23 @@ export async function getActiveSessionIds() {
|
|
|
34
41
|
catch { }
|
|
35
42
|
return active;
|
|
36
43
|
}
|
|
44
|
+
// locate ~/.claude/projects/<slug>/<sessionId>.jsonl in any project folder
|
|
45
|
+
export function findSessionJsonl(sessionId) {
|
|
46
|
+
const projectsDir = path.join(os.homedir(), '.claude', 'projects');
|
|
47
|
+
if (!fs.existsSync(projectsDir))
|
|
48
|
+
return null;
|
|
49
|
+
for (const entry of fs.readdirSync(projectsDir, { withFileTypes: true })) {
|
|
50
|
+
if (!entry.isDirectory())
|
|
51
|
+
continue;
|
|
52
|
+
const candidate = path.join(projectsDir, entry.name, `${sessionId}.jsonl`);
|
|
53
|
+
if (fs.existsSync(candidate))
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
37
58
|
// list sessions for a given cwd with their first user message and last activity time
|
|
38
59
|
export async function getSessionListForCwd(cwdOverride) {
|
|
39
|
-
const cwd
|
|
40
|
-
const folderName = cwdToProjectFolder(cwd);
|
|
41
|
-
const projectDir = path.join(os.homedir(), '.claude', 'projects', folderName);
|
|
60
|
+
const { cwd, folderName, projectDir } = projectDirFor(cwdOverride);
|
|
42
61
|
log(`[session_list] cwd=${cwd}, folder=${folderName}, dir=${projectDir}`);
|
|
43
62
|
const sessions = [];
|
|
44
63
|
try {
|
|
@@ -53,9 +72,17 @@ export async function getSessionListForCwd(cwdOverride) {
|
|
|
53
72
|
let firstMessage = '';
|
|
54
73
|
let lastTimestamp = '';
|
|
55
74
|
let hasMessages = false;
|
|
75
|
+
let messageCount = 0;
|
|
76
|
+
let customTitle = '';
|
|
77
|
+
let aiTitle = '';
|
|
56
78
|
for (const line of lines) {
|
|
57
79
|
try {
|
|
58
80
|
const entry = JSON.parse(line);
|
|
81
|
+
// titles are rewritten as the session goes on; the last one wins
|
|
82
|
+
if (entry['type'] === 'custom-title' && typeof entry['customTitle'] === 'string')
|
|
83
|
+
customTitle = entry['customTitle'];
|
|
84
|
+
if (entry['type'] === 'ai-title' && typeof entry['aiTitle'] === 'string')
|
|
85
|
+
aiTitle = entry['aiTitle'];
|
|
59
86
|
if (entry['type'] !== 'user' && entry['type'] !== 'assistant')
|
|
60
87
|
continue;
|
|
61
88
|
const msgObj = entry['message'];
|
|
@@ -65,23 +92,26 @@ export async function getSessionListForCwd(cwdOverride) {
|
|
|
65
92
|
const ts = entry['timestamp'];
|
|
66
93
|
if (ts)
|
|
67
94
|
lastTimestamp = ts;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
text
|
|
74
|
-
|
|
75
|
-
.map((b) => b['text']).join('').slice(0, 200);
|
|
76
|
-
}
|
|
77
|
-
if (!/<local-command-/i.test(text))
|
|
78
|
-
firstMessage = text;
|
|
95
|
+
let text = '';
|
|
96
|
+
if (typeof msgObj['content'] === 'string')
|
|
97
|
+
text = msgObj['content'];
|
|
98
|
+
else if (Array.isArray(msgObj['content'])) {
|
|
99
|
+
text = msgObj['content']
|
|
100
|
+
.filter((b) => b['type'] === 'text' && b['text'])
|
|
101
|
+
.map((b) => b['text']).join('');
|
|
79
102
|
}
|
|
103
|
+
const isCommand = /<local-command-/i.test(text);
|
|
104
|
+
// tool results, subagent and meta lines are not chat bubbles
|
|
105
|
+
if (text.trim() && !isCommand && !entry['isMeta'] && !entry['isSidechain'])
|
|
106
|
+
messageCount++;
|
|
107
|
+
if (!firstMessage && msgObj['role'] === 'user' && !isCommand)
|
|
108
|
+
firstMessage = text.slice(0, 200);
|
|
80
109
|
}
|
|
81
110
|
catch { }
|
|
82
111
|
}
|
|
112
|
+
const title = customTitle || aiTitle;
|
|
83
113
|
if (hasMessages)
|
|
84
|
-
sessions.push({ sessionId, firstMessage, lastTimestamp });
|
|
114
|
+
sessions.push({ sessionId, firstMessage, lastTimestamp, messageCount, ...(title ? { title } : {}) });
|
|
85
115
|
}
|
|
86
116
|
catch { }
|
|
87
117
|
}
|
|
@@ -101,12 +131,15 @@ export async function deleteSessionFile(sessionId, cwdOverride) {
|
|
|
101
131
|
log(`[delete_session] file not found: ${sessionFile}`);
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
|
-
|
|
134
|
+
// claude's transcript folder for a project cwd (defaults to the cli's cwd)
|
|
135
|
+
function projectDirFor(cwdOverride) {
|
|
105
136
|
const cwd = cwdOverride && cwdOverride.length > 0 ? cwdOverride : process.cwd();
|
|
106
137
|
const folderName = cwdToProjectFolder(cwd);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
return { cwd, folderName, projectDir: path.join(os.homedir(), '.claude', 'projects', folderName) };
|
|
139
|
+
}
|
|
140
|
+
export function getSessionFileInfo(sessionId, cwdOverride) {
|
|
141
|
+
const info = projectDirFor(cwdOverride);
|
|
142
|
+
return { ...info, sessionFile: path.join(info.projectDir, `${sessionId}.jsonl`) };
|
|
110
143
|
}
|
|
111
144
|
export function readSessionJsonlLines(sessionId, cwdOverride) {
|
|
112
145
|
const { sessionFile } = getSessionFileInfo(sessionId, cwdOverride);
|
|
@@ -114,38 +147,25 @@ export function readSessionJsonlLines(sessionId, cwdOverride) {
|
|
|
114
147
|
return [];
|
|
115
148
|
return fs.readFileSync(sessionFile, 'utf-8').split('\n').filter((line) => line.trim().length > 0);
|
|
116
149
|
}
|
|
117
|
-
export function writeSessionJsonlLines(sessionId, lines, cwdOverride) {
|
|
118
|
-
const { projectDir, sessionFile } = getSessionFileInfo(sessionId, cwdOverride);
|
|
119
|
-
fs.mkdirSync(projectDir, { recursive: true });
|
|
120
|
-
const tempFile = `${sessionFile}.tmp`;
|
|
121
|
-
const nextContent = lines.length > 0 ? `${lines.join('\n')}\n` : '';
|
|
122
|
-
fs.writeFileSync(tempFile, nextContent, 'utf-8');
|
|
123
|
-
fs.renameSync(tempFile, sessionFile);
|
|
124
|
-
}
|
|
125
|
-
export function backupSessionFile(sessionId, cwdOverride) {
|
|
126
|
-
const { sessionFile } = getSessionFileInfo(sessionId, cwdOverride);
|
|
127
|
-
if (!fs.existsSync(sessionFile))
|
|
128
|
-
return null;
|
|
129
|
-
const backupFile = `${sessionFile}.rollback-${Date.now()}.bak`;
|
|
130
|
-
fs.copyFileSync(sessionFile, backupFile);
|
|
131
|
-
return backupFile;
|
|
132
|
-
}
|
|
133
150
|
// read a session jsonl file and materialize messages for the app
|
|
134
151
|
export function readSessionHistory(sessionId) {
|
|
135
|
-
const
|
|
136
|
-
if (!fs.existsSync(sessionFile))
|
|
137
|
-
return [];
|
|
138
|
-
const raw = fs.readFileSync(sessionFile, 'utf-8');
|
|
152
|
+
const lines = readSessionJsonlLines(sessionId);
|
|
139
153
|
const messages = [];
|
|
140
154
|
const seenUuids = new Set();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
const toolResults = new Map();
|
|
156
|
+
for (const line of lines) {
|
|
157
|
+
try {
|
|
158
|
+
rememberToolResults(JSON.parse(line), toolResults);
|
|
159
|
+
}
|
|
160
|
+
catch { }
|
|
161
|
+
}
|
|
162
|
+
for (const line of lines) {
|
|
144
163
|
try {
|
|
145
164
|
const parsed = parseTranscriptMessage(JSON.parse(line), {
|
|
146
165
|
sessionId,
|
|
147
166
|
seenUuids,
|
|
148
167
|
includeNoise: true,
|
|
168
|
+
toolResults,
|
|
149
169
|
});
|
|
150
170
|
if (parsed)
|
|
151
171
|
messages.push(parsed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionService.js","sourceRoot":"","sources":["../../src/services/sessionService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"sessionService.js","sourceRoot":"","sources":["../../src/services/sessionService.ts"],"names":[],"mappings":"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"}
|