kumo-cli 1.0.5 → 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.
Files changed (197) hide show
  1. package/README.md +131 -127
  2. package/dist/auth/credentialsStore.js +1 -1
  3. package/dist/auth/credentialsStore.js.map +1 -1
  4. package/dist/claude/transcriptParser.js +110 -11
  5. package/dist/claude/transcriptParser.js.map +1 -1
  6. package/dist/core/config.js +1 -4
  7. package/dist/core/config.js.map +1 -1
  8. package/dist/core/logger.js +6 -18
  9. package/dist/core/logger.js.map +1 -1
  10. package/dist/engine/claudeArgs.js +102 -0
  11. package/dist/engine/claudeArgs.js.map +1 -0
  12. package/dist/engine/claudeBinary.js +85 -0
  13. package/dist/engine/claudeBinary.js.map +1 -0
  14. package/dist/engine/claudeConfig.js +113 -0
  15. package/dist/engine/claudeConfig.js.map +1 -0
  16. package/dist/engine/controlChannel.js +63 -0
  17. package/dist/engine/controlChannel.js.map +1 -0
  18. package/dist/engine/liveTranscript.js +101 -0
  19. package/dist/engine/liveTranscript.js.map +1 -0
  20. package/dist/engine/ndjson.js +43 -0
  21. package/dist/engine/ndjson.js.map +1 -0
  22. package/dist/engine/permissions.js +98 -0
  23. package/dist/engine/permissions.js.map +1 -0
  24. package/dist/engine/sessionManager.js +429 -0
  25. package/dist/engine/sessionManager.js.map +1 -0
  26. package/dist/engine/settingsCommands.js +204 -0
  27. package/dist/engine/settingsCommands.js.map +1 -0
  28. package/dist/engine/streamSession.js +509 -0
  29. package/dist/engine/streamSession.js.map +1 -0
  30. package/dist/engine/taskTracker.js +110 -0
  31. package/dist/engine/taskTracker.js.map +1 -0
  32. package/dist/handlers/promptImages.js +8 -39
  33. package/dist/handlers/promptImages.js.map +1 -1
  34. package/dist/handlers/runtimeHandlers.js +195 -27
  35. package/dist/handlers/runtimeHandlers.js.map +1 -1
  36. package/dist/handlers/sessionHandlers.js +41 -70
  37. package/dist/handlers/sessionHandlers.js.map +1 -1
  38. package/dist/index.js +35 -40
  39. package/dist/index.js.map +1 -1
  40. package/dist/services/cliRuntime.js +37 -30
  41. package/dist/services/cliRuntime.js.map +1 -1
  42. package/dist/services/effortService.js +13 -60
  43. package/dist/services/effortService.js.map +1 -1
  44. package/dist/services/forkService.js +120 -0
  45. package/dist/services/forkService.js.map +1 -0
  46. package/dist/services/modelService.js +37 -84
  47. package/dist/services/modelService.js.map +1 -1
  48. package/dist/services/sessionListService.js +7 -9
  49. package/dist/services/sessionListService.js.map +1 -1
  50. package/dist/services/sessionService.js +77 -57
  51. package/dist/services/sessionService.js.map +1 -1
  52. package/dist/services/tunnelService.js +4 -5
  53. package/dist/services/tunnelService.js.map +1 -1
  54. package/dist/transport/wsClient.js +0 -4
  55. package/dist/transport/wsClient.js.map +1 -1
  56. package/dist/utils/ignorePaths.js +3 -3
  57. package/dist/utils/ignorePaths.js.map +1 -1
  58. package/package.json +62 -69
  59. package/dist/ansiCodes.js +0 -107
  60. package/dist/ansiCodes.js.map +0 -1
  61. package/dist/auth/credentialsStore.test.js +0 -60
  62. package/dist/auth/credentialsStore.test.js.map +0 -1
  63. package/dist/claude/fileHistory.js +0 -79
  64. package/dist/claude/fileHistory.js.map +0 -1
  65. package/dist/claude/generateHookSettings.js +0 -23
  66. package/dist/claude/generateHookSettings.js.map +0 -1
  67. package/dist/claude/hookServer.js +0 -33
  68. package/dist/claude/hookServer.js.map +0 -1
  69. package/dist/claude/sessionScanner.js +0 -162
  70. package/dist/claude/sessionScanner.js.map +0 -1
  71. package/dist/claude/sessionScanner.test.js +0 -24
  72. package/dist/claude/sessionScanner.test.js.map +0 -1
  73. package/dist/claude/transcriptParser.test.js +0 -78
  74. package/dist/claude/transcriptParser.test.js.map +0 -1
  75. package/dist/commands/cliArgs.test.js +0 -25
  76. package/dist/commands/cliArgs.test.js.map +0 -1
  77. package/dist/config.js +0 -40
  78. package/dist/config.js.map +0 -1
  79. package/dist/credentialsStore.js +0 -57
  80. package/dist/credentialsStore.js.map +0 -1
  81. package/dist/generateHookSettings.js +0 -30
  82. package/dist/generateHookSettings.js.map +0 -1
  83. package/dist/handlers/fileHandlerPayloads.test.js +0 -55
  84. package/dist/handlers/fileHandlerPayloads.test.js.map +0 -1
  85. package/dist/handlers/promptImages.test.js +0 -52
  86. package/dist/handlers/promptImages.test.js.map +0 -1
  87. package/dist/hookServer.js +0 -32
  88. package/dist/hookServer.js.map +0 -1
  89. package/dist/ignorePaths.js +0 -68
  90. package/dist/ignorePaths.js.map +0 -1
  91. package/dist/loadDotEnv.js +0 -79
  92. package/dist/loadDotEnv.js.map +0 -1
  93. package/dist/logger.js +0 -29
  94. package/dist/logger.js.map +0 -1
  95. package/dist/portForwardManager.js +0 -97
  96. package/dist/portForwardManager.js.map +0 -1
  97. package/dist/projectHistoryReader.js +0 -85
  98. package/dist/projectHistoryReader.js.map +0 -1
  99. package/dist/pty/ansiCodes.js +0 -14
  100. package/dist/pty/ansiCodes.js.map +0 -1
  101. package/dist/pty/notificationDetector.js +0 -29
  102. package/dist/pty/notificationDetector.js.map +0 -1
  103. package/dist/pty/notificationDetector.test.js +0 -24
  104. package/dist/pty/notificationDetector.test.js.map +0 -1
  105. package/dist/pty/ptyMenuParser.js +0 -91
  106. package/dist/pty/ptyMenuParser.js.map +0 -1
  107. package/dist/pty/ptyMenuParser.test.js +0 -26
  108. package/dist/pty/ptyMenuParser.test.js.map +0 -1
  109. package/dist/pty/ptySnapshotRenderer.js +0 -71
  110. package/dist/pty/ptySnapshotRenderer.js.map +0 -1
  111. package/dist/pty/selectionMenuDetector.js +0 -49
  112. package/dist/pty/selectionMenuDetector.js.map +0 -1
  113. package/dist/pty/selectionMenuDetector.test.js +0 -62
  114. package/dist/pty/selectionMenuDetector.test.js.map +0 -1
  115. package/dist/pty/selectionMenuMeta.js +0 -54
  116. package/dist/pty/selectionMenuMeta.js.map +0 -1
  117. package/dist/pty/selectionMenuMeta.test.js +0 -26
  118. package/dist/pty/selectionMenuMeta.test.js.map +0 -1
  119. package/dist/pty/selectionMenuParser.js +0 -83
  120. package/dist/pty/selectionMenuParser.js.map +0 -1
  121. package/dist/pty/selectionMenuParser.test.js +0 -30
  122. package/dist/pty/selectionMenuParser.test.js.map +0 -1
  123. package/dist/pty/spawn.js +0 -103
  124. package/dist/pty/spawn.js.map +0 -1
  125. package/dist/pty/spawn.test.js +0 -16
  126. package/dist/pty/spawn.test.js.map +0 -1
  127. package/dist/pty/statusSessionDetector.js +0 -28
  128. package/dist/pty/statusSessionDetector.js.map +0 -1
  129. package/dist/pty/statusSessionDetector.test.js +0 -23
  130. package/dist/pty/statusSessionDetector.test.js.map +0 -1
  131. package/dist/pty/textInputDetector.js +0 -60
  132. package/dist/pty/textInputDetector.js.map +0 -1
  133. package/dist/pty/textInputDetector.test.js +0 -32
  134. package/dist/pty/textInputDetector.test.js.map +0 -1
  135. package/dist/ptyMenuParser.js +0 -470
  136. package/dist/ptyMenuParser.js.map +0 -1
  137. package/dist/ptySnapshotRenderer.js +0 -78
  138. package/dist/ptySnapshotRenderer.js.map +0 -1
  139. package/dist/services/checkpointService.js +0 -113
  140. package/dist/services/checkpointService.js.map +0 -1
  141. package/dist/services/checkpointService.test.js +0 -61
  142. package/dist/services/checkpointService.test.js.map +0 -1
  143. package/dist/services/claudeMenuBridge.js +0 -116
  144. package/dist/services/claudeMenuBridge.js.map +0 -1
  145. package/dist/services/claudeMenuBridge.test.js +0 -90
  146. package/dist/services/claudeMenuBridge.test.js.map +0 -1
  147. package/dist/services/claudeService.js +0 -146
  148. package/dist/services/claudeService.js.map +0 -1
  149. package/dist/services/claudeService.test.js +0 -39
  150. package/dist/services/claudeService.test.js.map +0 -1
  151. package/dist/services/cliRuntime.test.js +0 -55
  152. package/dist/services/cliRuntime.test.js.map +0 -1
  153. package/dist/services/modelAdapter.test.js +0 -47
  154. package/dist/services/modelAdapter.test.js.map +0 -1
  155. package/dist/services/modelArgs.test.js +0 -64
  156. package/dist/services/modelArgs.test.js.map +0 -1
  157. package/dist/services/modelBaseUrl.test.js +0 -32
  158. package/dist/services/modelBaseUrl.test.js.map +0 -1
  159. package/dist/services/modelService.test.js +0 -136
  160. package/dist/services/modelService.test.js.map +0 -1
  161. package/dist/services/notificationDedupe.js +0 -23
  162. package/dist/services/notificationDedupe.js.map +0 -1
  163. package/dist/services/notificationDedupe.test.js +0 -20
  164. package/dist/services/notificationDedupe.test.js.map +0 -1
  165. package/dist/services/sessionListService.test.js +0 -22
  166. package/dist/services/sessionListService.test.js.map +0 -1
  167. package/dist/services/sessionRollbackService.js +0 -195
  168. package/dist/services/sessionRollbackService.js.map +0 -1
  169. package/dist/services/sessionRollbackService.test.js +0 -142
  170. package/dist/services/sessionRollbackService.test.js.map +0 -1
  171. package/dist/services/tunnelHelpers.test.js +0 -42
  172. package/dist/services/tunnelHelpers.test.js.map +0 -1
  173. package/dist/services/tunnelService.test.js +0 -91
  174. package/dist/services/tunnelService.test.js.map +0 -1
  175. package/dist/sessionScanner.js +0 -271
  176. package/dist/sessionScanner.js.map +0 -1
  177. package/dist/snapshotScanner.js +0 -154
  178. package/dist/snapshotScanner.js.map +0 -1
  179. package/dist/spawn.js +0 -79
  180. package/dist/spawn.js.map +0 -1
  181. package/dist/terminalManager.js +0 -73
  182. package/dist/terminalManager.js.map +0 -1
  183. package/dist/transport/directWsServer.js +0 -135
  184. package/dist/transport/directWsServer.js.map +0 -1
  185. package/dist/transport/webrtcTransport.js +0 -145
  186. package/dist/transport/webrtcTransport.js.map +0 -1
  187. package/dist/transport/webrtcTransport.test.js +0 -104
  188. package/dist/transport/webrtcTransport.test.js.map +0 -1
  189. package/dist/transport/webrtcTypes.js +0 -29
  190. package/dist/transport/webrtcTypes.js.map +0 -1
  191. package/dist/transport/webrtcTypes.test.js +0 -20
  192. package/dist/transport/webrtcTypes.test.js.map +0 -1
  193. package/dist/utils/ptyBuffer.js +0 -46
  194. package/dist/utils/ptyBuffer.js.map +0 -1
  195. package/scripts/claude_launcher.cjs +0 -71
  196. package/scripts/run-tests.mjs +0 -46
  197. package/scripts/session_hook_forwarder.cjs +0 -44
