mstro-app 0.4.52 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +129 -190
- package/PRIVACY.md +3 -3
- package/README.md +15 -6
- package/bin/commands/config.js +0 -1
- package/bin/mstro.js +1 -2
- package/bin/postinstall.js +0 -1
- package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-process.js +0 -1
- package/dist/server/cli/headless/claude-invoker-process.js.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stall.js +7 -3
- package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stream.js +0 -1
- package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
- package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-tools.js +0 -1
- package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -1
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +1 -2
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.js +0 -1
- package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
- package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
- package/dist/server/cli/headless/headless-logger.js +0 -1
- package/dist/server/cli/headless/headless-logger.js.map +1 -1
- package/dist/server/cli/headless/index.d.ts.map +1 -1
- package/dist/server/cli/headless/index.js +0 -1
- package/dist/server/cli/headless/index.js.map +1 -1
- package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -1
- package/dist/server/cli/headless/native-timeout-detector.js +0 -1
- package/dist/server/cli/headless/native-timeout-detector.js.map +1 -1
- package/dist/server/cli/headless/output-utils.d.ts.map +1 -1
- package/dist/server/cli/headless/output-utils.js +0 -1
- package/dist/server/cli/headless/output-utils.js.map +1 -1
- package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -1
- package/dist/server/cli/headless/prompt-utils.js +0 -1
- package/dist/server/cli/headless/prompt-utils.js.map +1 -1
- package/dist/server/cli/headless/resilient-runner.d.ts.map +1 -1
- package/dist/server/cli/headless/resilient-runner.js +0 -1
- package/dist/server/cli/headless/resilient-runner.js.map +1 -1
- package/dist/server/cli/headless/retry-strategies.d.ts.map +1 -1
- package/dist/server/cli/headless/retry-strategies.js +0 -1
- package/dist/server/cli/headless/retry-strategies.js.map +1 -1
- package/dist/server/cli/headless/runner.d.ts.map +1 -1
- package/dist/server/cli/headless/runner.js +63 -68
- package/dist/server/cli/headless/runner.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +9 -5
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +0 -1
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/headless/types.js +0 -1
- package/dist/server/cli/headless/types.js.map +1 -1
- package/dist/server/cli/improvisation-attachments.d.ts.map +1 -1
- package/dist/server/cli/improvisation-attachments.js +0 -1
- package/dist/server/cli/improvisation-attachments.js.map +1 -1
- package/dist/server/cli/improvisation-history-store.d.ts +16 -0
- package/dist/server/cli/improvisation-history-store.d.ts.map +1 -0
- package/dist/server/cli/improvisation-history-store.js +51 -0
- package/dist/server/cli/improvisation-history-store.js.map +1 -0
- package/dist/server/cli/improvisation-movements.d.ts +31 -0
- package/dist/server/cli/improvisation-movements.d.ts.map +1 -0
- package/dist/server/cli/improvisation-movements.js +92 -0
- package/dist/server/cli/improvisation-movements.js.map +1 -0
- package/dist/server/cli/improvisation-output-queue.d.ts +13 -0
- package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -0
- package/dist/server/cli/improvisation-output-queue.js +39 -0
- package/dist/server/cli/improvisation-output-queue.js.map +1 -0
- package/dist/server/cli/improvisation-retry.d.ts +21 -51
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
- package/dist/server/cli/improvisation-retry.js +18 -434
- package/dist/server/cli/improvisation-retry.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +10 -8
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +53 -149
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/improvisation-types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-types.js +0 -1
- package/dist/server/cli/improvisation-types.js.map +1 -1
- package/dist/server/cli/retry/retry-best-result.d.ts +4 -0
- package/dist/server/cli/retry/retry-best-result.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-best-result.js +60 -0
- package/dist/server/cli/retry/retry-best-result.js.map +1 -0
- package/dist/server/cli/retry/retry-context-loss.d.ts +6 -0
- package/dist/server/cli/retry/retry-context-loss.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-context-loss.js +67 -0
- package/dist/server/cli/retry/retry-context-loss.js.map +1 -0
- package/dist/server/cli/retry/retry-premature-completion.d.ts +5 -0
- package/dist/server/cli/retry/retry-premature-completion.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-premature-completion.js +80 -0
- package/dist/server/cli/retry/retry-premature-completion.js.map +1 -0
- package/dist/server/cli/retry/retry-recovery-strategies.d.ts +13 -0
- package/dist/server/cli/retry/retry-recovery-strategies.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-recovery-strategies.js +165 -0
- package/dist/server/cli/retry/retry-recovery-strategies.js.map +1 -0
- package/dist/server/cli/retry/retry-resume-strategy.d.ts +12 -0
- package/dist/server/cli/retry/retry-resume-strategy.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-resume-strategy.js +21 -0
- package/dist/server/cli/retry/retry-resume-strategy.js.map +1 -0
- package/dist/server/cli/retry/retry-runner-factory.d.ts +11 -0
- package/dist/server/cli/retry/retry-runner-factory.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-runner-factory.js +59 -0
- package/dist/server/cli/retry/retry-runner-factory.js.map +1 -0
- package/dist/server/cli/retry/retry-tool-results.d.ts +9 -0
- package/dist/server/cli/retry/retry-tool-results.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-tool-results.js +23 -0
- package/dist/server/cli/retry/retry-tool-results.js.map +1 -0
- package/dist/server/cli/retry/retry-types.d.ts +30 -0
- package/dist/server/cli/retry/retry-types.d.ts.map +1 -0
- package/dist/server/cli/retry/retry-types.js +3 -0
- package/dist/server/cli/retry/retry-types.js.map +1 -0
- package/dist/server/index.js +21 -110
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-cli.js +0 -1
- package/dist/server/mcp/bouncer-cli.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-haiku.js +0 -1
- package/dist/server/mcp/bouncer-haiku.js.map +1 -1
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +0 -1
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-analysis.d.ts.map +1 -1
- package/dist/server/mcp/security-analysis.js +0 -1
- package/dist/server/mcp/security-analysis.js.map +1 -1
- package/dist/server/mcp/security-audit.d.ts.map +1 -1
- package/dist/server/mcp/security-audit.js +0 -1
- package/dist/server/mcp/security-audit.js.map +1 -1
- package/dist/server/mcp/security-patterns.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.js +0 -1
- package/dist/server/mcp/security-patterns.js.map +1 -1
- package/dist/server/mcp/server.js +0 -1
- package/dist/server/mcp/server.js.map +1 -1
- package/dist/server/routes/files.d.ts.map +1 -1
- package/dist/server/routes/files.js +0 -1
- package/dist/server/routes/files.js.map +1 -1
- package/dist/server/routes/improvise.d.ts.map +1 -1
- package/dist/server/routes/improvise.js +0 -1
- package/dist/server/routes/improvise.js.map +1 -1
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +0 -1
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/instances.d.ts.map +1 -1
- package/dist/server/routes/instances.js +0 -1
- package/dist/server/routes/instances.js.map +1 -1
- package/dist/server/routes/notifications.d.ts.map +1 -1
- package/dist/server/routes/notifications.js +0 -1
- package/dist/server/routes/notifications.js.map +1 -1
- package/dist/server/server-setup.d.ts +16 -1
- package/dist/server/server-setup.d.ts.map +1 -1
- package/dist/server/server-setup.js +107 -1
- package/dist/server/server-setup.js.map +1 -1
- package/dist/server/services/analytics.d.ts.map +1 -1
- package/dist/server/services/analytics.js +0 -1
- package/dist/server/services/analytics.js.map +1 -1
- package/dist/server/services/auth.d.ts.map +1 -1
- package/dist/server/services/auth.js +0 -1
- package/dist/server/services/auth.js.map +1 -1
- package/dist/server/services/client-id.d.ts.map +1 -1
- package/dist/server/services/client-id.js +0 -1
- package/dist/server/services/client-id.js.map +1 -1
- package/dist/server/services/file-explorer-ops.d.ts.map +1 -1
- package/dist/server/services/file-explorer-ops.js +0 -1
- package/dist/server/services/file-explorer-ops.js.map +1 -1
- package/dist/server/services/files.d.ts.map +1 -1
- package/dist/server/services/files.js +0 -1
- package/dist/server/services/files.js.map +1 -1
- package/dist/server/services/instances.d.ts.map +1 -1
- package/dist/server/services/instances.js +0 -1
- package/dist/server/services/instances.js.map +1 -1
- package/dist/server/services/pathUtils.d.ts.map +1 -1
- package/dist/server/services/pathUtils.js +0 -1
- package/dist/server/services/pathUtils.js.map +1 -1
- package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
- package/dist/server/services/plan/agent-loader.js +0 -1
- package/dist/server/services/plan/agent-loader.js.map +1 -1
- package/dist/server/services/plan/board-config.d.ts +21 -0
- package/dist/server/services/plan/board-config.d.ts.map +1 -0
- package/dist/server/services/plan/board-config.js +111 -0
- package/dist/server/services/plan/board-config.js.map +1 -0
- package/dist/server/services/plan/composer.d.ts +1 -1
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +7 -6
- package/dist/server/services/plan/composer.js.map +1 -1
- package/dist/server/services/plan/config-installer.d.ts.map +1 -1
- package/dist/server/services/plan/config-installer.js +0 -1
- package/dist/server/services/plan/config-installer.js.map +1 -1
- package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
- package/dist/server/services/plan/dependency-resolver.js +0 -1
- package/dist/server/services/plan/dependency-resolver.js.map +1 -1
- package/dist/server/services/plan/executor.d.ts +48 -48
- package/dist/server/services/plan/executor.d.ts.map +1 -1
- package/dist/server/services/plan/executor.js +202 -458
- package/dist/server/services/plan/executor.js.map +1 -1
- package/dist/server/services/plan/front-matter.d.ts.map +1 -1
- package/dist/server/services/plan/front-matter.js +0 -1
- package/dist/server/services/plan/front-matter.js.map +1 -1
- package/dist/server/services/plan/issue-classification.d.ts.map +1 -1
- package/dist/server/services/plan/issue-classification.js +0 -1
- package/dist/server/services/plan/issue-classification.js.map +1 -1
- package/dist/server/services/plan/issue-loader.d.ts +16 -0
- package/dist/server/services/plan/issue-loader.d.ts.map +1 -0
- package/dist/server/services/plan/issue-loader.js +45 -0
- package/dist/server/services/plan/issue-loader.js.map +1 -0
- package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
- package/dist/server/services/plan/issue-prompt-builder.js +0 -1
- package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
- package/dist/server/services/plan/issue-retry.d.ts +3 -1
- package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
- package/dist/server/services/plan/issue-retry.js +2 -1
- package/dist/server/services/plan/issue-retry.js.map +1 -1
- package/dist/server/services/plan/issue-writer.d.ts +34 -0
- package/dist/server/services/plan/issue-writer.d.ts.map +1 -0
- package/dist/server/services/plan/issue-writer.js +109 -0
- package/dist/server/services/plan/issue-writer.js.map +1 -0
- package/dist/server/services/plan/output-manager.js +2 -2
- package/dist/server/services/plan/output-manager.js.map +1 -1
- package/dist/server/services/plan/parser-core.d.ts.map +1 -1
- package/dist/server/services/plan/parser-core.js +0 -1
- package/dist/server/services/plan/parser-core.js.map +1 -1
- package/dist/server/services/plan/parser-migration.d.ts.map +1 -1
- package/dist/server/services/plan/parser-migration.js +0 -1
- package/dist/server/services/plan/parser-migration.js.map +1 -1
- package/dist/server/services/plan/parser.d.ts.map +1 -1
- package/dist/server/services/plan/parser.js +0 -1
- package/dist/server/services/plan/parser.js.map +1 -1
- package/dist/server/services/plan/progress-log.d.ts +11 -0
- package/dist/server/services/plan/progress-log.d.ts.map +1 -0
- package/dist/server/services/plan/progress-log.js +80 -0
- package/dist/server/services/plan/progress-log.js.map +1 -0
- package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
- package/dist/server/services/plan/prompt-builder.js +48 -32
- package/dist/server/services/plan/prompt-builder.js.map +1 -1
- package/dist/server/services/plan/readiness-planner.d.ts +15 -0
- package/dist/server/services/plan/readiness-planner.d.ts.map +1 -0
- package/dist/server/services/plan/readiness-planner.js +40 -0
- package/dist/server/services/plan/readiness-planner.js.map +1 -0
- package/dist/server/services/plan/review-gate.d.ts +31 -0
- package/dist/server/services/plan/review-gate.d.ts.map +1 -1
- package/dist/server/services/plan/review-gate.js +52 -3
- package/dist/server/services/plan/review-gate.js.map +1 -1
- package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
- package/dist/server/services/plan/state-reconciler.js +0 -1
- package/dist/server/services/plan/state-reconciler.js.map +1 -1
- package/dist/server/services/plan/types.d.ts.map +1 -1
- package/dist/server/services/plan/types.js +0 -1
- package/dist/server/services/plan/types.js.map +1 -1
- package/dist/server/services/plan/watcher.d.ts.map +1 -1
- package/dist/server/services/plan/watcher.js +0 -1
- package/dist/server/services/plan/watcher.js.map +1 -1
- package/dist/server/services/platform-credentials.d.ts.map +1 -1
- package/dist/server/services/platform-credentials.js +0 -1
- package/dist/server/services/platform-credentials.js.map +1 -1
- package/dist/server/services/platform-token-lifecycle.d.ts +70 -0
- package/dist/server/services/platform-token-lifecycle.d.ts.map +1 -0
- package/dist/server/services/platform-token-lifecycle.js +156 -0
- package/dist/server/services/platform-token-lifecycle.js.map +1 -0
- package/dist/server/services/platform.d.ts +25 -4
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +150 -92
- package/dist/server/services/platform.js.map +1 -1
- package/dist/server/services/sentry.d.ts.map +1 -1
- package/dist/server/services/sentry.js +0 -1
- package/dist/server/services/sentry.js.map +1 -1
- package/dist/server/services/settings.d.ts.map +1 -1
- package/dist/server/services/settings.js +0 -1
- package/dist/server/services/settings.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +0 -1
- package/dist/server/services/terminal/pty-manager.js.map +1 -1
- package/dist/server/services/terminal/pty-utils.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-utils.js +0 -1
- package/dist/server/services/terminal/pty-utils.js.map +1 -1
- package/dist/server/services/websocket/autocomplete.d.ts.map +1 -1
- package/dist/server/services/websocket/autocomplete.js +0 -1
- package/dist/server/services/websocket/autocomplete.js.map +1 -1
- package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/file-definition-handlers.js +0 -1
- package/dist/server/services/websocket/file-definition-handlers.js.map +1 -1
- package/dist/server/services/websocket/file-download-handler.d.ts +17 -0
- package/dist/server/services/websocket/file-download-handler.d.ts.map +1 -0
- package/dist/server/services/websocket/file-download-handler.js +164 -0
- package/dist/server/services/websocket/file-download-handler.js.map +1 -0
- package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/file-explorer-handlers.js +0 -1
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/file-search-handlers.js +0 -1
- package/dist/server/services/websocket/file-search-handlers.js.map +1 -1
- package/dist/server/services/websocket/file-upload-handler.d.ts +2 -3
- package/dist/server/services/websocket/file-upload-handler.d.ts.map +1 -1
- package/dist/server/services/websocket/file-upload-handler.js +4 -7
- package/dist/server/services/websocket/file-upload-handler.js.map +1 -1
- package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
- package/dist/server/services/websocket/file-utils.js +0 -1
- package/dist/server/services/websocket/file-utils.js.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.js +0 -1
- package/dist/server/services/websocket/git-branch-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-diff-handlers.js +0 -1
- package/dist/server/services/websocket/git-diff-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-handlers.js +58 -6
- package/dist/server/services/websocket/git-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-head-watcher.d.ts.map +1 -1
- package/dist/server/services/websocket/git-head-watcher.js +0 -1
- package/dist/server/services/websocket/git-head-watcher.js.map +1 -1
- package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-log-handlers.js +0 -1
- package/dist/server/services/websocket/git-log-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.js +0 -1
- package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-tag-handlers.js +0 -1
- package/dist/server/services/websocket/git-tag-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-utils.d.ts +18 -3
- package/dist/server/services/websocket/git-utils.d.ts.map +1 -1
- package/dist/server/services/websocket/git-utils.js +58 -8
- package/dist/server/services/websocket/git-utils.js.map +1 -1
- package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-worktree-handlers.js +258 -16
- package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler-context.d.ts +15 -0
- package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
- package/dist/server/services/websocket/handler-context.js +0 -1
- package/dist/server/services/websocket/handler-context.js.map +1 -1
- package/dist/server/services/websocket/handler.d.ts +7 -0
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +76 -15
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/index.d.ts.map +1 -1
- package/dist/server/services/websocket/index.js +0 -1
- package/dist/server/services/websocket/index.js.map +1 -1
- package/dist/server/services/websocket/msg-id-tracker.d.ts +21 -0
- package/dist/server/services/websocket/msg-id-tracker.d.ts.map +1 -0
- package/dist/server/services/websocket/msg-id-tracker.js +76 -0
- package/dist/server/services/websocket/msg-id-tracker.js.map +1 -0
- package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.js +0 -1
- package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-execution-handlers.js +6 -2
- package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-handlers.js +0 -1
- package/dist/server/services/websocket/plan-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-helpers.js +0 -1
- package/dist/server/services/websocket/plan-helpers.js.map +1 -1
- package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-issue-handlers.js +0 -1
- package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-sprint-handlers.js +0 -1
- package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-complexity.js +0 -1
- package/dist/server/services/websocket/quality-complexity.js.map +1 -1
- package/dist/server/services/websocket/quality-grading.d.ts +46 -0
- package/dist/server/services/websocket/quality-grading.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-grading.js +482 -0
- package/dist/server/services/websocket/quality-grading.js.map +1 -0
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +15 -4
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-linting.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-linting.js +0 -1
- package/dist/server/services/websocket/quality-linting.js.map +1 -1
- package/dist/server/services/websocket/quality-persistence.d.ts +14 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-persistence.js +28 -12
- package/dist/server/services/websocket/quality-persistence.js.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.js +2 -3
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-service.d.ts +3 -1
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +53 -58
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-tools.js +6 -3
- package/dist/server/services/websocket/quality-tools.js.map +1 -1
- package/dist/server/services/websocket/quality-types.d.ts +18 -2
- package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-types.js +0 -1
- package/dist/server/services/websocket/quality-types.js.map +1 -1
- package/dist/server/services/websocket/session-handlers.d.ts +48 -2
- package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +204 -66
- package/dist/server/services/websocket/session-handlers.js.map +1 -1
- package/dist/server/services/websocket/session-history.d.ts.map +1 -1
- package/dist/server/services/websocket/session-history.js +0 -1
- package/dist/server/services/websocket/session-history.js.map +1 -1
- package/dist/server/services/websocket/session-initialization.d.ts +2 -2
- package/dist/server/services/websocket/session-initialization.d.ts.map +1 -1
- package/dist/server/services/websocket/session-initialization.js +75 -18
- package/dist/server/services/websocket/session-initialization.js.map +1 -1
- package/dist/server/services/websocket/session-registry.d.ts +29 -1
- package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
- package/dist/server/services/websocket/session-registry.js +53 -5
- package/dist/server/services/websocket/session-registry.js.map +1 -1
- package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/settings-handlers.js +0 -1
- package/dist/server/services/websocket/settings-handlers.js.map +1 -1
- package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/skill-handlers.js +0 -1
- package/dist/server/services/websocket/skill-handlers.js.map +1 -1
- package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -1
- package/dist/server/services/websocket/skill-watcher.js +0 -1
- package/dist/server/services/websocket/skill-watcher.js.map +1 -1
- package/dist/server/services/websocket/tab-broadcast.d.ts +24 -0
- package/dist/server/services/websocket/tab-broadcast.d.ts.map +1 -0
- package/dist/server/services/websocket/tab-broadcast.js +12 -0
- package/dist/server/services/websocket/tab-broadcast.js.map +1 -0
- package/dist/server/services/websocket/tab-event-buffer.d.ts +103 -0
- package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -0
- package/dist/server/services/websocket/tab-event-buffer.js +106 -0
- package/dist/server/services/websocket/tab-event-buffer.js.map +1 -0
- package/dist/server/services/websocket/tab-event-replay.d.ts +20 -0
- package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -0
- package/dist/server/services/websocket/tab-event-replay.js +20 -0
- package/dist/server/services/websocket/tab-event-replay.js.map +1 -0
- package/dist/server/services/websocket/tab-handlers.d.ts +0 -1
- package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-handlers.js +2 -10
- package/dist/server/services/websocket/tab-handlers.js.map +1 -1
- package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/terminal-handlers.js +39 -4
- package/dist/server/services/websocket/terminal-handlers.js.map +1 -1
- package/dist/server/services/websocket/types.d.ts +17 -8
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/services/websocket/types.js +8 -7
- package/dist/server/services/websocket/types.js.map +1 -1
- package/dist/server/utils/agent-manager.d.ts.map +1 -1
- package/dist/server/utils/agent-manager.js +0 -1
- package/dist/server/utils/agent-manager.js.map +1 -1
- package/dist/server/utils/paths.d.ts.map +1 -1
- package/dist/server/utils/paths.js +0 -1
- package/dist/server/utils/paths.js.map +1 -1
- package/dist/server/utils/port-manager.d.ts.map +1 -1
- package/dist/server/utils/port-manager.js +0 -1
- package/dist/server/utils/port-manager.js.map +1 -1
- package/dist/server/utils/port.d.ts.map +1 -1
- package/dist/server/utils/port.js +0 -1
- package/dist/server/utils/port.js.map +1 -1
- package/package.json +2 -2
- package/server/README.md +1 -1
- package/server/cli/headless/claude-invoker-process.ts +0 -1
- package/server/cli/headless/claude-invoker-stall.ts +7 -3
- package/server/cli/headless/claude-invoker-stream.ts +0 -1
- package/server/cli/headless/claude-invoker-tools.ts +0 -1
- package/server/cli/headless/claude-invoker.ts +1 -2
- package/server/cli/headless/haiku-assessments.ts +0 -1
- package/server/cli/headless/headless-logger.ts +0 -1
- package/server/cli/headless/index.ts +0 -1
- package/server/cli/headless/native-timeout-detector.ts +0 -1
- package/server/cli/headless/output-utils.ts +0 -1
- package/server/cli/headless/prompt-utils.ts +0 -1
- package/server/cli/headless/resilient-runner.ts +0 -1
- package/server/cli/headless/retry-strategies.ts +0 -1
- package/server/cli/headless/runner.ts +67 -73
- package/server/cli/headless/stall-assessor.ts +9 -5
- package/server/cli/headless/tool-watchdog.ts +0 -1
- package/server/cli/headless/types.ts +1 -2
- package/server/cli/improvisation-attachments.ts +0 -1
- package/server/cli/improvisation-history-store.ts +61 -0
- package/server/cli/improvisation-movements.ts +119 -0
- package/server/cli/improvisation-output-queue.ts +41 -0
- package/server/cli/improvisation-retry.ts +25 -601
- package/server/cli/improvisation-session-manager.ts +74 -161
- package/server/cli/improvisation-types.ts +0 -1
- package/server/cli/retry/retry-best-result.ts +69 -0
- package/server/cli/retry/retry-context-loss.ts +86 -0
- package/server/cli/retry/retry-premature-completion.ts +112 -0
- package/server/cli/retry/retry-recovery-strategies.ts +246 -0
- package/server/cli/retry/retry-resume-strategy.ts +32 -0
- package/server/cli/retry/retry-runner-factory.ts +69 -0
- package/server/cli/retry/retry-tool-results.ts +30 -0
- package/server/cli/retry/retry-types.ts +31 -0
- package/server/index.ts +37 -124
- package/server/mcp/bouncer-cli.ts +0 -1
- package/server/mcp/bouncer-haiku.ts +0 -1
- package/server/mcp/bouncer-integration.ts +0 -1
- package/server/mcp/security-analysis.ts +0 -1
- package/server/mcp/security-audit.ts +0 -1
- package/server/mcp/security-patterns.ts +0 -1
- package/server/mcp/server.ts +0 -1
- package/server/routes/files.ts +0 -1
- package/server/routes/improvise.ts +0 -1
- package/server/routes/index.ts +0 -1
- package/server/routes/instances.ts +0 -1
- package/server/routes/notifications.ts +0 -1
- package/server/server-setup.ts +126 -2
- package/server/services/analytics.ts +0 -1
- package/server/services/auth.ts +0 -1
- package/server/services/client-id.ts +0 -1
- package/server/services/file-explorer-ops.ts +0 -1
- package/server/services/files.ts +0 -1
- package/server/services/instances.ts +0 -1
- package/server/services/pathUtils.ts +0 -1
- package/server/services/plan/agent-loader.ts +0 -1
- package/server/services/plan/agents/assess-stall.md +11 -4
- package/server/services/plan/agents/code-review.md +13 -11
- package/server/services/plan/board-config.ts +121 -0
- package/server/services/plan/composer.ts +7 -6
- package/server/services/plan/config-installer.ts +0 -1
- package/server/services/plan/dependency-resolver.ts +0 -1
- package/server/services/plan/executor.ts +259 -470
- package/server/services/plan/front-matter.ts +0 -1
- package/server/services/plan/issue-classification.ts +0 -1
- package/server/services/plan/issue-loader.ts +63 -0
- package/server/services/plan/issue-prompt-builder.ts +0 -1
- package/server/services/plan/issue-retry.ts +5 -2
- package/server/services/plan/issue-writer.ts +136 -0
- package/server/services/plan/output-manager.ts +2 -2
- package/server/services/plan/parser-core.ts +0 -1
- package/server/services/plan/parser-migration.ts +0 -1
- package/server/services/plan/parser.ts +0 -1
- package/server/services/plan/progress-log.ts +91 -0
- package/server/services/plan/prompt-builder.ts +73 -36
- package/server/services/plan/readiness-planner.ts +49 -0
- package/server/services/plan/review-gate.ts +102 -3
- package/server/services/plan/state-reconciler.ts +0 -1
- package/server/services/plan/types.ts +0 -1
- package/server/services/plan/watcher.ts +0 -1
- package/server/services/platform-credentials.ts +0 -1
- package/server/services/platform-token-lifecycle.ts +171 -0
- package/server/services/platform.ts +168 -105
- package/server/services/sentry.ts +0 -1
- package/server/services/settings.ts +0 -1
- package/server/services/terminal/pty-manager.ts +0 -1
- package/server/services/terminal/pty-utils.ts +0 -1
- package/server/services/websocket/autocomplete.ts +0 -1
- package/server/services/websocket/file-definition-handlers.ts +0 -1
- package/server/services/websocket/file-download-handler.ts +190 -0
- package/server/services/websocket/file-explorer-handlers.ts +0 -1
- package/server/services/websocket/file-search-handlers.ts +0 -1
- package/server/services/websocket/file-upload-handler.ts +6 -5
- package/server/services/websocket/file-utils.ts +0 -1
- package/server/services/websocket/git-branch-handlers.ts +0 -1
- package/server/services/websocket/git-diff-handlers.ts +0 -1
- package/server/services/websocket/git-handlers.ts +66 -10
- package/server/services/websocket/git-head-watcher.ts +0 -1
- package/server/services/websocket/git-log-handlers.ts +0 -1
- package/server/services/websocket/git-pr-handlers.ts +0 -1
- package/server/services/websocket/git-tag-handlers.ts +0 -1
- package/server/services/websocket/git-utils.ts +69 -9
- package/server/services/websocket/git-worktree-handlers.ts +289 -19
- package/server/services/websocket/handler-context.ts +15 -1
- package/server/services/websocket/handler.ts +79 -16
- package/server/services/websocket/index.ts +0 -1
- package/server/services/websocket/msg-id-tracker.ts +83 -0
- package/server/services/websocket/plan-board-handlers.ts +0 -1
- package/server/services/websocket/plan-execution-handlers.ts +6 -2
- package/server/services/websocket/plan-handlers.ts +0 -1
- package/server/services/websocket/plan-helpers.ts +0 -1
- package/server/services/websocket/plan-issue-handlers.ts +0 -1
- package/server/services/websocket/plan-sprint-handlers.ts +0 -1
- package/server/services/websocket/quality-complexity.ts +0 -1
- package/server/services/websocket/quality-grading.ts +611 -0
- package/server/services/websocket/quality-handlers.ts +16 -4
- package/server/services/websocket/quality-linting.ts +0 -1
- package/server/services/websocket/quality-persistence.ts +30 -8
- package/server/services/websocket/quality-review-agent.ts +2 -3
- package/server/services/websocket/quality-service.ts +54 -55
- package/server/services/websocket/quality-tools.ts +11 -3
- package/server/services/websocket/quality-types.ts +21 -3
- package/server/services/websocket/session-handlers.ts +213 -69
- package/server/services/websocket/session-history.ts +0 -1
- package/server/services/websocket/session-initialization.ts +83 -20
- package/server/services/websocket/session-registry.ts +61 -5
- package/server/services/websocket/settings-handlers.ts +0 -1
- package/server/services/websocket/skill-handlers.ts +0 -1
- package/server/services/websocket/skill-watcher.ts +0 -1
- package/server/services/websocket/tab-broadcast.ts +37 -0
- package/server/services/websocket/tab-event-buffer.ts +158 -0
- package/server/services/websocket/tab-event-replay.ts +41 -0
- package/server/services/websocket/tab-handlers.ts +2 -10
- package/server/services/websocket/terminal-handlers.ts +39 -3
- package/server/services/websocket/types.ts +19 -7
- package/server/utils/agent-manager.ts +0 -1
- package/server/utils/paths.ts +0 -1
- package/server/utils/port-manager.ts +0 -1
- package/server/utils/port.ts +0 -1
|
@@ -1,22 +1,41 @@
|
|
|
1
1
|
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
-
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Improvisation Session Manager v2
|
|
6
5
|
*
|
|
7
6
|
* Optimized for fast, direct prompt execution in Improvise mode.
|
|
8
7
|
* For complex multi-part prompts with parallel/sequential movements, use Compose tab instead.
|
|
8
|
+
*
|
|
9
|
+
* Delegates to focused helpers:
|
|
10
|
+
* - improvisation-output-queue.ts — buffered stdout flush loop
|
|
11
|
+
* - improvisation-history-store.ts — .mstro/history/*.json load/save
|
|
12
|
+
* - improvisation-movements.ts — pure movement-record builders
|
|
13
|
+
* - improvisation-retry.ts — retry decision tree + recovery strategies
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import { EventEmitter } from 'node:events';
|
|
12
|
-
import { existsSync,
|
|
17
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
18
|
import { join } from 'node:path';
|
|
14
19
|
import { AnalyticsEvents, trackEvent } from '../services/analytics.js';
|
|
15
20
|
import { herror } from './headless/headless-logger.js';
|
|
16
21
|
import { cleanupAttachments, preparePromptAndAttachments } from './improvisation-attachments.js';
|
|
22
|
+
import {
|
|
23
|
+
ensureHistoryDir,
|
|
24
|
+
loadHistory,
|
|
25
|
+
resolveHistoryPaths,
|
|
26
|
+
saveHistory,
|
|
27
|
+
} from './improvisation-history-store.js';
|
|
28
|
+
import {
|
|
29
|
+
buildCancelledMovement,
|
|
30
|
+
buildErrorMovement,
|
|
31
|
+
buildSuccessMovement,
|
|
32
|
+
CANCELLED_FALLBACK_RESULT,
|
|
33
|
+
shouldAutoContinue,
|
|
34
|
+
} from './improvisation-movements.js';
|
|
35
|
+
import { OutputQueue } from './improvisation-output-queue.js';
|
|
17
36
|
import type { RetryCallbacks, RetrySessionState } from './improvisation-retry.js';
|
|
18
|
-
import {applyToolTimeoutRetry,
|
|
19
|
-
createExecutionRunner,detectNativeTimeoutContextLoss, detectResumeContextLoss,
|
|
37
|
+
import {applyToolTimeoutRetry,
|
|
38
|
+
createExecutionRunner,detectNativeTimeoutContextLoss, detectResumeContextLoss,
|
|
20
39
|
determineResumeStrategy,
|
|
21
40
|
selectBestResult,
|
|
22
41
|
shouldRetryContextLoss,
|
|
@@ -40,8 +59,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
40
59
|
plan: unknown;
|
|
41
60
|
resolve: (approved: boolean) => void;
|
|
42
61
|
};
|
|
43
|
-
private
|
|
44
|
-
private queueTimer: NodeJS.Timeout | null = null;
|
|
62
|
+
private outputBuffer: OutputQueue;
|
|
45
63
|
private isFirstPrompt: boolean = true;
|
|
46
64
|
private claudeSessionId: string | undefined;
|
|
47
65
|
private isResumedSession: boolean = false;
|
|
@@ -54,6 +72,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
54
72
|
private _cancelCompleteEmitted: boolean = false;
|
|
55
73
|
private _currentUserPrompt: string = '';
|
|
56
74
|
private _currentSequenceNumber: number = 0;
|
|
75
|
+
private _hasPersistedToDisk: boolean = false;
|
|
57
76
|
|
|
58
77
|
static resumeFromHistory(workingDir: string, historicalSessionId: string, overrides?: Partial<ImprovisationOptions>): ImprovisationSessionManager {
|
|
59
78
|
const historyDir = join(workingDir, '.mstro', 'history');
|
|
@@ -79,6 +98,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
79
98
|
|
|
80
99
|
manager.isResumedSession = true;
|
|
81
100
|
manager.isFirstPrompt = true;
|
|
101
|
+
manager._hasPersistedToDisk = true;
|
|
82
102
|
if (historyData.claudeSessionId) {
|
|
83
103
|
manager.claudeSessionId = historyData.claudeSessionId;
|
|
84
104
|
}
|
|
@@ -101,33 +121,29 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
101
121
|
};
|
|
102
122
|
|
|
103
123
|
this.sessionId = this.options.sessionId;
|
|
104
|
-
|
|
105
|
-
this.
|
|
124
|
+
const paths = resolveHistoryPaths(this.options.workingDir, this.sessionId);
|
|
125
|
+
this.improviseDir = paths.improviseDir;
|
|
126
|
+
this.historyPath = paths.historyPath;
|
|
127
|
+
ensureHistoryDir(this.improviseDir);
|
|
106
128
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
129
|
+
this.history = loadHistory(this.historyPath, this.sessionId);
|
|
130
|
+
// History is persisted lazily on the first `persistHistory` call (see
|
|
131
|
+
// `executePrompt`). Deferring the initial write keeps the Chat History
|
|
132
|
+
// view from showing "0 prompts" entries for tabs the user opens but
|
|
133
|
+
// never prompts.
|
|
110
134
|
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
113
|
-
this.startQueueProcessor();
|
|
135
|
+
this.outputBuffer = new OutputQueue(text => this.emit('onOutput', text));
|
|
136
|
+
this.outputBuffer.start();
|
|
114
137
|
}
|
|
115
138
|
|
|
116
139
|
// ========== Output Queue ==========
|
|
117
140
|
|
|
118
|
-
private startQueueProcessor(): void {
|
|
119
|
-
this.queueTimer = setInterval(() => { this.flushOutputQueue(); }, 50);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
141
|
private queueOutput(text: string): void {
|
|
123
|
-
this.
|
|
142
|
+
this.outputBuffer.queue_(text);
|
|
124
143
|
}
|
|
125
144
|
|
|
126
145
|
private flushOutputQueue(): void {
|
|
127
|
-
|
|
128
|
-
const item = this.outputQueue.shift();
|
|
129
|
-
if (item) this.emit('onOutput', item.text);
|
|
130
|
-
}
|
|
146
|
+
this.outputBuffer.flush();
|
|
131
147
|
}
|
|
132
148
|
|
|
133
149
|
// ========== Main Execution ==========
|
|
@@ -174,7 +190,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
174
190
|
...(isAutoContinue && { isAutoContinue: true }),
|
|
175
191
|
};
|
|
176
192
|
this.history.movements.push(pendingMovement);
|
|
177
|
-
this.
|
|
193
|
+
this.persistHistory();
|
|
178
194
|
|
|
179
195
|
try {
|
|
180
196
|
this.executionEventLog.push({
|
|
@@ -212,7 +228,11 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
212
228
|
this.captureSessionAndSurfaceErrors(result);
|
|
213
229
|
this.isFirstPrompt = false;
|
|
214
230
|
|
|
215
|
-
const movement =
|
|
231
|
+
const movement = buildSuccessMovement(
|
|
232
|
+
result,
|
|
233
|
+
{ sequenceNumber, userPrompt: displayPrompt, execStart: _execStart, isAutoContinue },
|
|
234
|
+
state.retryLog,
|
|
235
|
+
);
|
|
216
236
|
this.handleConflicts(result);
|
|
217
237
|
this.persistMovement(movement);
|
|
218
238
|
|
|
@@ -345,7 +365,14 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
345
365
|
return false;
|
|
346
366
|
}
|
|
347
367
|
|
|
348
|
-
// ========== Cancel Handling ==========
|
|
368
|
+
// ========== Cancel / Error Handling ==========
|
|
369
|
+
|
|
370
|
+
private resetExecutionState(): void {
|
|
371
|
+
this._isExecuting = false;
|
|
372
|
+
this._executionStartTimestamp = undefined;
|
|
373
|
+
this.executionEventLog = [];
|
|
374
|
+
this.currentRunner = null;
|
|
375
|
+
}
|
|
349
376
|
|
|
350
377
|
private handleCancelledExecution(
|
|
351
378
|
result: HeadlessRunResult | undefined,
|
|
@@ -353,39 +380,16 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
353
380
|
sequenceNumber: number,
|
|
354
381
|
execStart: number,
|
|
355
382
|
): MovementRecord {
|
|
356
|
-
this.
|
|
357
|
-
this._executionStartTimestamp = undefined;
|
|
358
|
-
this.executionEventLog = [];
|
|
359
|
-
this.currentRunner = null;
|
|
383
|
+
this.resetExecutionState();
|
|
360
384
|
|
|
361
385
|
if (this._cancelCompleteEmitted) {
|
|
362
386
|
const existing = this.history.movements.find(m => m.sequenceNumber === sequenceNumber);
|
|
363
387
|
if (existing) return existing;
|
|
364
388
|
}
|
|
365
389
|
|
|
366
|
-
const cancelledMovement
|
|
367
|
-
id: `prompt-${sequenceNumber}`,
|
|
368
|
-
sequenceNumber,
|
|
369
|
-
userPrompt,
|
|
370
|
-
timestamp: new Date().toISOString(),
|
|
371
|
-
tokensUsed: result ? result.totalTokens : 0,
|
|
372
|
-
summary: '',
|
|
373
|
-
filesModified: [],
|
|
374
|
-
assistantResponse: result?.assistantResponse,
|
|
375
|
-
thinkingOutput: result?.thinkingOutput,
|
|
376
|
-
toolUseHistory: result?.toolUseHistory?.map(t => ({
|
|
377
|
-
toolName: t.toolName, toolId: t.toolId, toolInput: t.toolInput,
|
|
378
|
-
result: t.result,
|
|
379
|
-
})),
|
|
380
|
-
errorOutput: 'Execution cancelled by user',
|
|
381
|
-
durationMs: Date.now() - execStart,
|
|
382
|
-
};
|
|
390
|
+
const cancelledMovement = buildCancelledMovement(result, { sequenceNumber, userPrompt, execStart });
|
|
383
391
|
this.persistMovement(cancelledMovement);
|
|
384
|
-
|
|
385
|
-
completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
|
|
386
|
-
output: '', exitCode: 1, signalName: 'SIGTERM',
|
|
387
|
-
} as HeadlessRunResult;
|
|
388
|
-
this.emitMovementComplete(cancelledMovement, result ?? fallbackResult, execStart, sequenceNumber);
|
|
392
|
+
this.emitMovementComplete(cancelledMovement, result ?? CANCELLED_FALLBACK_RESULT, execStart, sequenceNumber);
|
|
389
393
|
return cancelledMovement;
|
|
390
394
|
}
|
|
391
395
|
|
|
@@ -395,23 +399,10 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
395
399
|
sequenceNumber: number,
|
|
396
400
|
execStart: number,
|
|
397
401
|
): never {
|
|
398
|
-
this.
|
|
399
|
-
this._executionStartTimestamp = undefined;
|
|
400
|
-
this.executionEventLog = [];
|
|
401
|
-
this.currentRunner = null;
|
|
402
|
+
this.resetExecutionState();
|
|
402
403
|
|
|
403
404
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
404
|
-
const errorMovement:
|
|
405
|
-
id: `prompt-${sequenceNumber}`,
|
|
406
|
-
sequenceNumber,
|
|
407
|
-
userPrompt: displayPrompt,
|
|
408
|
-
timestamp: new Date().toISOString(),
|
|
409
|
-
tokensUsed: 0,
|
|
410
|
-
summary: '',
|
|
411
|
-
filesModified: [],
|
|
412
|
-
errorOutput: errorMessage,
|
|
413
|
-
durationMs: Date.now() - execStart,
|
|
414
|
-
};
|
|
405
|
+
const errorMovement = buildErrorMovement(errorMessage, { sequenceNumber, userPrompt: displayPrompt, execStart });
|
|
415
406
|
this.persistMovement(errorMovement);
|
|
416
407
|
|
|
417
408
|
this.emit('onMovementError', error);
|
|
@@ -440,35 +431,6 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
440
431
|
}
|
|
441
432
|
}
|
|
442
433
|
|
|
443
|
-
private buildMovementRecord(
|
|
444
|
-
result: HeadlessRunResult,
|
|
445
|
-
userPrompt: string,
|
|
446
|
-
sequenceNumber: number,
|
|
447
|
-
execStart: number,
|
|
448
|
-
retryLog?: import('./improvisation-types.js').RetryLogEntry[],
|
|
449
|
-
isAutoContinue?: boolean,
|
|
450
|
-
): MovementRecord {
|
|
451
|
-
return {
|
|
452
|
-
id: `prompt-${sequenceNumber}`,
|
|
453
|
-
sequenceNumber,
|
|
454
|
-
userPrompt,
|
|
455
|
-
timestamp: new Date().toISOString(),
|
|
456
|
-
tokensUsed: result.totalTokens,
|
|
457
|
-
summary: '',
|
|
458
|
-
filesModified: [],
|
|
459
|
-
assistantResponse: result.assistantResponse,
|
|
460
|
-
thinkingOutput: result.thinkingOutput,
|
|
461
|
-
toolUseHistory: result.toolUseHistory?.map(t => ({
|
|
462
|
-
toolName: t.toolName, toolId: t.toolId, toolInput: t.toolInput,
|
|
463
|
-
result: t.result, isError: t.isError, duration: t.duration,
|
|
464
|
-
})),
|
|
465
|
-
errorOutput: result.error,
|
|
466
|
-
durationMs: Date.now() - execStart,
|
|
467
|
-
retryLog: retryLog && retryLog.length > 0 ? retryLog : undefined,
|
|
468
|
-
...(isAutoContinue && { isAutoContinue: true }),
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
|
|
472
434
|
private handleConflicts(result: HeadlessRunResult): void {
|
|
473
435
|
if (!result.conflicts || result.conflicts.length === 0) return;
|
|
474
436
|
this.queueOutput(`\n⚠ File conflicts detected: ${result.conflicts.length}`);
|
|
@@ -489,7 +451,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
489
451
|
this.history.movements.push(movement);
|
|
490
452
|
this.history.totalTokens += movement.tokensUsed;
|
|
491
453
|
}
|
|
492
|
-
this.
|
|
454
|
+
this.persistHistory();
|
|
493
455
|
}
|
|
494
456
|
|
|
495
457
|
private emitMovementComplete(movement: MovementRecord, result: HeadlessRunResult, execStart: number, sequenceNumber: number): void {
|
|
@@ -515,26 +477,10 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
515
477
|
const isStallKill = !this._cancelled && !!result.signalName;
|
|
516
478
|
if (isStallKill && this._autoContinueCount < ImprovisationSessionManager.MAX_AUTO_CONTINUES) {
|
|
517
479
|
this.scheduleAutoContinue('Process stalled');
|
|
518
|
-
} else if (
|
|
480
|
+
} else if (shouldAutoContinue(result, this._autoContinueCount, ImprovisationSessionManager.MAX_AUTO_CONTINUES, this._cancelled)) {
|
|
519
481
|
this.scheduleAutoContinue();
|
|
520
482
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
private shouldAutoContinue(result: HeadlessRunResult, _userPrompt: string): boolean {
|
|
524
|
-
if (this._autoContinueCount >= ImprovisationSessionManager.MAX_AUTO_CONTINUES) return false;
|
|
525
|
-
if (this._cancelled) return false;
|
|
526
|
-
if (!result.completed || result.signalName) return false;
|
|
527
|
-
if (result.stopReason !== 'end_turn') return false;
|
|
528
|
-
|
|
529
|
-
const thinkingLen = result.thinkingOutput?.length ?? 0;
|
|
530
|
-
const responseLen = result.assistantResponse?.length ?? 0;
|
|
531
|
-
const successfulToolCalls = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
|
|
532
|
-
|
|
533
|
-
if (thinkingLen < 500 || responseLen > 1000) return false;
|
|
534
|
-
// When the agent executed tool calls and produced a non-trivial response,
|
|
535
|
-
// long thinking is expected — the work happened in the tools, not the text.
|
|
536
|
-
if (successfulToolCalls > 0 && responseLen > 200) return false;
|
|
537
|
-
return thinkingLen >= responseLen * 3;
|
|
483
|
+
void userPrompt;
|
|
538
484
|
}
|
|
539
485
|
|
|
540
486
|
private scheduleAutoContinue(reason?: string): void {
|
|
@@ -555,27 +501,12 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
555
501
|
|
|
556
502
|
// ========== History I/O ==========
|
|
557
503
|
|
|
558
|
-
private
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
} catch (error) {
|
|
564
|
-
herror('Failed to load history:', error);
|
|
565
|
-
}
|
|
504
|
+
private persistHistory(): void {
|
|
505
|
+
saveHistory(this.historyPath, this.history);
|
|
506
|
+
if (!this._hasPersistedToDisk) {
|
|
507
|
+
this._hasPersistedToDisk = true;
|
|
508
|
+
this.emit('onHistoryPersisted');
|
|
566
509
|
}
|
|
567
|
-
return {
|
|
568
|
-
sessionId: this.sessionId,
|
|
569
|
-
startedAt: new Date().toISOString(),
|
|
570
|
-
lastActivityAt: new Date().toISOString(),
|
|
571
|
-
totalTokens: 0,
|
|
572
|
-
movements: [],
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
private saveHistory(): void {
|
|
577
|
-
this.history.lastActivityAt = new Date().toISOString();
|
|
578
|
-
writeFileSync(this.historyPath, JSON.stringify(this.history, null, 2));
|
|
579
510
|
}
|
|
580
511
|
|
|
581
512
|
getHistory(): SessionHistory {
|
|
@@ -592,7 +523,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
592
523
|
this.currentRunner = null;
|
|
593
524
|
}
|
|
594
525
|
|
|
595
|
-
this.
|
|
526
|
+
this.outputBuffer.destroy();
|
|
596
527
|
|
|
597
528
|
if (this._isExecuting && !this._cancelCompleteEmitted) {
|
|
598
529
|
this._cancelCompleteEmitted = true;
|
|
@@ -600,38 +531,20 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
600
531
|
this._isExecuting = false;
|
|
601
532
|
this._executionStartTimestamp = undefined;
|
|
602
533
|
|
|
603
|
-
const cancelledMovement
|
|
604
|
-
id: `prompt-${this._currentSequenceNumber}`,
|
|
534
|
+
const cancelledMovement = buildCancelledMovement(undefined, {
|
|
605
535
|
sequenceNumber: this._currentSequenceNumber,
|
|
606
536
|
userPrompt: this._currentUserPrompt,
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
summary: '',
|
|
610
|
-
filesModified: [],
|
|
611
|
-
errorOutput: 'Execution cancelled by user',
|
|
612
|
-
durationMs: Date.now() - execStart,
|
|
613
|
-
};
|
|
537
|
+
execStart,
|
|
538
|
+
});
|
|
614
539
|
this.persistMovement(cancelledMovement);
|
|
615
|
-
|
|
616
|
-
const fallbackResult = {
|
|
617
|
-
completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
|
|
618
|
-
output: '', exitCode: 1, signalName: 'SIGTERM',
|
|
619
|
-
} as HeadlessRunResult;
|
|
620
|
-
this.emitMovementComplete(cancelledMovement, fallbackResult, execStart, this._currentSequenceNumber);
|
|
540
|
+
this.emitMovementComplete(cancelledMovement, CANCELLED_FALLBACK_RESULT, execStart, this._currentSequenceNumber);
|
|
621
541
|
}
|
|
622
542
|
|
|
623
543
|
this.flushOutputQueue();
|
|
624
544
|
}
|
|
625
545
|
|
|
626
|
-
private destroyQueueTimer(): void {
|
|
627
|
-
if (this.queueTimer) {
|
|
628
|
-
clearInterval(this.queueTimer);
|
|
629
|
-
this.queueTimer = null;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
546
|
destroy(): void {
|
|
634
|
-
this.
|
|
547
|
+
this.outputBuffer.destroy();
|
|
635
548
|
this.flushOutputQueue();
|
|
636
549
|
}
|
|
637
550
|
|
|
@@ -642,7 +555,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
642
555
|
this.isFirstPrompt = true;
|
|
643
556
|
this.claudeSessionId = undefined;
|
|
644
557
|
cleanupAttachments(this.options.workingDir, this.sessionId);
|
|
645
|
-
this.
|
|
558
|
+
this.persistHistory();
|
|
646
559
|
this.emit('onSessionUpdate', this.getHistory());
|
|
647
560
|
}
|
|
648
561
|
|
|
@@ -684,7 +597,7 @@ export class ImprovisationSessionManager extends EventEmitter {
|
|
|
684
597
|
}
|
|
685
598
|
|
|
686
599
|
startNewSession(overrides?: Partial<ImprovisationOptions>): ImprovisationSessionManager {
|
|
687
|
-
this.
|
|
600
|
+
this.persistHistory();
|
|
688
601
|
return new ImprovisationSessionManager({
|
|
689
602
|
...this.options,
|
|
690
603
|
sessionId: `improv-${Date.now()}`,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Picks the best result across retry attempts. Prefers Haiku's judgment
|
|
5
|
+
* when available; falls back to a numeric score when Haiku is unreachable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { hlog } from '../headless/headless-logger.js';
|
|
9
|
+
import { assessBestResult } from '../headless/stall-assessor.js';
|
|
10
|
+
import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
|
|
11
|
+
import { scoreRunResult } from '../improvisation-types.js';
|
|
12
|
+
|
|
13
|
+
/** Select the best result across retries using Haiku assessment */
|
|
14
|
+
export async function selectBestResult(
|
|
15
|
+
state: RetryLoopState,
|
|
16
|
+
result: HeadlessRunResult,
|
|
17
|
+
userPrompt: string,
|
|
18
|
+
verbose: boolean,
|
|
19
|
+
): Promise<HeadlessRunResult> {
|
|
20
|
+
if (!state.bestResult || state.bestResult === result || state.retryNumber === 0) {
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
|
|
25
|
+
const bestToolCount = state.bestResult.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
|
|
26
|
+
const currentToolCount = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const verdict = await assessBestResult({
|
|
30
|
+
originalPrompt: userPrompt,
|
|
31
|
+
resultA: {
|
|
32
|
+
successfulToolCalls: bestToolCount,
|
|
33
|
+
responseLength: state.bestResult.assistantResponse?.length ?? 0,
|
|
34
|
+
hasThinking: !!state.bestResult.thinkingOutput,
|
|
35
|
+
responseTail: (state.bestResult.assistantResponse ?? '').slice(-500),
|
|
36
|
+
},
|
|
37
|
+
resultB: {
|
|
38
|
+
successfulToolCalls: currentToolCount,
|
|
39
|
+
responseLength: result.assistantResponse?.length ?? 0,
|
|
40
|
+
hasThinking: !!result.thinkingOutput,
|
|
41
|
+
responseTail: (result.assistantResponse ?? '').slice(-500),
|
|
42
|
+
},
|
|
43
|
+
}, claudeCmd, verbose);
|
|
44
|
+
|
|
45
|
+
if (verdict.winner === 'A') {
|
|
46
|
+
if (verbose) hlog(`[BEST-RESULT] Haiku picked earlier attempt: ${verdict.reason}`);
|
|
47
|
+
return mergeResultSessionId(state.bestResult, result.claudeSessionId);
|
|
48
|
+
}
|
|
49
|
+
if (verbose) hlog(`[BEST-RESULT] Haiku picked final attempt: ${verdict.reason}`);
|
|
50
|
+
return result;
|
|
51
|
+
} catch {
|
|
52
|
+
return fallbackBestResult(state.bestResult, result, verbose);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function mergeResultSessionId(result: HeadlessRunResult, sessionId: string | undefined): HeadlessRunResult {
|
|
57
|
+
if (sessionId) return { ...result, claudeSessionId: sessionId };
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function fallbackBestResult(bestResult: HeadlessRunResult, result: HeadlessRunResult, verbose: boolean): HeadlessRunResult {
|
|
62
|
+
if (scoreRunResult(bestResult) > scoreRunResult(result)) {
|
|
63
|
+
if (verbose) {
|
|
64
|
+
hlog(`[BEST-RESULT] Haiku unavailable, numeric fallback: earlier attempt (score ${scoreRunResult(bestResult)} vs ${scoreRunResult(result)})`);
|
|
65
|
+
}
|
|
66
|
+
return mergeResultSessionId(bestResult, result.claudeSessionId);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context-loss detection: figures out when a run's output indicates the
|
|
5
|
+
* Claude session dropped its memory, either on `--resume` (Path 1) or after
|
|
6
|
+
* native tool timeouts scrambled the conversation (Path 2).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { hlog } from '../headless/headless-logger.js';
|
|
10
|
+
import { assessContextLoss, type ContextLossContext } from '../headless/stall-assessor.js';
|
|
11
|
+
import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
|
|
12
|
+
|
|
13
|
+
const WRITE_TOOL_NAMES = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
14
|
+
|
|
15
|
+
/** Detect resume context loss (Path 1): session expired on --resume */
|
|
16
|
+
export function detectResumeContextLoss(
|
|
17
|
+
result: HeadlessRunResult,
|
|
18
|
+
state: RetryLoopState,
|
|
19
|
+
useResume: boolean,
|
|
20
|
+
maxRetries: number,
|
|
21
|
+
nativeTimeouts: number,
|
|
22
|
+
verbose: boolean,
|
|
23
|
+
): void {
|
|
24
|
+
if (!useResume || state.checkpointRef.value || state.retryNumber >= maxRetries || nativeTimeouts > 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!result.assistantResponse || result.assistantResponse.trim().length === 0) {
|
|
28
|
+
state.contextLost = true;
|
|
29
|
+
if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: null/empty response');
|
|
30
|
+
} else if (result.resumeBufferedOutput !== undefined) {
|
|
31
|
+
state.contextLost = true;
|
|
32
|
+
if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: buffer never flushed (no thinking/tools)');
|
|
33
|
+
} else if (
|
|
34
|
+
(!result.toolUseHistory || result.toolUseHistory.length === 0) &&
|
|
35
|
+
!result.thinkingOutput &&
|
|
36
|
+
result.assistantResponse.length < 500
|
|
37
|
+
) {
|
|
38
|
+
state.contextLost = true;
|
|
39
|
+
if (verbose) hlog('[CONTEXT-RECOVERY] Resume context loss: no tools, no thinking, short response');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Detect native timeout context loss (Path 2): tool timeouts caused confusion */
|
|
44
|
+
export async function detectNativeTimeoutContextLoss(
|
|
45
|
+
result: HeadlessRunResult,
|
|
46
|
+
state: RetryLoopState,
|
|
47
|
+
maxRetries: number,
|
|
48
|
+
nativeTimeouts: number,
|
|
49
|
+
verbose: boolean,
|
|
50
|
+
): Promise<void> {
|
|
51
|
+
if (state.contextLost) return;
|
|
52
|
+
|
|
53
|
+
const { effectiveTimeouts } = computeEffectiveTimeouts(result, nativeTimeouts);
|
|
54
|
+
if (effectiveTimeouts === 0 || !result.assistantResponse || state.checkpointRef.value || state.retryNumber >= maxRetries) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const contextLossCtx: ContextLossContext = {
|
|
59
|
+
assistantResponse: result.assistantResponse,
|
|
60
|
+
effectiveTimeouts,
|
|
61
|
+
nativeTimeoutCount: nativeTimeouts,
|
|
62
|
+
successfulToolCalls: result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0,
|
|
63
|
+
thinkingOutputLength: result.thinkingOutput?.length ?? 0,
|
|
64
|
+
hasSuccessfulWrite: result.toolUseHistory?.some(
|
|
65
|
+
t => WRITE_TOOL_NAMES.has(t.toolName) && t.result !== undefined && !t.isError
|
|
66
|
+
) ?? false,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
|
|
70
|
+
const verdict = await assessContextLoss(contextLossCtx, claudeCmd, verbose);
|
|
71
|
+
state.contextLost = verdict.contextLost;
|
|
72
|
+
if (verbose) {
|
|
73
|
+
hlog(`[CONTEXT-RECOVERY] Haiku verdict: ${state.contextLost ? 'LOST' : 'OK'} — ${verdict.reason}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function computeEffectiveTimeouts(result: HeadlessRunResult, nativeTimeouts: number): { effectiveTimeouts: number } {
|
|
78
|
+
const succeededIds = new Set<string>();
|
|
79
|
+
const allIds = new Set<string>();
|
|
80
|
+
for (const t of result.toolUseHistory ?? []) {
|
|
81
|
+
allIds.add(t.toolId);
|
|
82
|
+
if (t.result !== undefined) succeededIds.add(t.toolId);
|
|
83
|
+
}
|
|
84
|
+
const toolsWithoutResult = [...allIds].filter(id => !succeededIds.has(id)).length;
|
|
85
|
+
return { effectiveTimeouts: Math.max(nativeTimeouts, toolsWithoutResult) };
|
|
86
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detects when a claimed-complete run is actually unfinished (hit
|
|
5
|
+
* max_tokens, abandoned mid-task, or Haiku says the end_turn response is
|
|
6
|
+
* a stop short of the goal) and triggers a continuation retry.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AnalyticsEvents, trackEvent } from '../../services/analytics.js';
|
|
10
|
+
import { hlog } from '../headless/headless-logger.js';
|
|
11
|
+
import { extractFinalTextBlock, isResponseAbandoned } from '../headless/retry-strategies.js';
|
|
12
|
+
import { assessPrematureCompletion } from '../headless/stall-assessor.js';
|
|
13
|
+
import type { HeadlessRunResult, RetryLoopState } from '../improvisation-types.js';
|
|
14
|
+
import type { RetryCallbacks, RetrySessionState } from './retry-types.js';
|
|
15
|
+
|
|
16
|
+
/** Guard checks for premature completion */
|
|
17
|
+
function isPrematureCompletionCandidate(
|
|
18
|
+
result: HeadlessRunResult,
|
|
19
|
+
state: RetryLoopState,
|
|
20
|
+
maxRetries: number,
|
|
21
|
+
): boolean {
|
|
22
|
+
if (!result.completed || result.signalName || state.retryNumber >= maxRetries) return false;
|
|
23
|
+
if (state.checkpointRef.value || state.contextLost) return false;
|
|
24
|
+
if (!result.claudeSessionId || !result.stopReason) return false;
|
|
25
|
+
return result.stopReason === 'max_tokens' || result.stopReason === 'end_turn';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Use Haiku to assess whether an end_turn response is genuinely complete */
|
|
29
|
+
async function assessEndTurnCompletion(result: HeadlessRunResult, verbose: boolean): Promise<boolean> {
|
|
30
|
+
if (!result.assistantResponse) return false;
|
|
31
|
+
|
|
32
|
+
const successfulToolCalls = result.toolUseHistory?.filter(t => t.result !== undefined && !t.isError).length ?? 0;
|
|
33
|
+
const claudeCmd = process.env.CLAUDE_COMMAND || 'claude';
|
|
34
|
+
const verdict = await assessPrematureCompletion({
|
|
35
|
+
responseTail: extractFinalTextBlock(result.assistantResponse, 800),
|
|
36
|
+
successfulToolCalls,
|
|
37
|
+
hasThinking: !!result.thinkingOutput,
|
|
38
|
+
responseLength: result.assistantResponse.length,
|
|
39
|
+
}, claudeCmd, verbose);
|
|
40
|
+
|
|
41
|
+
if (verbose) {
|
|
42
|
+
hlog(`[PREMATURE-COMPLETION] Haiku verdict: ${verdict.isIncomplete ? 'INCOMPLETE' : 'COMPLETE'} — ${verdict.reason}`);
|
|
43
|
+
}
|
|
44
|
+
return verdict.isIncomplete;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Apply premature completion retry */
|
|
48
|
+
function applyPrematureCompletionRetry(
|
|
49
|
+
result: HeadlessRunResult,
|
|
50
|
+
state: RetryLoopState,
|
|
51
|
+
session: RetrySessionState,
|
|
52
|
+
maxRetries: number,
|
|
53
|
+
stopReason: string,
|
|
54
|
+
isMaxTokens: boolean,
|
|
55
|
+
callbacks: RetryCallbacks,
|
|
56
|
+
): void {
|
|
57
|
+
state.retryNumber++;
|
|
58
|
+
const reason = isMaxTokens ? 'Output limit reached' : 'Task appears unfinished (AI assessment)';
|
|
59
|
+
|
|
60
|
+
state.retryLog.push({
|
|
61
|
+
retryNumber: state.retryNumber,
|
|
62
|
+
path: 'PrematureCompletion',
|
|
63
|
+
reason,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
callbacks.emit('onAutoRetry', {
|
|
68
|
+
retryNumber: state.retryNumber,
|
|
69
|
+
maxRetries,
|
|
70
|
+
toolName: `PrematureCompletion(${stopReason})`,
|
|
71
|
+
completedCount: result.toolUseHistory?.length ?? 0,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
trackEvent(AnalyticsEvents.IMPROVISE_AUTO_RETRY, {
|
|
75
|
+
retry_number: state.retryNumber,
|
|
76
|
+
hung_tool: `premature_completion:${stopReason}`,
|
|
77
|
+
completed_tools: result.toolUseHistory?.length ?? 0,
|
|
78
|
+
resume_attempted: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
callbacks.queueOutput(
|
|
82
|
+
`\n\n${reason} — resuming session (retry ${state.retryNumber}/${maxRetries}).\n\n`
|
|
83
|
+
);
|
|
84
|
+
callbacks.flushOutputQueue();
|
|
85
|
+
|
|
86
|
+
state.contextRecoverySessionId = result.claudeSessionId;
|
|
87
|
+
session.claudeSessionId = result.claudeSessionId;
|
|
88
|
+
state.currentPrompt = 'continue';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Detect and retry premature completion. Returns true if loop should continue. */
|
|
92
|
+
export async function shouldRetryPrematureCompletion(
|
|
93
|
+
result: HeadlessRunResult,
|
|
94
|
+
state: RetryLoopState,
|
|
95
|
+
session: RetrySessionState,
|
|
96
|
+
maxRetries: number,
|
|
97
|
+
callbacks: RetryCallbacks,
|
|
98
|
+
): Promise<boolean> {
|
|
99
|
+
if (!isPrematureCompletionCandidate(result, state, maxRetries)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const stopReason = result.stopReason!;
|
|
104
|
+
const isMaxTokens = stopReason === 'max_tokens';
|
|
105
|
+
const abandoned = isResponseAbandoned(result);
|
|
106
|
+
const isIncomplete = isMaxTokens || abandoned || await assessEndTurnCompletion(result, session.options.verbose);
|
|
107
|
+
|
|
108
|
+
if (!isIncomplete) return false;
|
|
109
|
+
|
|
110
|
+
applyPrematureCompletionRetry(result, state, session, maxRetries, stopReason, isMaxTokens, callbacks);
|
|
111
|
+
return true;
|
|
112
|
+
}
|