mstro-app 0.4.38 → 0.4.43
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/bin/commands/login.js +17 -7
- package/bin/commands/logout.js +14 -6
- package/bin/commands/status.js +9 -3
- package/bin/commands/whoami.js +10 -4
- package/bin/mstro.js +11 -1
- package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stream.js +1 -0
- package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
- package/dist/server/cli/headless/index.d.ts +1 -0
- package/dist/server/cli/headless/index.d.ts.map +1 -1
- package/dist/server/cli/headless/index.js +2 -0
- package/dist/server/cli/headless/index.js.map +1 -1
- package/dist/server/cli/headless/resilient-runner.d.ts +47 -0
- package/dist/server/cli/headless/resilient-runner.d.ts.map +1 -0
- package/dist/server/cli/headless/resilient-runner.js +234 -0
- package/dist/server/cli/headless/resilient-runner.js.map +1 -0
- package/dist/server/cli/headless/retry-strategies.d.ts +44 -0
- package/dist/server/cli/headless/retry-strategies.d.ts.map +1 -0
- package/dist/server/cli/headless/retry-strategies.js +262 -0
- package/dist/server/cli/headless/retry-strategies.js.map +1 -0
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +5 -0
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +2 -0
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +31 -4
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
- package/dist/server/cli/improvisation-retry.js +1 -30
- package/dist/server/cli/improvisation-retry.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +1 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +16 -3
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/prompt-builders.d.ts.map +1 -1
- package/dist/server/cli/prompt-builders.js +31 -13
- package/dist/server/cli/prompt-builders.js.map +1 -1
- package/dist/server/index.js +1 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-cli.js +5 -4
- package/dist/server/mcp/bouncer-cli.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.js +1 -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 +14 -8
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-patterns.js +1 -1
- package/dist/server/mcp/security-patterns.js.map +1 -1
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +19 -9
- package/dist/server/services/plan/composer.js.map +1 -1
- package/dist/server/services/plan/executor.d.ts +6 -1
- package/dist/server/services/plan/executor.d.ts.map +1 -1
- package/dist/server/services/plan/executor.js +158 -76
- package/dist/server/services/plan/executor.js.map +1 -1
- package/dist/server/services/plan/front-matter.d.ts +1 -0
- package/dist/server/services/plan/front-matter.d.ts.map +1 -1
- package/dist/server/services/plan/front-matter.js +6 -0
- package/dist/server/services/plan/front-matter.js.map +1 -1
- package/dist/server/services/plan/issue-classification.d.ts +11 -0
- package/dist/server/services/plan/issue-classification.d.ts.map +1 -0
- package/dist/server/services/plan/issue-classification.js +20 -0
- package/dist/server/services/plan/issue-classification.js.map +1 -0
- package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
- package/dist/server/services/plan/issue-prompt-builder.js +10 -5
- package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
- package/dist/server/services/plan/issue-retry.d.ts +0 -5
- package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
- package/dist/server/services/plan/issue-retry.js +12 -241
- package/dist/server/services/plan/issue-retry.js.map +1 -1
- package/dist/server/services/plan/parser-core.d.ts.map +1 -1
- package/dist/server/services/plan/parser-core.js +1 -0
- package/dist/server/services/plan/parser-core.js.map +1 -1
- package/dist/server/services/plan/review-gate.d.ts.map +1 -1
- package/dist/server/services/plan/review-gate.js +9 -6
- package/dist/server/services/plan/review-gate.js.map +1 -1
- package/dist/server/services/plan/types.d.ts +1 -0
- package/dist/server/services/plan/types.d.ts.map +1 -1
- package/dist/server/services/platform-credentials.d.ts.map +1 -1
- package/dist/server/services/platform-credentials.js +11 -4
- package/dist/server/services/platform-credentials.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +7 -1
- package/dist/server/services/terminal/pty-manager.js.map +1 -1
- package/dist/server/services/websocket/handler-context.d.ts +2 -0
- package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
- 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 +18 -7
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-execution-handlers.js +6 -6
- package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-fix-agent.js +90 -42
- package/dist/server/services/websocket/quality-fix-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +48 -7
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-persistence.d.ts +22 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-persistence.js +48 -1
- 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 +74 -32
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-tools.js +18 -18
- package/dist/server/services/websocket/quality-tools.js.map +1 -1
- package/dist/server/services/websocket/skill-handlers.d.ts +3 -1
- package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/skill-handlers.js +52 -41
- package/dist/server/services/websocket/skill-handlers.js.map +1 -1
- package/dist/server/services/websocket/skill-watcher.d.ts +17 -0
- package/dist/server/services/websocket/skill-watcher.d.ts.map +1 -0
- package/dist/server/services/websocket/skill-watcher.js +85 -0
- package/dist/server/services/websocket/skill-watcher.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +2 -268
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/services/websocket/types.js +0 -4
- package/dist/server/services/websocket/types.js.map +1 -1
- package/package.json +1 -1
- package/server/cli/headless/claude-invoker-stream.ts +1 -0
- package/server/cli/headless/index.ts +2 -0
- package/server/cli/headless/resilient-runner.ts +354 -0
- package/server/cli/headless/retry-strategies.ts +330 -0
- package/server/cli/headless/stall-assessor.ts +5 -0
- package/server/cli/headless/tool-watchdog.ts +40 -4
- package/server/cli/improvisation-retry.ts +1 -32
- package/server/cli/improvisation-session-manager.ts +17 -3
- package/server/cli/prompt-builders.ts +33 -12
- package/server/index.ts +1 -9
- package/server/mcp/bouncer-cli.ts +5 -4
- package/server/mcp/bouncer-haiku.ts +1 -1
- package/server/mcp/bouncer-integration.ts +15 -8
- package/server/mcp/security-patterns.ts +1 -1
- package/server/services/plan/agents/code-review.md +109 -0
- package/server/services/plan/agents/commit-message.md +26 -0
- package/server/services/plan/agents/execute-issue.md +10 -1
- package/server/services/plan/agents/fix-quality.md +24 -0
- package/server/services/plan/agents/pr-description.md +28 -0
- package/server/services/plan/composer.ts +20 -9
- package/server/services/plan/executor.ts +160 -76
- package/server/services/plan/front-matter.ts +7 -0
- package/server/services/plan/issue-classification.ts +21 -0
- package/server/services/plan/issue-prompt-builder.ts +11 -5
- package/server/services/plan/issue-retry.ts +15 -330
- package/server/services/plan/parser-core.ts +1 -0
- package/server/services/plan/review-gate.ts +9 -6
- package/server/services/plan/types.ts +3 -0
- package/server/services/platform-credentials.ts +10 -4
- package/server/services/terminal/pty-manager.ts +7 -1
- package/server/services/websocket/handler-context.ts +2 -0
- package/server/services/websocket/handler.ts +18 -8
- package/server/services/websocket/plan-execution-handlers.ts +7 -7
- package/server/services/websocket/quality-fix-agent.ts +86 -44
- package/server/services/websocket/quality-handlers.ts +48 -7
- package/server/services/websocket/quality-persistence.ts +75 -1
- package/server/services/websocket/quality-review-agent.ts +70 -31
- package/server/services/websocket/quality-tools.ts +16 -14
- package/server/services/websocket/skill-handlers.ts +50 -40
- package/server/services/websocket/skill-watcher.ts +79 -0
- package/server/services/websocket/types.ts +0 -311
- package/dist/server/services/deploy/ai-broker.d.ts +0 -63
- package/dist/server/services/deploy/ai-broker.d.ts.map +0 -1
- package/dist/server/services/deploy/ai-broker.js +0 -360
- package/dist/server/services/deploy/ai-broker.js.map +0 -1
- package/dist/server/services/deploy/board-execution-handler.d.ts +0 -114
- package/dist/server/services/deploy/board-execution-handler.d.ts.map +0 -1
- package/dist/server/services/deploy/board-execution-handler.js +0 -621
- package/dist/server/services/deploy/board-execution-handler.js.map +0 -1
- package/dist/server/services/deploy/credentials.d.ts +0 -35
- package/dist/server/services/deploy/credentials.d.ts.map +0 -1
- package/dist/server/services/deploy/credentials.js +0 -177
- package/dist/server/services/deploy/credentials.js.map +0 -1
- package/dist/server/services/deploy/deploy-ai-service.d.ts +0 -107
- package/dist/server/services/deploy/deploy-ai-service.d.ts.map +0 -1
- package/dist/server/services/deploy/deploy-ai-service.js +0 -294
- package/dist/server/services/deploy/deploy-ai-service.js.map +0 -1
- package/dist/server/services/deploy/headless-session-handler.d.ts +0 -94
- package/dist/server/services/deploy/headless-session-handler.d.ts.map +0 -1
- package/dist/server/services/deploy/headless-session-handler.js +0 -266
- package/dist/server/services/deploy/headless-session-handler.js.map +0 -1
- package/dist/server/services/websocket/deploy-handlers.d.ts +0 -14
- package/dist/server/services/websocket/deploy-handlers.d.ts.map +0 -1
- package/dist/server/services/websocket/deploy-handlers.js +0 -409
- package/dist/server/services/websocket/deploy-handlers.js.map +0 -1
- package/dist/server/services/websocket/handlers/deploy-handlers.d.ts +0 -11
- package/dist/server/services/websocket/handlers/deploy-handlers.d.ts.map +0 -1
- package/dist/server/services/websocket/handlers/deploy-handlers.js +0 -176
- package/dist/server/services/websocket/handlers/deploy-handlers.js.map +0 -1
- package/server/cli/headless/RESEARCH.md +0 -627
- package/server/services/deploy/ai-broker.ts +0 -512
- package/server/services/deploy/board-execution-handler.ts +0 -847
- package/server/services/deploy/credentials.ts +0 -200
- package/server/services/deploy/deploy-ai-service.ts +0 -401
- package/server/services/deploy/headless-session-handler.ts +0 -414
- package/server/services/websocket/deploy-handlers.ts +0 -544
- package/server/services/websocket/handlers/deploy-handlers.ts +0 -228
|
@@ -1,621 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
-
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
-
/**
|
|
4
|
-
* Board Execution Handler
|
|
5
|
-
*
|
|
6
|
-
* Handles PM Board execution requests from a developer's backend on behalf
|
|
7
|
-
* of end users. Each execution is isolated — no shared context between
|
|
8
|
-
* end users.
|
|
9
|
-
*
|
|
10
|
-
* Flow:
|
|
11
|
-
* 1. Validate boardTemplateId against deployment's allowedBoardTemplateIds
|
|
12
|
-
* 2. Load the referenced board template from .mstro/pm/boards/
|
|
13
|
-
* 3. Create an isolated working directory (git worktree)
|
|
14
|
-
* 4. Use headless Claude Code to customize the board from end-user prompt
|
|
15
|
-
* 5. Trigger PM Board "implement all" execution via PlanExecutor
|
|
16
|
-
* 6. Collect results and return them
|
|
17
|
-
*
|
|
18
|
-
* Board executions are long-running — returns a job ID immediately with
|
|
19
|
-
* polling for status and results.
|
|
20
|
-
*
|
|
21
|
-
* Security: End-user prompts are untrusted input. They are always passed
|
|
22
|
-
* as user messages, never injected into system instructions.
|
|
23
|
-
*/
|
|
24
|
-
import { execSync } from 'node:child_process';
|
|
25
|
-
import { randomUUID } from 'node:crypto';
|
|
26
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
|
|
27
|
-
import { tmpdir } from 'node:os';
|
|
28
|
-
import { join } from 'node:path';
|
|
29
|
-
import { HeadlessRunner } from '../../cli/headless/runner.js';
|
|
30
|
-
import { PlanExecutor } from '../plan/executor.js';
|
|
31
|
-
import { parseBoardDirectory, resolvePmDir } from '../plan/parser.js';
|
|
32
|
-
import { readOwnerApiCredential } from './deploy-ai-service.js';
|
|
33
|
-
// ========== Prompt Sanitization ==========
|
|
34
|
-
/**
|
|
35
|
-
* Maximum allowed length for an end-user prompt.
|
|
36
|
-
* Prevents memory abuse and ensures reasonable prompt sizes.
|
|
37
|
-
*/
|
|
38
|
-
const MAX_END_USER_PROMPT_LENGTH = 100_000;
|
|
39
|
-
/**
|
|
40
|
-
* Sanitize an end-user prompt before passing it to the AI.
|
|
41
|
-
*
|
|
42
|
-
* SECURITY: End-user prompts are untrusted. This function:
|
|
43
|
-
* 1. Strips system instruction XML delimiters to prevent prompt escape
|
|
44
|
-
* 2. Removes null bytes and zero-width characters used for evasion
|
|
45
|
-
* 3. Truncates to MAX_END_USER_PROMPT_LENGTH
|
|
46
|
-
*
|
|
47
|
-
* Note: This does NOT strip tool-use instructions or path traversal text —
|
|
48
|
-
* those are handled by the Security Bouncer (tool execution level) and
|
|
49
|
-
* the isolated working directory (filesystem level).
|
|
50
|
-
*/
|
|
51
|
-
export function sanitizeEndUserPrompt(prompt) {
|
|
52
|
-
let sanitized = prompt;
|
|
53
|
-
// Strip system instruction XML tags that could break prompt structure
|
|
54
|
-
sanitized = sanitized.replace(/<\/?system-instruction>/gi, '');
|
|
55
|
-
// Remove null bytes
|
|
56
|
-
sanitized = sanitized.replace(/\x00/g, '');
|
|
57
|
-
// Remove zero-width characters used for evasion
|
|
58
|
-
// U+200B Zero Width Space, U+200C Zero Width Non-Joiner,
|
|
59
|
-
// U+200D Zero Width Joiner, U+FEFF Byte Order Mark
|
|
60
|
-
sanitized = sanitized.replace(/\u200B|\u200C|\u200D|\uFEFF/g, '');
|
|
61
|
-
// Truncate to max length
|
|
62
|
-
if (sanitized.length > MAX_END_USER_PROMPT_LENGTH) {
|
|
63
|
-
sanitized = sanitized.slice(0, MAX_END_USER_PROMPT_LENGTH);
|
|
64
|
-
}
|
|
65
|
-
return sanitized;
|
|
66
|
-
}
|
|
67
|
-
const rateBuckets = new Map();
|
|
68
|
-
function getBucket(deploymentId) {
|
|
69
|
-
let bucket = rateBuckets.get(deploymentId);
|
|
70
|
-
if (!bucket) {
|
|
71
|
-
bucket = { timestamps: [], activeExecutions: 0 };
|
|
72
|
-
rateBuckets.set(deploymentId, bucket);
|
|
73
|
-
}
|
|
74
|
-
return bucket;
|
|
75
|
-
}
|
|
76
|
-
function pruneTimestamps(bucket) {
|
|
77
|
-
const oneMinuteAgo = Date.now() - 60_000;
|
|
78
|
-
while (bucket.timestamps.length > 0 && bucket.timestamps[0] < oneMinuteAgo) {
|
|
79
|
-
bucket.timestamps.shift();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function checkRateLimit(config) {
|
|
83
|
-
const bucket = getBucket(config.deploymentId);
|
|
84
|
-
// Check concurrent executions
|
|
85
|
-
if (bucket.activeExecutions >= config.maxConcurrentBoardExecutions) {
|
|
86
|
-
return {
|
|
87
|
-
code: 'CONCURRENT_LIMIT_EXCEEDED',
|
|
88
|
-
message: `Deployment has reached the maximum of ${config.maxConcurrentBoardExecutions} concurrent board executions. Wait for an existing execution to complete.`,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
// Check executions per minute
|
|
92
|
-
if (config.maxBoardExecutionsPerMinute !== null) {
|
|
93
|
-
pruneTimestamps(bucket);
|
|
94
|
-
if (bucket.timestamps.length >= config.maxBoardExecutionsPerMinute) {
|
|
95
|
-
return {
|
|
96
|
-
code: 'RATE_LIMIT_EXCEEDED',
|
|
97
|
-
message: `Deployment has exceeded the rate limit of ${config.maxBoardExecutionsPerMinute} board executions per minute. Try again shortly.`,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
function recordExecutionStart(deploymentId) {
|
|
104
|
-
const bucket = getBucket(deploymentId);
|
|
105
|
-
bucket.timestamps.push(Date.now());
|
|
106
|
-
bucket.activeExecutions++;
|
|
107
|
-
}
|
|
108
|
-
function recordExecutionEnd(deploymentId) {
|
|
109
|
-
const bucket = getBucket(deploymentId);
|
|
110
|
-
bucket.activeExecutions = Math.max(0, bucket.activeExecutions - 1);
|
|
111
|
-
}
|
|
112
|
-
// ========== Job Store ==========
|
|
113
|
-
/** Retention window for completed/failed jobs before cleanup (5 minutes) */
|
|
114
|
-
const JOB_RETENTION_MS = 300_000;
|
|
115
|
-
const jobs = new Map();
|
|
116
|
-
function createJob(request) {
|
|
117
|
-
const jobId = `board-exec-${request.deploymentId}-${randomUUID()}`;
|
|
118
|
-
const now = Date.now();
|
|
119
|
-
const job = {
|
|
120
|
-
jobId,
|
|
121
|
-
deploymentId: request.deploymentId,
|
|
122
|
-
endUserId: request.endUserId,
|
|
123
|
-
boardTemplateId: request.boardTemplateId,
|
|
124
|
-
endUserPrompt: request.endUserPrompt,
|
|
125
|
-
status: 'customizing',
|
|
126
|
-
progress: {
|
|
127
|
-
phase: 'isolating',
|
|
128
|
-
issuesTotal: 0,
|
|
129
|
-
issuesCompleted: 0,
|
|
130
|
-
currentWaveIds: [],
|
|
131
|
-
},
|
|
132
|
-
result: null,
|
|
133
|
-
error: null,
|
|
134
|
-
createdAt: now,
|
|
135
|
-
updatedAt: now,
|
|
136
|
-
isolatedDir: null,
|
|
137
|
-
};
|
|
138
|
-
jobs.set(jobId, job);
|
|
139
|
-
return job;
|
|
140
|
-
}
|
|
141
|
-
function updateJob(jobId, updates) {
|
|
142
|
-
const job = jobs.get(jobId);
|
|
143
|
-
if (!job)
|
|
144
|
-
return;
|
|
145
|
-
Object.assign(job, updates, { updatedAt: Date.now() });
|
|
146
|
-
}
|
|
147
|
-
function scheduleJobCleanup(jobId) {
|
|
148
|
-
setTimeout(() => {
|
|
149
|
-
const job = jobs.get(jobId);
|
|
150
|
-
if (job && job.status !== 'customizing' && job.status !== 'executing') {
|
|
151
|
-
if (job.isolatedDir) {
|
|
152
|
-
cleanupIsolatedDir(job.isolatedDir);
|
|
153
|
-
}
|
|
154
|
-
jobs.delete(jobId);
|
|
155
|
-
}
|
|
156
|
-
}, JOB_RETENTION_MS);
|
|
157
|
-
}
|
|
158
|
-
// ========== Isolation ==========
|
|
159
|
-
function isGitRepo(dir) {
|
|
160
|
-
try {
|
|
161
|
-
execSync('git rev-parse --is-inside-work-tree', { cwd: dir, stdio: 'pipe' });
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Create an isolated working directory for a board execution.
|
|
170
|
-
*
|
|
171
|
-
* Uses git worktree for git repos (efficient — shares object store).
|
|
172
|
-
* Falls back to a filtered directory copy for non-git repos.
|
|
173
|
-
*
|
|
174
|
-
* .mstro/pm/ is gitignored, so it is always copied manually.
|
|
175
|
-
*/
|
|
176
|
-
function createIsolatedDir(workingDir) {
|
|
177
|
-
const prefix = join(tmpdir(), 'mstro-board-exec-');
|
|
178
|
-
if (isGitRepo(workingDir)) {
|
|
179
|
-
const isolatedDir = mkdtempSync(prefix);
|
|
180
|
-
// git worktree needs a non-existent path
|
|
181
|
-
rmSync(isolatedDir, { recursive: true, force: true });
|
|
182
|
-
execSync(`git worktree add --detach "${isolatedDir}"`, {
|
|
183
|
-
cwd: workingDir,
|
|
184
|
-
stdio: 'pipe',
|
|
185
|
-
});
|
|
186
|
-
// .mstro/ is gitignored — copy the PM directory manually
|
|
187
|
-
const pmDir = join(workingDir, '.mstro', 'pm');
|
|
188
|
-
const isolatedPmDir = join(isolatedDir, '.mstro', 'pm');
|
|
189
|
-
if (existsSync(pmDir) && !existsSync(isolatedPmDir)) {
|
|
190
|
-
mkdirSync(join(isolatedDir, '.mstro'), { recursive: true });
|
|
191
|
-
cpSync(pmDir, isolatedPmDir, { recursive: true });
|
|
192
|
-
}
|
|
193
|
-
return isolatedDir;
|
|
194
|
-
}
|
|
195
|
-
// Fallback: filtered directory copy for non-git repos
|
|
196
|
-
const isolatedDir = mkdtempSync(prefix);
|
|
197
|
-
cpSync(workingDir, isolatedDir, {
|
|
198
|
-
recursive: true,
|
|
199
|
-
filter: (src) => !src.includes('node_modules') && !src.includes('.git'),
|
|
200
|
-
});
|
|
201
|
-
return isolatedDir;
|
|
202
|
-
}
|
|
203
|
-
function cleanupIsolatedDir(isolatedDir) {
|
|
204
|
-
try {
|
|
205
|
-
// Try git worktree remove first
|
|
206
|
-
execSync(`git worktree remove --force "${isolatedDir}"`, { stdio: 'pipe' });
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
// Fallback: direct removal
|
|
210
|
-
try {
|
|
211
|
-
rmSync(isolatedDir, { recursive: true, force: true });
|
|
212
|
-
}
|
|
213
|
-
catch { /* best-effort cleanup */ }
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
// ========== Board Template Loading ==========
|
|
217
|
-
function validateBoardTemplate(workingDir, boardTemplateId) {
|
|
218
|
-
const pmDir = resolvePmDir(workingDir);
|
|
219
|
-
if (!pmDir)
|
|
220
|
-
return null;
|
|
221
|
-
const boardState = parseBoardDirectory(pmDir, boardTemplateId);
|
|
222
|
-
if (!boardState)
|
|
223
|
-
return null;
|
|
224
|
-
return {
|
|
225
|
-
issueCount: boardState.issues.filter(i => i.type !== 'epic').length,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
// ========== Board Customization ==========
|
|
229
|
-
/**
|
|
230
|
-
* Build the customization prompt. The system instruction explains the task;
|
|
231
|
-
* the end-user prompt is in a separate, clearly delimited section.
|
|
232
|
-
*
|
|
233
|
-
* SECURITY: The end-user prompt is never interpolated into the system
|
|
234
|
-
* instruction. It appears in the user-message section only.
|
|
235
|
-
*/
|
|
236
|
-
function buildCustomizationPrompt(boardTemplateId, endUserPrompt, isolatedDir) {
|
|
237
|
-
const pmDir = resolvePmDir(isolatedDir);
|
|
238
|
-
const boardDir = pmDir ? join(pmDir, 'boards', boardTemplateId) : '';
|
|
239
|
-
const backlogDir = boardDir ? join(boardDir, 'backlog') : '';
|
|
240
|
-
const systemInstruction = `You are customizing a PM Board template for an end user's specific needs.
|
|
241
|
-
|
|
242
|
-
## Board Template
|
|
243
|
-
Board ID: ${boardTemplateId}
|
|
244
|
-
Board directory: ${boardDir}
|
|
245
|
-
Backlog directory: ${backlogDir}
|
|
246
|
-
|
|
247
|
-
## Task
|
|
248
|
-
|
|
249
|
-
Read all issue files in the board's backlog directory. Then adapt every issue to fulfill the end user's request below. For each issue:
|
|
250
|
-
|
|
251
|
-
1. Update the description to be specific to the end user's needs
|
|
252
|
-
2. Update acceptance criteria to match their requirements
|
|
253
|
-
3. Update technical notes with relevant implementation details
|
|
254
|
-
4. Update "Files to Modify" if applicable
|
|
255
|
-
5. Preserve all YAML front matter fields (id, type, status, priority, blocked_by, etc.)
|
|
256
|
-
6. Do NOT change issue IDs, dependency edges, or the overall board structure
|
|
257
|
-
|
|
258
|
-
If issues need to be added or removed to properly serve the end user's request, you may do so — but preserve the dependency graph's integrity.
|
|
259
|
-
|
|
260
|
-
## Rules
|
|
261
|
-
|
|
262
|
-
- All changes must be within ${backlogDir}
|
|
263
|
-
- Preserve YAML front matter structure exactly
|
|
264
|
-
- Keep issue scoping appropriate (1-5 story points each)
|
|
265
|
-
- Ensure blocked_by references remain valid
|
|
266
|
-
- Do NOT modify board.md, STATE.md, or any files outside the backlog
|
|
267
|
-
- Respond briefly describing what you changed`;
|
|
268
|
-
return [
|
|
269
|
-
'<system-instruction>',
|
|
270
|
-
systemInstruction,
|
|
271
|
-
'</system-instruction>',
|
|
272
|
-
'',
|
|
273
|
-
endUserPrompt,
|
|
274
|
-
].join('\n');
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Customize a board template via headless Claude Code session.
|
|
278
|
-
* Claude reads the board's issues and adapts them for the end user's prompt.
|
|
279
|
-
*/
|
|
280
|
-
async function customizeBoard(boardTemplateId, endUserPrompt, isolatedDir, apiKey) {
|
|
281
|
-
const prompt = buildCustomizationPrompt(boardTemplateId, endUserPrompt, isolatedDir);
|
|
282
|
-
const runner = new HeadlessRunner({
|
|
283
|
-
workingDir: isolatedDir,
|
|
284
|
-
directPrompt: prompt,
|
|
285
|
-
stallWarningMs: 300_000, // 5 min
|
|
286
|
-
stallKillMs: 900_000, // 15 min
|
|
287
|
-
stallHardCapMs: 1_800_000, // 30 min hard cap
|
|
288
|
-
extraEnv: { ANTHROPIC_API_KEY: apiKey },
|
|
289
|
-
verbose: false,
|
|
290
|
-
deployMode: true, // Activate deploy-specific bouncer patterns
|
|
291
|
-
});
|
|
292
|
-
const result = await runner.run();
|
|
293
|
-
return { completed: result.completed, error: result.error };
|
|
294
|
-
}
|
|
295
|
-
// ========== Board Execution ==========
|
|
296
|
-
/**
|
|
297
|
-
* Run the full board execution ("implement all") via PlanExecutor.
|
|
298
|
-
* Listens to executor events to track progress on the parent job.
|
|
299
|
-
*/
|
|
300
|
-
async function executeBoard(boardTemplateId, isolatedDir, job, apiKey) {
|
|
301
|
-
const startTime = Date.now();
|
|
302
|
-
const executor = new PlanExecutor(isolatedDir, {
|
|
303
|
-
extraEnv: { ANTHROPIC_API_KEY: apiKey },
|
|
304
|
-
});
|
|
305
|
-
// Track progress via executor events
|
|
306
|
-
executor.on('waveStarted', (data) => {
|
|
307
|
-
const current = jobs.get(job.jobId);
|
|
308
|
-
if (current) {
|
|
309
|
-
updateJob(job.jobId, {
|
|
310
|
-
progress: { ...current.progress, currentWaveIds: data.issueIds },
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
executor.on('issueCompleted', () => {
|
|
315
|
-
const current = jobs.get(job.jobId);
|
|
316
|
-
if (current) {
|
|
317
|
-
updateJob(job.jobId, {
|
|
318
|
-
progress: {
|
|
319
|
-
...current.progress,
|
|
320
|
-
issuesCompleted: current.progress.issuesCompleted + 1,
|
|
321
|
-
currentWaveIds: [],
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
await executor.startBoard(boardTemplateId);
|
|
327
|
-
// Collect output artifacts
|
|
328
|
-
const outputs = collectOutputs(isolatedDir, boardTemplateId);
|
|
329
|
-
const metrics = executor.getMetrics();
|
|
330
|
-
return {
|
|
331
|
-
completed: executor.getStatus() === 'complete',
|
|
332
|
-
issuesTotal: metrics.issuesAttempted,
|
|
333
|
-
issuesCompleted: metrics.issuesCompleted,
|
|
334
|
-
issuesFailed: metrics.issuesAttempted - metrics.issuesCompleted,
|
|
335
|
-
outputs,
|
|
336
|
-
durationMs: Date.now() - startTime,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
// ========== Result Collection ==========
|
|
340
|
-
function collectOutputs(isolatedDir, boardTemplateId) {
|
|
341
|
-
const pmDir = resolvePmDir(isolatedDir);
|
|
342
|
-
if (!pmDir)
|
|
343
|
-
return {};
|
|
344
|
-
const outDir = join(pmDir, 'boards', boardTemplateId, 'out');
|
|
345
|
-
if (!existsSync(outDir))
|
|
346
|
-
return {};
|
|
347
|
-
const outputs = {};
|
|
348
|
-
try {
|
|
349
|
-
for (const file of readdirSync(outDir)) {
|
|
350
|
-
if (file.endsWith('.md')) {
|
|
351
|
-
outputs[file] = readFileSync(join(outDir, file), 'utf-8');
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
catch { /* non-fatal */ }
|
|
356
|
-
return outputs;
|
|
357
|
-
}
|
|
358
|
-
// ========== Background Execution ==========
|
|
359
|
-
/**
|
|
360
|
-
* Orchestrates the full board execution lifecycle. Updates job state
|
|
361
|
-
* as it progresses through isolation, customization, execution, and
|
|
362
|
-
* result collection phases.
|
|
363
|
-
*/
|
|
364
|
-
async function runBoardExecution(job, config, apiKey) {
|
|
365
|
-
try {
|
|
366
|
-
// Phase 1: Create isolated working directory
|
|
367
|
-
updateJob(job.jobId, {
|
|
368
|
-
progress: { ...job.progress, phase: 'isolating' },
|
|
369
|
-
});
|
|
370
|
-
let isolatedDir;
|
|
371
|
-
try {
|
|
372
|
-
isolatedDir = createIsolatedDir(config.workingDir);
|
|
373
|
-
}
|
|
374
|
-
catch (error) {
|
|
375
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
376
|
-
updateJob(job.jobId, {
|
|
377
|
-
status: 'failed',
|
|
378
|
-
error: `Failed to create isolated directory: ${message}`,
|
|
379
|
-
});
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
updateJob(job.jobId, { isolatedDir });
|
|
383
|
-
// Phase 2: Customize board via headless Claude Code
|
|
384
|
-
updateJob(job.jobId, {
|
|
385
|
-
status: 'customizing',
|
|
386
|
-
progress: { ...job.progress, phase: 'customizing' },
|
|
387
|
-
});
|
|
388
|
-
const customization = await customizeBoard(job.boardTemplateId, sanitizeEndUserPrompt(job.endUserPrompt), isolatedDir, apiKey);
|
|
389
|
-
if (!customization.completed) {
|
|
390
|
-
updateJob(job.jobId, {
|
|
391
|
-
status: 'failed',
|
|
392
|
-
error: `Board customization failed: ${customization.error || 'Unknown error'}`,
|
|
393
|
-
});
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
// Phase 3: Execute board ("implement all")
|
|
397
|
-
updateJob(job.jobId, {
|
|
398
|
-
status: 'executing',
|
|
399
|
-
progress: { ...job.progress, phase: 'executing' },
|
|
400
|
-
});
|
|
401
|
-
const result = await executeBoard(job.boardTemplateId, isolatedDir, job, apiKey);
|
|
402
|
-
// Phase 4: Store results
|
|
403
|
-
updateJob(job.jobId, {
|
|
404
|
-
status: result.completed ? 'completed' : 'failed',
|
|
405
|
-
progress: {
|
|
406
|
-
phase: 'done',
|
|
407
|
-
issuesTotal: result.issuesTotal,
|
|
408
|
-
issuesCompleted: result.issuesCompleted,
|
|
409
|
-
currentWaveIds: [],
|
|
410
|
-
},
|
|
411
|
-
result,
|
|
412
|
-
error: result.completed ? null : 'Board execution did not complete all issues',
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
417
|
-
updateJob(job.jobId, {
|
|
418
|
-
status: 'failed',
|
|
419
|
-
error: message,
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
finally {
|
|
423
|
-
recordExecutionEnd(job.deploymentId);
|
|
424
|
-
scheduleJobCleanup(job.jobId);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
// ========== Public API ==========
|
|
428
|
-
/**
|
|
429
|
-
* Start a board execution for an end user. Returns a job ID immediately.
|
|
430
|
-
* The execution runs asynchronously — poll with getBoardExecutionStatus().
|
|
431
|
-
*
|
|
432
|
-
* Validates the deployment config, checks rate limits, verifies the board
|
|
433
|
-
* template exists and is allowed, then launches the background execution.
|
|
434
|
-
*
|
|
435
|
-
* @returns Structured result with either the job ID or an error.
|
|
436
|
-
*/
|
|
437
|
-
export function startBoardExecution(request, config) {
|
|
438
|
-
// ── Validate request ───────────────────────────────────────
|
|
439
|
-
if (!request.endUserPrompt || request.endUserPrompt.trim().length === 0) {
|
|
440
|
-
return {
|
|
441
|
-
ok: false,
|
|
442
|
-
error: { code: 'INVALID_REQUEST', message: 'endUserPrompt is required and must not be empty.' },
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
if (request.endUserPrompt.length > MAX_END_USER_PROMPT_LENGTH) {
|
|
446
|
-
return {
|
|
447
|
-
ok: false,
|
|
448
|
-
error: {
|
|
449
|
-
code: 'INVALID_REQUEST',
|
|
450
|
-
message: `endUserPrompt exceeds the maximum allowed length of ${MAX_END_USER_PROMPT_LENGTH.toLocaleString()} characters.`,
|
|
451
|
-
},
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
if (!request.endUserId || request.endUserId.trim().length === 0) {
|
|
455
|
-
return {
|
|
456
|
-
ok: false,
|
|
457
|
-
error: { code: 'INVALID_REQUEST', message: 'endUserId is required.' },
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
if (!request.boardTemplateId || request.boardTemplateId.trim().length === 0) {
|
|
461
|
-
return {
|
|
462
|
-
ok: false,
|
|
463
|
-
error: { code: 'INVALID_REQUEST', message: 'boardTemplateId is required.' },
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
// ── Validate boardTemplateId format (path traversal defense) ─
|
|
467
|
-
if (/[/\\]|\.\.|\x00/.test(request.boardTemplateId)) {
|
|
468
|
-
return {
|
|
469
|
-
ok: false,
|
|
470
|
-
error: {
|
|
471
|
-
code: 'INVALID_BOARD_TEMPLATE',
|
|
472
|
-
message: 'boardTemplateId contains invalid characters (/, \\, .., or null bytes).',
|
|
473
|
-
},
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
// ── Validate AI is enabled ─────────────────────────────────
|
|
477
|
-
if (!config.aiEnabled) {
|
|
478
|
-
return {
|
|
479
|
-
ok: false,
|
|
480
|
-
error: { code: 'AI_DISABLED', message: 'AI features are not enabled for this deployment.' },
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
// ── Validate board-execution capability ────────────────────
|
|
484
|
-
if (!config.allowedAiCapabilities.includes('board-execution')) {
|
|
485
|
-
return {
|
|
486
|
-
ok: false,
|
|
487
|
-
error: {
|
|
488
|
-
code: 'CAPABILITY_DENIED',
|
|
489
|
-
message: "This deployment does not have the 'board-execution' AI capability enabled.",
|
|
490
|
-
},
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
// ── Validate board template is allowed ─────────────────────
|
|
494
|
-
if (!config.allowedBoardTemplateIds.includes(request.boardTemplateId)) {
|
|
495
|
-
return {
|
|
496
|
-
ok: false,
|
|
497
|
-
error: {
|
|
498
|
-
code: 'INVALID_BOARD_TEMPLATE',
|
|
499
|
-
message: `Board template '${request.boardTemplateId}' is not allowed for this deployment.`,
|
|
500
|
-
},
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
// ── Validate board template exists ─────────────────────────
|
|
504
|
-
const template = validateBoardTemplate(config.workingDir, request.boardTemplateId);
|
|
505
|
-
if (!template) {
|
|
506
|
-
return {
|
|
507
|
-
ok: false,
|
|
508
|
-
error: {
|
|
509
|
-
code: 'BOARD_TEMPLATE_NOT_FOUND',
|
|
510
|
-
message: `Board template '${request.boardTemplateId}' not found in project.`,
|
|
511
|
-
},
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
// ── Rate limit checks ─────────────────────────────────────
|
|
515
|
-
const rateLimitError = checkRateLimit(config);
|
|
516
|
-
if (rateLimitError) {
|
|
517
|
-
return { ok: false, error: rateLimitError };
|
|
518
|
-
}
|
|
519
|
-
// ── Verify API key ─────────────────────────────────────────
|
|
520
|
-
const credential = readOwnerApiCredential();
|
|
521
|
-
if (!credential || credential.type !== 'api-key') {
|
|
522
|
-
return {
|
|
523
|
-
ok: false,
|
|
524
|
-
error: {
|
|
525
|
-
code: 'EXECUTION_FAILED',
|
|
526
|
-
message: 'Deploy requires an Anthropic API key. Add your key in Deploy \u2192 AI Config or set ANTHROPIC_API_KEY in your environment.',
|
|
527
|
-
},
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
// ── Create job and launch background execution ─────────────
|
|
531
|
-
const job = createJob(request);
|
|
532
|
-
job.progress.issuesTotal = template.issueCount;
|
|
533
|
-
recordExecutionStart(config.deploymentId);
|
|
534
|
-
// Fire-and-forget — execution runs in background, errors captured in job
|
|
535
|
-
runBoardExecution(job, config, credential.key).catch(() => { });
|
|
536
|
-
return { ok: true, jobId: job.jobId };
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Get the current status of a board execution job.
|
|
540
|
-
*
|
|
541
|
-
* Optionally pass endUserId to enforce isolation — returns null if the
|
|
542
|
-
* job belongs to a different end user.
|
|
543
|
-
*
|
|
544
|
-
* @returns Job status or null if not found / access denied.
|
|
545
|
-
*/
|
|
546
|
-
export function getBoardExecutionStatus(jobId, endUserId) {
|
|
547
|
-
const job = jobs.get(jobId);
|
|
548
|
-
if (!job)
|
|
549
|
-
return null;
|
|
550
|
-
// Enforce end-user isolation when endUserId is provided
|
|
551
|
-
if (endUserId !== undefined && job.endUserId !== endUserId) {
|
|
552
|
-
return null;
|
|
553
|
-
}
|
|
554
|
-
return {
|
|
555
|
-
jobId: job.jobId,
|
|
556
|
-
status: job.status,
|
|
557
|
-
progress: { ...job.progress },
|
|
558
|
-
result: job.result,
|
|
559
|
-
error: job.error,
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Get the current rate limit state for a deployment's board executions.
|
|
564
|
-
* Useful for status/monitoring endpoints.
|
|
565
|
-
*/
|
|
566
|
-
export function getDeploymentBoardExecutionState(deploymentId) {
|
|
567
|
-
const bucket = getBucket(deploymentId);
|
|
568
|
-
pruneTimestamps(bucket);
|
|
569
|
-
return {
|
|
570
|
-
executionsInLastMinute: bucket.timestamps.length,
|
|
571
|
-
activeExecutions: bucket.activeExecutions,
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Reset rate limit state for a deployment's board executions.
|
|
576
|
-
* Call when a deployment is deleted.
|
|
577
|
-
*/
|
|
578
|
-
export function resetDeploymentBoardExecutionRateLimit(deploymentId) {
|
|
579
|
-
rateBuckets.delete(deploymentId);
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Sweep stale isolated directories left behind by crashed executions.
|
|
583
|
-
*
|
|
584
|
-
* Board execution creates temp dirs prefixed with 'mstro-board-exec-'.
|
|
585
|
-
* If the process crashes before cleanup, these dirs leak. This function
|
|
586
|
-
* removes any that are older than the retention window + buffer.
|
|
587
|
-
*
|
|
588
|
-
* Safe to call on startup or periodically.
|
|
589
|
-
*/
|
|
590
|
-
export function sweepStaleIsolatedDirs() {
|
|
591
|
-
const prefix = 'mstro-board-exec-';
|
|
592
|
-
const maxAgeMs = JOB_RETENTION_MS * 2; // 10 minutes — generous buffer
|
|
593
|
-
let swept = 0;
|
|
594
|
-
try {
|
|
595
|
-
const tmpDir = tmpdir();
|
|
596
|
-
const entries = readdirSync(tmpDir);
|
|
597
|
-
const now = Date.now();
|
|
598
|
-
for (const entry of entries) {
|
|
599
|
-
if (!entry.startsWith(prefix))
|
|
600
|
-
continue;
|
|
601
|
-
const fullPath = join(tmpDir, entry);
|
|
602
|
-
try {
|
|
603
|
-
// Extract timestamp from dir name: mstro-board-exec-<random>
|
|
604
|
-
// Use filesystem stat for age instead of parsing name
|
|
605
|
-
const { mtimeMs } = statSync(fullPath);
|
|
606
|
-
if (now - mtimeMs > maxAgeMs) {
|
|
607
|
-
cleanupIsolatedDir(fullPath);
|
|
608
|
-
swept++;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
catch {
|
|
612
|
-
// Can't stat or clean — skip
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
catch {
|
|
617
|
-
// Can't read tmpdir — skip
|
|
618
|
-
}
|
|
619
|
-
return swept;
|
|
620
|
-
}
|
|
621
|
-
//# sourceMappingURL=board-execution-handler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"board-execution-handler.js","sourceRoot":"","sources":["../../../../server/services/deploy/board-execution-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Check if a validation attempt is allowed under the rate limit.
|
|
3
|
-
* Returns true if allowed, false if rate-limited.
|
|
4
|
-
*/
|
|
5
|
-
export declare function checkValidationRateLimit(): boolean;
|
|
6
|
-
/**
|
|
7
|
-
* Store an encrypted API key to ~/.mstro/deploy-credentials.json.
|
|
8
|
-
* Creates the directory if it doesn't exist. File is mode 0600.
|
|
9
|
-
*/
|
|
10
|
-
export declare function storeApiKey(apiKey: string): {
|
|
11
|
-
lastFour: string;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Read and decrypt the stored API key. Returns null if missing or corrupted.
|
|
15
|
-
*/
|
|
16
|
-
export declare function readApiKey(): string | null;
|
|
17
|
-
/**
|
|
18
|
-
* Get API key status without exposing the key.
|
|
19
|
-
* Checks env var first (highest priority), then stored credentials.
|
|
20
|
-
*/
|
|
21
|
-
export declare function getApiKeyStatus(): {
|
|
22
|
-
status: 'valid' | 'missing';
|
|
23
|
-
lastFour?: string;
|
|
24
|
-
source?: 'env' | 'stored';
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Delete stored API key.
|
|
28
|
-
*/
|
|
29
|
-
export declare function deleteApiKey(): void;
|
|
30
|
-
/**
|
|
31
|
-
* Validate an Anthropic API key by calling GET /v1/models.
|
|
32
|
-
* Returns true if the key is valid, false otherwise.
|
|
33
|
-
*/
|
|
34
|
-
export declare function validateAnthropicKey(apiKey: string): Promise<boolean>;
|
|
35
|
-
//# sourceMappingURL=credentials.d.ts.map
|