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
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chunked File Download Handler
|
|
5
|
+
*
|
|
6
|
+
* Streams files to the web client as a sequence of WebSocket chunk messages.
|
|
7
|
+
* Mirrors the chunked upload path in reverse. Used for large binary files
|
|
8
|
+
* (images, PDFs) where a single base64-in-JSON `fileContent` message would
|
|
9
|
+
* exceed the relay's per-message cap or block the event loop during encoding.
|
|
10
|
+
*
|
|
11
|
+
* Chunk sizing: we emit 192 KB of raw bytes per chunk, which base64-encodes
|
|
12
|
+
* to ~256 KB — comfortably under the relay's 16 MB per-message limit even
|
|
13
|
+
* with JSON envelope overhead.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createReadStream, existsSync, type ReadStream, statSync } from 'node:fs';
|
|
17
|
+
import { basename, resolve, sep } from 'node:path';
|
|
18
|
+
import { isBinaryFile, isPathInSafeLocation } from './file-utils.js';
|
|
19
|
+
import type { WebSocketResponse, WSContext } from './types.js';
|
|
20
|
+
|
|
21
|
+
const CHUNK_RAW_BYTES = 192 * 1024; // ~256 KB once base64-encoded
|
|
22
|
+
const MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024;
|
|
23
|
+
const IDLE_TIMEOUT_MS = 120_000;
|
|
24
|
+
|
|
25
|
+
interface DownloadState {
|
|
26
|
+
downloadId: string;
|
|
27
|
+
stream: ReadStream;
|
|
28
|
+
cancelled: boolean;
|
|
29
|
+
lastActivity: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getMimeType(fullPath: string): string {
|
|
33
|
+
const ext = fullPath.toLowerCase().split('.').pop() || '';
|
|
34
|
+
if (ext === 'svg') return 'image/svg+xml';
|
|
35
|
+
if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg';
|
|
36
|
+
if (ext === 'pdf') return 'application/pdf';
|
|
37
|
+
if (['png', 'gif', 'webp', 'bmp', 'tiff', 'ico'].includes(ext)) return `image/${ext}`;
|
|
38
|
+
return 'application/octet-stream';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class FileDownloadHandler {
|
|
42
|
+
private active = new Map<string, DownloadState>();
|
|
43
|
+
private cleanupInterval: ReturnType<typeof setInterval>;
|
|
44
|
+
|
|
45
|
+
constructor(private workingDir: string) {
|
|
46
|
+
this.cleanupInterval = setInterval(() => this.cleanupStale(), 30_000);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
handleDownloadStart(
|
|
50
|
+
ws: WSContext,
|
|
51
|
+
send: (ws: WSContext, response: WebSocketResponse) => void,
|
|
52
|
+
tabId: string,
|
|
53
|
+
data: { downloadId: string; filePath: string },
|
|
54
|
+
): void {
|
|
55
|
+
const { downloadId, filePath } = data;
|
|
56
|
+
const sendError = (error: string) => send(ws, {
|
|
57
|
+
type: 'fileDownloadError' as WebSocketResponse['type'],
|
|
58
|
+
tabId,
|
|
59
|
+
data: { downloadId, error },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const fullPath = filePath.startsWith('/') ? filePath : resolve(this.workingDir, filePath);
|
|
64
|
+
const normalized = resolve(fullPath);
|
|
65
|
+
const normalizedWorkingDir = resolve(this.workingDir);
|
|
66
|
+
|
|
67
|
+
// Sandbox: must be under workingDir OR a known safe location (matches readFileContent)
|
|
68
|
+
const withinDir = normalized === normalizedWorkingDir
|
|
69
|
+
|| normalized.startsWith(normalizedWorkingDir + sep);
|
|
70
|
+
if (!withinDir && !isPathInSafeLocation(normalized)) {
|
|
71
|
+
sendError('Access denied: path outside allowed locations');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!existsSync(normalized)) {
|
|
75
|
+
sendError('File not found');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const stats = statSync(normalized);
|
|
80
|
+
if (stats.isDirectory()) {
|
|
81
|
+
sendError('Path is a directory');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (stats.size > MAX_DOWNLOAD_SIZE) {
|
|
85
|
+
sendError(`File too large: ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds ${MAX_DOWNLOAD_SIZE / 1024 / 1024}MB limit`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const totalChunks = Math.max(1, Math.ceil(stats.size / CHUNK_RAW_BYTES));
|
|
90
|
+
const fileName = basename(normalized);
|
|
91
|
+
const isImg = isBinaryFile(normalized);
|
|
92
|
+
|
|
93
|
+
send(ws, {
|
|
94
|
+
type: 'fileDownloadReady' as WebSocketResponse['type'],
|
|
95
|
+
tabId,
|
|
96
|
+
data: {
|
|
97
|
+
downloadId,
|
|
98
|
+
filePath,
|
|
99
|
+
fileName,
|
|
100
|
+
size: stats.size,
|
|
101
|
+
mimeType: getMimeType(normalized),
|
|
102
|
+
isImage: isImg,
|
|
103
|
+
totalChunks,
|
|
104
|
+
modifiedAt: stats.mtime.toISOString(),
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const stream = createReadStream(normalized, { highWaterMark: CHUNK_RAW_BYTES });
|
|
109
|
+
const state: DownloadState = {
|
|
110
|
+
downloadId,
|
|
111
|
+
stream,
|
|
112
|
+
cancelled: false,
|
|
113
|
+
lastActivity: Date.now(),
|
|
114
|
+
};
|
|
115
|
+
this.active.set(downloadId, state);
|
|
116
|
+
|
|
117
|
+
let chunkIndex = 0;
|
|
118
|
+
stream.on('data', (buf: Buffer | string) => {
|
|
119
|
+
if (state.cancelled) return;
|
|
120
|
+
// Node may deliver buffers larger than highWaterMark on stream edges;
|
|
121
|
+
// slice back down so each WS frame stays predictable.
|
|
122
|
+
const chunk = typeof buf === 'string' ? Buffer.from(buf) : buf;
|
|
123
|
+
for (let off = 0; off < chunk.length; off += CHUNK_RAW_BYTES) {
|
|
124
|
+
const slice = chunk.subarray(off, Math.min(off + CHUNK_RAW_BYTES, chunk.length));
|
|
125
|
+
send(ws, {
|
|
126
|
+
type: 'fileDownloadChunk' as WebSocketResponse['type'],
|
|
127
|
+
tabId,
|
|
128
|
+
data: {
|
|
129
|
+
downloadId,
|
|
130
|
+
chunkIndex: chunkIndex++,
|
|
131
|
+
content: slice.toString('base64'),
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
state.lastActivity = Date.now();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
stream.on('end', () => {
|
|
139
|
+
if (state.cancelled) return;
|
|
140
|
+
send(ws, {
|
|
141
|
+
type: 'fileDownloadComplete' as WebSocketResponse['type'],
|
|
142
|
+
tabId,
|
|
143
|
+
data: { downloadId },
|
|
144
|
+
});
|
|
145
|
+
this.active.delete(downloadId);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
stream.on('error', (err) => {
|
|
149
|
+
sendError(`Read failed: ${err.message}`);
|
|
150
|
+
this.active.delete(downloadId);
|
|
151
|
+
});
|
|
152
|
+
} catch (err) {
|
|
153
|
+
sendError(err instanceof Error ? err.message : String(err));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
handleDownloadCancel(
|
|
158
|
+
_ws: WSContext,
|
|
159
|
+
_send: (ws: WSContext, response: WebSocketResponse) => void,
|
|
160
|
+
_tabId: string,
|
|
161
|
+
data: { downloadId: string },
|
|
162
|
+
): void {
|
|
163
|
+
const state = this.active.get(data.downloadId);
|
|
164
|
+
if (!state) return;
|
|
165
|
+
state.cancelled = true;
|
|
166
|
+
state.stream.destroy();
|
|
167
|
+
this.active.delete(data.downloadId);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private cleanupStale(): void {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
for (const [id, state] of this.active) {
|
|
173
|
+
if (now - state.lastActivity > IDLE_TIMEOUT_MS) {
|
|
174
|
+
console.warn(`[FileDownloadHandler] Download ${id} idle, cleaning up`);
|
|
175
|
+
state.cancelled = true;
|
|
176
|
+
state.stream.destroy();
|
|
177
|
+
this.active.delete(id);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
destroy(): void {
|
|
183
|
+
clearInterval(this.cleanupInterval);
|
|
184
|
+
for (const state of this.active.values()) {
|
|
185
|
+
state.cancelled = true;
|
|
186
|
+
state.stream.destroy();
|
|
187
|
+
}
|
|
188
|
+
this.active.clear();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
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
|
* Chunked File Upload Handler
|
|
6
5
|
*
|
|
7
6
|
* Receives files in chunks over WebSocket from remote web clients.
|
|
7
|
+
* The destination working directory is passed per-call (effective dir for the tab,
|
|
8
|
+
* which resolves to the worktree path when the tab is on a worktree).
|
|
8
9
|
* - When `targetPath` is provided: streams to <workingDir>/<targetPath> (drag-drop into file tree).
|
|
9
|
-
* - Otherwise: streams to
|
|
10
|
+
* - Otherwise: streams to <workingDir>/.mstro/tmp/attachments/{tabId}/ (prompt attachments).
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import type { WriteStream } from 'node:fs';
|
|
@@ -50,7 +51,6 @@ export class FileUploadHandler {
|
|
|
50
51
|
private cleanupInterval: ReturnType<typeof setInterval>;
|
|
51
52
|
|
|
52
53
|
constructor(
|
|
53
|
-
private workingDir: string,
|
|
54
54
|
private ctx?: HandlerContext,
|
|
55
55
|
) {
|
|
56
56
|
// Periodically clean up stale uploads
|
|
@@ -74,6 +74,7 @@ export class FileUploadHandler {
|
|
|
74
74
|
send: (ws: WSContext, response: WebSocketResponse) => void,
|
|
75
75
|
tabId: string,
|
|
76
76
|
data: { uploadId: string; fileName: string; fileSize: number; mimeType: string; isImage: boolean; totalChunks: number; targetPath?: string; overwrite?: boolean },
|
|
77
|
+
workingDir: string,
|
|
77
78
|
permission?: 'view',
|
|
78
79
|
): void {
|
|
79
80
|
const { uploadId, fileName, fileSize, mimeType, isImage, totalChunks, targetPath, overwrite } = data;
|
|
@@ -89,8 +90,8 @@ export class FileUploadHandler {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
const resolved = targetPath !== undefined
|
|
92
|
-
? resolveFileTreeTarget({ targetPath, fileName, workingDir
|
|
93
|
-
: resolveAttachmentTarget({ workingDir
|
|
93
|
+
? resolveFileTreeTarget({ targetPath, fileName, workingDir, permission, overwrite })
|
|
94
|
+
: resolveAttachmentTarget({ workingDir, tabId, fileName });
|
|
94
95
|
|
|
95
96
|
if (!resolved.ok) {
|
|
96
97
|
sendError(resolved.error);
|
|
@@ -1,5 +1,4 @@
|
|
|
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
|
import { executeGitCommand, sendGitError } from './git-utils.js';
|
|
5
4
|
import { findWorktreePathForBranch, handleTabWorktreeSwitch } from './git-worktree-handlers.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
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
|
import { resolve } from 'node:path';
|
|
5
4
|
import { loadSkillPrompt } from '../plan/agent-loader.js';
|
|
@@ -8,7 +7,7 @@ import { handleGitCommitDiff, handleGitDiff, handleGitShowCommit } from './git-d
|
|
|
8
7
|
import { handleGitDiscoverRepos, handleGitLog, handleGitSetDirectory } from './git-log-handlers.js';
|
|
9
8
|
import { handleGitPRMessage } from './git-pr-handlers.js';
|
|
10
9
|
import { handleGitCreateTag, handleGitListTags, handleGitPushTag } from './git-tag-handlers.js';
|
|
11
|
-
import { executeGitCommand, parseGitStatus, sendGitError, spawnHaikuWithPrompt, stripCoauthorLines, truncateDiff } from './git-utils.js';
|
|
10
|
+
import { classifyHaikuFailure, executeGitCommand, type HaikuResult, logCommitMessageEvent, parseGitStatus, sendGitError, spawnHaikuWithPrompt, stripCoauthorLines, truncateDiff } from './git-utils.js';
|
|
12
11
|
import { handleGitWorktreeMessage } from './git-worktree-handlers.js';
|
|
13
12
|
import type { HandlerContext } from './handler-context.js';
|
|
14
13
|
import type { GitStatusResponse, WebSocketMessage, WSContext } from './types.js';
|
|
@@ -200,7 +199,50 @@ async function handleGitCommit(ctx: HandlerContext, ws: WSContext, msg: WebSocke
|
|
|
200
199
|
}
|
|
201
200
|
}
|
|
202
201
|
|
|
202
|
+
/** Tabs currently generating an AI commit message. Prevents double-clicks
|
|
203
|
+
* from spawning two `claude` subprocesses for the same tab and clobbering
|
|
204
|
+
* the UI when the second response arrives. Module-scoped so it survives
|
|
205
|
+
* HandlerContext lifecycle (one process per CLI machine). */
|
|
206
|
+
const inflightCommitMessage = new Set<string>();
|
|
207
|
+
|
|
208
|
+
const haikuSucceeded = (r: HaikuResult): boolean => r.exitCode === 0 && r.stdout.trim().length > 0;
|
|
209
|
+
// rate_limit is terminal because a 500ms retry hits the same window the API
|
|
210
|
+
// expects you to wait ~60s on; retrying just doubles user-perceived latency
|
|
211
|
+
// before we surface the "wait a minute" message.
|
|
212
|
+
const RETRY_TERMINAL_REASONS = new Set(['binary_missing', 'auth', 'rate_limit']);
|
|
213
|
+
|
|
214
|
+
/** Run Haiku with one retry on transient failures. Logs each attempt. */
|
|
215
|
+
async function runHaikuForCommitMessage(
|
|
216
|
+
prompt: string, systemPrompt: string, workingDir: string,
|
|
217
|
+
meta: { tabId: string; startedAt: number; diffBytes: number },
|
|
218
|
+
): Promise<{ result: HaikuResult; attempts: number }> {
|
|
219
|
+
let result = await spawnHaikuWithPrompt(prompt, systemPrompt, workingDir);
|
|
220
|
+
if (haikuSucceeded(result)) return { result, attempts: 1 };
|
|
221
|
+
|
|
222
|
+
const first = classifyHaikuFailure(result);
|
|
223
|
+
if (RETRY_TERMINAL_REASONS.has(first.reason)) return { result, attempts: 1 };
|
|
224
|
+
|
|
225
|
+
logCommitMessageEvent(workingDir, {
|
|
226
|
+
tabId: meta.tabId, attempt: 1, success: false, reason: first.reason,
|
|
227
|
+
exitCode: result.exitCode, timedOut: result.timedOut,
|
|
228
|
+
stderrTail: (result.stderr || '').trim().slice(-500),
|
|
229
|
+
latencyMs: Date.now() - meta.startedAt, diffBytes: meta.diffBytes, willRetry: true,
|
|
230
|
+
});
|
|
231
|
+
await new Promise(r => setTimeout(r, 500));
|
|
232
|
+
result = await spawnHaikuWithPrompt(prompt, systemPrompt, workingDir);
|
|
233
|
+
return { result, attempts: 2 };
|
|
234
|
+
}
|
|
235
|
+
|
|
203
236
|
async function handleGitCommitWithAI(ctx: HandlerContext, ws: WSContext, msg: WebSocketMessage, tabId: string, workingDir: string): Promise<void> {
|
|
237
|
+
if (inflightCommitMessage.has(tabId)) {
|
|
238
|
+
// Drop the duplicate request silently — the user already has one in
|
|
239
|
+
// flight. Surfacing "already generating" as a toast is noisier than
|
|
240
|
+
// just ignoring the click.
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
inflightCommitMessage.add(tabId);
|
|
244
|
+
const startedAt = Date.now();
|
|
245
|
+
|
|
204
246
|
try {
|
|
205
247
|
const statusResult = await executeGitCommand(['status', '--porcelain=v1'], workingDir);
|
|
206
248
|
const { staged } = parseGitStatus(statusResult.stdout);
|
|
@@ -216,25 +258,37 @@ async function handleGitCommitWithAI(ctx: HandlerContext, ws: WSContext, msg: We
|
|
|
216
258
|
const recentCommits = logResult.stdout.trim() || 'No recent commits';
|
|
217
259
|
const stagedFiles = staged.map(f => `${f.status} ${f.path}`).join('\n');
|
|
218
260
|
const diff = truncateDiff(diffResult.stdout);
|
|
261
|
+
const diffBytes = diffResult.stdout.length;
|
|
219
262
|
|
|
220
263
|
const prompt = loadSkillPrompt('commit-message', { recentCommits, stagedFiles, diff }, workingDir)
|
|
221
264
|
?? `You are generating a git commit message for the following staged changes.\n\nRECENT COMMIT MESSAGES (for style reference):\n${recentCommits}\n\nSTAGED FILES:\n${stagedFiles}\n\nDIFF OF STAGED CHANGES:\n${diff}\n\nGenerate a commit message: imperative mood, max 72 characters, focus on "why". Respond with ONLY the commit message.`;
|
|
222
265
|
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
workingDir,
|
|
227
|
-
);
|
|
266
|
+
const systemPrompt = 'You are a commit message assistant. Respond with only the commit message, no preamble or explanation.';
|
|
267
|
+
|
|
268
|
+
const { result, attempts } = await runHaikuForCommitMessage(prompt, systemPrompt, workingDir, { tabId, startedAt, diffBytes });
|
|
228
269
|
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
|
|
270
|
+
if (!haikuSucceeded(result)) {
|
|
271
|
+
const failure = classifyHaikuFailure(result);
|
|
272
|
+
logCommitMessageEvent(workingDir, {
|
|
273
|
+
tabId, attempt: attempts, success: false, reason: failure.reason,
|
|
274
|
+
exitCode: result.exitCode, timedOut: result.timedOut,
|
|
275
|
+
stderrTail: (result.stderr || '').trim().slice(-500),
|
|
276
|
+
latencyMs: Date.now() - startedAt, diffBytes,
|
|
277
|
+
});
|
|
278
|
+
console.error(`[git] commit-message failed (${failure.reason}):`, result.stderr || 'no stderr');
|
|
279
|
+
ctx.send(ws, { type: 'gitError', tabId, data: { error: failure.userMessage } });
|
|
232
280
|
return;
|
|
233
281
|
}
|
|
234
282
|
|
|
235
283
|
const commitMessage = extractCommitMessage(result.stdout.trim());
|
|
236
284
|
const autoCommit = !!msg.data?.autoCommit;
|
|
237
285
|
|
|
286
|
+
logCommitMessageEvent(workingDir, {
|
|
287
|
+
tabId, attempt: attempts, success: true,
|
|
288
|
+
latencyMs: Date.now() - startedAt, diffBytes, autoCommit,
|
|
289
|
+
messageLength: commitMessage.length,
|
|
290
|
+
});
|
|
291
|
+
|
|
238
292
|
ctx.send(ws, { type: 'gitCommitMessage', tabId, data: { message: commitMessage, autoCommit } });
|
|
239
293
|
|
|
240
294
|
if (autoCommit) {
|
|
@@ -250,6 +304,8 @@ async function handleGitCommitWithAI(ctx: HandlerContext, ws: WSContext, msg: We
|
|
|
250
304
|
}
|
|
251
305
|
} catch (error: unknown) {
|
|
252
306
|
sendGitError(ctx, ws, tabId, error);
|
|
307
|
+
} finally {
|
|
308
|
+
inflightCommitMessage.delete(tabId);
|
|
253
309
|
}
|
|
254
310
|
}
|
|
255
311
|
|
|
@@ -1,8 +1,8 @@
|
|
|
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
|
import { spawn } from 'node:child_process';
|
|
5
|
-
import {
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { appendFileSync, existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import type { HandlerContext } from './handler-context.js';
|
|
8
8
|
import type { GitFileStatus, WSContext } from './types.js';
|
|
@@ -171,17 +171,31 @@ export function truncateDiff(diff: string, maxLength = 8000): string {
|
|
|
171
171
|
return `${diff.slice(0, headSize)}\n\n... [diff truncated] ...\n\n${diff.slice(-tailSize)}`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
/**
|
|
174
|
+
/** Result of a Haiku spawn. `timedOut` is set when the process was killed by our timer. */
|
|
175
|
+
export interface HaikuResult {
|
|
176
|
+
stdout: string;
|
|
177
|
+
stderr: string;
|
|
178
|
+
exitCode: number;
|
|
179
|
+
timedOut: boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Spawn Claude Haiku with a prompt file and return captured output.
|
|
183
|
+
*
|
|
184
|
+
* Default timeout is 90s — measured p99 of Haiku responses is ~31s for tiny
|
|
185
|
+
* bouncer prompts; commit-message and PR-description prompts ship a full diff
|
|
186
|
+
* and run materially longer. 90s gives a 3x margin while still failing fast
|
|
187
|
+
* enough that the UI doesn't spin forever. */
|
|
175
188
|
export function spawnHaikuWithPrompt(
|
|
176
189
|
prompt: string,
|
|
177
190
|
systemPrompt: string,
|
|
178
191
|
workingDir: string,
|
|
179
|
-
timeoutMs =
|
|
180
|
-
): Promise<
|
|
192
|
+
timeoutMs = 90000,
|
|
193
|
+
): Promise<HaikuResult> {
|
|
181
194
|
return new Promise((resolve) => {
|
|
182
195
|
const tempDir = join(workingDir, '.mstro', 'tmp');
|
|
183
196
|
if (!existsSync(tempDir)) mkdirSync(tempDir, { recursive: true });
|
|
184
|
-
|
|
197
|
+
// randomUUID — Date.now() collided when two requests fired in the same ms.
|
|
198
|
+
const promptFile = join(tempDir, `haiku-${randomUUID()}.txt`);
|
|
185
199
|
writeFileSync(promptFile, prompt);
|
|
186
200
|
|
|
187
201
|
const args = ['--print', '--model', 'haiku', '--system-prompt', systemPrompt, promptFile];
|
|
@@ -189,25 +203,71 @@ export function spawnHaikuWithPrompt(
|
|
|
189
203
|
|
|
190
204
|
let stdout = '';
|
|
191
205
|
let stderr = '';
|
|
206
|
+
let timedOut = false;
|
|
192
207
|
proc.stdout?.on('data', (d: Buffer) => { stdout += d.toString(); });
|
|
193
208
|
proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });
|
|
194
209
|
|
|
195
|
-
const timer = setTimeout(() => proc.kill(), timeoutMs);
|
|
210
|
+
const timer = setTimeout(() => { timedOut = true; proc.kill(); }, timeoutMs);
|
|
196
211
|
|
|
197
212
|
proc.on('close', (code) => {
|
|
198
213
|
clearTimeout(timer);
|
|
199
214
|
try { unlinkSync(promptFile); } catch { /* ignore cleanup errors */ }
|
|
200
|
-
resolve({ stdout, stderr, exitCode: code ?? 1 });
|
|
215
|
+
resolve({ stdout, stderr, exitCode: code ?? 1, timedOut });
|
|
201
216
|
});
|
|
202
217
|
|
|
203
218
|
proc.on('error', (err: Error) => {
|
|
204
219
|
clearTimeout(timer);
|
|
205
220
|
try { unlinkSync(promptFile); } catch { /* ignore cleanup errors */ }
|
|
206
|
-
|
|
221
|
+
// ENOENT here means the `claude` binary wasn't found on PATH.
|
|
222
|
+
const enoent = (err as NodeJS.ErrnoException).code === 'ENOENT';
|
|
223
|
+
resolve({ stdout: '', stderr: enoent ? `claude: command not found (${err.message})` : err.message, exitCode: 1, timedOut: false });
|
|
207
224
|
});
|
|
208
225
|
});
|
|
209
226
|
}
|
|
210
227
|
|
|
228
|
+
/** Map a Haiku failure to an actionable user-facing message + a stable reason code. */
|
|
229
|
+
export function classifyHaikuFailure(result: HaikuResult): { reason: string; userMessage: string } {
|
|
230
|
+
const stderr = (result.stderr || '').toLowerCase();
|
|
231
|
+
const stdout = (result.stdout || '').toLowerCase();
|
|
232
|
+
const combined = `${stderr} ${stdout}`;
|
|
233
|
+
|
|
234
|
+
if (result.timedOut) {
|
|
235
|
+
return { reason: 'timeout', userMessage: 'Claude took too long to respond. Try again, or stage fewer files at once.' };
|
|
236
|
+
}
|
|
237
|
+
if (combined.includes('command not found') || combined.includes('enoent')) {
|
|
238
|
+
return { reason: 'binary_missing', userMessage: 'Claude CLI is not installed or not on PATH. Install it with `npm i -g @anthropic-ai/claude-code` and re-launch mstro.' };
|
|
239
|
+
}
|
|
240
|
+
if (/not\s+(logged|signed)\s*in|not\s+authenticated|please\s+(log|sign)\s*in|api\s*key|unauthor/.test(combined)) {
|
|
241
|
+
return { reason: 'auth', userMessage: 'Claude CLI is not authenticated. Run `claude /login` in a terminal, then try again.' };
|
|
242
|
+
}
|
|
243
|
+
if (/rate\s*limit|usage\s*limit|429|too\s+many\s+requests/.test(combined)) {
|
|
244
|
+
return { reason: 'rate_limit', userMessage: 'Claude rate limit reached. Wait a minute and try again.' };
|
|
245
|
+
}
|
|
246
|
+
if (/overloaded|529|service\s+unavailable|503/.test(combined)) {
|
|
247
|
+
return { reason: 'overloaded', userMessage: "Claude is temporarily overloaded. Try again in a few seconds." };
|
|
248
|
+
}
|
|
249
|
+
if (result.exitCode === 0 && !result.stdout.trim()) {
|
|
250
|
+
return { reason: 'empty_output', userMessage: 'Claude returned an empty response. Try again.' };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const tail = (result.stderr || result.stdout || '').trim().slice(-200);
|
|
254
|
+
return { reason: 'unknown', userMessage: `Failed to generate commit message${tail ? `: ${tail}` : ''}` };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Append a structured event to .mstro/logs/commit-message.jsonl for observability. */
|
|
258
|
+
export function logCommitMessageEvent(workingDir: string, entry: Record<string, unknown>): void {
|
|
259
|
+
try {
|
|
260
|
+
const logDir = join(workingDir, '.mstro', 'logs');
|
|
261
|
+
if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
|
|
262
|
+
const logFile = join(logDir, 'commit-message.jsonl');
|
|
263
|
+
const line = `${JSON.stringify({ timestamp: new Date().toISOString(), ...entry })}\n`;
|
|
264
|
+
appendFileSync(logFile, line, 'utf-8');
|
|
265
|
+
} catch (err) {
|
|
266
|
+
// Logging must never break the user-facing flow.
|
|
267
|
+
console.error('[git] failed to write commit-message log:', err);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
211
271
|
/**
|
|
212
272
|
* Strip injected coauthor/attribution lines from a commit message.
|
|
213
273
|
*/
|