mstro-app 0.3.7 → 0.3.9

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.
Files changed (131) hide show
  1. package/README.md +4 -8
  2. package/bin/mstro.js +54 -15
  3. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  4. package/dist/server/cli/headless/claude-invoker.js +18 -9
  5. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  6. package/dist/server/cli/headless/headless-logger.d.ts +10 -0
  7. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -0
  8. package/dist/server/cli/headless/headless-logger.js +66 -0
  9. package/dist/server/cli/headless/headless-logger.js.map +1 -0
  10. package/dist/server/cli/headless/mcp-config.d.ts.map +1 -1
  11. package/dist/server/cli/headless/mcp-config.js +6 -5
  12. package/dist/server/cli/headless/mcp-config.js.map +1 -1
  13. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  14. package/dist/server/cli/headless/runner.js +4 -0
  15. package/dist/server/cli/headless/runner.js.map +1 -1
  16. package/dist/server/cli/headless/stall-assessor.d.ts +21 -0
  17. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  18. package/dist/server/cli/headless/stall-assessor.js +74 -20
  19. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  20. package/dist/server/cli/headless/tool-watchdog.d.ts +0 -12
  21. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  22. package/dist/server/cli/headless/tool-watchdog.js +30 -9
  23. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  24. package/dist/server/cli/headless/types.d.ts +8 -1
  25. package/dist/server/cli/headless/types.d.ts.map +1 -1
  26. package/dist/server/cli/improvisation-session-manager.d.ts +16 -0
  27. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  28. package/dist/server/cli/improvisation-session-manager.js +94 -11
  29. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  30. package/dist/server/index.js +0 -4
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/mcp/bouncer-cli.d.ts +3 -0
  33. package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
  34. package/dist/server/mcp/bouncer-cli.js +54 -0
  35. package/dist/server/mcp/bouncer-cli.js.map +1 -0
  36. package/dist/server/mcp/bouncer-integration.d.ts +2 -0
  37. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  38. package/dist/server/mcp/bouncer-integration.js +55 -39
  39. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  40. package/dist/server/mcp/bouncer-sandbox.d.ts +60 -0
  41. package/dist/server/mcp/bouncer-sandbox.d.ts.map +1 -0
  42. package/dist/server/mcp/bouncer-sandbox.js +182 -0
  43. package/dist/server/mcp/bouncer-sandbox.js.map +1 -0
  44. package/dist/server/mcp/security-patterns.d.ts +6 -12
  45. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  46. package/dist/server/mcp/security-patterns.js +197 -10
  47. package/dist/server/mcp/security-patterns.js.map +1 -1
  48. package/dist/server/services/plan/composer.d.ts +4 -0
  49. package/dist/server/services/plan/composer.d.ts.map +1 -0
  50. package/dist/server/services/plan/composer.js +181 -0
  51. package/dist/server/services/plan/composer.js.map +1 -0
  52. package/dist/server/services/plan/dependency-resolver.d.ts +28 -0
  53. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -0
  54. package/dist/server/services/plan/dependency-resolver.js +152 -0
  55. package/dist/server/services/plan/dependency-resolver.js.map +1 -0
  56. package/dist/server/services/plan/executor.d.ts +91 -0
  57. package/dist/server/services/plan/executor.d.ts.map +1 -0
  58. package/dist/server/services/plan/executor.js +545 -0
  59. package/dist/server/services/plan/executor.js.map +1 -0
  60. package/dist/server/services/plan/parser.d.ts +11 -0
  61. package/dist/server/services/plan/parser.d.ts.map +1 -0
  62. package/dist/server/services/plan/parser.js +415 -0
  63. package/dist/server/services/plan/parser.js.map +1 -0
  64. package/dist/server/services/plan/state-reconciler.d.ts +2 -0
  65. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -0
  66. package/dist/server/services/plan/state-reconciler.js +105 -0
  67. package/dist/server/services/plan/state-reconciler.js.map +1 -0
  68. package/dist/server/services/plan/types.d.ts +120 -0
  69. package/dist/server/services/plan/types.d.ts.map +1 -0
  70. package/dist/server/services/plan/types.js +4 -0
  71. package/dist/server/services/plan/types.js.map +1 -0
  72. package/dist/server/services/plan/watcher.d.ts +14 -0
  73. package/dist/server/services/plan/watcher.d.ts.map +1 -0
  74. package/dist/server/services/plan/watcher.js +69 -0
  75. package/dist/server/services/plan/watcher.js.map +1 -0
  76. package/dist/server/services/websocket/file-explorer-handlers.js +20 -0
  77. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  78. package/dist/server/services/websocket/handler.d.ts +0 -1
  79. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  80. package/dist/server/services/websocket/handler.js +28 -2
  81. package/dist/server/services/websocket/handler.js.map +1 -1
  82. package/dist/server/services/websocket/plan-handlers.d.ts +6 -0
  83. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -0
  84. package/dist/server/services/websocket/plan-handlers.js +494 -0
  85. package/dist/server/services/websocket/plan-handlers.js.map +1 -0
  86. package/dist/server/services/websocket/quality-handlers.d.ts +4 -0
  87. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -0
  88. package/dist/server/services/websocket/quality-handlers.js +470 -0
  89. package/dist/server/services/websocket/quality-handlers.js.map +1 -0
  90. package/dist/server/services/websocket/quality-persistence.d.ts +45 -0
  91. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -0
  92. package/dist/server/services/websocket/quality-persistence.js +187 -0
  93. package/dist/server/services/websocket/quality-persistence.js.map +1 -0
  94. package/dist/server/services/websocket/quality-service.d.ts +54 -0
  95. package/dist/server/services/websocket/quality-service.d.ts.map +1 -0
  96. package/dist/server/services/websocket/quality-service.js +816 -0
  97. package/dist/server/services/websocket/quality-service.js.map +1 -0
  98. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  99. package/dist/server/services/websocket/session-handlers.js +23 -0
  100. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  101. package/dist/server/services/websocket/types.d.ts +2 -2
  102. package/dist/server/services/websocket/types.d.ts.map +1 -1
  103. package/package.json +3 -2
  104. package/server/cli/headless/claude-invoker.ts +21 -9
  105. package/server/cli/headless/headless-logger.ts +78 -0
  106. package/server/cli/headless/mcp-config.ts +6 -5
  107. package/server/cli/headless/runner.ts +4 -0
  108. package/server/cli/headless/stall-assessor.ts +101 -20
  109. package/server/cli/headless/tool-watchdog.ts +18 -9
  110. package/server/cli/headless/types.ts +10 -1
  111. package/server/cli/improvisation-session-manager.ts +118 -11
  112. package/server/index.ts +0 -4
  113. package/server/mcp/bouncer-cli.ts +73 -0
  114. package/server/mcp/bouncer-integration.ts +66 -44
  115. package/server/mcp/bouncer-sandbox.ts +214 -0
  116. package/server/mcp/security-patterns.ts +206 -10
  117. package/server/services/plan/composer.ts +199 -0
  118. package/server/services/plan/dependency-resolver.ts +179 -0
  119. package/server/services/plan/executor.ts +604 -0
  120. package/server/services/plan/parser.ts +459 -0
  121. package/server/services/plan/state-reconciler.ts +132 -0
  122. package/server/services/plan/types.ts +164 -0
  123. package/server/services/plan/watcher.ts +73 -0
  124. package/server/services/websocket/file-explorer-handlers.ts +20 -0
  125. package/server/services/websocket/handler.ts +28 -2
  126. package/server/services/websocket/plan-handlers.ts +592 -0
  127. package/server/services/websocket/quality-handlers.ts +570 -0
  128. package/server/services/websocket/quality-persistence.ts +250 -0
  129. package/server/services/websocket/quality-service.ts +975 -0
  130. package/server/services/websocket/session-handlers.ts +26 -0
  131. package/server/services/websocket/types.ts +62 -2
