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
|
@@ -2,34 +2,62 @@ import * as pty from 'node-pty';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { safeCwd } from '../utils/safePath.js';
|
|
5
|
+
// pty output is coalesced into one frame per window instead of one frame per chunk
|
|
6
|
+
const OUTPUT_FLUSH_MS = 30;
|
|
7
|
+
const RECENT_OUTPUT_CHARS = 256 * 1024;
|
|
8
|
+
const clamp = (value, min, max) => Math.min(Math.max(Math.trunc(value), min), max);
|
|
9
|
+
const clampSize = (cols, rows) => ({ cols: clamp(cols, 20, 300), rows: clamp(rows, 5, 100) });
|
|
5
10
|
// manages multiple user-facing shell sessions backed by node-pty
|
|
6
11
|
export class TerminalManager {
|
|
7
12
|
onData;
|
|
8
13
|
onExit;
|
|
9
14
|
terminals = new Map();
|
|
15
|
+
// output only streams while an app shows it; otherwise it just piles up in `recent`
|
|
16
|
+
live = true;
|
|
10
17
|
constructor(onData, onExit) {
|
|
11
18
|
this.onData = onData;
|
|
12
19
|
this.onExit = onExit;
|
|
13
20
|
}
|
|
14
|
-
create(cols
|
|
21
|
+
create(cols, rows, cwd) {
|
|
15
22
|
const id = randomUUID();
|
|
16
23
|
const shell = os.platform() === 'win32' ? 'cmd.exe' : process.env.SHELL || '/bin/bash';
|
|
17
|
-
const safeCols = Math.min(Math.max(Math.trunc(cols), 20), 300);
|
|
18
|
-
const safeRows = Math.min(Math.max(Math.trunc(rows), 5), 100);
|
|
19
24
|
const child = pty.spawn(shell, [], {
|
|
20
25
|
name: 'xterm-256color',
|
|
21
|
-
cols
|
|
26
|
+
...clampSize(cols, rows),
|
|
22
27
|
cwd: safeCwd(cwd),
|
|
23
28
|
env: process.env,
|
|
24
29
|
});
|
|
25
|
-
|
|
30
|
+
const session = { id, pty: child, pending: '', flushTimer: null, recent: [], recentChars: 0 };
|
|
31
|
+
child.onData((data) => {
|
|
32
|
+
this.remember(session, data);
|
|
33
|
+
if (!this.live)
|
|
34
|
+
return;
|
|
35
|
+
session.pending += data;
|
|
36
|
+
session.flushTimer ??= setTimeout(() => this.flush(session), OUTPUT_FLUSH_MS);
|
|
37
|
+
});
|
|
26
38
|
child.onExit(({ exitCode }) => {
|
|
39
|
+
this.flush(session);
|
|
27
40
|
this.terminals.delete(id);
|
|
28
41
|
this.onExit(id, exitCode);
|
|
29
42
|
});
|
|
30
|
-
this.terminals.set(id,
|
|
43
|
+
this.terminals.set(id, session);
|
|
31
44
|
return id;
|
|
32
45
|
}
|
|
46
|
+
setLive(live) {
|
|
47
|
+
this.live = live;
|
|
48
|
+
if (live)
|
|
49
|
+
return;
|
|
50
|
+
for (const session of this.terminals.values()) {
|
|
51
|
+
if (session.flushTimer)
|
|
52
|
+
clearTimeout(session.flushTimer);
|
|
53
|
+
session.flushTimer = null;
|
|
54
|
+
session.pending = '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
recentOutput(id) {
|
|
58
|
+
const session = this.terminals.get(id);
|
|
59
|
+
return session ? session.recent.join('').slice(-RECENT_OUTPUT_CHARS) : '';
|
|
60
|
+
}
|
|
33
61
|
write(id, data) {
|
|
34
62
|
const session = this.terminals.get(id);
|
|
35
63
|
if (!session)
|
|
@@ -42,11 +70,8 @@ export class TerminalManager {
|
|
|
42
70
|
if (!session)
|
|
43
71
|
return false;
|
|
44
72
|
try {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
session.pty.resize(safeCols, safeRows);
|
|
48
|
-
session.cols = safeCols;
|
|
49
|
-
session.rows = safeRows;
|
|
73
|
+
const size = clampSize(cols, rows);
|
|
74
|
+
session.pty.resize(size.cols, size.rows);
|
|
50
75
|
return true;
|
|
51
76
|
}
|
|
52
77
|
catch {
|
|
@@ -57,6 +82,8 @@ export class TerminalManager {
|
|
|
57
82
|
const session = this.terminals.get(id);
|
|
58
83
|
if (!session)
|
|
59
84
|
return false;
|
|
85
|
+
if (session.flushTimer)
|
|
86
|
+
clearTimeout(session.flushTimer);
|
|
60
87
|
try {
|
|
61
88
|
session.pty.kill();
|
|
62
89
|
}
|
|
@@ -67,5 +94,25 @@ export class TerminalManager {
|
|
|
67
94
|
list() {
|
|
68
95
|
return Array.from(this.terminals.keys());
|
|
69
96
|
}
|
|
97
|
+
// keep the chunks, dropping whole old ones once they hold twice what a replay needs
|
|
98
|
+
remember(session, data) {
|
|
99
|
+
session.recent.push(data);
|
|
100
|
+
session.recentChars += data.length;
|
|
101
|
+
if (session.recentChars <= 2 * RECENT_OUTPUT_CHARS)
|
|
102
|
+
return;
|
|
103
|
+
while (session.recentChars - session.recent[0].length >= RECENT_OUTPUT_CHARS) {
|
|
104
|
+
session.recentChars -= session.recent.shift().length;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
flush(session) {
|
|
108
|
+
if (session.flushTimer)
|
|
109
|
+
clearTimeout(session.flushTimer);
|
|
110
|
+
session.flushTimer = null;
|
|
111
|
+
if (!session.pending)
|
|
112
|
+
return;
|
|
113
|
+
const data = session.pending;
|
|
114
|
+
session.pending = '';
|
|
115
|
+
this.onData(session.id, data);
|
|
116
|
+
}
|
|
70
117
|
}
|
|
71
118
|
//# sourceMappingURL=terminalManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminalManager.js","sourceRoot":"","sources":["../../src/pty/terminalManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"terminalManager.js","sourceRoot":"","sources":["../../src/pty/terminalManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,22 @@ export async function ensureBackendReachableOrThrow() {
|
|
|
7
7
|
return;
|
|
8
8
|
throw new Error(`[kumo-cli] cannot reach backend at ${SERVER_HTTP()}. check KUMO_SERVER_URL and that the server is running.`);
|
|
9
9
|
}
|
|
10
|
+
const VERIFY_ATTEMPTS = 3;
|
|
11
|
+
// a passing backend hiccup gets a few tries; past that the cli stops with the token kept
|
|
12
|
+
async function verifyWithRetry(creds, delayMs = 2000) {
|
|
13
|
+
for (let attempt = 1;; attempt++) {
|
|
14
|
+
try {
|
|
15
|
+
return await verifyCredentials(creds);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (attempt >= VERIFY_ATTEMPTS) {
|
|
19
|
+
throw new Error(`[kumo-cli] could not check the saved device token (${error.message}). it is kept; try again in a moment.`);
|
|
20
|
+
}
|
|
21
|
+
console.warn(`[kumo-cli] backend not ready (${error.message}), retrying...`);
|
|
22
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs * attempt));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
10
26
|
// restore cached credentials when possible, otherwise fall back to a fresh pairing flow
|
|
11
27
|
export async function resolveActiveCredentials() {
|
|
12
28
|
await ensureBackendReachableOrThrow();
|
|
@@ -15,7 +31,7 @@ export async function resolveActiveCredentials() {
|
|
|
15
31
|
return pairFlow();
|
|
16
32
|
}
|
|
17
33
|
ensureDeviceUuid(activeCredentials.deviceUuid);
|
|
18
|
-
const verified = await
|
|
34
|
+
const verified = await verifyWithRetry(activeCredentials);
|
|
19
35
|
if (!verified) {
|
|
20
36
|
console.warn('[kumo-cli] cached device token was revoked or deleted, clearing credentials and re-pairing with the existing device identity...');
|
|
21
37
|
clearCredentials();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapService.js","sourceRoot":"","sources":["../../src/services/bootstrapService.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,kBAAkB,GAEnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEzF,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,6BAA6B;IACjD,IAAI,MAAM,qBAAqB,EAAE;QAAE,OAAO;IAC1C,MAAM,IAAI,KAAK,CAAC,sCAAsC,WAAW,EAAE,yDAAyD,CAAC,CAAC;AAChI,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,MAAM,6BAA6B,EAAE,CAAC;IAEtC,IAAI,iBAAiB,GAAG,eAAe,EAAE,CAAC;IAC1C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;IAED,gBAAgB,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"bootstrapService.js","sourceRoot":"","sources":["../../src/services/bootstrapService.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,kBAAkB,GAEnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEzF,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,6BAA6B;IACjD,IAAI,MAAM,qBAAqB,EAAE;QAAE,OAAO;IAC1C,MAAM,IAAI,KAAK,CAAC,sCAAsC,WAAW,EAAE,yDAAyD,CAAC,CAAC;AAChI,CAAC;AAED,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,yFAAyF;AACzF,KAAK,UAAU,eAAe,CAAC,KAAsB,EAAE,OAAO,GAAG,IAAI;IACnE,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,IAAI,eAAe,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,sDAAuD,KAAe,CAAC,OAAO,uCAAuC,CAAC,CAAC;YACzI,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,iCAAkC,KAAe,CAAC,OAAO,gBAAgB,CAAC,CAAC;YACxF,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;AACH,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,MAAM,6BAA6B,EAAE,CAAC;IAEtC,IAAI,iBAAiB,GAAG,eAAe,EAAE,CAAC;IAC1C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;IAED,gBAAgB,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,iIAAiI,CAAC,CAAC;QAChJ,gBAAgB,EAAE,CAAC;QACnB,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;IAED,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -1,24 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import Fastify from 'fastify';
|
|
3
3
|
import OpenAI from 'openai';
|
|
4
4
|
import { convertRequestToOpenAI, convertResponseToAnthropic, createErrorResponse, } from 'claude-adapter';
|
|
5
5
|
import { streamXmlOpenAIToAnthropic } from 'claude-adapter/dist/converters/xmlStreaming.js';
|
|
6
6
|
// local Anthropic-compatible proxy that forwards to OpenAI chat/completions upstream
|
|
7
|
-
// bypasses claude-adapter's strict validation to support all Claude Code message roles
|
|
7
|
+
// bypasses claude-adapter's strict validation to support all Claude Code message roles.
|
|
8
|
+
// it spends the provider key, so only a caller holding its random token (the claude it was
|
|
9
|
+
// started for) and naming it by its loopback host gets through
|
|
8
10
|
export class ClaudeAdapterProxy {
|
|
9
11
|
app = null;
|
|
10
12
|
key = null;
|
|
11
13
|
url = null;
|
|
14
|
+
secret = null;
|
|
15
|
+
// starts and stops run one at a time, so two spawns never leave a second server behind
|
|
16
|
+
queue = Promise.resolve();
|
|
17
|
+
// the bearer token claude must send (ANTHROPIC_AUTH_TOKEN)
|
|
18
|
+
get token() { return this.secret; }
|
|
12
19
|
// start or reuse a local proxy for OpenAI chat completions
|
|
13
|
-
|
|
20
|
+
start(config) {
|
|
21
|
+
return this.serial(() => this.startNow(config));
|
|
22
|
+
}
|
|
23
|
+
// stop the current adapter proxy if one is running
|
|
24
|
+
stop() {
|
|
25
|
+
return this.serial(() => this.stopNow());
|
|
26
|
+
}
|
|
27
|
+
serial(run) {
|
|
28
|
+
const next = this.queue.then(run);
|
|
29
|
+
this.queue = next.catch(() => undefined);
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
async startNow(config) {
|
|
14
33
|
const key = `${config.baseURL}|${config.apiKey}|${config.model}`;
|
|
15
34
|
if (this.app && this.key === key && this.url)
|
|
16
35
|
return this.url;
|
|
17
|
-
await this.
|
|
18
|
-
const port = await findAvailablePort();
|
|
36
|
+
await this.stopNow();
|
|
19
37
|
const upstreamBaseUrl = config.baseURL.replace(/\/chat\/completions\/?$/i, '');
|
|
20
38
|
const openai = new OpenAI({ baseURL: upstreamBaseUrl, apiKey: config.apiKey });
|
|
21
39
|
const app = Fastify({ logger: false });
|
|
40
|
+
const secret = randomBytes(24).toString('hex');
|
|
41
|
+
let port = 0;
|
|
42
|
+
app.addHook('onRequest', async (request, reply) => {
|
|
43
|
+
const host = request.headers.host ?? '';
|
|
44
|
+
const auth = request.headers.authorization ?? '';
|
|
45
|
+
const apiKey = request.headers['x-api-key'];
|
|
46
|
+
const allowedHost = host === `127.0.0.1:${port}` || host === `localhost:${port}`;
|
|
47
|
+
if (!allowedHost || (auth !== `Bearer ${secret}` && apiKey !== secret)) {
|
|
48
|
+
return reply.code(401).send({ type: 'error', error: { type: 'authentication_error', message: 'unauthorized' } });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
22
51
|
app.post('/v1/messages', async (request, reply) => {
|
|
23
52
|
try {
|
|
24
53
|
const body = request.body;
|
|
@@ -29,7 +58,8 @@ export class ClaudeAdapterProxy {
|
|
|
29
58
|
stripAdapterBranding(openaiRequest.messages);
|
|
30
59
|
if (isStreaming) {
|
|
31
60
|
const stream = await openai.chat.completions.create({ ...openaiRequest, stream: true });
|
|
32
|
-
|
|
61
|
+
const counted = reportPromptTokens(stream, reply.raw);
|
|
62
|
+
await streamXmlOpenAIToAnthropic(counted, reply, body.model, upstreamBaseUrl);
|
|
33
63
|
}
|
|
34
64
|
else {
|
|
35
65
|
const response = await openai.chat.completions.create({ ...openaiRequest, stream: false });
|
|
@@ -42,23 +72,52 @@ export class ClaudeAdapterProxy {
|
|
|
42
72
|
reply.code(errResp.status).send({ error: errResp.error });
|
|
43
73
|
}
|
|
44
74
|
});
|
|
45
|
-
|
|
75
|
+
// port 0: the os picks a free port at bind time, no check-then-bind race
|
|
76
|
+
await app.listen({ port: 0, host: '127.0.0.1' });
|
|
77
|
+
port = app.server.address().port;
|
|
46
78
|
this.app = app;
|
|
47
79
|
this.key = key;
|
|
80
|
+
this.secret = secret;
|
|
48
81
|
this.url = `http://127.0.0.1:${port}`;
|
|
49
82
|
return this.url;
|
|
50
83
|
}
|
|
51
|
-
|
|
52
|
-
async stop() {
|
|
84
|
+
async stopNow() {
|
|
53
85
|
if (!this.app)
|
|
54
86
|
return;
|
|
55
87
|
const app = this.app;
|
|
56
88
|
this.app = null;
|
|
57
89
|
this.key = null;
|
|
58
90
|
this.url = null;
|
|
91
|
+
this.secret = null;
|
|
59
92
|
await app.close().catch(() => undefined);
|
|
60
93
|
}
|
|
61
94
|
}
|
|
95
|
+
// the prompt's tokens only come with the stream's last chunk: claude-adapter has sent message_start
|
|
96
|
+
// with 0 by then, and its message_delta leaves them out. they go into that message_delta, so claude
|
|
97
|
+
// knows how big each turn was (and when to compact) instead of reading 0
|
|
98
|
+
function reportPromptTokens(stream, raw) {
|
|
99
|
+
let prompt;
|
|
100
|
+
let cached = 0;
|
|
101
|
+
const write = raw.write.bind(raw);
|
|
102
|
+
raw.write = ((chunk, ...rest) => {
|
|
103
|
+
if (prompt !== undefined && typeof chunk === 'string' && chunk.startsWith('data: ') && chunk.includes('"message_delta"')) {
|
|
104
|
+
const event = JSON.parse(chunk.slice('data: '.length));
|
|
105
|
+
// anthropic counts cache reads apart from the input, openai inside it
|
|
106
|
+
event.usage = { ...event.usage, input_tokens: Math.max(prompt - cached, 0), cache_read_input_tokens: cached };
|
|
107
|
+
chunk = `data: ${JSON.stringify(event)}\n\n`;
|
|
108
|
+
}
|
|
109
|
+
return write(chunk, ...rest);
|
|
110
|
+
});
|
|
111
|
+
return (async function* () {
|
|
112
|
+
for await (const chunk of stream) {
|
|
113
|
+
if (chunk?.usage) {
|
|
114
|
+
prompt = chunk.usage.prompt_tokens ?? 0;
|
|
115
|
+
cached = chunk.usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
116
|
+
}
|
|
117
|
+
yield chunk;
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
}
|
|
62
121
|
// replace Claude Code identifier before claude-adapter can inject its own branding
|
|
63
122
|
function normalizeSystemBranding(body) {
|
|
64
123
|
const CLAUDE_IDENTIFIER = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
@@ -89,16 +148,4 @@ function stripAdapterBranding(messages) {
|
|
|
89
148
|
}
|
|
90
149
|
}
|
|
91
150
|
}
|
|
92
|
-
// ask the OS for a currently free local TCP port
|
|
93
|
-
async function findAvailablePort() {
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
const server = net.createServer();
|
|
96
|
-
server.once('error', reject);
|
|
97
|
-
server.listen(0, '127.0.0.1', () => {
|
|
98
|
-
const address = server.address();
|
|
99
|
-
const port = typeof address === 'object' && address ? address.port : 0;
|
|
100
|
-
server.close(() => resolve(port));
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
151
|
//# sourceMappingURL=claudeAdapterProxy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeAdapterProxy.js","sourceRoot":"","sources":["../../src/services/claudeAdapterProxy.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"claudeAdapterProxy.js","sourceRoot":"","sources":["../../src/services/claudeAdapterProxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { buildClaudeArgs, buildClaudeEnv, filterPassthroughArgs } from '../engine/claudeArgs.js';
|
|
2
|
+
import { resolveClaudeCommand } from '../engine/claudeBinary.js';
|
|
3
|
+
import { isPermissionMode } from '../engine/permissions.js';
|
|
4
|
+
import { ALLOW_REMOTE_CONFIG_FLAG } from '../engine/remoteConfig.js';
|
|
3
5
|
import { loadSessionList } from './sessionListService.js';
|
|
4
|
-
//
|
|
5
|
-
export function
|
|
6
|
-
|
|
6
|
+
// derive session launch settings from `kumo claude <args>`; KUMO_PERMISSION_MODE overrides the default mode
|
|
7
|
+
export function resolveLaunchConfig(args, env = process.env) {
|
|
8
|
+
const parsed = filterPassthroughArgs(args.filter((arg) => arg !== ALLOW_REMOTE_CONFIG_FLAG));
|
|
9
|
+
const fromEnv = env['KUMO_PERMISSION_MODE'];
|
|
10
|
+
const permissionMode = isPermissionMode(fromEnv) ? fromEnv : parsed.permissionMode ?? 'default';
|
|
11
|
+
return {
|
|
12
|
+
passthrough: parsed.passthrough,
|
|
13
|
+
permissionMode,
|
|
14
|
+
allowBypass: parsed.allowBypass || permissionMode === 'bypassPermissions',
|
|
15
|
+
allowRemoteConfig: args.includes(ALLOW_REMOTE_CONFIG_FLAG),
|
|
16
|
+
};
|
|
7
17
|
}
|
|
8
|
-
//
|
|
9
|
-
export function
|
|
10
|
-
return (
|
|
11
|
-
params.
|
|
12
|
-
params.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
params.state.pendingPrompt = null;
|
|
29
|
-
params.dispatchPrompt(queuedPrompt);
|
|
18
|
+
// build the spawn spec of a session: per-session model (or device default), effort, binary and env
|
|
19
|
+
export function createSpawnSpecFactory(params) {
|
|
20
|
+
return async (request) => {
|
|
21
|
+
const model = request.model === undefined ? await params.model.fetchDefault(params.deviceToken()) : request.model;
|
|
22
|
+
const command = (params.resolveCommand ?? resolveClaudeCommand)();
|
|
23
|
+
return {
|
|
24
|
+
cmd: command.cmd,
|
|
25
|
+
shell: command.shell,
|
|
26
|
+
cwd: process.cwd(),
|
|
27
|
+
env: buildClaudeEnv(process.env, await params.model.buildEnv(model)),
|
|
28
|
+
args: buildClaudeArgs({
|
|
29
|
+
sessionId: request.sessionId,
|
|
30
|
+
resume: request.resume,
|
|
31
|
+
permissionMode: request.permissionMode,
|
|
32
|
+
allowBypass: request.allowBypass,
|
|
33
|
+
model: model?.model || undefined,
|
|
34
|
+
effort: params.effort.getCurrent() ?? undefined,
|
|
35
|
+
passthrough: params.passthrough,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
30
38
|
};
|
|
31
39
|
}
|
|
32
|
-
// create the ws onOpen hook that registers the cli,
|
|
40
|
+
// create the ws onOpen hook that registers the cli, reports status and refreshes sessions
|
|
33
41
|
export function createWsOpenHandler(params) {
|
|
34
42
|
return async () => {
|
|
35
43
|
const credentials = params.credentials();
|
|
@@ -37,12 +45,11 @@ export function createWsOpenHandler(params) {
|
|
|
37
45
|
type: 'register',
|
|
38
46
|
clientType: 'cli',
|
|
39
47
|
deviceToken: credentials?.deviceToken,
|
|
40
|
-
deviceUuid: credentials?.deviceUuid,
|
|
41
48
|
cwd: process.cwd(),
|
|
42
49
|
});
|
|
43
|
-
params.
|
|
44
|
-
params.
|
|
45
|
-
const sessions = await loadSessionList(undefined, params.
|
|
50
|
+
params.send({ type: 'cli_status', effort: params.effort() });
|
|
51
|
+
void params.refreshAuth();
|
|
52
|
+
const sessions = await loadSessionList(undefined, params.liveSessionIds());
|
|
46
53
|
params.send({ type: 'session_list', sessions });
|
|
47
54
|
};
|
|
48
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliRuntime.js","sourceRoot":"","sources":["../../src/services/cliRuntime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cliRuntime.js","sourceRoot":"","sources":["../../src/services/cliRuntime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,89 +1,42 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { kumoDir } from '../auth/credentialsStore.js';
|
|
4
5
|
import { log } from '../core/logger.js';
|
|
5
6
|
const VALID_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// read the whole settings.json as an object, returns empty object on failure
|
|
11
|
-
function readSettings() {
|
|
7
|
+
const settingsPath = () => path.join(kumoDir(), 'settings.json');
|
|
8
|
+
// older versions kept the effort in ~/settings.json
|
|
9
|
+
const legacySettingsPath = () => path.join(os.homedir(), 'settings.json');
|
|
10
|
+
function readSettings(file) {
|
|
12
11
|
try {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(raw);
|
|
12
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
15
13
|
}
|
|
16
14
|
catch {
|
|
17
15
|
return {};
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const raw = settings['effortLevel'];
|
|
23
|
-
if (typeof raw === 'string' && VALID_EFFORTS.includes(raw)) {
|
|
24
|
-
return raw;
|
|
25
|
-
}
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
// write settings back preserving existing keys
|
|
29
|
-
function writeSettings(data) {
|
|
30
|
-
const dir = path.dirname(settingsPath());
|
|
31
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
32
|
-
fs.writeFileSync(settingsPath(), JSON.stringify(data, null, 2), 'utf-8');
|
|
33
|
-
}
|
|
34
|
-
// strip any existing --effort / --effort=... flag pairs from args
|
|
35
|
-
export function removeEffortArgs(args) {
|
|
36
|
-
const result = [];
|
|
37
|
-
for (let i = 0; i < args.length; i++) {
|
|
38
|
-
const a = args[i];
|
|
39
|
-
if (a === '--effort') {
|
|
40
|
-
i++;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (a.startsWith('--effort='))
|
|
44
|
-
continue;
|
|
45
|
-
result.push(a);
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
// manages effort level stored in ~/settings.json and applied to claude args
|
|
18
|
+
const asEffort = (raw) => typeof raw === 'string' && VALID_EFFORTS.includes(raw) ? raw : null;
|
|
19
|
+
// device-wide effort level, persisted in the kumo state directory and passed to new claude processes
|
|
50
20
|
export class EffortService {
|
|
51
21
|
current = null;
|
|
52
22
|
getCurrent() { return this.current; }
|
|
53
23
|
getEffective() {
|
|
54
24
|
return this.current ?? 'medium';
|
|
55
25
|
}
|
|
56
|
-
// load effort from ~/settings.json
|
|
57
26
|
load() {
|
|
58
|
-
|
|
59
|
-
if (fromSettings) {
|
|
60
|
-
this.current = fromSettings;
|
|
61
|
-
}
|
|
27
|
+
this.current = asEffort(readSettings(settingsPath())['effortLevel']) ?? asEffort(readSettings(legacySettingsPath())['effortLevel']);
|
|
62
28
|
log(`[effort] loaded: ${this.current}`);
|
|
63
|
-
return this.current;
|
|
64
29
|
}
|
|
65
|
-
// persist effort to ~/settings.json and update current
|
|
66
30
|
save(level) {
|
|
67
31
|
if (!VALID_EFFORTS.includes(level))
|
|
68
32
|
return;
|
|
69
33
|
this.current = level;
|
|
70
|
-
const
|
|
34
|
+
const file = settingsPath();
|
|
35
|
+
const settings = readSettings(file);
|
|
71
36
|
settings['effortLevel'] = level;
|
|
72
|
-
|
|
37
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
38
|
+
fs.writeFileSync(file, JSON.stringify(settings, null, 2), 'utf-8');
|
|
73
39
|
log(`[effort] saved: ${level}`);
|
|
74
40
|
}
|
|
75
|
-
// apply effort flag to claude args, returns new args array
|
|
76
|
-
apply(args) {
|
|
77
|
-
const cleaned = removeEffortArgs(args);
|
|
78
|
-
if (this.current)
|
|
79
|
-
cleaned.push('--effort', this.current);
|
|
80
|
-
return cleaned;
|
|
81
|
-
}
|
|
82
|
-
// ensure effort is loaded before spawn, returns args with --effort flag
|
|
83
|
-
ensureBeforeSpawn(args) {
|
|
84
|
-
if (!this.current)
|
|
85
|
-
this.load();
|
|
86
|
-
return this.apply(args);
|
|
87
|
-
}
|
|
88
41
|
}
|
|
89
42
|
//# sourceMappingURL=effortService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effortService.js","sourceRoot":"","sources":["../../src/services/effortService.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;AAIxC,MAAM,aAAa,GAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAE/E
|
|
1
|
+
{"version":3,"file":"effortService.js","sourceRoot":"","sources":["../../src/services/effortService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAIxC,MAAM,aAAa,GAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAE/E,MAAM,YAAY,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AACzE,oDAAoD;AACpD,MAAM,kBAAkB,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAElF,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAA4B,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,GAAY,EAAsB,EAAE,CACpD,OAAO,GAAG,KAAK,QAAQ,IAAI,aAAa,CAAC,QAAQ,CAAC,GAAkB,CAAC,CAAC,CAAC,CAAE,GAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;AAEtG,qGAAqG;AACrG,MAAM,OAAO,aAAa;IAChB,OAAO,GAAuB,IAAI,CAAC;IAE3C,UAAU,KAAyB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzD,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;IAClC,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QACpI,GAAG,CAAC,oBAAoB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC,KAAkB;QACrB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO;QAC3C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACpC,QAAQ,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;QAChC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACnE,GAAG,CAAC,mBAAmB,KAAK,EAAE,CAAC,CAAC;IAClC,CAAC;CACF"}
|