codekin 0.5.4 → 0.6.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 (88) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/index-BvKzbtKg.css +1 -0
  3. package/dist/assets/index-D59Xr9pK.js +182 -0
  4. package/dist/index.html +2 -2
  5. package/package.json +1 -1
  6. package/server/dist/approval-manager.js +2 -3
  7. package/server/dist/approval-manager.js.map +1 -1
  8. package/server/dist/claude-process.d.ts +17 -5
  9. package/server/dist/claude-process.js +56 -66
  10. package/server/dist/claude-process.js.map +1 -1
  11. package/server/dist/coding-process.d.ts +83 -0
  12. package/server/dist/coding-process.js +32 -0
  13. package/server/dist/coding-process.js.map +1 -0
  14. package/server/dist/commit-event-handler.js +1 -0
  15. package/server/dist/commit-event-handler.js.map +1 -1
  16. package/server/dist/config.js +2 -1
  17. package/server/dist/config.js.map +1 -1
  18. package/server/dist/docs-routes.js +22 -1
  19. package/server/dist/docs-routes.js.map +1 -1
  20. package/server/dist/native-permissions.js +3 -2
  21. package/server/dist/native-permissions.js.map +1 -1
  22. package/server/dist/opencode-process.d.ts +104 -0
  23. package/server/dist/opencode-process.js +657 -0
  24. package/server/dist/opencode-process.js.map +1 -0
  25. package/server/dist/orchestrator-children.d.ts +9 -0
  26. package/server/dist/orchestrator-children.js +50 -7
  27. package/server/dist/orchestrator-children.js.map +1 -1
  28. package/server/dist/orchestrator-manager.js +17 -0
  29. package/server/dist/orchestrator-manager.js.map +1 -1
  30. package/server/dist/orchestrator-reports.d.ts +0 -4
  31. package/server/dist/orchestrator-reports.js +6 -12
  32. package/server/dist/orchestrator-reports.js.map +1 -1
  33. package/server/dist/orchestrator-routes.js +8 -1
  34. package/server/dist/orchestrator-routes.js.map +1 -1
  35. package/server/dist/prompt-router.d.ts +95 -0
  36. package/server/dist/prompt-router.js +589 -0
  37. package/server/dist/prompt-router.js.map +1 -0
  38. package/server/dist/session-lifecycle.d.ts +73 -0
  39. package/server/dist/session-lifecycle.js +408 -0
  40. package/server/dist/session-lifecycle.js.map +1 -0
  41. package/server/dist/session-manager.d.ts +42 -60
  42. package/server/dist/session-manager.js +310 -835
  43. package/server/dist/session-manager.js.map +1 -1
  44. package/server/dist/session-persistence.d.ts +1 -0
  45. package/server/dist/session-persistence.js +24 -4
  46. package/server/dist/session-persistence.js.map +1 -1
  47. package/server/dist/session-routes.js +15 -1
  48. package/server/dist/session-routes.js.map +1 -1
  49. package/server/dist/stepflow-handler.d.ts +2 -2
  50. package/server/dist/stepflow-handler.js +4 -4
  51. package/server/dist/stepflow-handler.js.map +1 -1
  52. package/server/dist/tool-labels.d.ts +8 -0
  53. package/server/dist/tool-labels.js +51 -0
  54. package/server/dist/tool-labels.js.map +1 -0
  55. package/server/dist/tsconfig.tsbuildinfo +1 -1
  56. package/server/dist/types.d.ts +27 -8
  57. package/server/dist/types.js +4 -1
  58. package/server/dist/types.js.map +1 -1
  59. package/server/dist/webhook-dedup.d.ts +11 -0
  60. package/server/dist/webhook-dedup.js +23 -0
  61. package/server/dist/webhook-dedup.js.map +1 -1
  62. package/server/dist/webhook-handler.d.ts +20 -4
  63. package/server/dist/webhook-handler.js +256 -20
  64. package/server/dist/webhook-handler.js.map +1 -1
  65. package/server/dist/webhook-pr-cache.d.ts +57 -0
  66. package/server/dist/webhook-pr-cache.js +95 -0
  67. package/server/dist/webhook-pr-cache.js.map +1 -0
  68. package/server/dist/webhook-pr-github.d.ts +68 -0
  69. package/server/dist/webhook-pr-github.js +202 -0
  70. package/server/dist/webhook-pr-github.js.map +1 -0
  71. package/server/dist/webhook-pr-prompt.d.ts +27 -0
  72. package/server/dist/webhook-pr-prompt.js +251 -0
  73. package/server/dist/webhook-pr-prompt.js.map +1 -0
  74. package/server/dist/webhook-types.d.ts +70 -1
  75. package/server/dist/webhook-workspace.js +20 -1
  76. package/server/dist/webhook-workspace.js.map +1 -1
  77. package/server/dist/workflow-config.d.ts +2 -0
  78. package/server/dist/workflow-config.js.map +1 -1
  79. package/server/dist/workflow-loader.js +3 -0
  80. package/server/dist/workflow-loader.js.map +1 -1
  81. package/server/dist/workflow-routes.js +6 -2
  82. package/server/dist/workflow-routes.js.map +1 -1
  83. package/server/dist/ws-message-handler.js +24 -4
  84. package/server/dist/ws-message-handler.js.map +1 -1
  85. package/server/dist/ws-server.js +10 -2
  86. package/server/dist/ws-server.js.map +1 -1
  87. package/dist/assets/index-COGLICp9.js +0 -178
  88. package/dist/assets/index-CjEQkT2b.css +0 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Claude process lifecycle management extracted from SessionManager.
