mstro-app 0.2.0 → 0.3.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 (114) hide show
  1. package/PRIVACY.md +126 -0
  2. package/README.md +24 -23
  3. package/bin/commands/login.js +79 -49
  4. package/bin/mstro.js +240 -37
  5. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  6. package/dist/server/cli/headless/claude-invoker.js +133 -27
  7. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  8. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  9. package/dist/server/cli/headless/runner.js +23 -0
  10. package/dist/server/cli/headless/runner.js.map +1 -1
  11. package/dist/server/cli/headless/stall-assessor.d.ts +3 -1
  12. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  13. package/dist/server/cli/headless/stall-assessor.js +20 -1
  14. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  15. package/dist/server/cli/headless/tool-watchdog.d.ts +4 -1
  16. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  17. package/dist/server/cli/headless/tool-watchdog.js +30 -24
  18. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  19. package/dist/server/cli/headless/types.d.ts +19 -1
  20. package/dist/server/cli/headless/types.d.ts.map +1 -1
  21. package/dist/server/cli/improvisation-session-manager.d.ts +28 -1
  22. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  23. package/dist/server/cli/improvisation-session-manager.js +221 -29
  24. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  25. package/dist/server/index.js +0 -3
  26. package/dist/server/index.js.map +1 -1
  27. package/dist/server/services/analytics.d.ts.map +1 -1
  28. package/dist/server/services/analytics.js +13 -1
  29. package/dist/server/services/analytics.js.map +1 -1
  30. package/dist/server/services/platform.d.ts.map +1 -1
  31. package/dist/server/services/platform.js +13 -1
  32. package/dist/server/services/platform.js.map +1 -1
  33. package/dist/server/services/terminal/pty-manager.d.ts +2 -0
  34. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  35. package/dist/server/services/terminal/pty-manager.js +50 -3
  36. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  37. package/dist/server/services/websocket/file-explorer-handlers.d.ts +5 -0
  38. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -0
  39. package/dist/server/services/websocket/file-explorer-handlers.js +518 -0
  40. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -0
  41. package/dist/server/services/websocket/git-handlers.d.ts +36 -0
  42. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -0
  43. package/dist/server/services/websocket/git-handlers.js +797 -0
  44. package/dist/server/services/websocket/git-handlers.js.map +1 -0
  45. package/dist/server/services/websocket/git-pr-handlers.d.ts +4 -0
  46. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -0
  47. package/dist/server/services/websocket/git-pr-handlers.js +299 -0
  48. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -0
  49. package/dist/server/services/websocket/git-worktree-handlers.d.ts +4 -0
  50. package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -0
  51. package/dist/server/services/websocket/git-worktree-handlers.js +353 -0
  52. package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -0
  53. package/dist/server/services/websocket/handler-context.d.ts +32 -0
  54. package/dist/server/services/websocket/handler-context.d.ts.map +1 -0
  55. package/dist/server/services/websocket/handler-context.js +4 -0
  56. package/dist/server/services/websocket/handler-context.js.map +1 -0
  57. package/dist/server/services/websocket/handler.d.ts +27 -359
  58. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  59. package/dist/server/services/websocket/handler.js +67 -2328
  60. package/dist/server/services/websocket/handler.js.map +1 -1
  61. package/dist/server/services/websocket/index.d.ts +1 -1
  62. package/dist/server/services/websocket/index.d.ts.map +1 -1
  63. package/dist/server/services/websocket/index.js.map +1 -1
  64. package/dist/server/services/websocket/session-handlers.d.ts +10 -0
  65. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -0
  66. package/dist/server/services/websocket/session-handlers.js +507 -0
  67. package/dist/server/services/websocket/session-handlers.js.map +1 -0
  68. package/dist/server/services/websocket/settings-handlers.d.ts +6 -0
  69. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -0
  70. package/dist/server/services/websocket/settings-handlers.js +125 -0
  71. package/dist/server/services/websocket/settings-handlers.js.map +1 -0
  72. package/dist/server/services/websocket/tab-handlers.d.ts +10 -0
  73. package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -0
  74. package/dist/server/services/websocket/tab-handlers.js +131 -0
  75. package/dist/server/services/websocket/tab-handlers.js.map +1 -0
  76. package/dist/server/services/websocket/terminal-handlers.d.ts +9 -0
  77. package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -0
  78. package/dist/server/services/websocket/terminal-handlers.js +220 -0
  79. package/dist/server/services/websocket/terminal-handlers.js.map +1 -0
  80. package/dist/server/services/websocket/types.d.ts +63 -2
  81. package/dist/server/services/websocket/types.d.ts.map +1 -1
  82. package/package.json +4 -2
  83. package/server/README.md +176 -159
  84. package/server/cli/headless/claude-invoker.ts +155 -31
  85. package/server/cli/headless/output-utils.test.ts +225 -0
  86. package/server/cli/headless/runner.ts +25 -0
  87. package/server/cli/headless/stall-assessor.test.ts +165 -0
  88. package/server/cli/headless/stall-assessor.ts +25 -0
  89. package/server/cli/headless/tool-watchdog.test.ts +429 -0
  90. package/server/cli/headless/tool-watchdog.ts +33 -25
  91. package/server/cli/headless/types.ts +10 -1
  92. package/server/cli/improvisation-session-manager.ts +277 -30
  93. package/server/index.ts +0 -4
  94. package/server/mcp/README.md +59 -67
  95. package/server/mcp/bouncer-integration.test.ts +161 -0
  96. package/server/mcp/security-patterns.test.ts +258 -0
  97. package/server/services/analytics.ts +13 -1
  98. package/server/services/platform.ts +12 -1
  99. package/server/services/terminal/pty-manager.ts +53 -3
  100. package/server/services/websocket/autocomplete.test.ts +194 -0
  101. package/server/services/websocket/file-explorer-handlers.ts +587 -0
  102. package/server/services/websocket/git-handlers.ts +924 -0
  103. package/server/services/websocket/git-pr-handlers.ts +363 -0
  104. package/server/services/websocket/git-worktree-handlers.ts +403 -0
  105. package/server/services/websocket/handler-context.ts +44 -0
  106. package/server/services/websocket/handler.test.ts +1 -1
  107. package/server/services/websocket/handler.ts +83 -2678
  108. package/server/services/websocket/index.ts +1 -1
  109. package/server/services/websocket/session-handlers.ts +574 -0
  110. package/server/services/websocket/settings-handlers.ts +150 -0
  111. package/server/services/websocket/tab-handlers.ts +150 -0
  112. package/server/services/websocket/terminal-handlers.ts +277 -0
  113. package/server/services/websocket/types.ts +135 -0
  114. package/bin/release.sh +0 -110
