mstro-app 0.5.0 → 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 +5 -1
- package/bin/commands/config.js +0 -1
- package/bin/mstro.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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.map +1 -1
- package/dist/server/cli/improvisation-history-store.js +0 -1
- package/dist/server/cli/improvisation-history-store.js.map +1 -1
- package/dist/server/cli/improvisation-movements.d.ts.map +1 -1
- package/dist/server/cli/improvisation-movements.js +0 -1
- package/dist/server/cli/improvisation-movements.js.map +1 -1
- package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -1
- package/dist/server/cli/improvisation-output-queue.js +0 -1
- package/dist/server/cli/improvisation-output-queue.js.map +1 -1
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
- package/dist/server/cli/improvisation-retry.js +0 -1
- package/dist/server/cli/improvisation-retry.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +0 -1
- 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.map +1 -1
- package/dist/server/cli/retry/retry-best-result.js +0 -1
- package/dist/server/cli/retry/retry-best-result.js.map +1 -1
- package/dist/server/cli/retry/retry-context-loss.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-context-loss.js +0 -1
- package/dist/server/cli/retry/retry-context-loss.js.map +1 -1
- package/dist/server/cli/retry/retry-premature-completion.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-premature-completion.js +1 -2
- package/dist/server/cli/retry/retry-premature-completion.js.map +1 -1
- package/dist/server/cli/retry/retry-recovery-strategies.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-recovery-strategies.js +0 -1
- package/dist/server/cli/retry/retry-recovery-strategies.js.map +1 -1
- package/dist/server/cli/retry/retry-resume-strategy.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-resume-strategy.js +0 -1
- package/dist/server/cli/retry/retry-resume-strategy.js.map +1 -1
- package/dist/server/cli/retry/retry-runner-factory.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-runner-factory.js +0 -1
- package/dist/server/cli/retry/retry-runner-factory.js.map +1 -1
- package/dist/server/cli/retry/retry-tool-results.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-tool-results.js +0 -1
- package/dist/server/cli/retry/retry-tool-results.js.map +1 -1
- package/dist/server/cli/retry/retry-types.d.ts.map +1 -1
- package/dist/server/cli/retry/retry-types.js +0 -1
- package/dist/server/cli/retry/retry-types.js.map +1 -1
- package/dist/server/index.js +0 -1
- 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.map +1 -1
- package/dist/server/server-setup.js +0 -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.map +1 -1
- package/dist/server/services/plan/board-config.js +0 -1
- package/dist/server/services/plan/board-config.js.map +1 -1
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +0 -1
- 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.map +1 -1
- package/dist/server/services/plan/executor.js +45 -3
- 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.map +1 -1
- package/dist/server/services/plan/issue-loader.js +0 -1
- package/dist/server/services/plan/issue-loader.js.map +1 -1
- 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.map +1 -1
- package/dist/server/services/plan/issue-writer.js +0 -1
- package/dist/server/services/plan/issue-writer.js.map +1 -1
- package/dist/server/services/plan/output-manager.d.ts.map +1 -1
- package/dist/server/services/plan/output-manager.js +0 -1
- 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.map +1 -1
- package/dist/server/services/plan/progress-log.js +0 -1
- package/dist/server/services/plan/progress-log.js.map +1 -1
- package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
- package/dist/server/services/plan/prompt-builder.js +0 -1
- package/dist/server/services/plan/prompt-builder.js.map +1 -1
- package/dist/server/services/plan/readiness-planner.d.ts.map +1 -1
- package/dist/server/services/plan/readiness-planner.js +0 -1
- package/dist/server/services/plan/readiness-planner.js.map +1 -1
- package/dist/server/services/plan/review-gate.d.ts.map +1 -1
- package/dist/server/services/plan/review-gate.js +0 -1
- 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 +21 -56
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +98 -142
- 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.map +1 -1
- package/dist/server/services/websocket/file-download-handler.js +0 -1
- package/dist/server/services/websocket/file-download-handler.js.map +1 -1
- 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 +230 -14
- package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
- 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.map +1 -1
- package/dist/server/services/websocket/handler.js +3 -4
- 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.map +1 -1
- package/dist/server/services/websocket/msg-id-tracker.js +0 -1
- package/dist/server/services/websocket/msg-id-tracker.js.map +1 -1
- 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 +0 -1
- 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 +0 -1
- 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.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +0 -1
- 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.map +1 -1
- package/dist/server/services/websocket/session-initialization.js +0 -1
- package/dist/server/services/websocket/session-initialization.js.map +1 -1
- package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
- package/dist/server/services/websocket/session-registry.js +0 -1
- 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.map +1 -1
- package/dist/server/services/websocket/tab-broadcast.js +0 -1
- package/dist/server/services/websocket/tab-broadcast.js.map +1 -1
- package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-event-buffer.js +0 -1
- package/dist/server/services/websocket/tab-event-buffer.js.map +1 -1
- package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-event-replay.js +0 -1
- package/dist/server/services/websocket/tab-event-replay.js.map +1 -1
- package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-handlers.js +0 -1
- 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 +2 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/services/websocket/types.js +2 -3
- 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/cli/headless/claude-invoker-process.ts +0 -1
- package/server/cli/headless/claude-invoker-stall.ts +0 -1
- 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 +0 -1
- 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 +0 -1
- package/server/cli/headless/stall-assessor.ts +0 -1
- package/server/cli/headless/tool-watchdog.ts +0 -1
- package/server/cli/headless/types.ts +0 -1
- package/server/cli/improvisation-attachments.ts +0 -1
- package/server/cli/improvisation-history-store.ts +0 -1
- package/server/cli/improvisation-movements.ts +0 -1
- package/server/cli/improvisation-output-queue.ts +0 -1
- package/server/cli/improvisation-retry.ts +0 -1
- package/server/cli/improvisation-session-manager.ts +0 -1
- package/server/cli/improvisation-types.ts +0 -1
- package/server/cli/retry/retry-best-result.ts +0 -1
- package/server/cli/retry/retry-context-loss.ts +0 -1
- package/server/cli/retry/retry-premature-completion.ts +1 -2
- package/server/cli/retry/retry-recovery-strategies.ts +0 -1
- package/server/cli/retry/retry-resume-strategy.ts +0 -1
- package/server/cli/retry/retry-runner-factory.ts +0 -1
- package/server/cli/retry/retry-tool-results.ts +0 -1
- package/server/cli/retry/retry-types.ts +0 -1
- package/server/index.ts +0 -1
- 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 +0 -1
- 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/code-review.md +13 -11
- package/server/services/plan/board-config.ts +0 -1
- package/server/services/plan/composer.ts +0 -1
- package/server/services/plan/config-installer.ts +0 -1
- package/server/services/plan/dependency-resolver.ts +0 -1
- package/server/services/plan/executor.ts +45 -3
- 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 +0 -1
- 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 +0 -1
- package/server/services/plan/output-manager.ts +0 -1
- 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 +0 -1
- package/server/services/plan/prompt-builder.ts +0 -1
- package/server/services/plan/readiness-planner.ts +0 -1
- package/server/services/plan/review-gate.ts +0 -1
- 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 +106 -148
- 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 +0 -1
- 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 +260 -17
- package/server/services/websocket/handler-context.ts +0 -1
- package/server/services/websocket/handler.ts +3 -4
- package/server/services/websocket/index.ts +0 -1
- package/server/services/websocket/msg-id-tracker.ts +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- package/server/services/websocket/session-history.ts +0 -1
- package/server/services/websocket/session-initialization.ts +0 -1
- package/server/services/websocket/session-registry.ts +0 -1
- 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 +0 -1
- package/server/services/websocket/tab-event-buffer.ts +0 -1
- package/server/services/websocket/tab-event-replay.ts +0 -1
- package/server/services/websocket/tab-handlers.ts +0 -1
- package/server/services/websocket/terminal-handlers.ts +39 -3
- package/server/services/websocket/types.ts +2 -3
- 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,171 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Token Lifecycle — refresh, verify, and auth-expired signaling for the
|
|
5
|
+
* platform device token. Extracted from PlatformConnection so the relay
|
|
6
|
+
* lifecycle (sockets, reconnect, heartbeat) and the auth lifecycle (token
|
|
7
|
+
* refresh, verify, expired-signal) can be reasoned about apart. The token
|
|
8
|
+
* lifecycle has its own clock (24h periodic check), its own remote endpoints
|
|
9
|
+
* (/refresh, /verify), and its own failure modes (revocation vs. transient
|
|
10
|
+
* network error) — none of which need to be in PlatformConnection.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
getCredentials,
|
|
15
|
+
shouldRefreshToken,
|
|
16
|
+
updateCredentials,
|
|
17
|
+
} from './platform-credentials.js'
|
|
18
|
+
|
|
19
|
+
const PERIODIC_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000
|
|
20
|
+
|
|
21
|
+
export interface TokenLifecycleDeps {
|
|
22
|
+
/** Platform base URL — used to compose /api/auth/device/{refresh,verify} */
|
|
23
|
+
platformUrl: string
|
|
24
|
+
/** Send a message upstream over the live relay socket (no-op if closed). */
|
|
25
|
+
send: (message: unknown) => void
|
|
26
|
+
/** Read the current relay connection ID at the moment auth-expired fires. */
|
|
27
|
+
getConnectionId: () => string | null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class TokenLifecycle {
|
|
31
|
+
private intervalHandle: ReturnType<typeof setInterval> | null = null
|
|
32
|
+
|
|
33
|
+
constructor(private readonly deps: TokenLifecycleDeps) {}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Refresh the device token if it's older than the refresh interval.
|
|
37
|
+
* Returns `true` if the token is (still) valid after this call, `false`
|
|
38
|
+
* if refresh was attempted and rejected with an auth error — in which
|
|
39
|
+
* case the caller should surface an auth-expired signal to the web
|
|
40
|
+
* rather than silently reusing a dead token.
|
|
41
|
+
*/
|
|
42
|
+
async maybeRefresh(): Promise<boolean> {
|
|
43
|
+
const creds = getCredentials()
|
|
44
|
+
if (!creds) return false
|
|
45
|
+
if (!shouldRefreshToken(creds)) return true
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch(`${this.deps.platformUrl}/api/auth/device/refresh`, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Authorization': `Bearer ${creds.token}`,
|
|
52
|
+
'Content-Type': 'application/json'
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if (response.ok) {
|
|
57
|
+
const data = await response.json() as { accessToken: string }
|
|
58
|
+
updateCredentials({
|
|
59
|
+
token: data.accessToken,
|
|
60
|
+
lastRefreshedAt: new Date().toISOString()
|
|
61
|
+
})
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
if (response.status === 401 || response.status === 403) {
|
|
65
|
+
console.warn(`[Platform] Token refresh failed — auth is expired (${response.status}). Run \`mstro login --force\`.`)
|
|
66
|
+
this.notifyAuthExpired()
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
console.warn(`[Platform] Token refresh failed with status ${response.status}, will retry later`)
|
|
70
|
+
return true
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.warn('[Platform] Token refresh error:', err)
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Verify the current token against the platform. A rejection (401/403)
|
|
79
|
+
* means the token is permanently invalid (revoked, signing-key rotation,
|
|
80
|
+
* account deleted); the caller should stop looping reconnects and tell
|
|
81
|
+
* the user to run `mstro login --force`.
|
|
82
|
+
*
|
|
83
|
+
* Returns `true` when the token is valid or the verification endpoint
|
|
84
|
+
* is unreachable (we prefer false negatives to false positives — a
|
|
85
|
+
* network blip shouldn't force a re-login).
|
|
86
|
+
*/
|
|
87
|
+
async verify(): Promise<boolean> {
|
|
88
|
+
const creds = getCredentials()
|
|
89
|
+
if (!creds?.token) return false
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(`${this.deps.platformUrl}/api/auth/device/verify`, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Authorization': `Bearer ${creds.token}` },
|
|
94
|
+
})
|
|
95
|
+
if (response.status === 401 || response.status === 403) {
|
|
96
|
+
console.warn(`[Platform] Token verify rejected (${response.status}) — auth is expired.`)
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
return true
|
|
100
|
+
} catch {
|
|
101
|
+
// Network error: treat as "probably valid" so a flaky connection
|
|
102
|
+
// doesn't force users to re-login. The WebSocket open itself will
|
|
103
|
+
// catch a truly bad token via the 4001 path.
|
|
104
|
+
return true
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Surface an auth-expired condition to any paired web clients.
|
|
110
|
+
*
|
|
111
|
+
* Two cooperating paths deliver this signal — either alone is enough,
|
|
112
|
+
* both together cover every timing edge:
|
|
113
|
+
*
|
|
114
|
+
* 1. **CLI-initiated (this method):** we detected a 401 from the
|
|
115
|
+
* `/refresh` or `/verify` endpoint *while the relay socket is
|
|
116
|
+
* still open*. The injected `send` pushes the message upstream so
|
|
117
|
+
* the server relays it to paired webs before the CLI closes.
|
|
118
|
+
* A no-op if the socket is already closed.
|
|
119
|
+
*
|
|
120
|
+
* 2. **Server-initiated:** when the platform closes a CLI socket
|
|
121
|
+
* with 4001 or 4008, `handleAuthClose` in `clientHandlers.ts`
|
|
122
|
+
* broadcasts the same `clientAuthExpired` to paired webs. This
|
|
123
|
+
* covers cases where the CLI never had a chance to detect the
|
|
124
|
+
* rejection itself (e.g. token revoked while the socket was idle,
|
|
125
|
+
* server-side token rotation).
|
|
126
|
+
*
|
|
127
|
+
* IMPORTANT: never route this through PlatformConnection's
|
|
128
|
+
* `onRelayedMessage` callback — that callback feeds INCOMING web→CLI
|
|
129
|
+
* requests into the local handler, which would treat
|
|
130
|
+
* `clientAuthExpired` as an unknown inbound request.
|
|
131
|
+
*/
|
|
132
|
+
notifyAuthExpired(): void {
|
|
133
|
+
this.deps.send({
|
|
134
|
+
type: 'clientAuthExpired',
|
|
135
|
+
data: {
|
|
136
|
+
connectionId: this.deps.getConnectionId(),
|
|
137
|
+
message: 'The CLI\'s device token is invalid — run `mstro login --force` on the machine.',
|
|
138
|
+
},
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Best-effort token verification, fired in parallel with the socket
|
|
144
|
+
* open so a slow verify endpoint never delays reconnect.
|
|
145
|
+
*
|
|
146
|
+
* Only runs when the token is stale enough that we'd be about to
|
|
147
|
+
* refresh anyway — keeps the hot path free of an extra network call.
|
|
148
|
+
* A truly-revoked token that slips past this check still hits 4001
|
|
149
|
+
* on the WebSocket, which also triggers `notifyAuthExpired`.
|
|
150
|
+
*/
|
|
151
|
+
maybeVerifyInParallel(): void {
|
|
152
|
+
const creds = getCredentials()
|
|
153
|
+
if (!creds || !shouldRefreshToken(creds)) return
|
|
154
|
+
this.verify().then((valid) => {
|
|
155
|
+
if (!valid) this.notifyAuthExpired()
|
|
156
|
+
}).catch(() => { /* network error — rely on 4001 close path */ })
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
startPeriodicCheck(): void {
|
|
160
|
+
this.intervalHandle = setInterval(() => {
|
|
161
|
+
this.maybeRefresh()
|
|
162
|
+
}, PERIODIC_CHECK_INTERVAL_MS)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
stopPeriodicCheck(): void {
|
|
166
|
+
if (this.intervalHandle) {
|
|
167
|
+
clearInterval(this.intervalHandle)
|
|
168
|
+
this.intervalHandle = null
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -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
|
/**
|
|
5
4
|
* Platform Connection Service
|
|
@@ -14,12 +13,8 @@ import { arch, hostname, type } from 'node:os'
|
|
|
14
13
|
import { basename } from 'node:path'
|
|
15
14
|
import { AnalyticsEvents, trackEvent } from './analytics.js'
|
|
16
15
|
import { getClientId } from './client-id.js'
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
getCredentials,
|
|
20
|
-
shouldRefreshToken,
|
|
21
|
-
updateCredentials,
|
|
22
|
-
} from './platform-credentials.js'
|
|
16
|
+
import { CLI_VERSION, getCredentials } from './platform-credentials.js'
|
|
17
|
+
import { TokenLifecycle } from './platform-token-lifecycle.js'
|
|
23
18
|
import { captureException } from './sentry.js'
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -50,6 +45,27 @@ if (typeof WebSocket !== 'undefined') {
|
|
|
50
45
|
// PLATFORM_URL is set via --server / --dev flag in mstro.js
|
|
51
46
|
const DEFAULT_PLATFORM_URL = process.env.PLATFORM_URL || 'https://api.mstro.app'
|
|
52
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Relay wire-format version this CLI speaks. Bumped by the server when the
|
|
50
|
+
* relay protocol changes incompatibly. Must match (or exceed) the server's
|
|
51
|
+
* `minProtocolVersion` in `server/src/relay/version-policy.ts` — when the
|
|
52
|
+
* server's floor moves above this value, the upgrade handshake returns 426
|
|
53
|
+
* and the CLI surfaces the upgrade message via `handleSocketClose`.
|
|
54
|
+
*
|
|
55
|
+
* This is a build-time constant, not user-configurable: a stale CLI must be
|
|
56
|
+
* told to upgrade rather than allowed to opt itself into compatibility.
|
|
57
|
+
*/
|
|
58
|
+
const PROTOCOL_VERSION = 1
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Long sentinel delay used after a 426 protocol-too-old close. The CLI
|
|
62
|
+
* auto-upgrades on the next `mstro` invocation, so a tight reconnect loop
|
|
63
|
+
* would just hammer the server with rejections that policy already decided
|
|
64
|
+
* to refuse. One hour is long enough to count as "stop", short enough that
|
|
65
|
+
* a forgotten foreground process eventually retries on its own.
|
|
66
|
+
*/
|
|
67
|
+
const PROTOCOL_UPGRADE_RECONNECT_DELAY_MS = 60 * 60 * 1000
|
|
68
|
+
|
|
53
69
|
interface ConnectionCallbacks {
|
|
54
70
|
onConnected?: (connectionId: string) => void
|
|
55
71
|
onDisconnected?: () => void
|
|
@@ -73,11 +89,12 @@ export class PlatformConnection {
|
|
|
73
89
|
private callbacks: ConnectionCallbacks
|
|
74
90
|
private connectionId: string | null = null
|
|
75
91
|
private isConnected = false
|
|
76
|
-
private tokenRefreshInterval: ReturnType<typeof setInterval> | null = null
|
|
77
92
|
private heartbeatInterval: ReturnType<typeof setInterval> | null = null
|
|
78
93
|
private missedPongs = 0
|
|
79
94
|
private everConnected = false
|
|
95
|
+
private protocolUpgradeRequired = false
|
|
80
96
|
private readonly startedAt: string
|
|
97
|
+
private readonly tokens: TokenLifecycle
|
|
81
98
|
|
|
82
99
|
constructor(
|
|
83
100
|
workingDirectory: string,
|
|
@@ -88,120 +105,13 @@ export class PlatformConnection {
|
|
|
88
105
|
this.platformUrl = platformUrl || DEFAULT_PLATFORM_URL
|
|
89
106
|
this.callbacks = callbacks
|
|
90
107
|
this.startedAt = new Date().toISOString()
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* Returns `true` if the token is (still) valid after this call, `false`
|
|
96
|
-
* if refresh was attempted and rejected with an auth error — in which
|
|
97
|
-
* case the caller should surface an auth-expired signal to the web
|
|
98
|
-
* rather than silently reusing a dead token.
|
|
99
|
-
*/
|
|
100
|
-
private async maybeRefreshToken(): Promise<boolean> {
|
|
101
|
-
const creds = getCredentials()
|
|
102
|
-
if (!creds) return false
|
|
103
|
-
if (!shouldRefreshToken(creds)) return true
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const response = await fetch(`${this.platformUrl}/api/auth/device/refresh`, {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
headers: {
|
|
109
|
-
'Authorization': `Bearer ${creds.token}`,
|
|
110
|
-
'Content-Type': 'application/json'
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
if (response.ok) {
|
|
115
|
-
const data = await response.json() as { accessToken: string }
|
|
116
|
-
updateCredentials({
|
|
117
|
-
token: data.accessToken,
|
|
118
|
-
lastRefreshedAt: new Date().toISOString()
|
|
119
|
-
})
|
|
120
|
-
return true
|
|
121
|
-
}
|
|
122
|
-
if (response.status === 401 || response.status === 403) {
|
|
123
|
-
console.warn(`[Platform] Token refresh failed — auth is expired (${response.status}). Run \`mstro login --force\`.`)
|
|
124
|
-
this.notifyAuthExpired()
|
|
125
|
-
return false
|
|
126
|
-
}
|
|
127
|
-
console.warn(`[Platform] Token refresh failed with status ${response.status}, will retry later`)
|
|
128
|
-
return true
|
|
129
|
-
} catch (err) {
|
|
130
|
-
console.warn('[Platform] Token refresh error:', err)
|
|
131
|
-
return true
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Verify the current token against the platform. A rejection (401/403)
|
|
137
|
-
* means the token is permanently invalid (revoked, signing-key rotation,
|
|
138
|
-
* account deleted); the caller should stop looping reconnects and tell
|
|
139
|
-
* the user to run `mstro login --force`.
|
|
140
|
-
*
|
|
141
|
-
* Returns `true` when the token is valid or the verification endpoint
|
|
142
|
-
* is unreachable (we prefer false negatives to false positives — a
|
|
143
|
-
* network blip shouldn't force a re-login).
|
|
144
|
-
*/
|
|
145
|
-
private async verifyToken(): Promise<boolean> {
|
|
146
|
-
const creds = getCredentials()
|
|
147
|
-
if (!creds?.token) return false
|
|
148
|
-
try {
|
|
149
|
-
const response = await fetch(`${this.platformUrl}/api/auth/device/verify`, {
|
|
150
|
-
method: 'POST',
|
|
151
|
-
headers: { 'Authorization': `Bearer ${creds.token}` },
|
|
152
|
-
})
|
|
153
|
-
if (response.status === 401 || response.status === 403) {
|
|
154
|
-
console.warn(`[Platform] Token verify rejected (${response.status}) — auth is expired.`)
|
|
155
|
-
return false
|
|
156
|
-
}
|
|
157
|
-
return true
|
|
158
|
-
} catch {
|
|
159
|
-
// Network error: treat as "probably valid" so a flaky connection
|
|
160
|
-
// doesn't force users to re-login. The WebSocket open itself will
|
|
161
|
-
// catch a truly bad token via the 4001 path.
|
|
162
|
-
return true
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Surface an auth-expired condition to any paired web clients.
|
|
168
|
-
*
|
|
169
|
-
* Two cooperating paths deliver this signal — either alone is enough,
|
|
170
|
-
* both together cover every timing edge:
|
|
171
|
-
*
|
|
172
|
-
* 1. **CLI-initiated (this method):** we detected a 401 from the
|
|
173
|
-
* `/refresh` or `/verify` endpoint *while the relay socket is
|
|
174
|
-
* still open*. `this.send` pushes the message upstream so the
|
|
175
|
-
* server relays it to paired webs before we intentionally close.
|
|
176
|
-
* A no-op if the socket is already closed.
|
|
177
|
-
*
|
|
178
|
-
* 2. **Server-initiated:** when the platform closes a CLI socket
|
|
179
|
-
* with 4001 or 4008, `handleAuthClose` in `clientHandlers.ts`
|
|
180
|
-
* broadcasts the same `clientAuthExpired` to paired webs. This
|
|
181
|
-
* covers the cases where the CLI never had a chance to detect
|
|
182
|
-
* the rejection itself (e.g. token revoked while the socket was
|
|
183
|
-
* idle, server-side token rotation).
|
|
184
|
-
*
|
|
185
|
-
* IMPORTANT: never call `this.callbacks.onRelayedMessage` here —
|
|
186
|
-
* that callback feeds INCOMING web→CLI requests into the local handler,
|
|
187
|
-
* which would treat `clientAuthExpired` as an unknown inbound request.
|
|
188
|
-
*/
|
|
189
|
-
private notifyAuthExpired(): void {
|
|
190
|
-
this.send({
|
|
191
|
-
type: 'clientAuthExpired',
|
|
192
|
-
data: {
|
|
193
|
-
connectionId: this.connectionId,
|
|
194
|
-
message: 'The CLI\'s device token is invalid — run `mstro login --force` on the machine.',
|
|
195
|
-
},
|
|
108
|
+
this.tokens = new TokenLifecycle({
|
|
109
|
+
platformUrl: this.platformUrl,
|
|
110
|
+
send: (msg) => this.send(msg),
|
|
111
|
+
getConnectionId: () => this.connectionId,
|
|
196
112
|
})
|
|
197
113
|
}
|
|
198
114
|
|
|
199
|
-
private startTokenRefreshCheck(): void {
|
|
200
|
-
this.tokenRefreshInterval = setInterval(() => {
|
|
201
|
-
this.maybeRefreshToken()
|
|
202
|
-
}, 24 * 60 * 60 * 1000)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
115
|
private startHeartbeat(): void {
|
|
206
116
|
this.missedPongs = 0
|
|
207
117
|
this.heartbeatInterval = setInterval(() => this.heartbeatTick(), 25_000)
|
|
@@ -232,15 +142,9 @@ export class PlatformConnection {
|
|
|
232
142
|
}
|
|
233
143
|
}
|
|
234
144
|
|
|
235
|
-
private stopTokenRefreshCheck(): void {
|
|
236
|
-
if (this.tokenRefreshInterval) {
|
|
237
|
-
clearInterval(this.tokenRefreshInterval)
|
|
238
|
-
this.tokenRefreshInterval = null
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
145
|
connect(): void {
|
|
243
146
|
this.isIntentionallyClosed = false
|
|
147
|
+
this.protocolUpgradeRequired = false
|
|
244
148
|
|
|
245
149
|
const authToken = getCredentials()?.token
|
|
246
150
|
if (!authToken) {
|
|
@@ -262,24 +166,7 @@ export class PlatformConnection {
|
|
|
262
166
|
|
|
263
167
|
const connectionTimeout = this.startConnectionTimeout()
|
|
264
168
|
this.attachSocketHandlers(this.ws, authToken, connectionTimeout)
|
|
265
|
-
this.
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Best-effort token verification, fired in parallel with the socket
|
|
270
|
-
* open so a slow verify endpoint never delays reconnect.
|
|
271
|
-
*
|
|
272
|
-
* Only runs when the token is stale enough that we'd be about to
|
|
273
|
-
* refresh anyway — keeps the hot path free of an extra network call.
|
|
274
|
-
* A truly-revoked token that slips past this check still hits 4001
|
|
275
|
-
* on the WebSocket, which also triggers `notifyAuthExpired`.
|
|
276
|
-
*/
|
|
277
|
-
private maybeVerifyTokenInParallel(): void {
|
|
278
|
-
const creds = getCredentials()
|
|
279
|
-
if (!creds || !shouldRefreshToken(creds)) return
|
|
280
|
-
this.verifyToken().then((valid) => {
|
|
281
|
-
if (!valid) this.notifyAuthExpired()
|
|
282
|
-
}).catch(() => { /* network error — rely on 4001 close path */ })
|
|
169
|
+
this.tokens.maybeVerifyInParallel()
|
|
283
170
|
}
|
|
284
171
|
|
|
285
172
|
private buildConnectionUrl(): string {
|
|
@@ -295,6 +182,7 @@ export class PlatformConnection {
|
|
|
295
182
|
cliVersion: CLI_VERSION,
|
|
296
183
|
capabilities: JSON.stringify({}),
|
|
297
184
|
startedAt: this.startedAt,
|
|
185
|
+
protocolVersion: String(PROTOCOL_VERSION),
|
|
298
186
|
})
|
|
299
187
|
return `${this.platformUrl.replace(/^http/, 'ws')}/ws/client?${params}`
|
|
300
188
|
}
|
|
@@ -319,8 +207,8 @@ export class PlatformConnection {
|
|
|
319
207
|
ws.onopen = () => {
|
|
320
208
|
clearTimeout(connectionTimeout)
|
|
321
209
|
ws.send(JSON.stringify({ type: 'auth', token: authToken }))
|
|
322
|
-
this.
|
|
323
|
-
this.
|
|
210
|
+
this.tokens.maybeRefresh()
|
|
211
|
+
this.tokens.startPeriodicCheck()
|
|
324
212
|
this.reconnectAttempts = 0
|
|
325
213
|
trackEvent(AnalyticsEvents.PLATFORM_CONNECTED)
|
|
326
214
|
}
|
|
@@ -342,6 +230,24 @@ export class PlatformConnection {
|
|
|
342
230
|
clearTimeout(connectionTimeout)
|
|
343
231
|
// onclose will be called after this
|
|
344
232
|
}
|
|
233
|
+
|
|
234
|
+
// The Node `ws` library exposes the raw HTTP upgrade response as an
|
|
235
|
+
// `unexpected-response` event when the server returns a non-101 status
|
|
236
|
+
// (for us: 426 Upgrade Required from the protocol-version gate). The
|
|
237
|
+
// global WebSocket in Bun / Node 21+ doesn't expose this — for those
|
|
238
|
+
// runtimes we rely on the close-code path below. Both paths feed into
|
|
239
|
+
// `protocolUpgradeRequired`, so `handleSocketClose` can decide once.
|
|
240
|
+
const wsWithEmitter = ws as unknown as {
|
|
241
|
+
on?: (event: string, listener: (...args: unknown[]) => void) => void
|
|
242
|
+
}
|
|
243
|
+
if (typeof wsWithEmitter.on === 'function') {
|
|
244
|
+
wsWithEmitter.on('unexpected-response', (...args: unknown[]) => {
|
|
245
|
+
const response = args[1] as { statusCode?: number } | undefined
|
|
246
|
+
if (response?.statusCode === 426) {
|
|
247
|
+
this.protocolUpgradeRequired = true
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
}
|
|
345
251
|
}
|
|
346
252
|
|
|
347
253
|
private handleSocketClose(event: CloseEvent): void {
|
|
@@ -350,6 +256,11 @@ export class PlatformConnection {
|
|
|
350
256
|
|
|
351
257
|
if (this.isIntentionallyClosed) return
|
|
352
258
|
|
|
259
|
+
if (this.isProtocolTooOldClose(event)) {
|
|
260
|
+
this.handleProtocolUpgradeRequired()
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
|
|
353
264
|
const isAuthFailure = event.code === 4001 ||
|
|
354
265
|
event.reason?.includes('Unauthorized') ||
|
|
355
266
|
(event.code === 1006 && !this.everConnected)
|
|
@@ -357,7 +268,7 @@ export class PlatformConnection {
|
|
|
357
268
|
if (isAuthFailure) {
|
|
358
269
|
console.error('\n❌ Authentication failed. Your device token may be invalid or expired.')
|
|
359
270
|
console.error(' Run `mstro login --force` to re-authenticate.\n')
|
|
360
|
-
this.notifyAuthExpired()
|
|
271
|
+
this.tokens.notifyAuthExpired()
|
|
361
272
|
this.callbacks.onError?.('Authentication failed - run `mstro login --force`')
|
|
362
273
|
return
|
|
363
274
|
}
|
|
@@ -368,6 +279,53 @@ export class PlatformConnection {
|
|
|
368
279
|
this.scheduleReconnect()
|
|
369
280
|
}
|
|
370
281
|
|
|
282
|
+
/**
|
|
283
|
+
* The relay can refuse a CLI for being too old in two shapes:
|
|
284
|
+
*
|
|
285
|
+
* 1. **HTTP 426 during upgrade** — the `ws` library surfaces this via
|
|
286
|
+
* its `unexpected-response` event, which sets
|
|
287
|
+
* `protocolUpgradeRequired` before `onclose` fires. This is the path
|
|
288
|
+
* the current server takes (`checkProtocolVersionGate`).
|
|
289
|
+
*
|
|
290
|
+
* 2. **WS close 1002/1008 with `protocol-too-old` reason** — reserved
|
|
291
|
+
* for a future server variant that completes the upgrade and then
|
|
292
|
+
* closes (e.g. when the policy check moves into a post-handshake
|
|
293
|
+
* stage). The reason string is part of the contract with the server.
|
|
294
|
+
*
|
|
295
|
+
* Anything else (1006 race after a successful run, 1001 going-away on
|
|
296
|
+
* deploy) must fall through to the regular reconnect path so transient
|
|
297
|
+
* failures keep healing on their own.
|
|
298
|
+
*/
|
|
299
|
+
private isProtocolTooOldClose(event: CloseEvent): boolean {
|
|
300
|
+
if (this.protocolUpgradeRequired) return true
|
|
301
|
+
const code = event.code
|
|
302
|
+
if ((code === 1002 || code === 1008) && event.reason?.includes('protocol-too-old')) {
|
|
303
|
+
return true
|
|
304
|
+
}
|
|
305
|
+
return false
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private handleProtocolUpgradeRequired(): void {
|
|
309
|
+
const message = 'Mstro CLI is out of date for this orchestra. Run `mstro` again to upgrade and reconnect.'
|
|
310
|
+
console.error(`\n❌ ${message}\n`)
|
|
311
|
+
this.callbacks.onError?.(message)
|
|
312
|
+
this.callbacks.onDisconnected?.()
|
|
313
|
+
|
|
314
|
+
// Don't exit the process — terminal sessions and other local state stay
|
|
315
|
+
// alive while the user re-runs `mstro`. Schedule a single, far-future
|
|
316
|
+
// reconnect as a sentinel so we silently retry exactly once if the
|
|
317
|
+
// process is somehow still around an hour later. The existing
|
|
318
|
+
// exponential-backoff path is bypassed deliberately: hammering a server
|
|
319
|
+
// that has already decided to refuse on policy is pointless.
|
|
320
|
+
if (this.reconnectTimeout) {
|
|
321
|
+
clearTimeout(this.reconnectTimeout)
|
|
322
|
+
}
|
|
323
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
324
|
+
this.reconnectTimeout = null
|
|
325
|
+
this.connect()
|
|
326
|
+
}, PROTOCOL_UPGRADE_RECONNECT_DELAY_MS)
|
|
327
|
+
}
|
|
328
|
+
|
|
371
329
|
private handleMessage(message: Record<string, unknown>): void {
|
|
372
330
|
switch (message.type) {
|
|
373
331
|
case 'paired':
|
|
@@ -430,7 +388,7 @@ export class PlatformConnection {
|
|
|
430
388
|
disconnect(): void {
|
|
431
389
|
this.isIntentionallyClosed = true
|
|
432
390
|
this.stopHeartbeat()
|
|
433
|
-
this.
|
|
391
|
+
this.tokens.stopPeriodicCheck()
|
|
434
392
|
|
|
435
393
|
if (this.reconnectTimeout) {
|
|
436
394
|
clearTimeout(this.reconnectTimeout)
|
|
@@ -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';
|