mstro-app 0.4.3 → 0.4.4
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/dist/server/cli/headless/claude-invoker-process.d.ts +11 -0
- package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-process.js +140 -0
- package/dist/server/cli/headless/claude-invoker-process.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stall.d.ts +40 -0
- package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stall.js +98 -0
- package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stream.d.ts +44 -0
- package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stream.js +276 -0
- package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-tools.d.ts +21 -0
- package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-tools.js +137 -0
- package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker.d.ts +6 -4
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +10 -807
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.d.ts +62 -0
- package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -0
- package/dist/server/cli/headless/haiku-assessments.js +281 -0
- package/dist/server/cli/headless/haiku-assessments.js.map +1 -0
- package/dist/server/cli/headless/headless-logger.d.ts +3 -2
- package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
- package/dist/server/cli/headless/headless-logger.js +28 -5
- package/dist/server/cli/headless/headless-logger.js.map +1 -1
- package/dist/server/cli/headless/native-timeout-detector.d.ts +44 -0
- package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -0
- package/dist/server/cli/headless/native-timeout-detector.js +99 -0
- package/dist/server/cli/headless/native-timeout-detector.js.map +1 -0
- package/dist/server/cli/headless/stall-assessor.d.ts +2 -110
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +65 -457
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/improvisation-attachments.d.ts +21 -0
- package/dist/server/cli/improvisation-attachments.d.ts.map +1 -0
- package/dist/server/cli/improvisation-attachments.js +116 -0
- package/dist/server/cli/improvisation-attachments.js.map +1 -0
- package/dist/server/cli/improvisation-retry.d.ts +52 -0
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -0
- package/dist/server/cli/improvisation-retry.js +434 -0
- package/dist/server/cli/improvisation-retry.js.map +1 -0
- package/dist/server/cli/improvisation-session-manager.d.ts +10 -266
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +117 -1079
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/improvisation-types.d.ts +86 -0
- package/dist/server/cli/improvisation-types.d.ts.map +1 -0
- package/dist/server/cli/improvisation-types.js +10 -0
- package/dist/server/cli/improvisation-types.js.map +1 -0
- package/dist/server/cli/prompt-builders.d.ts +68 -0
- package/dist/server/cli/prompt-builders.d.ts.map +1 -0
- package/dist/server/cli/prompt-builders.js +312 -0
- package/dist/server/cli/prompt-builders.js.map +1 -0
- package/dist/server/index.js +33 -212
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.d.ts +10 -0
- package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-haiku.js +152 -0
- package/dist/server/mcp/bouncer-haiku.js.map +1 -0
- package/dist/server/mcp/bouncer-integration.d.ts +3 -4
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +50 -196
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-analysis.d.ts +38 -0
- package/dist/server/mcp/security-analysis.d.ts.map +1 -0
- package/dist/server/mcp/security-analysis.js +183 -0
- package/dist/server/mcp/security-analysis.js.map +1 -0
- package/dist/server/mcp/security-audit.d.ts +1 -1
- package/dist/server/mcp/security-audit.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.d.ts +1 -25
- package/dist/server/mcp/security-patterns.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.js +55 -260
- package/dist/server/mcp/security-patterns.js.map +1 -1
- package/dist/server/server-setup.d.ts +22 -0
- package/dist/server/server-setup.d.ts.map +1 -0
- package/dist/server/server-setup.js +101 -0
- package/dist/server/server-setup.js.map +1 -0
- package/dist/server/services/file-explorer-ops.d.ts +24 -0
- package/dist/server/services/file-explorer-ops.d.ts.map +1 -0
- package/dist/server/services/file-explorer-ops.js +211 -0
- package/dist/server/services/file-explorer-ops.js.map +1 -0
- package/dist/server/services/files.d.ts +2 -85
- package/dist/server/services/files.d.ts.map +1 -1
- package/dist/server/services/files.js +7 -427
- package/dist/server/services/files.js.map +1 -1
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +2 -1
- package/dist/server/services/plan/composer.js.map +1 -1
- package/dist/server/services/plan/executor.d.ts.map +1 -1
- package/dist/server/services/plan/executor.js +3 -1
- package/dist/server/services/plan/executor.js.map +1 -1
- package/dist/server/services/plan/parser-core.d.ts +20 -0
- package/dist/server/services/plan/parser-core.d.ts.map +1 -0
- package/dist/server/services/plan/parser-core.js +350 -0
- package/dist/server/services/plan/parser-core.js.map +1 -0
- package/dist/server/services/plan/parser-migration.d.ts +5 -0
- package/dist/server/services/plan/parser-migration.d.ts.map +1 -0
- package/dist/server/services/plan/parser-migration.js +124 -0
- package/dist/server/services/plan/parser-migration.js.map +1 -0
- package/dist/server/services/plan/parser.d.ts +0 -8
- package/dist/server/services/plan/parser.d.ts.map +1 -1
- package/dist/server/services/plan/parser.js +50 -569
- package/dist/server/services/plan/parser.js.map +1 -1
- package/dist/server/services/plan/review-gate.d.ts +2 -0
- package/dist/server/services/plan/review-gate.d.ts.map +1 -1
- package/dist/server/services/plan/review-gate.js +2 -2
- package/dist/server/services/plan/review-gate.js.map +1 -1
- package/dist/server/services/plan/types.d.ts +2 -0
- package/dist/server/services/plan/types.d.ts.map +1 -1
- package/dist/server/services/platform-credentials.d.ts +24 -0
- package/dist/server/services/platform-credentials.d.ts.map +1 -0
- package/dist/server/services/platform-credentials.js +68 -0
- package/dist/server/services/platform-credentials.js.map +1 -0
- package/dist/server/services/platform.d.ts +1 -31
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +10 -119
- package/dist/server/services/platform.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts +7 -97
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +53 -266
- package/dist/server/services/terminal/pty-manager.js.map +1 -1
- package/dist/server/services/terminal/pty-utils.d.ts +57 -0
- package/dist/server/services/terminal/pty-utils.d.ts.map +1 -0
- package/dist/server/services/terminal/pty-utils.js +141 -0
- package/dist/server/services/terminal/pty-utils.js.map +1 -0
- package/dist/server/services/websocket/file-definition-handlers.d.ts +4 -0
- package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/file-definition-handlers.js +153 -0
- package/dist/server/services/websocket/file-definition-handlers.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 +52 -391
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/file-search-handlers.d.ts +5 -0
- package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/file-search-handlers.js +238 -0
- package/dist/server/services/websocket/file-search-handlers.js.map +1 -0
- package/dist/server/services/websocket/file-utils.js +3 -3
- package/dist/server/services/websocket/file-utils.js.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.d.ts +7 -0
- package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-branch-handlers.js +110 -0
- package/dist/server/services/websocket/git-branch-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-diff-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-diff-handlers.js +123 -0
- package/dist/server/services/websocket/git-diff-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-handlers.d.ts +2 -31
- package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-handlers.js +35 -541
- package/dist/server/services/websocket/git-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-log-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-log-handlers.js +128 -0
- package/dist/server/services/websocket/git-log-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.js +13 -53
- package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-tag-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-tag-handlers.js +76 -0
- package/dist/server/services/websocket/git-tag-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-utils.d.ts +43 -0
- package/dist/server/services/websocket/git-utils.d.ts.map +1 -0
- package/dist/server/services/websocket/git-utils.js +201 -0
- package/dist/server/services/websocket/git-utils.js.map +1 -0
- package/dist/server/services/websocket/handler.d.ts +2 -0
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +37 -126
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.d.ts +11 -0
- package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-board-handlers.js +218 -0
- package/dist/server/services/websocket/plan-board-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-execution-handlers.d.ts +9 -0
- package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-execution-handlers.js +142 -0
- package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-handlers.d.ts +7 -2
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-handlers.js +6 -925
- package/dist/server/services/websocket/plan-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-helpers.d.ts +19 -0
- package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-helpers.js +199 -0
- package/dist/server/services/websocket/plan-helpers.js.map +1 -0
- package/dist/server/services/websocket/plan-issue-handlers.d.ts +12 -0
- package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-issue-handlers.js +162 -0
- package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-sprint-handlers.d.ts +7 -0
- package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js +206 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -0
- package/dist/server/services/websocket/quality-complexity.d.ts +14 -0
- package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-complexity.js +262 -0
- package/dist/server/services/websocket/quality-complexity.js.map +1 -0
- package/dist/server/services/websocket/quality-fix-agent.d.ts +16 -0
- package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-fix-agent.js +140 -0
- package/dist/server/services/websocket/quality-fix-agent.js.map +1 -0
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +34 -346
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-linting.d.ts +9 -0
- package/dist/server/services/websocket/quality-linting.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-linting.js +178 -0
- package/dist/server/services/websocket/quality-linting.js.map +1 -0
- package/dist/server/services/websocket/quality-review-agent.d.ts +19 -0
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-review-agent.js +206 -0
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -0
- package/dist/server/services/websocket/quality-service.d.ts +3 -51
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +9 -651
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts +23 -0
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-tools.js +208 -0
- package/dist/server/services/websocket/quality-tools.js.map +1 -0
- package/dist/server/services/websocket/quality-types.d.ts +59 -0
- package/dist/server/services/websocket/quality-types.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-types.js +101 -0
- package/dist/server/services/websocket/quality-types.js.map +1 -0
- package/dist/server/services/websocket/session-handlers.d.ts +3 -4
- package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +3 -378
- package/dist/server/services/websocket/session-handlers.js.map +1 -1
- package/dist/server/services/websocket/session-history.d.ts +4 -0
- package/dist/server/services/websocket/session-history.d.ts.map +1 -0
- package/dist/server/services/websocket/session-history.js +208 -0
- package/dist/server/services/websocket/session-history.js.map +1 -0
- package/dist/server/services/websocket/session-initialization.d.ts +5 -0
- package/dist/server/services/websocket/session-initialization.d.ts.map +1 -0
- package/dist/server/services/websocket/session-initialization.js +163 -0
- package/dist/server/services/websocket/session-initialization.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +12 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/server/cli/headless/claude-invoker-process.ts +204 -0
- package/server/cli/headless/claude-invoker-stall.ts +164 -0
- package/server/cli/headless/claude-invoker-stream.ts +353 -0
- package/server/cli/headless/claude-invoker-tools.ts +187 -0
- package/server/cli/headless/claude-invoker.ts +15 -1096
- package/server/cli/headless/haiku-assessments.ts +365 -0
- package/server/cli/headless/headless-logger.ts +26 -5
- package/server/cli/headless/native-timeout-detector.ts +117 -0
- package/server/cli/headless/stall-assessor.ts +65 -618
- package/server/cli/improvisation-attachments.ts +148 -0
- package/server/cli/improvisation-retry.ts +602 -0
- package/server/cli/improvisation-session-manager.ts +140 -1349
- package/server/cli/improvisation-types.ts +98 -0
- package/server/cli/prompt-builders.ts +370 -0
- package/server/index.ts +35 -246
- package/server/mcp/bouncer-haiku.ts +182 -0
- package/server/mcp/bouncer-integration.ts +87 -248
- package/server/mcp/security-analysis.ts +217 -0
- package/server/mcp/security-audit.ts +1 -1
- package/server/mcp/security-patterns.ts +60 -283
- package/server/server-setup.ts +114 -0
- package/server/services/file-explorer-ops.ts +293 -0
- package/server/services/files.ts +20 -532
- package/server/services/plan/composer.ts +2 -1
- package/server/services/plan/executor.ts +3 -1
- package/server/services/plan/parser-core.ts +406 -0
- package/server/services/plan/parser-migration.ts +128 -0
- package/server/services/plan/parser.ts +52 -620
- package/server/services/plan/review-gate.ts +4 -2
- package/server/services/plan/types.ts +2 -0
- package/server/services/platform-credentials.ts +83 -0
- package/server/services/platform.ts +15 -141
- package/server/services/terminal/pty-manager.ts +66 -313
- package/server/services/terminal/pty-utils.ts +176 -0
- package/server/services/websocket/file-definition-handlers.ts +165 -0
- package/server/services/websocket/file-explorer-handlers.ts +37 -452
- package/server/services/websocket/file-search-handlers.ts +291 -0
- package/server/services/websocket/file-utils.ts +3 -3
- package/server/services/websocket/git-branch-handlers.ts +130 -0
- package/server/services/websocket/git-diff-handlers.ts +140 -0
- package/server/services/websocket/git-handlers.ts +40 -625
- package/server/services/websocket/git-log-handlers.ts +149 -0
- package/server/services/websocket/git-pr-handlers.ts +17 -62
- package/server/services/websocket/git-tag-handlers.ts +91 -0
- package/server/services/websocket/git-utils.ts +230 -0
- package/server/services/websocket/handler.ts +39 -126
- package/server/services/websocket/plan-board-handlers.ts +277 -0
- package/server/services/websocket/plan-execution-handlers.ts +184 -0
- package/server/services/websocket/plan-handlers.ts +8 -1114
- package/server/services/websocket/plan-helpers.ts +215 -0
- package/server/services/websocket/plan-issue-handlers.ts +204 -0
- package/server/services/websocket/plan-sprint-handlers.ts +252 -0
- package/server/services/websocket/quality-complexity.ts +294 -0
- package/server/services/websocket/quality-fix-agent.ts +181 -0
- package/server/services/websocket/quality-handlers.ts +36 -404
- package/server/services/websocket/quality-linting.ts +187 -0
- package/server/services/websocket/quality-review-agent.ts +246 -0
- package/server/services/websocket/quality-service.ts +11 -762
- package/server/services/websocket/quality-tools.ts +209 -0
- package/server/services/websocket/quality-types.ts +169 -0
- package/server/services/websocket/session-handlers.ts +5 -437
- package/server/services/websocket/session-history.ts +222 -0
- package/server/services/websocket/session-initialization.ts +209 -0
- package/server/services/websocket/types.ts +17 -0
|
@@ -29,6 +29,8 @@ export interface ReviewIssueOptions {
|
|
|
29
29
|
pmDir: string;
|
|
30
30
|
outputPath: string;
|
|
31
31
|
onOutput?: (text: string) => void;
|
|
32
|
+
/** Board-scoped log directory for execution logs. Falls back to global ~/.mstro/logs/headless/ */
|
|
33
|
+
logDir?: string;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
/**
|
|
@@ -36,7 +38,7 @@ export interface ReviewIssueOptions {
|
|
|
36
38
|
* Returns auto-pass on infrastructure failures to avoid blocking execution.
|
|
37
39
|
*/
|
|
38
40
|
export async function reviewIssue(options: ReviewIssueOptions): Promise<ReviewResult> {
|
|
39
|
-
const { workingDir, issue, pmDir, outputPath, onOutput } = options;
|
|
41
|
+
const { workingDir, issue, pmDir, outputPath, onOutput, logDir } = options;
|
|
40
42
|
const isCodeTask = issue.filesToModify.length > 0;
|
|
41
43
|
const issueType: ReviewResult['issueType'] = isCodeTask ? 'code' : 'non-code';
|
|
42
44
|
|
|
@@ -53,7 +55,7 @@ export async function reviewIssue(options: ReviewIssueOptions): Promise<ReviewRe
|
|
|
53
55
|
outputCallback: onOutput ? (text: string) => onOutput(`Review: ${text}`) : undefined,
|
|
54
56
|
});
|
|
55
57
|
|
|
56
|
-
const result = await runWithFileLogger('pm-review', () => runner.run());
|
|
58
|
+
const result = await runWithFileLogger('pm-review', () => runner.run(), logDir);
|
|
57
59
|
|
|
58
60
|
if (result.completed && result.assistantResponse) {
|
|
59
61
|
return parseReviewOutput(issue.id, issueType, result.assistantResponse);
|
|
@@ -226,6 +226,8 @@ export interface BoardArtifacts {
|
|
|
226
226
|
progressLog: string;
|
|
227
227
|
outputFiles: string[];
|
|
228
228
|
reviewResults: ReviewResult[];
|
|
229
|
+
/** Log file names from boards/BOARD-NNN/logs/ (wave execution + review logs) */
|
|
230
|
+
executionLogs: string[];
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
/** @deprecated Use BoardArtifacts — kept for migration compatibility */
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Platform Credentials — Token management for device authentication.
|
|
6
|
+
*
|
|
7
|
+
* Reads/writes credentials from ~/.mstro/credentials.json and handles
|
|
8
|
+
* periodic token refresh with the platform server.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
12
|
+
import { homedir } from 'node:os'
|
|
13
|
+
import { join } from 'node:path'
|
|
14
|
+
import { MSTRO_ROOT } from '../utils/paths.js'
|
|
15
|
+
|
|
16
|
+
// Read CLI version from package.json once at import time
|
|
17
|
+
export const CLI_VERSION = (() => {
|
|
18
|
+
try {
|
|
19
|
+
const pkg = JSON.parse(readFileSync(join(MSTRO_ROOT, 'package.json'), 'utf-8'))
|
|
20
|
+
return pkg.version || '0.0.0'
|
|
21
|
+
} catch {
|
|
22
|
+
return '0.0.0'
|
|
23
|
+
}
|
|
24
|
+
})()
|
|
25
|
+
|
|
26
|
+
const MSTRO_DIR = join(homedir(), '.mstro')
|
|
27
|
+
const CREDENTIALS_FILE = join(MSTRO_DIR, 'credentials.json')
|
|
28
|
+
|
|
29
|
+
/** Refresh token every 30 days */
|
|
30
|
+
export const TOKEN_REFRESH_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000
|
|
31
|
+
|
|
32
|
+
export interface StoredCredentials {
|
|
33
|
+
token: string
|
|
34
|
+
userId: string
|
|
35
|
+
email: string
|
|
36
|
+
name?: string
|
|
37
|
+
clientId: string
|
|
38
|
+
lastRefreshedAt?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get stored credentials from ~/.mstro/credentials.json
|
|
43
|
+
*/
|
|
44
|
+
export function getCredentials(): StoredCredentials | null {
|
|
45
|
+
if (!existsSync(CREDENTIALS_FILE)) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const content = readFileSync(CREDENTIALS_FILE, 'utf-8')
|
|
50
|
+
const creds = JSON.parse(content)
|
|
51
|
+
if (creds.token && creds.userId && creds.email) {
|
|
52
|
+
return creds
|
|
53
|
+
}
|
|
54
|
+
return null
|
|
55
|
+
} catch {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Update stored credentials (for token refresh)
|
|
62
|
+
*/
|
|
63
|
+
export function updateCredentials(updates: Partial<StoredCredentials>): void {
|
|
64
|
+
const creds = getCredentials()
|
|
65
|
+
if (!creds) return
|
|
66
|
+
|
|
67
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify({ ...creds, ...updates }, null, 2), {
|
|
68
|
+
mode: 0o600
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if token should be refreshed
|
|
74
|
+
*/
|
|
75
|
+
export function shouldRefreshToken(creds: StoredCredentials): boolean {
|
|
76
|
+
if (!creds.lastRefreshedAt) {
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const lastRefreshed = new Date(creds.lastRefreshedAt).getTime()
|
|
81
|
+
const now = Date.now()
|
|
82
|
+
return now - lastRefreshed > TOKEN_REFRESH_INTERVAL_MS
|
|
83
|
+
}
|
|
@@ -7,92 +7,23 @@
|
|
|
7
7
|
* Handles WebSocket connection to the Mstro platform.
|
|
8
8
|
* Requires token-based authentication from `mstro login`.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* 1. Client reads token from ~/.mstro/credentials.json
|
|
12
|
-
* 2. Client connects to platform WebSocket with auth token
|
|
13
|
-
* 3. Platform validates token and auto-pairs to user's account
|
|
14
|
-
* 4. Client becomes an "orchestra" visible in user's web dashboard
|
|
10
|
+
* Credential management lives in platform-credentials.ts.
|
|
15
11
|
*/
|
|
16
12
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { basename, join } from 'node:path'
|
|
13
|
+
import { arch, hostname, type } from 'node:os'
|
|
14
|
+
import { basename } from 'node:path'
|
|
20
15
|
import { AnalyticsEvents, trackEvent } from './analytics.js'
|
|
21
16
|
import { getClientId } from './client-id.js'
|
|
17
|
+
import {
|
|
18
|
+
CLI_VERSION,
|
|
19
|
+
getCredentials,
|
|
20
|
+
shouldRefreshToken,
|
|
21
|
+
updateCredentials,
|
|
22
|
+
} from './platform-credentials.js'
|
|
22
23
|
import { captureException } from './sentry.js'
|
|
23
24
|
|
|
24
|
-
// Read CLI version from package.json once at import time
|
|
25
|
-
const CLI_VERSION = (() => {
|
|
26
|
-
try {
|
|
27
|
-
const pkg = JSON.parse(readFileSync(join(import.meta.dirname || '.', '..', 'package.json'), 'utf-8'))
|
|
28
|
-
return pkg.version || '0.0.0'
|
|
29
|
-
} catch {
|
|
30
|
-
return '0.0.0'
|
|
31
|
-
}
|
|
32
|
-
})()
|
|
33
|
-
|
|
34
|
-
const MSTRO_DIR = join(homedir(), '.mstro')
|
|
35
|
-
const CREDENTIALS_FILE = join(MSTRO_DIR, 'credentials.json')
|
|
36
|
-
|
|
37
|
-
// Refresh token every 30 days
|
|
38
|
-
const TOKEN_REFRESH_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000
|
|
39
|
-
|
|
40
|
-
interface StoredCredentials {
|
|
41
|
-
token: string
|
|
42
|
-
userId: string
|
|
43
|
-
email: string
|
|
44
|
-
name?: string
|
|
45
|
-
clientId: string
|
|
46
|
-
lastRefreshedAt?: string
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get stored credentials from ~/.mstro/credentials.json
|
|
51
|
-
*/
|
|
52
|
-
function getCredentials(): StoredCredentials | null {
|
|
53
|
-
if (!existsSync(CREDENTIALS_FILE)) {
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
const content = readFileSync(CREDENTIALS_FILE, 'utf-8')
|
|
58
|
-
const creds = JSON.parse(content)
|
|
59
|
-
if (creds.token && creds.userId && creds.email) {
|
|
60
|
-
return creds
|
|
61
|
-
}
|
|
62
|
-
return null
|
|
63
|
-
} catch {
|
|
64
|
-
return null
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Update stored credentials (for token refresh)
|
|
70
|
-
*/
|
|
71
|
-
function updateCredentials(updates: Partial<StoredCredentials>): void {
|
|
72
|
-
const creds = getCredentials()
|
|
73
|
-
if (!creds) return
|
|
74
|
-
|
|
75
|
-
writeFileSync(CREDENTIALS_FILE, JSON.stringify({ ...creds, ...updates }, null, 2), {
|
|
76
|
-
mode: 0o600
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if token should be refreshed
|
|
82
|
-
*/
|
|
83
|
-
function shouldRefreshToken(creds: StoredCredentials): boolean {
|
|
84
|
-
if (!creds.lastRefreshedAt) {
|
|
85
|
-
return true // Never refreshed
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const lastRefreshed = new Date(creds.lastRefreshedAt).getTime()
|
|
89
|
-
const now = Date.now()
|
|
90
|
-
return now - lastRefreshed > TOKEN_REFRESH_INTERVAL_MS
|
|
91
|
-
}
|
|
92
|
-
|
|
93
25
|
/**
|
|
94
26
|
* Get machine identification string
|
|
95
|
-
* Format: "hostname @ node-vX.X.X platform (arch)"
|
|
96
27
|
* Example: "Jessica @ node-v22.21.1 linux (arm64)"
|
|
97
28
|
*/
|
|
98
29
|
export function getMachineIdentifier(): string {
|
|
@@ -124,9 +55,6 @@ interface ConnectionCallbacks {
|
|
|
124
55
|
onRelayedMessage?: (message: unknown) => void
|
|
125
56
|
}
|
|
126
57
|
|
|
127
|
-
/**
|
|
128
|
-
* Platform WebSocket connection with token-based authentication
|
|
129
|
-
*/
|
|
130
58
|
/** Number of missed pongs before treating connection as dead */
|
|
131
59
|
const MAX_MISSED_PONGS = 2
|
|
132
60
|
|
|
@@ -144,6 +72,7 @@ export class PlatformConnection {
|
|
|
144
72
|
private tokenRefreshInterval: ReturnType<typeof setInterval> | null = null
|
|
145
73
|
private heartbeatInterval: ReturnType<typeof setInterval> | null = null
|
|
146
74
|
private missedPongs = 0
|
|
75
|
+
private readonly startedAt: string
|
|
147
76
|
|
|
148
77
|
constructor(
|
|
149
78
|
workingDirectory: string,
|
|
@@ -153,16 +82,12 @@ export class PlatformConnection {
|
|
|
153
82
|
this.workingDirectory = workingDirectory
|
|
154
83
|
this.platformUrl = platformUrl || DEFAULT_PLATFORM_URL
|
|
155
84
|
this.callbacks = callbacks
|
|
85
|
+
this.startedAt = new Date().toISOString()
|
|
156
86
|
}
|
|
157
87
|
|
|
158
|
-
/**
|
|
159
|
-
* Refresh the device token if needed
|
|
160
|
-
*/
|
|
161
88
|
private async maybeRefreshToken(): Promise<void> {
|
|
162
89
|
const creds = getCredentials()
|
|
163
|
-
if (!creds || !shouldRefreshToken(creds))
|
|
164
|
-
return
|
|
165
|
-
}
|
|
90
|
+
if (!creds || !shouldRefreshToken(creds)) return
|
|
166
91
|
|
|
167
92
|
try {
|
|
168
93
|
const response = await fetch(`${this.platformUrl}/api/auth/device/refresh`, {
|
|
@@ -187,25 +112,14 @@ export class PlatformConnection {
|
|
|
187
112
|
}
|
|
188
113
|
}
|
|
189
114
|
|
|
190
|
-
/**
|
|
191
|
-
* Start periodic token refresh check
|
|
192
|
-
*/
|
|
193
115
|
private startTokenRefreshCheck(): void {
|
|
194
|
-
// Check every 24 hours
|
|
195
116
|
this.tokenRefreshInterval = setInterval(() => {
|
|
196
117
|
this.maybeRefreshToken()
|
|
197
118
|
}, 24 * 60 * 60 * 1000)
|
|
198
119
|
}
|
|
199
120
|
|
|
200
|
-
/**
|
|
201
|
-
* Start heartbeat to keep connection alive and refresh server-side TTL.
|
|
202
|
-
* Tracks missed pongs — if the server doesn't respond to MAX_MISSED_PONGS
|
|
203
|
-
* consecutive pings, the connection is considered dead and force-closed
|
|
204
|
-
* to trigger reconnection.
|
|
205
|
-
*/
|
|
206
121
|
private startHeartbeat(): void {
|
|
207
122
|
this.missedPongs = 0
|
|
208
|
-
// Send ping every 2 minutes (server TTL is 5 minutes)
|
|
209
123
|
this.heartbeatInterval = setInterval(() => this.heartbeatTick(), 2 * 60 * 1000)
|
|
210
124
|
}
|
|
211
125
|
|
|
@@ -227,9 +141,6 @@ export class PlatformConnection {
|
|
|
227
141
|
}
|
|
228
142
|
}
|
|
229
143
|
|
|
230
|
-
/**
|
|
231
|
-
* Stop heartbeat
|
|
232
|
-
*/
|
|
233
144
|
private stopHeartbeat(): void {
|
|
234
145
|
if (this.heartbeatInterval) {
|
|
235
146
|
clearInterval(this.heartbeatInterval)
|
|
@@ -237,9 +148,6 @@ export class PlatformConnection {
|
|
|
237
148
|
}
|
|
238
149
|
}
|
|
239
150
|
|
|
240
|
-
/**
|
|
241
|
-
* Stop periodic token refresh check
|
|
242
|
-
*/
|
|
243
151
|
private stopTokenRefreshCheck(): void {
|
|
244
152
|
if (this.tokenRefreshInterval) {
|
|
245
153
|
clearInterval(this.tokenRefreshInterval)
|
|
@@ -247,9 +155,6 @@ export class PlatformConnection {
|
|
|
247
155
|
}
|
|
248
156
|
}
|
|
249
157
|
|
|
250
|
-
/**
|
|
251
|
-
* Connect to platform WebSocket
|
|
252
|
-
*/
|
|
253
158
|
connect(): void {
|
|
254
159
|
this.isIntentionallyClosed = false
|
|
255
160
|
const name = basename(this.workingDirectory)
|
|
@@ -260,7 +165,6 @@ export class PlatformConnection {
|
|
|
260
165
|
const osType = type().toLowerCase()
|
|
261
166
|
const cpuArch = arch()
|
|
262
167
|
|
|
263
|
-
// Get auth token from credentials
|
|
264
168
|
const credentials = getCredentials()
|
|
265
169
|
const authToken = credentials?.token
|
|
266
170
|
|
|
@@ -270,8 +174,6 @@ export class PlatformConnection {
|
|
|
270
174
|
return
|
|
271
175
|
}
|
|
272
176
|
|
|
273
|
-
// Build URL params WITHOUT the auth token — token is sent post-connection
|
|
274
|
-
// to avoid leaking it in proxy logs, browser history, and server access logs
|
|
275
177
|
const params = new URLSearchParams({
|
|
276
178
|
name,
|
|
277
179
|
workingDirectory: this.workingDirectory,
|
|
@@ -282,7 +184,8 @@ export class PlatformConnection {
|
|
|
282
184
|
osType,
|
|
283
185
|
cpuArch,
|
|
284
186
|
cliVersion: CLI_VERSION,
|
|
285
|
-
capabilities: JSON.stringify({})
|
|
187
|
+
capabilities: JSON.stringify({}),
|
|
188
|
+
startedAt: this.startedAt,
|
|
286
189
|
})
|
|
287
190
|
|
|
288
191
|
const wsUrl = `${this.platformUrl.replace(/^http/, 'ws')}/ws/client?${params}`
|
|
@@ -297,10 +200,9 @@ export class PlatformConnection {
|
|
|
297
200
|
return
|
|
298
201
|
}
|
|
299
202
|
|
|
300
|
-
// Connection timeout - if not connected within 10 seconds, show helpful error
|
|
301
203
|
const connectionTimeout = setTimeout(() => {
|
|
302
204
|
const state = this.ws?.readyState
|
|
303
|
-
if (this.ws && (state === 0 || state === undefined)) {
|
|
205
|
+
if (this.ws && (state === 0 || state === undefined)) {
|
|
304
206
|
console.error('\n❌ Connection timeout. The platform may have rejected your credentials.')
|
|
305
207
|
console.error(' Run `mstro login --force` to re-authenticate.\n')
|
|
306
208
|
this.ws.close()
|
|
@@ -310,14 +212,8 @@ export class PlatformConnection {
|
|
|
310
212
|
|
|
311
213
|
this.ws.onopen = () => {
|
|
312
214
|
clearTimeout(connectionTimeout)
|
|
313
|
-
// Platform WebSocket open — auth will follow
|
|
314
|
-
|
|
315
|
-
// Send auth token as first message instead of URL param
|
|
316
215
|
this.ws!.send(JSON.stringify({ type: 'auth', token: authToken }))
|
|
317
|
-
|
|
318
|
-
// Check if token needs refresh on connect
|
|
319
216
|
this.maybeRefreshToken()
|
|
320
|
-
// Start periodic refresh checks
|
|
321
217
|
this.startTokenRefreshCheck()
|
|
322
218
|
this.reconnectAttempts = 0
|
|
323
219
|
trackEvent(AnalyticsEvents.PLATFORM_CONNECTED)
|
|
@@ -332,7 +228,6 @@ export class PlatformConnection {
|
|
|
332
228
|
}
|
|
333
229
|
}
|
|
334
230
|
|
|
335
|
-
// Track if we ever successfully connected (received 'paired' message)
|
|
336
231
|
let everConnected = false
|
|
337
232
|
const originalOnConnected = this.callbacks.onConnected
|
|
338
233
|
this.callbacks.onConnected = (connectionId) => {
|
|
@@ -341,12 +236,10 @@ export class PlatformConnection {
|
|
|
341
236
|
}
|
|
342
237
|
|
|
343
238
|
this.ws.onclose = (event) => {
|
|
344
|
-
// Stop heartbeat on any close
|
|
345
239
|
this.stopHeartbeat()
|
|
346
240
|
this.isConnected = false
|
|
347
241
|
|
|
348
242
|
if (!this.isIntentionallyClosed) {
|
|
349
|
-
// Check if we were rejected due to auth (code 4001 or 1006 before ever connecting)
|
|
350
243
|
const isAuthFailure = event.code === 4001 ||
|
|
351
244
|
event.reason?.includes('Unauthorized') ||
|
|
352
245
|
(event.code === 1006 && !everConnected)
|
|
@@ -375,29 +268,21 @@ export class PlatformConnection {
|
|
|
375
268
|
case 'paired':
|
|
376
269
|
this.isConnected = true
|
|
377
270
|
this.connectionId = message.connectionId as string
|
|
378
|
-
// Connection status printed by onConnected callback
|
|
379
|
-
// Start heartbeat to keep server-side TTL refreshed
|
|
380
271
|
this.startHeartbeat()
|
|
381
272
|
this.callbacks.onConnected?.(message.connectionId as string)
|
|
382
273
|
break
|
|
383
|
-
|
|
384
274
|
case 'web_connected':
|
|
385
275
|
this.callbacks.onWebConnected?.()
|
|
386
276
|
trackEvent(AnalyticsEvents.WEB_CLIENT_CONNECTED)
|
|
387
277
|
break
|
|
388
|
-
|
|
389
278
|
case 'web_disconnected':
|
|
390
279
|
this.callbacks.onWebDisconnected?.()
|
|
391
280
|
trackEvent(AnalyticsEvents.WEB_CLIENT_DISCONNECTED)
|
|
392
281
|
break
|
|
393
|
-
|
|
394
282
|
case 'pong':
|
|
395
283
|
this.missedPongs = 0
|
|
396
284
|
break
|
|
397
|
-
|
|
398
285
|
default:
|
|
399
|
-
// Relay message from web to wsHandler
|
|
400
|
-
// These are messages like 'execute', 'initTab', 'autocomplete', etc.
|
|
401
286
|
this.callbacks.onRelayedMessage?.(message)
|
|
402
287
|
break
|
|
403
288
|
}
|
|
@@ -420,29 +305,18 @@ export class PlatformConnection {
|
|
|
420
305
|
}, delay)
|
|
421
306
|
}
|
|
422
307
|
|
|
423
|
-
/**
|
|
424
|
-
* Send message to platform (will be relayed to web if connected)
|
|
425
|
-
*/
|
|
426
308
|
send(message: unknown): void {
|
|
427
309
|
if (this.ws && this.ws.readyState === WebSocketImpl.OPEN) {
|
|
428
310
|
this.ws.send(JSON.stringify(message))
|
|
429
311
|
}
|
|
430
312
|
}
|
|
431
313
|
|
|
432
|
-
/**
|
|
433
|
-
* Check if connected to platform
|
|
434
|
-
*/
|
|
435
314
|
isConnectedToPlatform(): boolean {
|
|
436
315
|
return this.isConnected && this.ws?.readyState === WebSocketImpl.OPEN
|
|
437
316
|
}
|
|
438
317
|
|
|
439
|
-
/**
|
|
440
|
-
* Disconnect from platform
|
|
441
|
-
*/
|
|
442
318
|
disconnect(): void {
|
|
443
319
|
this.isIntentionallyClosed = true
|
|
444
|
-
|
|
445
|
-
// Stop heartbeat and token refresh checks
|
|
446
320
|
this.stopHeartbeat()
|
|
447
321
|
this.stopTokenRefreshCheck()
|
|
448
322
|
|