@@ -0,0 +1,545 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * Plan Executor — Wave-based execution with Claude Code Agent Teams.
5
+ *
6
+ * Reads the dependency DAG from .pm/, picks ALL unblocked issues per wave,
7
+ * spawns a coordinator Claude session that uses Agent Teams to execute them
8
+ * in parallel, then reconciles state and repeats for newly-unblocked issues.
9
+ */
10
+ import { EventEmitter } from 'node:events';
11
+ import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { runWithFileLogger } from '../../cli/headless/headless-logger.js';
14
+ import { HeadlessRunner } from '../../cli/headless/index.js';
15
+ import { generateMcpConfig } from '../../cli/headless/mcp-config.js';
16
+ import { resolveReadyToWork } from './dependency-resolver.js';
17
+ import { parsePlanDirectory, resolvePmDir } from './parser.js';
18
+ import { reconcileState } from './state-reconciler.js';
19
+ export class PlanExecutor extends EventEmitter {
20
+ status = 'idle';
21
+ workingDir;
22
+ shouldStop = false;
23
+ shouldPause = false;
24
+ epicScope = null;
25
+ metrics = {
26
+ issuesCompleted: 0,
27
+ issuesAttempted: 0,
28
+ totalDuration: 0,
29
+ currentIssueId: null,
30
+ currentWaveIds: [],
31
+ };
32
+ constructor(workingDir) {
33
+ super();
34
+ this.workingDir = workingDir;
35
+ }
36
+ getStatus() {
37
+ return this.status;
38
+ }
39
+ getMetrics() {
40
+ return { ...this.metrics };
41
+ }
42
+ async startEpic(epicPath) {
43
+ this.epicScope = epicPath;
44
+ return this.start();
45
+ }
46
+ async start() {
47
+ if (this.status === 'executing' || this.status === 'starting')
48
+ return;
49
+ this.shouldStop = false;
50
+ this.shouldPause = false;
51
+ this.status = 'starting';
52
+ this.emit('statusChanged', this.status);
53
+ const startTime = Date.now();
54
+ try {
55
+ this.status = 'executing';
56
+ this.emit('statusChanged', this.status);
57
+ while (!this.shouldStop && !this.shouldPause) {
58
+ const readyIssues = this.pickReadyIssues();
59
+ if (readyIssues.length === 0)
60
+ break;
61
+ // Always use wave execution with Agent Teams — even for single issues.
62
+ // Each teammate runs as a separate process with its own context window,
63
+ // bouncer coverage via .mcp.json + PreToolUse hook, and disk persistence.
64
+ await this.executeWave(readyIssues);
65
+ }
66
+ }
67
+ catch (error) {
68
+ this.status = 'error';
69
+ this.emit('error', error instanceof Error ? error.message : String(error));
70
+ return;
71
+ }
72
+ this.metrics.totalDuration = Date.now() - startTime;
73
+ if (this.shouldPause) {
74
+ this.status = 'paused';
75
+ }
76
+ else if (this.shouldStop) {
77
+ this.status = 'idle';
78
+ }
79
+ else {
80
+ this.status = 'complete';
81
+ }
82
+ this.emit('statusChanged', this.status);
83
+ }
84
+ pause() {
85
+ this.shouldPause = true;
86
+ }
87
+ stop() {
88
+ this.shouldStop = true;
89
+ }
90
+ resume() {
91
+ if (this.status !== 'paused')
92
+ return Promise.resolve();
93
+ this.shouldPause = false;
94
+ return this.start();
95
+ }
96
+ // ── Wave execution (Agent Teams) ──────────────────────────────
97
+ async executeWave(issues) {
98
+ const waveIds = issues.map(i => i.id);
99
+ this.metrics.currentWaveIds = waveIds;
100
+ this.metrics.issuesAttempted += issues.length;
101
+ this.emit('waveStarted', { issueIds: waveIds });
102
+ // Pre-approve tools so teammates don't hit interactive permission prompts
103
+ this.installTeammatePermissions();
104
+ // Install bouncer .mcp.json so Agent Teams teammates discover it
105
+ this.installBouncerForSubagents();
106
+ // Mark all wave issues as in_progress
107
+ for (const issue of issues) {
108
+ this.updateIssueFrontMatter(issue.path, 'in_progress');
109
+ }
110
+ const prompt = this.buildCoordinatorPrompt(issues);
111
+ try {
112
+ const runner = new HeadlessRunner({
113
+ workingDir: this.workingDir,
114
+ directPrompt: prompt,
115
+ stallKillMs: 3_600_000, // 60 min — waves run longer
116
+ stallHardCapMs: 7_200_000, // 2 hr hard cap
117
+ extraEnv: {
118
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
119
+ },
120
+ outputCallback: (text) => {
121
+ this.emit('output', { issueId: `wave[${waveIds.join(',')}]`, text });
122
+ },
123
+ });
124
+ const result = await runWithFileLogger('pm-execute-wave', () => runner.run());
125
+ if (!result.completed || result.error) {
126
+ this.emit('waveError', {
127
+ issueIds: waveIds,
128
+ error: result.error || 'Wave did not complete successfully',
129
+ });
130
+ }
131
+ // Check which issues the agents actually completed by reading disk
132
+ this.reconcileWaveResults(issues);
133
+ }
134
+ catch (error) {
135
+ this.emit('waveError', {
136
+ issueIds: waveIds,
137
+ error: error instanceof Error ? error.message : String(error),
138
+ });
139
+ this.revertIncompleteIssues(issues);
140
+ }
141
+ // Clean up temporary configs
142
+ this.uninstallBouncerForSubagents();
143
+ this.uninstallTeammatePermissions();
144
+ // Reconcile STATE.md after wave
145
+ reconcileState(this.workingDir);
146
+ this.emit('stateUpdated');
147
+ this.metrics.currentWaveIds = [];
148
+ }
149
+ /**
150
+ * After a wave, check each issue's status on disk.
151
+ * The coordinator agent is instructed to mark issues as done via front matter,
152
+ * so we trust the disk state and update metrics accordingly.
153
+ */
154
+ reconcileWaveResults(issues) {
155
+ const pmDir = resolvePmDir(this.workingDir);
156
+ if (!pmDir)
157
+ return;
158
+ for (const issue of issues) {
159
+ const fullPath = join(pmDir, issue.path);
160
+ try {
161
+ const content = readFileSync(fullPath, 'utf-8');
162
+ const statusMatch = content.match(/^status:\s*(\S+)/m);
163
+ const currentStatus = statusMatch?.[1] ?? 'unknown';
164
+ if (currentStatus === 'done') {
165
+ this.metrics.issuesCompleted++;
166
+ this.emit('issueCompleted', issue);
167
+ }
168
+ else if (currentStatus === 'in_progress') {
169
+ // Agent didn't finish — check if output doc exists (partial completion)
170
+ const outputDoc = this.findOutputDoc(issue.id);
171
+ if (outputDoc) {
172
+ // Output was written but status not updated — mark done
173
+ this.updateIssueFrontMatter(issue.path, 'done');
174
+ this.metrics.issuesCompleted++;
175
+ this.emit('issueCompleted', issue);
176
+ }
177
+ else {
178
+ // Genuinely incomplete — revert to prior status
179
+ this.updateIssueFrontMatter(issue.path, issue.status);
180
+ this.emit('issueError', {
181
+ issueId: issue.id,
182
+ error: 'Issue did not complete during wave execution',
183
+ });
184
+ }
185
+ }
186
+ }
187
+ catch {
188
+ // File read error — treat as incomplete
189
+ this.emit('issueError', { issueId: issue.id, error: 'Could not read issue file after wave' });
190
+ }
191
+ }
192
+ }
193
+ /**
194
+ * Look for an output document matching an issue ID in .pm/docs/.
195
+ */
196
+ findOutputDoc(issueId) {
197
+ const pmDir = resolvePmDir(this.workingDir);
198
+ if (!pmDir)
199
+ return null;
200
+ const docsDir = join(pmDir, 'docs');
201
+ if (!existsSync(docsDir))
202
+ return null;
203
+ try {
204
+ const files = readdirSync(docsDir);
205
+ const prefix = issueId.toLowerCase();
206
+ const match = files.find(f => f.toLowerCase().startsWith(prefix) && f.endsWith('.md'));
207
+ return match ? join(docsDir, match) : null;
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ }
213
+ // ── Issue picking ─────────────────────────────────────────────
214
+ pickReadyIssues() {
215
+ const fullState = parsePlanDirectory(this.workingDir);
216
+ if (!fullState) {
217
+ this.emit('error', 'No .pm/ directory found');
218
+ return [];
219
+ }
220
+ if (fullState.state.paused) {
221
+ this.emit('error', 'Project is paused');
222
+ return [];
223
+ }
224
+ const readyIssues = resolveReadyToWork(fullState.issues, this.epicScope ?? undefined);
225
+ if (readyIssues.length === 0) {
226
+ this.emit('complete', this.epicScope ? 'All epic issues are done or blocked' : 'All work is done or blocked');
227
+ }
228
+ return readyIssues;
229
+ }
230
+ // ── Prompt building ───────────────────────────────────────────
231
+ /**
232
+ * Build the team lead prompt for a wave of issues.
233
+ * Uses Agent Teams (TeamCreate/SendMessage) for true parallel execution
234
+ * as separate processes — each teammate gets its own context window.
235
+ */
236
+ buildCoordinatorPrompt(issues) {
237
+ const pmDir = resolvePmDir(this.workingDir);
238
+ const docsDir = pmDir ? join(pmDir, 'docs') : '.pm/docs';
239
+ // Collect existing output docs that issues may need as input
240
+ const existingDocs = this.listExistingDocs();
241
+ const issueBlocks = issues.map(issue => {
242
+ const criteria = issue.acceptanceCriteria
243
+ .map(c => `- [${c.checked ? 'x' : ' '}] ${c.text}`)
244
+ .join('\n');
245
+ const files = issue.filesToModify.length > 0
246
+ ? `\nFiles to modify:\n${issue.filesToModify.map(f => `- ${f}`).join('\n')}`
247
+ : '';
248
+ // Find predecessor output docs this issue should read
249
+ const predecessorDocs = issue.blockedBy
250
+ .map(bp => {
251
+ const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
252
+ return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
253
+ })
254
+ .filter(Boolean);
255
+ const predecessorSection = predecessorDocs.length > 0
256
+ ? `\nPredecessor outputs to read:\n${predecessorDocs.map(d => `- ${d}`).join('\n')}`
257
+ : '';
258
+ return `### ${issue.id}: ${issue.title}
259
+
260
+ **Type**: ${issue.type} | **Priority**: ${issue.priority} | **Estimate**: ${issue.estimate ?? 'unestimated'}
261
+
262
+ **Description**:
263
+ ${issue.description}
264
+
265
+ **Acceptance Criteria**:
266
+ ${criteria || 'No specific criteria defined.'}
267
+
268
+ **Technical Notes**:
269
+ ${issue.technicalNotes || 'None'}
270
+ ${files}${predecessorSection}
271
+
272
+ **Output file**: ${docsDir}/${issue.id}-${this.slugify(issue.title)}.md`;
273
+ }).join('\n\n---\n\n');
274
+ const teammateNames = issues.map(i => i.id.toLowerCase()).join(', ');
275
+ const teamName = `pm-wave-${Date.now()}`;
276
+ const teammateSpawns = issues.map(issue => {
277
+ const predecessorDocs = issue.blockedBy
278
+ .map(bp => {
279
+ const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
280
+ return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
281
+ })
282
+ .filter(Boolean);
283
+ const predInstr = predecessorDocs.length > 0
284
+ ? `Read these predecessor output docs before starting: ${predecessorDocs.join(', ')}. `
285
+ : '';
286
+ const outputFile = `${docsDir}/${issue.id}-${this.slugify(issue.title)}.md`;
287
+ return `Spawn teammate **${issue.id.toLowerCase()}** using the **Agent** tool with \`team_name: "${teamName}"\` and \`name: "${issue.id.toLowerCase()}"\`:
288
+ > ${predInstr}Work on issue ${issue.id}: ${issue.title}.
289
+ > Read the full spec at ${pmDir ? join(pmDir, issue.path) : issue.path}.
290
+ > Execute all acceptance criteria.
291
+ > CRITICAL: Write ALL output/results to ${outputFile} — this is the handoff artifact for downstream issues.
292
+ > After writing output, update the issue front matter: change \`status: in_progress\` to \`status: done\`.
293
+ > Do not modify STATE.md. Do not work on anything outside this issue's scope.`;
294
+ }).join('\n\n');
295
+ return `You are the team lead coordinating ${issues.length} issue${issues.length > 1 ? 's' : ''} using Agent Teams.
296
+
297
+ ## Project Directory
298
+ Working directory: ${this.workingDir}
299
+ Plan directory: ${pmDir || '.pm/'}
300
+
301
+ ## Issues to Execute
302
+
303
+ ${issueBlocks}
304
+
305
+ ## Execution Protocol — Agent Teams
306
+
307
+ ### Step 1: Create the team
308
+
309
+ Use **TeamCreate** to create a team named \`${teamName}\`.
310
+
311
+ ### Step 2: Spawn teammates
312
+
313
+ Spawn all ${issues.length} teammates in parallel using the **Agent** tool with \`team_name\` and \`name\` parameters. Send a single message with ${issues.length} Agent tool calls.
314
+
315
+ ${teammateSpawns}
316
+
317
+ ### Step 3: Monitor completion
318
+
319
+ After spawning all teammates, poll for completion:
320
+ 1. Use **SendMessage** to each teammate (${teammateNames}) asking for status
321
+ 2. A teammate is done when its output file exists on disk AND the issue status is \`done\`
322
+ 3. If a teammate reports completion, verify by reading the output file yourself
323
+ 4. If a teammate is struggling, provide guidance via SendMessage
324
+
325
+ ### Step 4: Verify and clean up
326
+
327
+ Once all teammates report done:
328
+ 1. Verify each output file exists in ${docsDir}/
329
+ 2. Verify each issue's front matter status is \`done\`
330
+ 3. If any teammate failed to write output or update status, do it yourself
331
+ 4. Use **TeamDelete** to clean up the team \`${teamName}\`
332
+ 5. Do NOT modify STATE.md — the orchestrator handles that
333
+
334
+ ## Critical Rules
335
+
336
+ - Create ONE team with TeamCreate, then spawn teammates with Agent(team_name="${teamName}", name="...").
337
+ - Each teammate MUST write its output to disk. Research only in conversation is LOST.
338
+ - Each teammate MUST update the issue front matter status to \`done\`.
339
+ - One issue per teammate — no cross-issue work.
340
+ - Do not exit until ALL teammates have completed and output files are verified.`;
341
+ }
342
+ /**
343
+ * Revert issues that stayed in_progress after a failed wave.
344
+ */
345
+ revertIncompleteIssues(issues) {
346
+ const pmDir = resolvePmDir(this.workingDir);
347
+ if (!pmDir)
348
+ return;
349
+ for (const issue of issues) {
350
+ const fullPath = join(pmDir, issue.path);
351
+ try {
352
+ const content = readFileSync(fullPath, 'utf-8');
353
+ if (content.match(/^status:\s*in_progress$/m)) {
354
+ this.updateIssueFrontMatter(issue.path, issue.status);
355
+ }
356
+ }
357
+ catch { /* file may be gone */ }
358
+ }
359
+ }
360
+ // ── Teammate permissions ─────────────────────────────────────
361
+ /** Saved content of any pre-existing .claude/settings.json so we can restore it */
362
+ savedClaudeSettings = null;
363
+ claudeSettingsInstalled = false;
364
+ /**
365
+ * Pre-approve tools in project .claude/settings.json so Agent Teams
366
+ * teammates can work without interactive permission prompts.
367
+ * Teammates are separate processes that inherit the lead's permission
368
+ * settings. Without pre-approved tools, they hit interactive prompts
369
+ * that can't be answered in headless/background mode (known bug #25254).
370
+ */
371
+ installTeammatePermissions() {
372
+ const claudeDir = join(this.workingDir, '.claude');
373
+ const settingsPath = join(claudeDir, 'settings.json');
374
+ if (!existsSync(claudeDir)) {
375
+ mkdirSync(claudeDir, { recursive: true });
376
+ }
377
+ // Tools that teammates may need during execution
378
+ const requiredPermissions = [
379
+ 'Bash',
380
+ 'Read',
381
+ 'Edit',
382
+ 'Write',
383
+ 'Glob',
384
+ 'Grep',
385
+ 'WebFetch',
386
+ 'WebSearch',
387
+ 'Agent',
388
+ ];
389
+ try {
390
+ // Save existing settings
391
+ if (existsSync(settingsPath)) {
392
+ this.savedClaudeSettings = readFileSync(settingsPath, 'utf-8');
393
+ const existing = JSON.parse(this.savedClaudeSettings);
394
+ // Merge permissions into existing settings
395
+ if (!existing.permissions)
396
+ existing.permissions = {};
397
+ if (!existing.permissions.allow)
398
+ existing.permissions.allow = [];
399
+ for (const tool of requiredPermissions) {
400
+ if (!existing.permissions.allow.includes(tool)) {
401
+ existing.permissions.allow.push(tool);
402
+ }
403
+ }
404
+ writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
405
+ }
406
+ else {
407
+ this.savedClaudeSettings = null;
408
+ writeFileSync(settingsPath, JSON.stringify({
409
+ permissions: { allow: requiredPermissions },
410
+ }, null, 2));
411
+ }
412
+ this.claudeSettingsInstalled = true;
413
+ }
414
+ catch {
415
+ // Non-fatal — teammates may hit permission prompts
416
+ }
417
+ }
418
+ /**
419
+ * Restore original .claude/settings.json after wave execution.
420
+ */
421
+ uninstallTeammatePermissions() {
422
+ if (!this.claudeSettingsInstalled)
423
+ return;
424
+ const settingsPath = join(this.workingDir, '.claude', 'settings.json');
425
+ try {
426
+ if (this.savedClaudeSettings !== null) {
427
+ writeFileSync(settingsPath, this.savedClaudeSettings);
428
+ }
429
+ else {
430
+ unlinkSync(settingsPath);
431
+ }
432
+ }
433
+ catch {
434
+ // Best effort
435
+ }
436
+ this.savedClaudeSettings = null;
437
+ this.claudeSettingsInstalled = false;
438
+ }
439
+ // ── Bouncer propagation for sub-agents ─────────────────────
440
+ /** Saved content of any pre-existing .mcp.json so we can restore it */
441
+ savedMcpJson = null;
442
+ mcpJsonInstalled = false;
443
+ /**
444
+ * Write .mcp.json in the working directory so Agent Teams teammates
445
+ * (separate processes) auto-discover the bouncer MCP server.
446
+ * This is essential — teammates don't inherit --mcp-config or
447
+ * --permission-prompt-tool from the team lead. .mcp.json project-level
448
+ * discovery + global PreToolUse hooks are the two bouncer paths for teammates.
449
+ *
450
+ * Also generates ~/.mstro/mcp-config.json for the team lead (--mcp-config).
451
+ */
452
+ installBouncerForSubagents() {
453
+ const mcpJsonPath = join(this.workingDir, '.mcp.json');
454
+ // Generate the standard MCP config (for parent --mcp-config)
455
+ generateMcpConfig(this.workingDir);
456
+ // Read the generated config and write it as .mcp.json for sub-agent discovery
457
+ try {
458
+ const generatedPath = generateMcpConfig(this.workingDir);
459
+ if (!generatedPath)
460
+ return;
461
+ const mcpConfig = readFileSync(generatedPath, 'utf-8');
462
+ // Save any existing .mcp.json
463
+ if (existsSync(mcpJsonPath)) {
464
+ this.savedMcpJson = readFileSync(mcpJsonPath, 'utf-8');
465
+ // Merge: add bouncer to existing config
466
+ const existing = JSON.parse(this.savedMcpJson);
467
+ const generated = JSON.parse(mcpConfig);
468
+ existing.mcpServers = {
469
+ ...existing.mcpServers,
470
+ 'mstro-bouncer': generated.mcpServers['mstro-bouncer'],
471
+ };
472
+ writeFileSync(mcpJsonPath, JSON.stringify(existing, null, 2));
473
+ }
474
+ else {
475
+ writeFileSync(mcpJsonPath, mcpConfig);
476
+ }
477
+ this.mcpJsonInstalled = true;
478
+ }
479
+ catch {
480
+ // Non-fatal: parent has MCP via --mcp-config, teammates fall back to PreToolUse hooks
481
+ }
482
+ }
483
+ /**
484
+ * Restore or remove .mcp.json after execution.
485
+ */
486
+ uninstallBouncerForSubagents() {
487
+ if (!this.mcpJsonInstalled)
488
+ return;
489
+ const mcpJsonPath = join(this.workingDir, '.mcp.json');
490
+ try {
491
+ if (this.savedMcpJson !== null) {
492
+ // Restore the original
493
+ writeFileSync(mcpJsonPath, this.savedMcpJson);
494
+ }
495
+ else {
496
+ // We created it — remove it
497
+ unlinkSync(mcpJsonPath);
498
+ }
499
+ }
500
+ catch {
501
+ // Best effort cleanup
502
+ }
503
+ this.savedMcpJson = null;
504
+ this.mcpJsonInstalled = false;
505
+ }
506
+ // ── Helpers ───────────────────────────────────────────────────
507
+ listExistingDocs() {
508
+ const pmDir = resolvePmDir(this.workingDir);
509
+ if (!pmDir)
510
+ return [];
511
+ const docsDir = join(pmDir, 'docs');
512
+ if (!existsSync(docsDir))
513
+ return [];
514
+ try {
515
+ return readdirSync(docsDir, { recursive: true })
516
+ .filter((f) => typeof f === 'string' && f.endsWith('.md'))
517
+ .map(f => join(docsDir, f));
518
+ }
519
+ catch {
520
+ return [];
521
+ }
522
+ }
523
+ slugify(text) {
524
+ return text
525
+ .toLowerCase()
526
+ .replace(/[^a-z0-9]+/g, '-')
527
+ .replace(/^-+|-+$/g, '')
528
+ .slice(0, 60);
529
+ }
530
+ updateIssueFrontMatter(issuePath, newStatus) {
531
+ const pmDir = resolvePmDir(this.workingDir);
532
+ if (!pmDir)
533
+ return;
534
+ const fullPath = join(pmDir, issuePath);
535
+ try {
536
+ let content = readFileSync(fullPath, 'utf-8');
537
+ content = content.replace(/^(status:\s*).+$/m, `$1${newStatus}`);
538
+ writeFileSync(fullPath, content, 'utf-8');
539
+ }
540
+ catch {
541
+ // Ignore errors — file may have been moved
542
+ }
543
+ }
544
+ }
545
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../server/services/plan/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Issue, Milestone, PlanFullState, Sprint } from './types.js';
2
+ /** Resolve the PM directory — prefers .pm/, falls back to legacy .plan/ */
3
+ export declare function resolvePmDir(workingDir: string): string | null;
4
+ export declare function planDirExists(workingDir: string): boolean;
5
+ export declare function parsePlanDirectory(workingDir: string): PlanFullState | null;
6
+ export declare function parseSingleIssue(workingDir: string, issuePath: string): Issue | null;
7
+ export declare function parseSingleSprint(workingDir: string, sprintPath: string): Sprint | null;
8
+ export declare function parseSingleMilestone(workingDir: string, milestonePath: string): Milestone | null;
9
+ /** Compute the next available ID for a given prefix (e.g., "IS" → "IS-004") */
10
+ export declare function getNextId(issues: Issue[], prefix: string): string;
11
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/parser.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,KAAK,EAEL,SAAS,EAET,aAAa,EAGb,MAAM,EAIP,MAAM,YAAY,CAAC;AA6UpB,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM9D;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEzD;AAqBD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA6B3E;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAOpF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvF;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOhG;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUjE"}