@@ -0,0 +1,429 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { log } from '../core/logger.js';
3
+ import { findSessionJsonl } from '../services/sessionService.js';
4
+ import { readAuthStatus } from './settingsCommands.js';
5
+ import { CONTROL_WHITELIST, LIVE_ONLY_CONTROLS, SESSION_SCOPED_CONTROLS, controlPayload, controlTimeoutMs, sanitizeControlResponse } from './claudeConfig.js';
6
+ import { NOT_LOGGED_IN_MESSAGE, StreamSession } from './streamSession.js';
7
+ export const MAX_LIVE_SESSIONS = 6;
8
+ // the user signs in on the phone's browser, give them time
9
+ const LOGIN_TIMEOUT_MS = 10 * 60_000;
10
+ // provider identity of a model selection; undefined (device default) is unknown until spawn
11
+ const providerKey = (model) => model === undefined ? null : `${model?.baseURL ?? ''}|${model?.apiKey ?? ''}`;
12
+ // owns every claude session of this cli: lazy spawn and the live-process cap
13
+ export class SessionManager {
14
+ options;
15
+ entries = new Map();
16
+ recentId = null;
17
+ config = null;
18
+ // the throwaway process running claude's oauth while the user signs in
19
+ login = null;
20
+ probing = null;
21
+ maxLive;
22
+ defaultPermissionMode;
23
+ allowBypass;
24
+ sessionExists;
25
+ constructor(options) {
26
+ this.options = options;
27
+ this.maxLive = options.maxLive ?? MAX_LIVE_SESSIONS;
28
+ this.defaultPermissionMode = options.defaultPermissionMode ?? 'default';
29
+ this.allowBypass = options.allowBypass ?? false;
30
+ this.sessionExists = options.sessionExists ?? ((sessionId) => findSessionJsonl(sessionId) !== null);
31
+ }
32
+ get recentSessionId() { return this.recentId; }
33
+ // register (or update) a session without spawning; returns true when its model changed
34
+ open(sessionId, opts = {}) {
35
+ this.recentId = sessionId;
36
+ let entry = this.entries.get(sessionId);
37
+ if (!entry) {
38
+ entry = {
39
+ sessionId,
40
+ model: opts.model,
41
+ permissionMode: opts.permissionMode ?? this.defaultPermissionMode,
42
+ session: null,
43
+ starting: null,
44
+ restartWhenIdle: false,
45
+ };
46
+ this.entries.set(sessionId, entry);
47
+ return false;
48
+ }
49
+ if (opts.permissionMode)
50
+ entry.permissionMode = opts.permissionMode;
51
+ if (!('model' in opts) || JSON.stringify(opts.model) === JSON.stringify(entry.model))
52
+ return false;
53
+ entry.model = opts.model;
54
+ return true;
55
+ }
56
+ has(sessionId) { return this.entries.has(sessionId); }
57
+ isRunning(sessionId) {
58
+ return this.entries.get(sessionId)?.session?.alive === true;
59
+ }
60
+ liveSessionIds() {
61
+ return this.liveEntries().map((e) => e.sessionId);
62
+ }
63
+ // spawn the session process when it is not live yet
64
+ async ensureRunning(sessionId) {
65
+ const entry = this.entryFor(sessionId);
66
+ if (entry.session?.alive)
67
+ return entry.session;
68
+ if (!entry.starting)
69
+ entry.starting = this.spawn(entry).finally(() => { entry.starting = null; });
70
+ return entry.starting;
71
+ }
72
+ async sendPrompt(sessionId, text, images = [], uuid) {
73
+ const entry = this.entryFor(sessionId);
74
+ this.recentId = sessionId;
75
+ entry.title ??= text.trim().slice(0, 80) || undefined;
76
+ const session = await this.ensureRunning(sessionId);
77
+ if (!session.sendPrompt(text, images, uuid))
78
+ throw new Error('claude process exited before the prompt was sent');
79
+ }
80
+ async interrupt(sessionId) {
81
+ const session = this.entries.get(sessionId)?.session;
82
+ if (session?.alive)
83
+ await session.interrupt();
84
+ }
85
+ // route a permission answer; a missing session id falls back to searching every live session
86
+ respondPermission(sessionId, requestId, decision) {
87
+ const candidates = sessionId ? [this.entries.get(sessionId)] : [...this.entries.values()];
88
+ return candidates.some((entry) => entry?.session?.respondPermission(requestId, decision) === true);
89
+ }
90
+ async setMode(sessionId, mode) {
91
+ const entry = this.entryFor(sessionId);
92
+ // a live session reports the new mode itself and syncs it back to the entry on exit
93
+ const session = entry.session;
94
+ if (session?.alive) {
95
+ try {
96
+ await session.setPermissionMode(mode);
97
+ }
98
+ catch (error) {
99
+ // e.g. auto mode gated off for this account: put the app back on the real mode
100
+ this.options.emit({ type: 'claude_status', sessionId, permissionMode: session.permissionMode });
101
+ throw error;
102
+ }
103
+ return;
104
+ }
105
+ entry.permissionMode = mode;
106
+ this.options.emit({ type: 'claude_status', sessionId, permissionMode: mode });
107
+ }
108
+ // restart a live session with --resume so new spawn settings apply; deferred while a turn runs
109
+ async restart(sessionId) {
110
+ const entry = this.entries.get(sessionId);
111
+ if (!entry?.session?.alive)
112
+ return;
113
+ if (entry.session.state !== 'idle') {
114
+ entry.restartWhenIdle = true;
115
+ return;
116
+ }
117
+ entry.restartWhenIdle = false;
118
+ await entry.session.close('restart');
119
+ await this.ensureRunning(sessionId);
120
+ }
121
+ // apply a changed model to a live session: in place when the provider is unchanged, else resume in a new process
122
+ async applyModel(sessionId) {
123
+ const entry = this.entries.get(sessionId);
124
+ const session = entry?.session;
125
+ if (!entry || !session?.alive)
126
+ return;
127
+ const key = providerKey(entry.model);
128
+ if (key !== null && key === providerKey(entry.spawnedModel)) {
129
+ try {
130
+ await session.setModel(entry.model?.model || null);
131
+ entry.spawnedModel = entry.model;
132
+ return;
133
+ }
134
+ catch (error) {
135
+ log(`[engine] set_model failed, restarting: ${error.message}`);
136
+ }
137
+ }
138
+ await this.restart(sessionId);
139
+ }
140
+ // effort is device-wide: live sessions switch in place, new spawns get --effort
141
+ async applyEffort(effort) {
142
+ await Promise.all(this.liveEntries().map(async (entry) => {
143
+ try {
144
+ await entry.session.controlRequest({ subtype: 'apply_flag_settings', settings: { effortLevel: effort } });
145
+ }
146
+ catch (error) {
147
+ log(`[engine] effort switch failed, restarting: ${error.message}`);
148
+ await this.restart(entry.sessionId);
149
+ }
150
+ }));
151
+ }
152
+ async setFast(sessionId, enabled) {
153
+ const entry = this.entryFor(sessionId);
154
+ entry.fast = enabled;
155
+ if (entry.session?.alive)
156
+ await entry.session.setFast(enabled);
157
+ this.options.emit({ type: 'claude_status', sessionId, fast: enabled });
158
+ }
159
+ async setThinking(sessionId, enabled) {
160
+ const entry = this.entryFor(sessionId);
161
+ entry.thinking = enabled;
162
+ if (entry.session?.alive)
163
+ await entry.session.setThinking(enabled);
164
+ this.options.emit({ type: 'claude_status', sessionId, thinking: enabled });
165
+ }
166
+ // run a whitelisted read-only control request; account-wide ones fall back to any live process or a probe
167
+ async control(sessionId, subtype, payload) {
168
+ if (!CONTROL_WHITELIST.has(subtype))
169
+ throw new Error(`control request ${subtype} is not allowed`);
170
+ const request = { subtype, ...controlPayload(subtype, payload) };
171
+ const timeoutMs = controlTimeoutMs(subtype);
172
+ const target = sessionId ? this.entries.get(sessionId)?.session : undefined;
173
+ let session = target?.alive ? target : undefined;
174
+ const liveOnly = LIVE_ONLY_CONTROLS.get(subtype);
175
+ if (!session && liveOnly)
176
+ throw new Error(liveOnly);
177
+ if (!session && SESSION_SCOPED_CONTROLS.has(subtype)) {
178
+ // a saved session is resumed (no message is sent); an unsaved one has nothing to read yet
179
+ if (!sessionId || !this.sessionExists(sessionId))
180
+ throw new Error('Session is not running');
181
+ session = await this.ensureRunning(sessionId);
182
+ }
183
+ session ??= this.liveEntries()[0]?.session ?? undefined;
184
+ const response = session
185
+ ? await session.controlRequest(request, timeoutMs)
186
+ : await this.withProbe((probe) => probe.controlRequest(request, timeoutMs));
187
+ return sanitizeControlResponse(subtype, response);
188
+ }
189
+ // ask claude whether it is signed in and tell the app (claude_auth) and the backend (cli_status)
190
+ async refreshAuth() {
191
+ const read = this.options.authStatus ?? (() => readAuthStatus(process.cwd()));
192
+ const status = await read().catch(() => null);
193
+ if (!status)
194
+ return null;
195
+ this.options.emit({ type: 'cli_status', loggedIn: status.loggedIn });
196
+ this.options.emit({ type: 'claude_auth', ...status });
197
+ return status;
198
+ }
199
+ // sign claude in with its own oauth over the control channel of a throwaway process, as the
200
+ // extension does: the link comes back to open on the phone, the code that page shows goes to
201
+ // submitLoginCode, and once claude says it is done the account and models refresh
202
+ async startLogin(useConsole = false) {
203
+ await this.cancelLogin();
204
+ const sessionId = randomUUID();
205
+ const session = new StreamSession({ sessionId, permissionMode: 'default', emit: () => undefined, closeGraceMs: this.options.closeGraceMs });
206
+ session.start(await this.options.spawnSpec({ sessionId, resume: false, permissionMode: 'default', allowBypass: false, model: null }));
207
+ this.login = session;
208
+ try {
209
+ const response = await session.controlRequest({ subtype: 'claude_authenticate', loginWithClaudeAi: !useConsole });
210
+ const url = typeof response['manualUrl'] === 'string' ? response['manualUrl'] : '';
211
+ if (!url)
212
+ throw new Error('Claude did not return a sign-in link');
213
+ session.controlRequest({ subtype: 'claude_oauth_wait_for_completion' }, LOGIN_TIMEOUT_MS)
214
+ .then(() => this.finishLogin(session, null), (error) => this.finishLogin(session, error));
215
+ return url;
216
+ }
217
+ catch (error) {
218
+ await this.cancelLogin();
219
+ throw error;
220
+ }
221
+ }
222
+ // the code the sign-in page shows, `code#state`
223
+ async submitLoginCode(code) {
224
+ const session = this.login;
225
+ if (!session?.alive)
226
+ throw new Error('No sign-in is in progress, start it again');
227
+ const value = code.trim();
228
+ const hash = value.indexOf('#');
229
+ try {
230
+ await session.controlRequest({
231
+ subtype: 'claude_oauth_callback',
232
+ authorizationCode: hash < 0 ? value : value.slice(0, hash),
233
+ state: hash < 0 ? '' : value.slice(hash + 1),
234
+ }, 60_000);
235
+ }
236
+ catch (error) {
237
+ // the token endpoint answers a bad or stale code with a bare 4xx
238
+ if (/status code 4\d\d/.test(error.message))
239
+ throw new Error('That code did not work, copy it again from the sign-in page');
240
+ throw error;
241
+ }
242
+ }
243
+ async cancelLogin() {
244
+ const session = this.login;
245
+ this.login = null;
246
+ await session?.close('login_cancelled');
247
+ }
248
+ async finishLogin(session, error) {
249
+ if (this.login !== session)
250
+ return;
251
+ this.login = null;
252
+ await session.close('login_done');
253
+ this.options.emit({ type: 'claude_login_result', ok: !error, ...(error ? { error: error.message } : {}) });
254
+ await this.refreshAuth();
255
+ if (error)
256
+ return;
257
+ // the new account may see other models
258
+ this.config = null;
259
+ this.sendConfig();
260
+ }
261
+ // a request failed authentication: only a signed-out claude means "not logged in", a custom
262
+ // provider rejecting its key does not
263
+ async handleAuthFailure(sessionId) {
264
+ const status = await this.refreshAuth();
265
+ if (status?.loggedIn !== false)
266
+ return;
267
+ this.options.emit({ type: 'notification', sessionId, level: 'error', message: NOT_LOGGED_IN_MESSAGE });
268
+ }
269
+ // emit the cached claude_config, probing a throwaway process when no session has initialized yet
270
+ sendConfig() {
271
+ if (this.config) {
272
+ this.options.emit({ type: 'claude_config', ...this.config });
273
+ return;
274
+ }
275
+ this.probing ??= this.withProbe(async () => undefined)
276
+ .catch((error) => log(`[engine] config probe failed: ${error.message}`))
277
+ .finally(() => { this.probing = null; });
278
+ }
279
+ // stop the process; forget drops the session registration entirely
280
+ async close(sessionId, opts = {}) {
281
+ const entry = this.entries.get(sessionId);
282
+ if (!entry)
283
+ return;
284
+ if (entry.starting)
285
+ await entry.starting.catch(() => undefined);
286
+ await entry.session?.close(opts.reason ?? 'closed');
287
+ if (opts.forget) {
288
+ this.entries.delete(sessionId);
289
+ if (this.recentId === sessionId)
290
+ this.recentId = null;
291
+ }
292
+ }
293
+ async closeAll() {
294
+ await Promise.all([...this.entries.keys()].map((sessionId) => this.close(sessionId)));
295
+ }
296
+ // emit the current turn state and pending permissions of a live session (re-attach)
297
+ replay(sessionId) {
298
+ const session = this.entries.get(sessionId)?.session;
299
+ if (!session?.alive)
300
+ return;
301
+ this.options.emit({ type: 'claude_turn', sessionId, state: session.state, ...(session.label ? { label: session.label } : {}) });
302
+ for (const request of session.pendingRequests)
303
+ this.options.emit({ ...request });
304
+ }
305
+ snapshot() {
306
+ const sessions = [];
307
+ for (const entry of this.entries.values()) {
308
+ const session = entry.session;
309
+ if (!session?.alive)
310
+ continue;
311
+ sessions.push({
312
+ sessionId: entry.sessionId,
313
+ state: session.state,
314
+ label: session.label,
315
+ permissionMode: session.permissionMode,
316
+ model: session.model || entry.model?.model || undefined,
317
+ thinking: entry.thinking,
318
+ fast: entry.fast,
319
+ fastMode: session.fastMode,
320
+ title: entry.title,
321
+ pending: session.pendingRequests,
322
+ queued: session.queuedPrompts,
323
+ tasks: session.taskList,
324
+ });
325
+ }
326
+ return { sessions };
327
+ }
328
+ // the session's entry, registering it first when it is unknown
329
+ entryFor(sessionId) {
330
+ if (!this.entries.has(sessionId))
331
+ this.open(sessionId);
332
+ return this.entries.get(sessionId);
333
+ }
334
+ liveEntries() {
335
+ return [...this.entries.values()].filter((e) => e.session?.alive);
336
+ }
337
+ updateConfig(patch) {
338
+ this.config = { ...this.config, ...patch };
339
+ this.options.emit({ type: 'claude_config', ...this.config });
340
+ }
341
+ // spawn a silent session (no transcript, no app events) just to run initialize-time requests
342
+ async withProbe(fn) {
343
+ const sessionId = randomUUID();
344
+ const spec = await this.options.spawnSpec({
345
+ sessionId,
346
+ resume: false,
347
+ permissionMode: this.defaultPermissionMode,
348
+ allowBypass: this.allowBypass,
349
+ model: undefined,
350
+ });
351
+ const probe = new StreamSession({
352
+ sessionId,
353
+ permissionMode: this.defaultPermissionMode,
354
+ emit: () => { },
355
+ onConfig: (patch) => this.updateConfig(patch),
356
+ // a probe never sends a prompt; stay quiet instead of flagging the login
357
+ onAuthFailure: () => undefined,
358
+ closeGraceMs: this.options.closeGraceMs,
359
+ });
360
+ probe.start(spec);
361
+ try {
362
+ await probe.ready;
363
+ return await fn(probe);
364
+ }
365
+ finally {
366
+ await probe.close('probe');
367
+ }
368
+ }
369
+ liveCount(exceptId) {
370
+ return [...this.entries.values()].filter((e) => e.sessionId !== exceptId && (e.session?.alive || e.starting)).length;
371
+ }
372
+ // close the idle live session with the oldest activity until there is room for one more
373
+ async evictIfNeeded(sessionId) {
374
+ while (this.liveCount(sessionId) >= this.maxLive) {
375
+ const victim = [...this.entries.values()]
376
+ .filter((e) => e.sessionId !== sessionId && e.session?.alive && !e.starting && e.session.state === 'idle' && e.session.pendingRequests.length === 0)
377
+ .sort((a, b) => a.session.lastActivity - b.session.lastActivity)[0];
378
+ if (!victim) {
379
+ log(`[engine] live session cap ${this.maxLive} reached with no idle session to evict`);
380
+ return;
381
+ }
382
+ log(`[engine] evicting idle session ${victim.sessionId}`);
383
+ await this.close(victim.sessionId, { reason: 'evicted' });
384
+ }
385
+ }
386
+ async spawn(entry) {
387
+ await this.evictIfNeeded(entry.sessionId);
388
+ const resume = this.sessionExists(entry.sessionId);
389
+ const spec = await this.options.spawnSpec({
390
+ sessionId: entry.sessionId,
391
+ resume,
392
+ permissionMode: entry.permissionMode,
393
+ allowBypass: this.allowBypass,
394
+ model: entry.model,
395
+ });
396
+ const session = new StreamSession({
397
+ sessionId: entry.sessionId,
398
+ permissionMode: entry.permissionMode,
399
+ allowBypass: this.allowBypass,
400
+ emit: this.options.emit,
401
+ console: this.options.console,
402
+ closeGraceMs: this.options.closeGraceMs,
403
+ onStateChange: (state) => {
404
+ if (state !== 'idle' || !entry.restartWhenIdle || entry.session !== session)
405
+ return;
406
+ this.restart(entry.sessionId).catch((error) => log(`[engine] restart failed: ${error}`));
407
+ },
408
+ onConfig: (patch) => this.updateConfig(patch),
409
+ onAuthFailure: () => { void this.handleAuthFailure(entry.sessionId); },
410
+ startupControls: () => [
411
+ ...(entry.thinking === false ? [{ subtype: 'set_max_thinking_tokens', max_thinking_tokens: 0 }] : []),
412
+ ...(entry.fast ? [{ subtype: 'apply_flag_settings', settings: { fastMode: true } }] : []),
413
+ ],
414
+ onExit: () => this.handleExit(entry, session),
415
+ });
416
+ entry.session = session;
417
+ entry.spawnedModel = entry.model;
418
+ this.options.console?.(`[${entry.sessionId.slice(0, 4)}] ● ${resume ? 'resume' : 'new'} session ${entry.sessionId}`);
419
+ session.start(spec);
420
+ return session;
421
+ }
422
+ handleExit(entry, session) {
423
+ if (entry.session !== session)
424
+ return;
425
+ entry.permissionMode = session.permissionMode;
426
+ entry.session = null;
427
+ }
428
+ }
429
+ //# sourceMappingURL=sessionManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionManager.js","sourceRoot":"","sources":["../../src/engine/sessionManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,204 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { buildClaudeEnv } from './claudeArgs.js';
3
+ import { buildShellCommandLine, resolveClaudeCommand } from './claudeBinary.js';
4
+ import { stripAnsi } from './permissions.js';
5
+ const SUBCOMMAND_TIMEOUT_MS = 30_000;
6
+ const BEHAVIORS = new Set(['allow', 'deny', 'ask']);
7
+ const DESTINATIONS = new Set(['userSettings', 'projectSettings', 'localSettings']);
8
+ // run `claude <args>`, optionally with one json document on stdin, like the vs code extension
9
+ function runClaude(args, input, cwd, timeout = SUBCOMMAND_TIMEOUT_MS) {
10
+ const { cmd, shell } = resolveClaudeCommand();
11
+ const options = { cwd, env: buildClaudeEnv(process.env), encoding: 'utf-8', timeout, windowsHide: true, maxBuffer: 32 << 20 };
12
+ return new Promise((resolve) => {
13
+ const callback = (error, stdout, stderr) => {
14
+ resolve({ code: error ? (typeof error.code === 'number' ? error.code : null) : 0, stdout, stderr });
15
+ };
16
+ const child = shell
17
+ ? execFile(buildShellCommandLine(cmd, args), { ...options, shell: true }, callback)
18
+ : execFile(cmd, args, options, callback);
19
+ child.stdin?.on('error', () => { });
20
+ child.stdin?.end(input ? JSON.stringify(input) : undefined);
21
+ });
22
+ }
23
+ // `claude auth status --json`; null when claude could not be asked
24
+ export async function readAuthStatus(cwd) {
25
+ const result = await runClaude(['auth', 'status', '--json'], null, cwd);
26
+ try {
27
+ const status = JSON.parse(result.stdout);
28
+ if (typeof status['loggedIn'] !== 'boolean')
29
+ return null;
30
+ const text = (key) => (typeof status[key] === 'string' ? { [key]: status[key] } : {});
31
+ return { loggedIn: status['loggedIn'], ...text('email'), ...text('authMethod'), ...text('subscriptionType') };
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ // validate an app permission-rule edit into the shape `claude edit-permission-rules` reads
38
+ export function toPermissionRuleEdit(msg) {
39
+ const behavior = msg['behavior'];
40
+ if (typeof behavior !== 'string' || !BEHAVIORS.has(behavior))
41
+ return null;
42
+ const rule = typeof msg['rule'] === 'string' ? msg['rule'].trim() : '';
43
+ if (!rule || rule.length > 10_000)
44
+ return null;
45
+ if (msg['op'] === 'add') {
46
+ const destination = msg['destination'] ?? 'localSettings';
47
+ return typeof destination === 'string' && DESTINATIONS.has(destination) ? { op: 'add', rules: [rule], behavior, destination } : null;
48
+ }
49
+ if (msg['op'] === 'remove') {
50
+ const source = msg['source'];
51
+ return typeof source === 'string' && DESTINATIONS.has(source) ? { op: 'remove', rule, behavior, source } : null;
52
+ }
53
+ return null;
54
+ }
55
+ export async function editPermissionRules(edit, cwd) {
56
+ const result = await runClaude(['edit-permission-rules', '--json'], edit, cwd);
57
+ if (result.code === 0)
58
+ return;
59
+ const reason = stripAnsi(result.stderr).trim().replace(/^Error:\s*/, '');
60
+ throw new Error(reason || `claude could not save the permission rule (${result.code === null ? 'timed out' : `exit code ${result.code}`})`);
61
+ }
62
+ const SOURCES = DESTINATIONS;
63
+ const str = (value, max = 10_000) => typeof value === 'string' && value.trim() && value.length <= max ? value : null;
64
+ const obj = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : null;
65
+ // the edits the app may make through `claude edit-*`, validated into the shape each one reads
66
+ const SETTING_EDITS = {
67
+ hook: {
68
+ subcommand: 'edit-hook',
69
+ validate: (edit) => {
70
+ const op = edit['op'];
71
+ const source = edit['source'];
72
+ const event = str(edit['event'], 100);
73
+ if ((op !== 'add' && op !== 'replace' && op !== 'remove') || typeof source !== 'string' || !SOURCES.has(source) || !event)
74
+ return null;
75
+ const out = { op, source, event };
76
+ if (typeof edit['matcher'] === 'string')
77
+ out['matcher'] = edit['matcher'];
78
+ if (obj(edit['hook']))
79
+ out['hook'] = edit['hook'];
80
+ if (obj(edit['target']))
81
+ out['target'] = edit['target'];
82
+ if (op !== 'remove' && !out['hook'])
83
+ return null;
84
+ return JSON.stringify(out).length <= 500_000 ? out : null;
85
+ },
86
+ },
87
+ sandbox: {
88
+ subcommand: 'edit-sandbox-settings',
89
+ validate: (edit) => {
90
+ const out = {};
91
+ if (edit['mode'] === 'auto-allow' || edit['mode'] === 'regular' || edit['mode'] === 'disabled')
92
+ out['mode'] = edit['mode'];
93
+ if (typeof edit['allowUnsandboxedCommands'] === 'boolean')
94
+ out['allowUnsandboxedCommands'] = edit['allowUnsandboxedCommands'];
95
+ const command = str(edit['excludeCommand'], 1000);
96
+ if (command)
97
+ out['excludeCommand'] = command;
98
+ return Object.keys(out).length > 0 ? out : null;
99
+ },
100
+ },
101
+ skill: {
102
+ subcommand: 'edit-skill-overrides',
103
+ validate: (edit) => {
104
+ const name = str(edit['name'], 300);
105
+ const state = edit['state'];
106
+ if (!name || (state !== 'on' && state !== 'name-only' && state !== 'user-invocable-only' && state !== 'off'))
107
+ return null;
108
+ return { name, state, ...(obj(edit['handles']) ? { handles: edit['handles'] } : {}) };
109
+ },
110
+ },
111
+ memory: {
112
+ subcommand: 'edit-memory-settings',
113
+ validate: (edit) => {
114
+ const out = {};
115
+ for (const key of ['autoMemoryEnabled', 'autoDreamEnabled'])
116
+ if (typeof edit[key] === 'boolean')
117
+ out[key] = edit[key];
118
+ return Object.keys(out).length > 0 ? out : null;
119
+ },
120
+ },
121
+ };
122
+ // the last json line a `claude edit-*` / `claude plugin` command printed
123
+ function lastJson(stdout) {
124
+ const lines = stdout.trim().split(/\r?\n/).reverse();
125
+ for (const line of lines) {
126
+ try {
127
+ return JSON.parse(line);
128
+ }
129
+ catch { }
130
+ }
131
+ return null;
132
+ }
133
+ function failure(result, what) {
134
+ const reason = stripAnsi(result.stderr).trim().replace(/^Error:\s*/, '');
135
+ return new Error(reason || `claude could not ${what} (${result.code === null ? 'timed out' : `exit code ${result.code}`})`);
136
+ }
137
+ // one hook, sandbox, skill or memory change, run like the extension does
138
+ export async function editSetting(kind, edit, cwd) {
139
+ const spec = SETTING_EDITS[kind];
140
+ const input = spec && obj(edit) ? spec.validate(edit) : null;
141
+ if (!spec || !input)
142
+ throw new Error(`invalid ${kind} change`);
143
+ const result = await runClaude([spec.subcommand, '--json'], input, cwd);
144
+ const reply = lastJson(result.stdout);
145
+ if (reply && reply['ok'] === false)
146
+ throw new Error(typeof reply['error'] === 'string' ? reply['error'] : `claude refused the ${kind} change`);
147
+ if (result.code !== 0)
148
+ throw failure(result, `save the ${kind} change`);
149
+ return reply ?? {};
150
+ }
151
+ const PLUGIN_ID = /^\w[\w.@:/+-]{0,199}$/;
152
+ const PLUGIN_SCOPES = new Set(['user', 'project', 'local']);
153
+ const PLUGIN_TIMEOUT_MS = 180_000;
154
+ const AVAILABLE_LIMIT = 50;
155
+ // installed plugins, and the most installed available ones matching the query, without the mcp
156
+ // configs (env, headers, tokens) they carry
157
+ export function toPluginList(raw, query = '') {
158
+ const source = Array.isArray(raw) ? { installed: raw, available: [] } : (obj(raw) ?? {});
159
+ const pick = (item, keys) => Object.fromEntries(keys.filter((k) => obj(item)?.[k] !== undefined).map((k) => [k, obj(item)[k]]));
160
+ const items = (value) => (Array.isArray(value) ? value.filter(obj) : []);
161
+ const installed = items(source['installed']).map((p) => pick(p, ['id', 'version', 'scope', 'enabled', 'projectEnabled', 'errors']));
162
+ const ids = new Set(installed.map((p) => p['id']));
163
+ const needle = query.trim().toLowerCase();
164
+ const matches = items(source['available']).filter((p) => !ids.has(p['pluginId'])
165
+ && (!needle || [p['name'], p['description']].some((v) => typeof v === 'string' && v.toLowerCase().includes(needle))));
166
+ const count = (p) => (typeof p['installCount'] === 'number' ? p['installCount'] : 0);
167
+ return {
168
+ installed,
169
+ available: matches.sort((a, b) => count(b) - count(a)).slice(0, AVAILABLE_LIMIT)
170
+ .map((p) => pick(p, ['pluginId', 'name', 'description', 'marketplaceName', 'version', 'installCount'])),
171
+ availableTotal: matches.length,
172
+ };
173
+ }
174
+ // `claude plugin …` for the app: list, or change one plugin
175
+ export async function pluginCommand(op, id, scope, cwd, query = '') {
176
+ if (op === 'list') {
177
+ const result = await runClaude(['plugin', 'list', '--json', '--available'], null, cwd, PLUGIN_TIMEOUT_MS);
178
+ if (result.code !== 0)
179
+ throw failure(result, 'list plugins');
180
+ let parsed = null;
181
+ try {
182
+ parsed = JSON.parse(result.stdout);
183
+ }
184
+ catch { }
185
+ return toPluginList(parsed, typeof query === 'string' ? query.slice(0, 200) : '');
186
+ }
187
+ if (typeof id !== 'string' || !PLUGIN_ID.test(id))
188
+ throw new Error('invalid plugin id');
189
+ const scopeArg = typeof scope === 'string' && PLUGIN_SCOPES.has(scope) ? scope : 'user';
190
+ const args = {
191
+ install: ['plugin', 'install', '--scope', scopeArg, '--', id],
192
+ uninstall: ['plugin', 'uninstall', '--', id],
193
+ enable: ['plugin', 'enable', '--', id],
194
+ disable: ['plugin', 'disable', '--', id],
195
+ update: ['plugin', 'update', id, '--scope', scopeArg],
196
+ }[op];
197
+ if (!args)
198
+ throw new Error(`unknown plugin action ${op}`);
199
+ const result = await runClaude(args, null, cwd, PLUGIN_TIMEOUT_MS);
200
+ if (result.code !== 0)
201
+ throw failure(result, `${op} ${id}`);
202
+ return { message: stripAnsi(result.stdout).trim().split(/\r?\n/).at(-1) ?? '' };
203
+ }
204
+ //# sourceMappingURL=settingsCommands.js.map