3
+ *
4
+ * Handles:
5
+ * - Starting/stopping Claude CLI processes (startClaude, stopClaude, stopClaudeAndWait)
6
+ * - Waiting for process readiness (waitForReady)
7
+ * - Wiring Claude process event handlers (wireClaudeEvents)
8
+ * - Handling process exit and auto-restart logic (handleClaudeExit)
9
+ */
10
+ import type { CodingProcess } from './coding-process.js';
11
+ import { ApprovalManager } from './approval-manager.js';
12
+ import type { PromptRouter } from './prompt-router.js';
13
+ import type { Session, WsServerMessage } from './types.js';
14
+ /** Dependencies injected by SessionManager so SessionLifecycle can interact with session state. */
15
+ export interface SessionLifecycleDeps {
16
+ getSession(id: string): Session | undefined;
17
+ hasSession(id: string): boolean;
18
+ broadcast(session: Session, msg: WsServerMessage): void;
19
+ addToHistory(session: Session, msg: WsServerMessage): void;
20
+ broadcastAndHistory(session: Session, msg: WsServerMessage): void;
21
+ persistToDisk(): void;
22
+ globalBroadcast: ((msg: WsServerMessage) => void) | null;
23
+ authToken: string;
24
+ serverPort: number;
25
+ approvalManager: ApprovalManager;
26
+ promptRouter: PromptRouter;
27
+ exitListeners: Array<(sessionId: string, code: number | null, signal: string | null, willRestart: boolean) => void>;
28
+ onSystemInit(cp: CodingProcess, session: Session, model: string): void;
29
+ onTextEvent(session: Session, sessionId: string, text: string): void;
30
+ onThinkingEvent(session: Session, summary: string): void;
31
+ onToolOutputEvent(session: Session, content: string, isError: boolean): void;
32
+ onImageEvent(session: Session, base64: string, mediaType: string): void;
33
+ onToolActiveEvent(session: Session, toolName: string, toolInput: string | undefined): void;
34
+ onToolDoneEvent(session: Session, toolName: string, summary: string | undefined): void;
35
+ handleClaudeResult(session: Session, sessionId: string, result: string, isError: boolean): void;
36
+ buildSessionContext(session: Session): string | null;
37
+ }
38
+ export declare class SessionLifecycle {
39
+ private deps;
40
+ constructor(deps: SessionLifecycleDeps);
41
+ /**
42
+ * Spawn (or re-spawn) a Claude CLI process for a session.
43
+ * Wires up all event handlers for streaming text, tools, prompts, and auto-restart.
44
+ */
45
+ startClaude(sessionId: string): boolean;
46
+ /**
47
+ * Wait for a session's Claude process to emit its system_init event,
48
+ * indicating it is ready to accept input. Resolves immediately if the
49
+ * session already has a claudeSessionId (process previously initialized).
50
+ * Times out after `timeoutMs` (default 30s) to avoid hanging indefinitely.
51
+ */
52
+ waitForReady(sessionId: string, timeoutMs?: number): Promise<void>;
53
+ /**
54
+ * Attach all ClaudeProcess event listeners for a session.
55
+ * Called by startClaude() to keep that method focused on process setup.
56
+ */
57
+ wireClaudeEvents(cp: CodingProcess, session: Session, sessionId: string): void;
58
+ /**
59
+ * Handle a Claude process 'exit' event: clean up state, notify exit listeners,
60
+ * and either auto-restart (within limits) or broadcast the final exit message.
61
+ *
62
+ * Uses evaluateRestart() for the restart decision, keeping this method focused
63
+ * on state updates, listener notification, and message broadcasting.
64
+ */
65
+ handleClaudeExit(exitedProcess: CodingProcess, session: Session, sessionId: string, code: number | null, signal: string | null): void;
66
+ stopClaude(sessionId: string): void;
67
+ /**
68
+ * Stop the Claude process and wait for it to fully exit before resolving.
69
+ * This prevents race conditions when restarting with the same session ID
70
+ * (e.g. during mid-session worktree migration).
71
+ */
72
+ stopClaudeAndWait(sessionId: string): Promise<void>;
73
+ }
@@ -0,0 +1,408 @@
1
+ /**
2
+ * Claude process lifecycle management extracted from SessionManager.
3
+ *
4
+ * Handles:
5
+ * - Starting/stopping Claude CLI processes (startClaude, stopClaude, stopClaudeAndWait)
6
+ * - Waiting for process readiness (waitForReady)
7
+ * - Wiring Claude process event handlers (wireClaudeEvents)
8
+ * - Handling process exit and auto-restart logic (handleClaudeExit)
9
+ */
10
+ import { existsSync } from 'fs';
11
+ import path from 'path';
12
+ import { ClaudeProcess } from './claude-process.js';
13
+ import { OpenCodeProcess } from './opencode-process.js';
14
+ import { PORT } from './config.js';
15
+ import { deriveSessionToken } from './crypto-utils.js';
16
+ import { evaluateRestart } from './session-restart-scheduler.js';
17
+ export class SessionLifecycle {
18
+ deps;
19
+ constructor(deps) {
20
+ this.deps = deps;
21
+ }
22
+ // ---------------------------------------------------------------------------
23
+ // Claude process lifecycle
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Spawn (or re-spawn) a Claude CLI process for a session.
27
+ * Wires up all event handlers for streaming text, tools, prompts, and auto-restart.
28
+ */
29
+ startClaude(sessionId) {
30
+ const session = this.deps.getSession(sessionId);
31
+ if (!session)
32
+ return false;
33
+ // Clear stopped flag and any pending restart timer on explicit start
34
+ session._stoppedByUser = false;
35
+ if (session._restartTimer) {
36
+ clearTimeout(session._restartTimer);
37
+ session._restartTimer = undefined;
38
+ }
39
+ // Validate that the working directory still exists. Worktree directories
40
+ // can be removed externally (cleanup, manual deletion, failed creation that
41
+ // left a stale placeholder). Fall back to groupDir (the original repo) so
42
+ // the session can still function instead of entering an infinite restart loop.
43
+ if (!existsSync(session.workingDir) || (session.worktreePath && !existsSync(path.join(session.workingDir, '.git')))) {
44
+ const fallback = session.groupDir ?? session.workingDir;
45
+ if (fallback !== session.workingDir && existsSync(fallback)) {
46
+ const deadPath = session.workingDir;
47
+ console.warn(`[startClaude] Working directory ${deadPath} missing or not a valid worktree — falling back to ${fallback}`);
48
+ session.workingDir = fallback;
49
+ session.worktreePath = undefined;
50
+ this.deps.persistToDisk();
51
+ this.deps.globalBroadcast?.({ type: 'sessions_updated' });
52
+ const fallbackMsg = {
53
+ type: 'system_message',
54
+ subtype: 'notification',
55
+ text: `Worktree directory ${deadPath} no longer exists. Falling back to original repository: ${fallback}`,
56
+ };
57
+ this.deps.addToHistory(session, fallbackMsg);
58
+ this.deps.broadcast(session, fallbackMsg);
59
+ }
60
+ else if (!existsSync(session.workingDir)) {
61
+ console.error(`[startClaude] Working directory ${session.workingDir} does not exist and no fallback available — cannot start`);
62
+ session._stoppedByUser = true; // prevent restart loop
63
+ const errMsg = {
64
+ type: 'system_message',
65
+ subtype: 'error',
66
+ text: `Working directory ${session.workingDir} no longer exists and no fallback is available. Session cannot start.`,
67
+ };
68
+ this.deps.addToHistory(session, errMsg);
69
+ this.deps.broadcast(session, errMsg);
70
+ return false;
71
+ }
72
+ }
73
+ // Kill existing process if any — remove listeners first to prevent the
74
+ // old process's exit handler from clobbering the new process reference
75
+ // and triggering an unwanted auto-restart cycle.
76
+ if (session.claudeProcess) {
77
+ session.claudeProcess.removeAllListeners();
78
+ session.claudeProcess.stop();
79
+ }
80
+ // Derive a session-scoped token instead of forwarding the master auth token.
81
+ // This limits child process privileges to approve/deny for their own session only.
82
+ const sessionToken = this.deps.authToken
83
+ ? deriveSessionToken(this.deps.authToken, sessionId)
84
+ : '';
85
+ // Both CODEKIN_TOKEN (legacy name, used by older hooks) and CODEKIN_AUTH_TOKEN
86
+ // (current canonical name) are set to the same derived value for backward compatibility.
87
+ const extraEnv = {
88
+ CODEKIN_SESSION_ID: sessionId,
89
+ CODEKIN_PORT: String(this.deps.serverPort || PORT),
90
+ CODEKIN_TOKEN: sessionToken,
91
+ CODEKIN_AUTH_TOKEN: sessionToken,
92
+ CODEKIN_SESSION_TYPE: session.source || 'manual',
93
+ ...(session.permissionMode === 'dangerouslySkipPermissions' ? { CODEKIN_SKIP_PERMISSIONS: '1' } : {}),
94
+ };
95
+ // Pass CLAUDE_PROJECT_DIR so hooks and CLAUDE.md resolve correctly
96
+ // even when the session's working directory differs from the project root
97
+ // (e.g. worktrees, webhook workspaces). Note: this does NOT control
98
+ // session storage path — Claude CLI uses the CWD for that.
99
+ if (session.groupDir) {
100
+ extraEnv.CLAUDE_PROJECT_DIR = session.groupDir;
101
+ }
102
+ else if (process.env.CLAUDE_PROJECT_DIR) {
103
+ extraEnv.CLAUDE_PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR;
104
+ }
105
+ // When claudeSessionId exists, the session has run before and a JSONL file
106
+ // exists on disk. Use --resume (not --session-id) to continue it — --session-id
107
+ // creates a *new* session and fails with "already in use" if the JSONL exists.
108
+ const resume = !!session.claudeSessionId;
109
+ // Build comprehensive allowedTools from session-level overrides + registry approvals
110
+ const repoDir = session.groupDir ?? session.workingDir;
111
+ const registryPatterns = this.deps.approvalManager.getAllowedToolsForRepo(repoDir);
112
+ const mergedAllowedTools = [...new Set([...(session.allowedTools || []), ...registryPatterns])];
113
+ let cp;
114
+ if (session.provider === 'opencode') {
115
+ cp = new OpenCodeProcess(session.workingDir, {
116
+ sessionId: sessionId,
117
+ opencodeSessionId: session.claudeSessionId || undefined,
118
+ model: session.model,
119
+ extraEnv,
120
+ permissionMode: session.permissionMode,
121
+ });
122
+ }
123
+ else {
124
+ cp = new ClaudeProcess(session.workingDir, {
125
+ sessionId: session.claudeSessionId || undefined,
126
+ extraEnv,
127
+ model: session.model,
128
+ permissionMode: session.permissionMode,
129
+ resume,
130
+ allowedTools: mergedAllowedTools,
131
+ addDirs: session.addDirs,
132
+ });
133
+ }
134
+ this.wireClaudeEvents(cp, session, sessionId);
135
+ cp.start();
136
+ session.claudeProcess = cp;
137
+ this.deps.globalBroadcast?.({ type: 'sessions_updated' });
138
+ const startMsg = { type: 'claude_started', sessionId };
139
+ this.deps.addToHistory(session, startMsg);
140
+ this.deps.broadcast(session, startMsg);
141
+ return true;
142
+ }
143
+ /**
144
+ * Wait for a session's Claude process to emit its system_init event,
145
+ * indicating it is ready to accept input. Resolves immediately if the
146
+ * session already has a claudeSessionId (process previously initialized).
147
+ * Times out after `timeoutMs` (default 30s) to avoid hanging indefinitely.
148
+ */
149
+ waitForReady(sessionId, timeoutMs = 30_000) {
150
+ const session = this.deps.getSession(sessionId);
151
+ if (!session?.claudeProcess)
152
+ return Promise.resolve();
153
+ // If the process is already fully initialized, resolve immediately.
154
+ // Uses isReady() which accounts for provider differences: Claude is ready
155
+ // as soon as alive (stdin buffered), OpenCode needs alive + opencodeSessionId.
156
+ if (session.claudeProcess.isReady())
157
+ return Promise.resolve();
158
+ return new Promise((resolve) => {
159
+ const done = () => { clearTimeout(timer); resolve(); };
160
+ const timer = setTimeout(() => {
161
+ console.warn(`[waitForReady] Timed out waiting for system_init on ${sessionId} after ${timeoutMs}ms`);
162
+ session.claudeProcess?.removeListener('exit', done);
163
+ resolve();
164
+ }, timeoutMs);
165
+ session.claudeProcess.once('system_init', done);
166
+ session.claudeProcess.once('exit', done); // fail-fast if process dies during init
167
+ });
168
+ }
169
+ /**
170
+ * Attach all ClaudeProcess event listeners for a session.
171
+ * Called by startClaude() to keep that method focused on process setup.
172
+ */
173
+ wireClaudeEvents(cp, session, sessionId) {
174
+ cp.on('system_init', (model) => this.deps.onSystemInit(cp, session, model));
175
+ cp.on('text', (text) => this.deps.onTextEvent(session, sessionId, text));
176
+ cp.on('thinking', (summary) => this.deps.onThinkingEvent(session, summary));
177
+ cp.on('tool_output', (content, isError) => this.deps.onToolOutputEvent(session, content, isError));
178
+ cp.on('image', (base64Data, mediaType) => this.deps.onImageEvent(session, base64Data, mediaType));
179
+ cp.on('tool_active', (toolName, toolInput) => this.deps.onToolActiveEvent(session, toolName, toolInput));
180
+ cp.on('tool_done', (toolName, summary) => this.deps.onToolDoneEvent(session, toolName, summary));
181
+ cp.on('planning_mode', (active) => {
182
+ // Route EnterPlanMode through PlanManager for UI state tracking.
183
+ // ExitPlanMode (active=false) is ignored here — the PreToolUse hook
184
+ // is the enforcement gate, and it calls handleExitPlanModeApproval()
185
+ // which transitions PlanManager to 'reviewing'.
186
+ if (active) {
187
+ session.planManager.onEnterPlanMode();
188
+ }
189
+ // ExitPlanMode stream event intentionally ignored — hook handles it.
190
+ });
191
+ cp.on('todo_update', (tasks) => { this.deps.broadcastAndHistory(session, { type: 'todo_update', tasks }); });
192
+ cp.on('prompt', (...args) => this.deps.promptRouter.onPromptEvent(session, ...args));
193
+ cp.on('control_request', (requestId, toolName, toolInput) => this.deps.promptRouter.onControlRequestEvent(cp, session, sessionId, requestId, toolName, toolInput));
194
+ cp.on('result', (result, isError) => {
195
+ session.planManager.onTurnEnd();
196
+ this.deps.handleClaudeResult(session, sessionId, result, isError);
197
+ });
198
+ cp.on('error', (message) => this.deps.broadcast(session, { type: 'error', message }));
199
+ cp.on('exit', (code, signal) => { cp.removeAllListeners(); this.handleClaudeExit(cp, session, sessionId, code, signal); });
200
+ }
201
+ /**
202
+ * Handle a Claude process 'exit' event: clean up state, notify exit listeners,
203
+ * and either auto-restart (within limits) or broadcast the final exit message.
204
+ *
205
+ * Uses evaluateRestart() for the restart decision, keeping this method focused
206
+ * on state updates, listener notification, and message broadcasting.
207
+ */
208
+ handleClaudeExit(exitedProcess, session, sessionId, code, signal) {
209
+ // Guard: ignore exit events from stale processes that were replaced by a
210
+ // new startClaude() call. Without this, the old process's exit handler
211
+ // would null out session.claudeProcess (which now points to the NEW
212
+ // process), orphaning it and triggering an unwanted auto-restart cycle.
213
+ if (session.claudeProcess && session.claudeProcess !== exitedProcess) {
214
+ console.log(`[restart] Ignoring exit from stale process for session ${sessionId}`);
215
+ return;
216
+ }
217
+ session.claudeProcess = null;
218
+ session.isProcessing = false;
219
+ session.planManager.reset();
220
+ this.deps.globalBroadcast?.({ type: 'sessions_updated' });
221
+ // "Session ID is already in use" means another process holds the lock.
222
+ // Retrying with the same session ID will fail every time, so treat this
223
+ // as a non-restartable exit (same as stopped-by-user).
224
+ // ClaudeProcess has diagnostic methods (hasSessionConflict, hadOutput, hasSpawnFailed)
225
+ // that OpenCodeProcess does not. Duck-type check via property existence.
226
+ const proc = exitedProcess;
227
+ const sessionConflict = proc.hasSessionConflict ? proc.hasSessionConflict() : false;
228
+ const producedOutput = proc.hadOutput ? proc.hadOutput() : true;
229
+ const spawnFailed = proc.hasSpawnFailed ? proc.hasSpawnFailed() : false;
230
+ // If the process exited without ever producing stdout output, --resume
231
+ // hung on a broken/stale session. Clear claudeSessionId so the next
232
+ // restart attempt uses a fresh session instead of retrying the same
233
+ // broken resume — which would just hang again.
234
+ // Exception: if spawn() itself failed (ENOENT/EACCES), the process never
235
+ // started — the session data on disk is fine, so preserve the ID for retry.
236
+ if (!producedOutput && session.claudeSessionId && !spawnFailed) {
237
+ console.warn(`[restart] Session ${sessionId} produced no output before exit — clearing claudeSessionId to force fresh session`);
238
+ session.claudeSessionId = null;
239
+ }
240
+ if (spawnFailed) {
241
+ console.warn(`[restart] Session ${sessionId} spawn failed (binary not found) — preserving claudeSessionId for retry`);
242
+ }
243
+ // Before evaluating restart, check if the working directory still exists.
244
+ // If a worktree was deleted mid-session, fall back to the original repo
245
+ // instead of entering a guaranteed restart death loop where every attempt
246
+ // fails with the same missing CWD.
247
+ if (!existsSync(session.workingDir)) {
248
+ const fallback = session.groupDir;
249
+ if (fallback && existsSync(fallback)) {
250
+ const deadPath = session.workingDir;
251
+ console.warn(`[restart] Working directory ${deadPath} no longer exists — falling back to ${fallback}`);
252
+ session.workingDir = fallback;
253
+ session.worktreePath = undefined;
254
+ this.deps.persistToDisk();
255
+ this.deps.globalBroadcast?.({ type: 'sessions_updated' });
256
+ const fallbackMsg = {
257
+ type: 'system_message',
258
+ subtype: 'notification',
259
+ text: `Worktree directory ${deadPath} was removed. Restarting in original repository: ${fallback}`,
260
+ };
261
+ this.deps.addToHistory(session, fallbackMsg);
262
+ this.deps.broadcast(session, fallbackMsg);
263
+ }
264
+ else {
265
+ // No fallback available — don't waste restart attempts
266
+ console.error(`[restart] Working directory ${session.workingDir} does not exist and no fallback — stopping session`);
267
+ session._stoppedByUser = true;
268
+ for (const listener of this.deps.exitListeners) {
269
+ try {
270
+ listener(sessionId, code, signal, false);
271
+ }
272
+ catch { /* listener error */ }
273
+ }
274
+ const msg = {
275
+ type: 'system_message',
276
+ subtype: 'error',
277
+ text: `Working directory ${session.workingDir} no longer exists and no fallback is available. Please delete this session and create a new one.`,
278
+ };
279
+ this.deps.addToHistory(session, msg);
280
+ this.deps.broadcast(session, msg);
281
+ this.deps.broadcast(session, { type: 'exit', code: code ?? -1, signal });
282
+ return;
283
+ }
284
+ }
285
+ const action = evaluateRestart({
286
+ restartCount: session.restartCount,
287
+ lastRestartAt: session.lastRestartAt,
288
+ stoppedByUser: session._stoppedByUser || sessionConflict,
289
+ });
290
+ if (action.kind === 'stopped_by_user') {
291
+ for (const listener of this.deps.exitListeners) {
292
+ try {
293
+ listener(sessionId, code, signal, false);
294
+ }
295
+ catch { /* listener error */ }
296
+ }
297
+ const text = sessionConflict
298
+ ? 'Claude process exited: session ID is already in use by another process. Please restart manually.'
299
+ : `Claude process exited: code=${code}, signal=${signal}`;
300
+ const msg = { type: 'system_message', subtype: 'exit', text };
301
+ this.deps.addToHistory(session, msg);
302
+ this.deps.broadcast(session, msg);
303
+ this.deps.broadcast(session, { type: 'exit', code: code ?? -1, signal });
304
+ return;
305
+ }
306
+ if (action.kind === 'restart') {
307
+ session.restartCount = action.updatedCount;
308
+ session.lastRestartAt = action.updatedLastRestartAt;
309
+ for (const listener of this.deps.exitListeners) {
310
+ try {
311
+ listener(sessionId, code, signal, true);
312
+ }
313
+ catch { /* listener error */ }
314
+ }
315
+ const msg = {
316
+ type: 'system_message',
317
+ subtype: 'restart',
318
+ text: `Claude process exited unexpectedly (code=${code}, signal=${signal}). Restarting (attempt ${action.attempt}/${action.maxAttempts})...`,
319
+ };
320
+ this.deps.addToHistory(session, msg);
321
+ this.deps.broadcast(session, msg);
322
+ // Clear any previously scheduled restart to prevent duplicate spawns
323
+ if (session._restartTimer)
324
+ clearTimeout(session._restartTimer);
325
+ session._restartTimer = setTimeout(() => {
326
+ session._restartTimer = undefined;
327
+ // Verify session still exists and hasn't been stopped
328
+ if (!this.deps.hasSession(sessionId) || session._stoppedByUser)
329
+ return;
330
+ // startClaude uses --resume when claudeSessionId exists, so the CLI
331
+ // picks up the full conversation history from the JSONL automatically.
332
+ this.startClaude(sessionId);
333
+ // Fallback: if claudeSessionId was already null (fresh session that
334
+ // crashed before system_init), inject a context summary so the new
335
+ // session has some awareness of prior conversation.
336
+ if (!session.claudeSessionId && session.claudeProcess && session.outputHistory.length > 0) {
337
+ session.claudeProcess.once('system_init', () => {
338
+ const context = this.deps.buildSessionContext(session);
339
+ if (context) {
340
+ session.claudeProcess?.sendMessage(context + '\n\n[Session resumed after process restart. Continue where you left off. If you were in the middle of a task, resume it.]');
341
+ }
342
+ });
343
+ }
344
+ }, action.delayMs);
345
+ return;
346
+ }
347
+ // action.kind === 'exhausted'
348
+ for (const listener of this.deps.exitListeners) {
349
+ try {
350
+ listener(sessionId, code, signal, false);
351
+ }
352
+ catch { /* listener error */ }
353
+ }
354
+ const msg = {
355
+ type: 'system_message',
356
+ subtype: 'error',
357
+ text: `Claude process exited unexpectedly (code=${code}, signal=${signal}). Auto-restart disabled after ${action.maxAttempts} attempts. Please restart manually.`,
358
+ };
359
+ this.deps.addToHistory(session, msg);
360
+ this.deps.broadcast(session, msg);
361
+ this.deps.broadcast(session, { type: 'exit', code: code ?? -1, signal });
362
+ }
363
+ stopClaude(sessionId) {
364
+ const session = this.deps.getSession(sessionId);
365
+ if (session?.claudeProcess) {
366
+ session._stoppedByUser = true;
367
+ if (session._apiRetry?.timer)
368
+ clearTimeout(session._apiRetry.timer);
369
+ if (session._restartTimer) {
370
+ clearTimeout(session._restartTimer);
371
+ session._restartTimer = undefined;
372
+ }
373
+ session.claudeProcess.removeAllListeners();
374
+ session.claudeProcess.stop();
375
+ session.claudeProcess = null;
376
+ this.deps.broadcast(session, { type: 'claude_stopped' });
377
+ }
378
+ }
379
+ /**
380
+ * Stop the Claude process and wait for it to fully exit before resolving.
381
+ * This prevents race conditions when restarting with the same session ID
382
+ * (e.g. during mid-session worktree migration).
383
+ */
384
+ async stopClaudeAndWait(sessionId) {
385
+ const session = this.deps.getSession(sessionId);
386
+ if (!session?.claudeProcess)
387
+ return;
388
+ const cp = session.claudeProcess;
389
+ session._stoppedByUser = true;
390
+ if (session._apiRetry?.timer)
391
+ clearTimeout(session._apiRetry.timer);
392
+ if (session._restartTimer) {
393
+ clearTimeout(session._restartTimer);
394
+ session._restartTimer = undefined;
395
+ }
396
+ cp.removeAllListeners();
397
+ cp.stop();
398
+ this.deps.broadcast(session, { type: 'claude_stopped' });
399
+ // Wait for the underlying OS process to fully exit BEFORE nulling the
400
+ // reference. Previously this was set to null before the await, which
401
+ // allowed another caller (e.g. move_to_worktree) to call startClaude()
402
+ // while the old process was still alive — causing concurrent git access
403
+ // and index corruption.
404
+ await cp.waitForExit();
405
+ session.claudeProcess = null;
406
+ }
407
+ }
408
+ //# sourceMappingURL=session-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../session-lifecycle.ts"],"names":[],"mappings":"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"}