@@ -86,6 +86,11 @@ export interface HeadlessConfig {
86
86
  outputCallback?: (text: string) => void;
87
87
  thinkingCallback?: (text: string) => void;
88
88
  toolUseCallback?: (event: ToolUseEvent) => void;
89
+ /** Called with cumulative API token counts as they arrive from the stream */
90
+ tokenUsageCallback?: (usage: {
91
+ inputTokens: number;
92
+ outputTokens: number;
93
+ }) => void;
89
94
  directPrompt?: string;
90
95
  promptContext?: PromptContext;
91
96
  continueSession?: boolean;
@@ -124,6 +129,8 @@ export interface SessionResult {
124
129
  totalTokens: number;
125
130
  sessionId: string;
126
131
  error?: string;
132
+ /** Signal name if Claude process was killed (e.g., 'SIGTERM', 'SIGKILL') */
133
+ signalName?: string;
127
134
  conflicts?: Array<{
128
135
  filePath: string;
129
136
  modifiedBy: string[];
@@ -164,6 +171,8 @@ export interface ExecutionResult {
164
171
  output: string;
165
172
  error?: string;
166
173
  exitCode: number;
174
+ /** Signal name if process was killed (e.g., 'SIGTERM', 'SIGKILL') */
175
+ signalName?: string;
167
176
  assistantResponse?: string;
168
177
  thinkingOutput?: string;
169
178
  toolUseHistory?: ToolUseAccumulator[];
@@ -176,12 +185,21 @@ export interface ExecutionResult {
176
185
  /** Assistant text buffered during resume assessment — held back until thinking/tool activity
177
186
  * confirms Claude has context. Undefined when not in resume mode or buffer was flushed. */
178
187
  resumeBufferedOutput?: string;
188
+ /** Actual API token usage from Claude Code stream events (summed across all turns) */
189
+ apiTokenUsage?: {
190
+ inputTokens: number;
191
+ outputTokens: number;
192
+ };
179
193
  }
180
194
  /** Resolved config with all defaults applied */
181
- export type ResolvedHeadlessConfig = Omit<Required<HeadlessConfig>, 'outputCallback' | 'thinkingCallback' | 'toolUseCallback' | 'continueSession' | 'claudeSessionId' | 'imageAttachments' | 'model' | 'toolTimeoutProfiles' | 'onToolTimeout' | 'sandboxed'> & {
195
+ export type ResolvedHeadlessConfig = Omit<Required<HeadlessConfig>, 'outputCallback' | 'thinkingCallback' | 'toolUseCallback' | 'tokenUsageCallback' | 'continueSession' | 'claudeSessionId' | 'imageAttachments' | 'model' | 'toolTimeoutProfiles' | 'onToolTimeout' | 'sandboxed'> & {
182
196
  outputCallback?: (text: string) => void;
183
197
  thinkingCallback?: (text: string) => void;
184
198
  toolUseCallback?: (event: ToolUseEvent) => void;
199
+ tokenUsageCallback?: (usage: {
200
+ inputTokens: number;
201
+ outputTokens: number;
202
+ }) => void;
185
203
  continueSession?: boolean;
186
204
  claudeSessionId?: string;
187
205
  imageAttachments?: ImageAttachment[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../server/cli/headless/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../server/cli/headless/types.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,7 @@ export interface MovementRecord {
43
43
  toolUseHistory?: ToolUseRecord[];
44
44
  errorOutput?: string;
45
45
  durationMs?: number;
46
+ retryLog?: RetryLogEntry[];
46
47
  }
47
48
  export interface SessionHistory {
48
49
  sessionId: string;
@@ -52,6 +53,14 @@ export interface SessionHistory {
52
53
  movements: MovementRecord[];
53
54
  claudeSessionId?: string;
54
55
  }
56
+ /** Entry in the retry log for debugging recovery paths */
57
+ interface RetryLogEntry {
58
+ retryNumber: number;
59
+ path: string;
60
+ reason: string;
61
+ timestamp: number;
62
+ durationMs?: number;
63
+ }
55
64
  export declare class ImprovisationSessionManager extends EventEmitter {
56
65
  private sessionId;
57
66
  private improviseDir;
@@ -72,6 +81,8 @@ export declare class ImprovisationSessionManager extends EventEmitter {
72
81
  private _executionStartTimestamp;
73
82
  /** Buffered events during current execution, for replay on reconnect */
74
83
  private executionEventLog;
84
+ /** Set by cancel() to signal the retry loop to exit */
85
+ private _cancelled;
75
86
  /**
76
87
  * Resume from a historical session.
77
88
  * Creates a new session manager that continues the conversation from a previous session.
@@ -113,7 +124,10 @@ export declare class ImprovisationSessionManager extends EventEmitter {
113
124
  */
114
125
  executePrompt(userPrompt: string, attachments?: FileAttachment[], options?: {
115
126
  sandboxed?: boolean;
127
+ workingDir?: string;
116
128
  }): Promise<MovementRecord>;
129
+ private handleCancelledExecution;
130
+ private runRetryLoop;
117
131
  /** Prepare prompt with attachments and limit image count */
118
132
  private preparePromptAndAttachments;
119
133
  /** Determine whether to use --resume and which session ID */
@@ -132,7 +146,10 @@ export declare class ImprovisationSessionManager extends EventEmitter {
132
146
  private flushPostTimeoutOutput;
133
147
  /** Check if context loss recovery should trigger a retry. Returns true if loop should continue. */
134
148
  private shouldRetryContextLoss;
135
- /** Accumulate completed tool results from a run into the retry state */
149
+ /** Accumulate completed tool results from a run into the retry state.
150
+ * Caps at MAX_ACCUMULATED_RESULTS to prevent recovery prompts from exceeding context limits.
151
+ * When the cap is reached, older results are evicted (FIFO) to make room for newer ones. */
152
+ private static readonly MAX_ACCUMULATED_RESULTS;
136
153
  private accumulateToolResults;
137
154
  /** Handle inter-movement context loss recovery (resume session expired) */
138
155
  private applyInterMovementRecovery;
@@ -140,6 +157,15 @@ export declare class ImprovisationSessionManager extends EventEmitter {
140
157
  private applyNativeTimeoutRecovery;
141
158
  /** Handle tool timeout checkpoint. Returns true if loop should continue. */
142
159
  private applyToolTimeoutRetry;
160
+ /**
161
+ * Detect and retry after a signal crash (e.g., SIGTERM exit code 143).
162
+ * When the Claude process is killed externally (OOM, system signal, internal timeout
163
+ * that bypasses our watchdog), no existing recovery path catches it because contextLost
164
+ * is never set and no checkpoint is created. This adds a dedicated recovery path.
165
+ */
166
+ private shouldRetrySignalCrash;
167
+ /** Build a recovery prompt after signal crash */
168
+ private buildSignalCrashRecoveryPrompt;
143
169
  /** Select the best result across retries using Haiku assessment */
144
170
  private selectBestResult;
145
171
  /** Fallback best result selection using numeric scoring */
@@ -278,4 +304,5 @@ export declare class ImprovisationSessionManager extends EventEmitter {
278
304
  */
279
305
  startNewSession(overrides?: Partial<ImprovisationOptions>): ImprovisationSessionManager;
280
306
  }
307
+ export {};
281
308
  //# sourceMappingURL=improvisation-session-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"improvisation-session-manager.d.ts","sourceRoot":"","sources":["../../../server/cli/improvisation-session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"improvisation-session-manager.d.ts","sourceRoot":"","sources":["../../../server/cli/improvisation-session-manager.ts"],"names":[],"mappings":"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"}
@@ -39,6 +39,8 @@ export class ImprovisationSessionManager extends EventEmitter {
39
39
  _executionStartTimestamp;
40
40
  /** Buffered events during current execution, for replay on reconnect */
41
41
  executionEventLog = [];
42
+ /** Set by cancel() to signal the retry loop to exit */
43
+ _cancelled = false;
42
44
  /**
43
45
  * Resume from a historical session.
44
46
  * Creates a new session manager that continues the conversation from a previous session.
@@ -199,6 +201,7 @@ export class ImprovisationSessionManager extends EventEmitter {
199
201
  async executePrompt(userPrompt, attachments, options) {
200
202
  const _execStart = Date.now();
201
203
  this._isExecuting = true;
204
+ this._cancelled = false;
202
205
  this._executionStartTimestamp = _execStart;
203
206
  this.executionEventLog = [];
204
207
  const sequenceNumber = this.history.movements.length + 1;
@@ -230,34 +233,21 @@ export class ImprovisationSessionManager extends EventEmitter {
230
233
  lastWatchdogCheckpoint: null,
231
234
  timedOutTools: [],
232
235
  bestResult: null,
236
+ retryLog: [],
233
237
  };
234
- const maxRetries = 3;
235
- let result;
236
- // eslint-disable-next-line no-constant-condition
237
- while (true) {
238
- this.resetIterationState(state);
239
- const { useResume, resumeSessionId } = this.determineResumeStrategy(state);
240
- const runner = this.createExecutionRunner(state, sequenceNumber, useResume, resumeSessionId, imageAttachments, options?.sandboxed);
241
- this.currentRunner = runner;
242
- result = await runner.run();
243
- this.currentRunner = null;
244
- this.updateBestResult(state, result);
245
- const nativeTimeouts = result.nativeTimeoutCount ?? 0;
246
- this.detectResumeContextLoss(result, state, useResume, maxRetries, nativeTimeouts);
247
- await this.detectNativeTimeoutContextLoss(result, state, maxRetries, nativeTimeouts);
248
- this.flushPostTimeoutOutput(result, state);
249
- if (this.shouldRetryContextLoss(result, state, useResume, nativeTimeouts, maxRetries, promptWithAttachments))
250
- continue;
251
- if (this.applyToolTimeoutRetry(state, maxRetries, promptWithAttachments))
252
- continue;
253
- break;
238
+ let result = await this.runRetryLoop(state, sequenceNumber, promptWithAttachments, imageAttachments, options?.sandboxed, options?.workingDir);
239
+ // If cancelled, emit a minimal movement and return early
240
+ if (this._cancelled) {
241
+ return this.handleCancelledExecution(result, userPrompt, sequenceNumber, _execStart);
254
242
  }
255
243
  if (state.contextLost)
256
244
  this.claudeSessionId = undefined;
245
+ // result is guaranteed assigned here: the loop always runs at least once (if _cancelled was
246
+ // true before the loop, we returned in the block above; otherwise runner.run() assigned it).
257
247
  result = await this.selectBestResult(state, result, userPrompt);
258
248
  this.captureSessionAndSurfaceErrors(result);
259
249
  this.isFirstPrompt = false;
260
- const movement = this.buildMovementRecord(result, userPrompt, sequenceNumber, _execStart);
250
+ const movement = this.buildMovementRecord(result, userPrompt, sequenceNumber, _execStart, state.retryLog);
261
251
  this.handleConflicts(result);
262
252
  this.persistMovement(movement);
263
253
  this._isExecuting = false;
@@ -287,6 +277,70 @@ export class ImprovisationSessionManager extends EventEmitter {
287
277
  }
288
278
  }
289
279
  // ========== Extracted helpers for executePrompt ==========
280
+ handleCancelledExecution(result, userPrompt, sequenceNumber, execStart) {
281
+ this._isExecuting = false;
282
+ this._executionStartTimestamp = undefined;
283
+ this.executionEventLog = [];
284
+ this.currentRunner = null;
285
+ const cancelledMovement = {
286
+ id: `prompt-${sequenceNumber}`,
287
+ sequenceNumber,
288
+ userPrompt,
289
+ timestamp: new Date().toISOString(),
290
+ tokensUsed: result ? result.totalTokens : 0,
291
+ summary: '',
292
+ filesModified: [],
293
+ assistantResponse: result?.assistantResponse,
294
+ thinkingOutput: result?.thinkingOutput,
295
+ toolUseHistory: result?.toolUseHistory?.map(t => ({
296
+ toolName: t.toolName,
297
+ toolId: t.toolId,
298
+ toolInput: t.toolInput,
299
+ result: t.result,
300
+ })),
301
+ errorOutput: 'Execution cancelled by user',
302
+ durationMs: Date.now() - execStart,
303
+ };
304
+ this.persistMovement(cancelledMovement);
305
+ const fallbackResult = {
306
+ completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
307
+ output: '', exitCode: 1, signalName: 'SIGTERM',
308
+ };
309
+ this.emitMovementComplete(cancelledMovement, result ?? fallbackResult, execStart, sequenceNumber);
310
+ return cancelledMovement;
311
+ }
312
+ async runRetryLoop(state, sequenceNumber, promptWithAttachments, imageAttachments, sandboxed, workingDirOverride) {
313
+ const maxRetries = 3;
314
+ let result;
315
+ // eslint-disable-next-line no-constant-condition
316
+ while (true) {
317
+ if (this._cancelled)
318
+ break;
319
+ this.resetIterationState(state);
320
+ const { useResume, resumeSessionId } = this.determineResumeStrategy(state);
321
+ const runner = this.createExecutionRunner(state, sequenceNumber, useResume, resumeSessionId, imageAttachments, sandboxed, workingDirOverride);
322
+ this.currentRunner = runner;
323
+ result = await runner.run();
324
+ this.currentRunner = null;
325
+ if (this._cancelled)
326
+ break;
327
+ this.updateBestResult(state, result);
328
+ const nativeTimeouts = result.nativeTimeoutCount ?? 0;
329
+ this.detectResumeContextLoss(result, state, useResume, maxRetries, nativeTimeouts);
330
+ await this.detectNativeTimeoutContextLoss(result, state, maxRetries, nativeTimeouts);
331
+ this.flushPostTimeoutOutput(result, state);
332
+ // Signal crashes checked first: they use --resume (lighter), and context loss
333
+ // recovery would clear the session ID, preventing future --resume attempts.
334
+ if (this.shouldRetrySignalCrash(result, state, maxRetries, promptWithAttachments))
335
+ continue;
336
+ if (this.shouldRetryContextLoss(result, state, useResume, nativeTimeouts, maxRetries, promptWithAttachments))
337
+ continue;
338
+ if (this.applyToolTimeoutRetry(state, maxRetries, promptWithAttachments))
339
+ continue;
340
+ break;
341
+ }
342
+ return result;
343
+ }
290
344
  /** Prepare prompt with attachments and limit image count */
291
345
  preparePromptAndAttachments(userPrompt, attachments) {
292
346
  const diskPaths = attachments ? this.persistAttachments(attachments) : [];
@@ -321,9 +375,9 @@ export class ImprovisationSessionManager extends EventEmitter {
321
375
  return { useResume: false, resumeSessionId: undefined };
322
376
  }
323
377
  /** Create HeadlessRunner for one retry iteration */
324
- createExecutionRunner(state, sequenceNumber, useResume, resumeSessionId, imageAttachments, sandboxed) {
378
+ createExecutionRunner(state, sequenceNumber, useResume, resumeSessionId, imageAttachments, sandboxed, workingDirOverride) {
325
379
  return new HeadlessRunner({
326
- workingDir: this.options.workingDir,
380
+ workingDir: workingDirOverride || this.options.workingDir,
327
381
  tokenBudgetThreshold: this.options.tokenBudgetThreshold,
328
382
  maxSessions: this.options.maxSessions,
329
383
  verbose: this.options.verbose,
@@ -348,6 +402,9 @@ export class ImprovisationSessionManager extends EventEmitter {
348
402
  this.emit('onToolUse', event);
349
403
  this.flushOutputQueue();
350
404
  },
405
+ tokenUsageCallback: (usage) => {
406
+ this.emit('onTokenUsage', usage);
407
+ },
351
408
  directPrompt: state.currentPrompt,
352
409
  imageAttachments,
353
410
  promptContext: (state.retryNumber === 0 && this.isResumedSession && this.isFirstPrompt)
@@ -399,7 +456,16 @@ export class ImprovisationSessionManager extends EventEmitter {
399
456
  async detectNativeTimeoutContextLoss(result, state, maxRetries, nativeTimeouts) {
400
457
  if (state.contextLost)
401
458
  return;
402
- const toolsWithoutResult = result.toolUseHistory?.filter(t => t.result === undefined).length ?? 0;
459
+ // Deduplicate by toolId: if a toolId has at least one entry with a result,
460
+ // its orphaned duplicates are Claude Code internal retries, not actual timeouts.
461
+ const succeededIds = new Set();
462
+ const allIds = new Set();
463
+ for (const t of result.toolUseHistory ?? []) {
464
+ allIds.add(t.toolId);
465
+ if (t.result !== undefined)
466
+ succeededIds.add(t.toolId);
467
+ }
468
+ const toolsWithoutResult = [...allIds].filter(id => !succeededIds.has(id)).length;
403
469
  const effectiveTimeouts = Math.max(nativeTimeouts, toolsWithoutResult);
404
470
  if (effectiveTimeouts === 0 || !result.assistantResponse || state.checkpointRef.value || state.retryNumber >= maxRetries) {
405
471
  return;
@@ -434,6 +500,13 @@ export class ImprovisationSessionManager extends EventEmitter {
434
500
  }
435
501
  this.accumulateToolResults(result, state);
436
502
  state.retryNumber++;
503
+ const path = (useResume && nativeTimeouts === 0) ? 'InterMovementRecovery' : 'NativeTimeoutRecovery';
504
+ state.retryLog.push({
505
+ retryNumber: state.retryNumber,
506
+ path,
507
+ reason: `Context lost (${nativeTimeouts} timeouts, ${state.accumulatedToolResults.length} tools preserved)`,
508
+ timestamp: Date.now(),
509
+ });
437
510
  if (useResume && nativeTimeouts === 0) {
438
511
  this.applyInterMovementRecovery(state, promptWithAttachments);
439
512
  }
@@ -442,7 +515,10 @@ export class ImprovisationSessionManager extends EventEmitter {
442
515
  }
443
516
  return true;
444
517
  }
445
- /** Accumulate completed tool results from a run into the retry state */
518
+ /** Accumulate completed tool results from a run into the retry state.
519
+ * Caps at MAX_ACCUMULATED_RESULTS to prevent recovery prompts from exceeding context limits.
520
+ * When the cap is reached, older results are evicted (FIFO) to make room for newer ones. */
521
+ static MAX_ACCUMULATED_RESULTS = 50;
446
522
  accumulateToolResults(result, state) {
447
523
  if (!result.toolUseHistory)
448
524
  return;
@@ -458,10 +534,17 @@ export class ImprovisationSessionManager extends EventEmitter {
458
534
  });
459
535
  }
460
536
  }
537
+ // Evict oldest results if over the cap
538
+ const cap = ImprovisationSessionManager.MAX_ACCUMULATED_RESULTS;
539
+ if (state.accumulatedToolResults.length > cap) {
540
+ state.accumulatedToolResults = state.accumulatedToolResults.slice(-cap);
541
+ }
461
542
  }
462
543
  /** Handle inter-movement context loss recovery (resume session expired) */
463
544
  applyInterMovementRecovery(state, promptWithAttachments) {
464
- this.claudeSessionId = undefined;
545
+ // Preserve session ID so --resume remains available on subsequent retries.
546
+ // The fresh recovery prompt will be used, but if this attempt also fails,
547
+ // the next retry can still try --resume via shouldRetrySignalCrash.
465
548
  const historicalResults = this.extractHistoricalToolResults();
466
549
  const allResults = [...historicalResults, ...state.accumulatedToolResults];
467
550
  this.emit('onAutoRetry', {
@@ -495,7 +578,7 @@ export class ImprovisationSessionManager extends EventEmitter {
495
578
  this.queueOutput(`\n[[MSTRO_CONTEXT_RECOVERY]] Continuing with fresh context — ${completedCount} preserved results injected (retry ${state.retryNumber}/3).\n`);
496
579
  this.flushOutputQueue();
497
580
  state.freshRecoveryMode = true;
498
- state.currentPrompt = this.buildFreshRecoveryPrompt(promptWithAttachments, state.accumulatedToolResults);
581
+ state.currentPrompt = this.buildFreshRecoveryPrompt(promptWithAttachments, state.accumulatedToolResults, state.timedOutTools);
499
582
  }
500
583
  }
501
584
  /** Handle tool timeout checkpoint. Returns true if loop should continue. */
@@ -511,6 +594,12 @@ export class ImprovisationSessionManager extends EventEmitter {
511
594
  timeoutMs: cp.hungTool.timeoutMs,
512
595
  });
513
596
  const canResumeSession = cp.inProgressTools.length === 0 && !!cp.claudeSessionId;
597
+ state.retryLog.push({
598
+ retryNumber: state.retryNumber,
599
+ path: 'ToolTimeout',
600
+ reason: `${cp.hungTool.toolName} timed out after ${cp.hungTool.timeoutMs}ms, ${cp.completedTools.length} tools completed, ${canResumeSession ? 'resuming' : 'fresh start'}`,
601
+ timestamp: Date.now(),
602
+ });
514
603
  this.emit('onAutoRetry', {
515
604
  retryNumber: state.retryNumber,
516
605
  maxRetries,
@@ -533,6 +622,104 @@ export class ImprovisationSessionManager extends EventEmitter {
533
622
  this.flushOutputQueue();
534
623
  return true;
535
624
  }
625
+ /**
626
+ * Detect and retry after a signal crash (e.g., SIGTERM exit code 143).
627
+ * When the Claude process is killed externally (OOM, system signal, internal timeout
628
+ * that bypasses our watchdog), no existing recovery path catches it because contextLost
629
+ * is never set and no checkpoint is created. This adds a dedicated recovery path.
630
+ */
631
+ shouldRetrySignalCrash(result, state, maxRetries, promptWithAttachments) {
632
+ // Only trigger for signal-killed processes (exit code 128+) that weren't already
633
+ // handled by context-loss or tool-timeout recovery paths.
634
+ // Must have an actual signal name — regular errors (e.g., auth failures, exit code 1)
635
+ // should NOT be retried as signal crashes.
636
+ const isSignalCrash = !!result.signalName;
637
+ const exitCodeSignal = !result.completed && !result.signalName && result.error?.match(/exited with code (1[2-9]\d|[2-9]\d{2})/);
638
+ if ((!isSignalCrash && !exitCodeSignal) || state.retryNumber >= maxRetries) {
639
+ return false;
640
+ }
641
+ // Don't re-trigger if tool timeout watchdog already handled this iteration
642
+ // (contextLost is NOT checked here — signal crash takes priority over context loss
643
+ // because it uses --resume which is lighter and avoids re-sending accumulated results)
644
+ if (state.checkpointRef.value) {
645
+ return false;
646
+ }
647
+ this.accumulateToolResults(result, state);
648
+ state.retryNumber++;
649
+ const completedCount = state.accumulatedToolResults.length;
650
+ const signalInfo = result.signalName || 'unknown signal';
651
+ const useResume = !!result.claudeSessionId && state.retryNumber === 1;
652
+ state.retryLog.push({
653
+ retryNumber: state.retryNumber,
654
+ path: 'SignalCrash',
655
+ reason: `Process killed (${signalInfo}), ${completedCount} tools preserved, ${useResume ? 'resuming' : 'fresh start'}`,
656
+ timestamp: Date.now(),
657
+ });
658
+ this.emit('onAutoRetry', {
659
+ retryNumber: state.retryNumber,
660
+ maxRetries,
661
+ toolName: `SignalCrash(${signalInfo})`,
662
+ completedCount,
663
+ });
664
+ trackEvent(AnalyticsEvents.IMPROVISE_AUTO_RETRY, {
665
+ retry_number: state.retryNumber,
666
+ hung_tool: `signal_crash:${signalInfo}`,
667
+ completed_tools: completedCount,
668
+ resume_attempted: useResume,
669
+ });
670
+ // If we have a session ID, try resuming first (preserves full context)
671
+ if (useResume) {
672
+ this.queueOutput(`\n[[MSTRO_SIGNAL_RECOVERY]] Process killed (${signalInfo}) — resuming session with ${completedCount} preserved results (retry ${state.retryNumber}/${maxRetries}).\n`);
673
+ this.flushOutputQueue();
674
+ state.contextRecoverySessionId = result.claudeSessionId;
675
+ this.claudeSessionId = result.claudeSessionId;
676
+ state.currentPrompt = this.buildSignalCrashRecoveryPrompt(promptWithAttachments, true);
677
+ }
678
+ else {
679
+ // Fresh start with accumulated results injected
680
+ this.queueOutput(`\n[[MSTRO_SIGNAL_RECOVERY]] Process killed (${signalInfo}) — restarting with ${completedCount} preserved results (retry ${state.retryNumber}/${maxRetries}).\n`);
681
+ this.flushOutputQueue();
682
+ state.freshRecoveryMode = true;
683
+ const allResults = [...this.extractHistoricalToolResults(), ...state.accumulatedToolResults];
684
+ state.currentPrompt = this.buildSignalCrashRecoveryPrompt(promptWithAttachments, false, allResults);
685
+ }
686
+ return true;
687
+ }
688
+ /** Build a recovery prompt after signal crash */
689
+ buildSignalCrashRecoveryPrompt(originalPrompt, isResume, toolResults) {
690
+ const parts = [];
691
+ if (isResume) {
692
+ parts.push('Your previous execution was interrupted by a system signal (the process was killed externally).');
693
+ parts.push('Your full conversation history is preserved — including all successful tool results.');
694
+ parts.push('');
695
+ parts.push('Review your conversation history above and continue from where you left off.');
696
+ }
697
+ else {
698
+ parts.push('## AUTOMATIC RETRY — Previous Execution Interrupted');
699
+ parts.push('');
700
+ parts.push('The previous execution was interrupted by a system signal (process killed).');
701
+ if (toolResults && toolResults.length > 0) {
702
+ parts.push(`${toolResults.length} tool results were preserved from prior work.`);
703
+ parts.push('');
704
+ parts.push('### Preserved results:');
705
+ for (const t of toolResults.slice(-20)) {
706
+ const inputSummary = JSON.stringify(t.toolInput).slice(0, 120);
707
+ const resultPreview = (t.result ?? '').slice(0, 200);
708
+ parts.push(`- **${t.toolName}**(${inputSummary}): ${resultPreview}`);
709
+ }
710
+ }
711
+ }
712
+ parts.push('');
713
+ parts.push('### Original task:');
714
+ parts.push(originalPrompt);
715
+ parts.push('');
716
+ parts.push('INSTRUCTIONS:');
717
+ parts.push('1. Use the results above -- do not re-fetch content you already have');
718
+ parts.push('2. Continue from where you left off');
719
+ parts.push('3. Prefer multiple small, focused tool calls over single large ones');
720
+ parts.push('4. Do NOT spawn Task subagents — do work inline to avoid further interruptions');
721
+ return parts.join('\n');
722
+ }
536
723
  /** Select the best result across retries using Haiku assessment */
537
724
  async selectBestResult(state, result, userPrompt) {
538
725
  if (!state.bestResult || state.bestResult === result || state.retryNumber === 0) {
@@ -598,7 +785,7 @@ export class ImprovisationSessionManager extends EventEmitter {
598
785
  }
599
786
  }
600
787
  /** Build a MovementRecord from execution result */
601
- buildMovementRecord(result, userPrompt, sequenceNumber, execStart) {
788
+ buildMovementRecord(result, userPrompt, sequenceNumber, execStart, retryLog) {
602
789
  return {
603
790
  id: `prompt-${sequenceNumber}`,
604
791
  sequenceNumber,
@@ -619,6 +806,7 @@ export class ImprovisationSessionManager extends EventEmitter {
619
806
  })),
620
807
  errorOutput: result.error,
621
808
  durationMs: Date.now() - execStart,
809
+ retryLog: retryLog && retryLog.length > 0 ? retryLog : undefined,
622
810
  };
623
811
  }
624
812
  /** Handle file conflicts from execution result */
@@ -786,7 +974,7 @@ export class ImprovisationSessionManager extends EventEmitter {
786
974
  * Injects all accumulated tool results from previous attempts so Claude can continue
787
975
  * the task without re-fetching data it already gathered.
788
976
  */
789
- buildFreshRecoveryPrompt(originalPrompt, toolResults) {
977
+ buildFreshRecoveryPrompt(originalPrompt, toolResults, timedOutTools) {
790
978
  const parts = [
791
979
  '## CONTINUING LONG-RUNNING TASK',
792
980
  '',
@@ -794,6 +982,9 @@ export class ImprovisationSessionManager extends EventEmitter {
794
982
  'Below are all results gathered before the interruption. Continue the task using these results.',
795
983
  '',
796
984
  ];
985
+ if (timedOutTools && timedOutTools.length > 0) {
986
+ parts.push(...this.formatTimedOutTools(timedOutTools), '');
987
+ }
797
988
  parts.push(...this.formatToolResults(toolResults));
798
989
  parts.push('### Original task:');
799
990
  parts.push(originalPrompt);
@@ -975,6 +1166,7 @@ export class ImprovisationSessionManager extends EventEmitter {
975
1166
  * Cancel current execution
976
1167
  */
977
1168
  cancel() {
1169
+ this._cancelled = true;
978
1170
  if (this.currentRunner) {
979
1171
  this.currentRunner.cleanup();
980
1172
  this.currentRunner = null;