@blockspool/mcp 0.3.0

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 (66) hide show
  1. package/README.md +174 -0
  2. package/dist/advance.d.ts +30 -0
  3. package/dist/advance.d.ts.map +1 -0
  4. package/dist/advance.js +514 -0
  5. package/dist/advance.js.map +1 -0
  6. package/dist/direct-client.d.ts +57 -0
  7. package/dist/direct-client.d.ts.map +1 -0
  8. package/dist/direct-client.js +92 -0
  9. package/dist/direct-client.js.map +1 -0
  10. package/dist/event-processor.d.ts +17 -0
  11. package/dist/event-processor.d.ts.map +1 -0
  12. package/dist/event-processor.js +360 -0
  13. package/dist/event-processor.js.map +1 -0
  14. package/dist/formulas.d.ts +37 -0
  15. package/dist/formulas.d.ts.map +1 -0
  16. package/dist/formulas.js +245 -0
  17. package/dist/formulas.js.map +1 -0
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +42 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/proposals.d.ts +51 -0
  23. package/dist/proposals.d.ts.map +1 -0
  24. package/dist/proposals.js +207 -0
  25. package/dist/proposals.js.map +1 -0
  26. package/dist/run-manager.d.ts +69 -0
  27. package/dist/run-manager.d.ts.map +1 -0
  28. package/dist/run-manager.js +315 -0
  29. package/dist/run-manager.js.map +1 -0
  30. package/dist/scope-policy.d.ts +34 -0
  31. package/dist/scope-policy.d.ts.map +1 -0
  32. package/dist/scope-policy.js +145 -0
  33. package/dist/scope-policy.js.map +1 -0
  34. package/dist/server.d.ts +16 -0
  35. package/dist/server.d.ts.map +1 -0
  36. package/dist/server.js +31 -0
  37. package/dist/server.js.map +1 -0
  38. package/dist/spindle.d.ts +41 -0
  39. package/dist/spindle.d.ts.map +1 -0
  40. package/dist/spindle.js +279 -0
  41. package/dist/spindle.js.map +1 -0
  42. package/dist/state.d.ts +36 -0
  43. package/dist/state.d.ts.map +1 -0
  44. package/dist/state.js +50 -0
  45. package/dist/state.js.map +1 -0
  46. package/dist/tools/execute.d.ts +7 -0
  47. package/dist/tools/execute.d.ts.map +1 -0
  48. package/dist/tools/execute.js +238 -0
  49. package/dist/tools/execute.js.map +1 -0
  50. package/dist/tools/git.d.ts +7 -0
  51. package/dist/tools/git.d.ts.map +1 -0
  52. package/dist/tools/git.js +67 -0
  53. package/dist/tools/git.js.map +1 -0
  54. package/dist/tools/scout.d.ts +7 -0
  55. package/dist/tools/scout.d.ts.map +1 -0
  56. package/dist/tools/scout.js +199 -0
  57. package/dist/tools/scout.js.map +1 -0
  58. package/dist/tools/session.d.ts +7 -0
  59. package/dist/tools/session.d.ts.map +1 -0
  60. package/dist/tools/session.js +296 -0
  61. package/dist/tools/session.js.map +1 -0
  62. package/dist/types.d.ts +116 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +13 -0
  65. package/dist/types.js.map +1 -0
  66. package/package.json +63 -0
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Spindle Loop Detection — MCP server adaptation.
3
+ *
4
+ * Monitors agent execution for unproductive patterns:
5
+ * - Oscillation: diffs flip-flopping (A→B→A)
6
+ * - Repetition: similar outputs repeated
7
+ * - Stalling: no file changes for N iterations
8
+ * - QA ping-pong: alternating test/lint failures
9
+ * - Command signature: same command fails repeatedly
10
+ *
11
+ * Ported from packages/cli/src/lib/spindle.ts, adapted for the
12
+ * event-driven MCP architecture.
13
+ */
14
+ import { createHash } from 'node:crypto';
15
+ export const DEFAULT_SPINDLE_CONFIG = {
16
+ similarityThreshold: 0.8,
17
+ maxSimilarOutputs: 3,
18
+ maxStallIterations: 5,
19
+ maxCommandFailures: 3,
20
+ maxQaPingPong: 3,
21
+ maxFileEdits: 3,
22
+ };
23
+ const PASS = {
24
+ shouldAbort: false,
25
+ shouldBlock: false,
26
+ confidence: 0,
27
+ diagnostics: {},
28
+ risk: 'none',
29
+ };
30
+ // ---------------------------------------------------------------------------
31
+ // Core check — runs on every advance()
32
+ // ---------------------------------------------------------------------------
33
+ export function checkSpindle(spindle, config = DEFAULT_SPINDLE_CONFIG) {
34
+ // 1. Stalling — no file changes
35
+ if (spindle.iterations_since_change >= config.maxStallIterations) {
36
+ return {
37
+ shouldAbort: true,
38
+ shouldBlock: false,
39
+ reason: 'stalling',
40
+ confidence: 0.9,
41
+ diagnostics: {
42
+ iterations_without_change: spindle.iterations_since_change,
43
+ threshold: config.maxStallIterations,
44
+ },
45
+ risk: 'high',
46
+ };
47
+ }
48
+ // 2. Oscillation — diff flip-flops
49
+ if (spindle.diff_hashes.length >= 3) {
50
+ const osc = detectOscillation(spindle.diff_hashes);
51
+ if (osc) {
52
+ return {
53
+ shouldAbort: true,
54
+ shouldBlock: false,
55
+ reason: 'oscillation',
56
+ confidence: 0.95,
57
+ diagnostics: { pattern: osc },
58
+ risk: 'high',
59
+ };
60
+ }
61
+ }
62
+ // 3. Repetition — similar output hashes
63
+ if (spindle.output_hashes.length >= config.maxSimilarOutputs) {
64
+ const rep = detectRepetition(spindle.output_hashes, config.maxSimilarOutputs);
65
+ if (rep) {
66
+ return {
67
+ shouldAbort: true,
68
+ shouldBlock: false,
69
+ reason: 'repetition',
70
+ confidence: 0.85,
71
+ diagnostics: { repeated_hash: rep, count: config.maxSimilarOutputs },
72
+ risk: 'high',
73
+ };
74
+ }
75
+ }
76
+ // 4. QA ping-pong — alternating failure types
77
+ if (spindle.failing_command_signatures.length >= config.maxQaPingPong * 2) {
78
+ const pp = detectQaPingPong(spindle.failing_command_signatures, config.maxQaPingPong);
79
+ if (pp) {
80
+ return {
81
+ shouldAbort: true,
82
+ shouldBlock: false,
83
+ reason: 'qa_ping_pong',
84
+ confidence: 0.9,
85
+ diagnostics: { pattern: pp },
86
+ risk: 'high',
87
+ };
88
+ }
89
+ }
90
+ // 5. Command signature — same command fails N times
91
+ const cmdFail = detectCommandFailure(spindle.failing_command_signatures, config.maxCommandFailures);
92
+ if (cmdFail) {
93
+ return {
94
+ shouldAbort: false,
95
+ shouldBlock: true, // → BLOCKED_NEEDS_HUMAN
96
+ reason: 'command_failure',
97
+ confidence: 0.8,
98
+ diagnostics: { command: cmdFail, threshold: config.maxCommandFailures },
99
+ risk: 'high',
100
+ };
101
+ }
102
+ // Compute risk level
103
+ const risk = computeRisk(spindle, config);
104
+ return { ...PASS, risk };
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // State update helpers — called from event processor
108
+ // ---------------------------------------------------------------------------
109
+ export function recordOutput(spindle, output) {
110
+ const hash = shortHash(output);
111
+ spindle.output_hashes.push(hash);
112
+ if (spindle.output_hashes.length > 10)
113
+ spindle.output_hashes.shift();
114
+ spindle.total_output_chars += output.length;
115
+ }
116
+ export function recordDiff(spindle, diff) {
117
+ if (!diff || diff.trim() === '') {
118
+ spindle.iterations_since_change++;
119
+ return;
120
+ }
121
+ spindle.iterations_since_change = 0;
122
+ const hash = shortHash(diff);
123
+ spindle.diff_hashes.push(hash);
124
+ if (spindle.diff_hashes.length > 10)
125
+ spindle.diff_hashes.shift();
126
+ spindle.total_change_chars += diff.length;
127
+ // Track per-file edit frequency
128
+ const files = extractFilesFromDiff(diff);
129
+ for (const f of files) {
130
+ const existing = spindle.file_edit_counts?.[f] ?? 0;
131
+ if (!spindle.file_edit_counts)
132
+ spindle.file_edit_counts = {};
133
+ spindle.file_edit_counts[f] = existing + 1;
134
+ }
135
+ }
136
+ export function recordCommandFailure(spindle, command, error) {
137
+ const sig = shortHash(`${command}::${error.slice(0, 200)}`);
138
+ spindle.failing_command_signatures.push(sig);
139
+ if (spindle.failing_command_signatures.length > 20)
140
+ spindle.failing_command_signatures.shift();
141
+ }
142
+ export function recordPlanHash(spindle, plan) {
143
+ const hash = shortHash(JSON.stringify(plan));
144
+ spindle.plan_hashes.push(hash);
145
+ if (spindle.plan_hashes.length > 10)
146
+ spindle.plan_hashes.shift();
147
+ }
148
+ export function recordTicketResult(spindle, changedFiles, diff) {
149
+ recordDiff(spindle, diff);
150
+ }
151
+ // ---------------------------------------------------------------------------
152
+ // Detection functions
153
+ // ---------------------------------------------------------------------------
154
+ /** Detect A→B→A hash oscillation */
155
+ function detectOscillation(hashes) {
156
+ // Check for A→B→A pattern in last 3
157
+ const recent = hashes.slice(-3);
158
+ if (recent.length === 3 && recent[0] === recent[2] && recent[0] !== recent[1]) {
159
+ return `Hash ${recent[0]} appeared at positions -3 and -1 (flip-flop)`;
160
+ }
161
+ // Check for any hash appearing in alternating positions
162
+ for (let i = hashes.length - 1; i >= 2; i--) {
163
+ if (hashes[i] === hashes[i - 2] && hashes[i] !== hashes[i - 1]) {
164
+ return `Hash ${hashes[i]} oscillating at positions ${i - 2}, ${i}`;
165
+ }
166
+ }
167
+ return null;
168
+ }
169
+ /** Detect N consecutive identical output hashes */
170
+ function detectRepetition(hashes, threshold) {
171
+ if (hashes.length < threshold)
172
+ return null;
173
+ const recent = hashes.slice(-threshold);
174
+ const first = recent[0];
175
+ if (recent.every(h => h === first)) {
176
+ return first;
177
+ }
178
+ return null;
179
+ }
180
+ /** Detect QA ping-pong: alternating failure signatures */
181
+ function detectQaPingPong(sigs, cycles) {
182
+ if (sigs.length < cycles * 2)
183
+ return null;
184
+ const recent = sigs.slice(-(cycles * 2));
185
+ // Check for A→B→A→B pattern
186
+ const a = recent[0];
187
+ const b = recent[1];
188
+ if (a === b)
189
+ return null; // Not alternating
190
+ let alternating = true;
191
+ for (let i = 0; i < recent.length; i++) {
192
+ const expected = i % 2 === 0 ? a : b;
193
+ if (recent[i] !== expected) {
194
+ alternating = false;
195
+ break;
196
+ }
197
+ }
198
+ if (alternating) {
199
+ return `Alternating failures: ${a} ↔ ${b} (${cycles} cycles)`;
200
+ }
201
+ return null;
202
+ }
203
+ /** Detect same command failing N times */
204
+ function detectCommandFailure(sigs, threshold) {
205
+ if (sigs.length < threshold)
206
+ return null;
207
+ // Count occurrences of each signature
208
+ const counts = new Map();
209
+ for (const sig of sigs) {
210
+ counts.set(sig, (counts.get(sig) ?? 0) + 1);
211
+ }
212
+ for (const [sig, count] of counts) {
213
+ if (count >= threshold)
214
+ return sig;
215
+ }
216
+ return null;
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // Risk computation
220
+ // ---------------------------------------------------------------------------
221
+ function computeRisk(spindle, config) {
222
+ let score = 0;
223
+ // Stall proximity
224
+ if (spindle.iterations_since_change >= config.maxStallIterations * 0.6)
225
+ score += 2;
226
+ else if (spindle.iterations_since_change >= 2)
227
+ score += 1;
228
+ // Repeated outputs
229
+ const recentOutputs = spindle.output_hashes.slice(-3);
230
+ if (recentOutputs.length >= 2 && recentOutputs[recentOutputs.length - 1] === recentOutputs[recentOutputs.length - 2]) {
231
+ score += 1;
232
+ }
233
+ // File edit frequency warnings
234
+ if (spindle.file_edit_counts) {
235
+ for (const count of Object.values(spindle.file_edit_counts)) {
236
+ if (count >= config.maxFileEdits)
237
+ score += 2;
238
+ }
239
+ }
240
+ // Command failures
241
+ if (spindle.failing_command_signatures.length >= 2)
242
+ score += 1;
243
+ if (score >= 4)
244
+ return 'high';
245
+ if (score >= 2)
246
+ return 'medium';
247
+ if (score >= 1)
248
+ return 'low';
249
+ return 'none';
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Helpers
253
+ // ---------------------------------------------------------------------------
254
+ function shortHash(s) {
255
+ return createHash('sha256').update(s).digest('hex').slice(0, 12);
256
+ }
257
+ /** Extract file paths from a unified diff */
258
+ function extractFilesFromDiff(diff) {
259
+ const files = [];
260
+ for (const line of diff.split('\n')) {
261
+ if (line.startsWith('+++ b/')) {
262
+ files.push(line.slice(6));
263
+ }
264
+ }
265
+ return files;
266
+ }
267
+ /** Get file edit frequency warnings */
268
+ export function getFileEditWarnings(spindle, threshold = 3) {
269
+ if (!spindle.file_edit_counts)
270
+ return [];
271
+ const warnings = [];
272
+ for (const [file, count] of Object.entries(spindle.file_edit_counts)) {
273
+ if (count >= threshold) {
274
+ warnings.push(`${file} edited ${count} times`);
275
+ }
276
+ }
277
+ return warnings;
278
+ }
279
+ //# sourceMappingURL=spindle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spindle.js","sourceRoot":"","sources":["../src/spindle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Session state manager (v2)
3
+ *
4
+ * Thin wrapper around RunManager + database.
5
+ * Each MCP server instance has at most one active run.
6
+ */
7
+ import type { DatabaseAdapter } from '@blockspool/core';
8
+ import type { Project } from '@blockspool/core';
9
+ import { RunManager } from './run-manager.js';
10
+ import type { RunState, SessionConfig } from './types.js';
11
+ export declare class SessionManager {
12
+ readonly db: DatabaseAdapter;
13
+ readonly project: Project;
14
+ readonly projectPath: string;
15
+ readonly run: RunManager;
16
+ constructor(db: DatabaseAdapter, project: Project, projectPath: string);
17
+ /** Start a new session/run */
18
+ start(config: SessionConfig): RunState;
19
+ /** Get active run state or throw */
20
+ requireActive(): RunState;
21
+ /** End the session */
22
+ end(): RunState;
23
+ /** Get current status summary */
24
+ getStatus(): {
25
+ sessionId: string;
26
+ runId: string;
27
+ phase: string;
28
+ stepCount: number;
29
+ budgetRemaining: number;
30
+ ticketsCompleted: number;
31
+ ticketsFailed: number;
32
+ currentTicketId: string | null;
33
+ timeRemainingMs: number | null;
34
+ };
35
+ }
36
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,cAAc;IAIvB,QAAQ,CAAC,EAAE,EAAE,eAAe;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM;IAL9B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;gBAGd,EAAE,EAAE,eAAe,EACnB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM;IAK9B,8BAA8B;IAC9B,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ;IAItC,oCAAoC;IACpC,aAAa,IAAI,QAAQ;IAIzB,sBAAsB;IACtB,GAAG,IAAI,QAAQ;IAIf,iCAAiC;IACjC,SAAS,IAAI;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC;CAkBF"}
package/dist/state.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Session state manager (v2)
3
+ *
4
+ * Thin wrapper around RunManager + database.
5
+ * Each MCP server instance has at most one active run.
6
+ */
7
+ import { RunManager } from './run-manager.js';
8
+ export class SessionManager {
9
+ db;
10
+ project;
11
+ projectPath;
12
+ run;
13
+ constructor(db, project, projectPath) {
14
+ this.db = db;
15
+ this.project = project;
16
+ this.projectPath = projectPath;
17
+ this.run = new RunManager(projectPath);
18
+ }
19
+ /** Start a new session/run */
20
+ start(config) {
21
+ return this.run.create(this.project.id, config);
22
+ }
23
+ /** Get active run state or throw */
24
+ requireActive() {
25
+ return this.run.require();
26
+ }
27
+ /** End the session */
28
+ end() {
29
+ return this.run.end();
30
+ }
31
+ /** Get current status summary */
32
+ getStatus() {
33
+ const s = this.run.require();
34
+ const timeRemainingMs = s.expires_at
35
+ ? Math.max(0, new Date(s.expires_at).getTime() - Date.now())
36
+ : null;
37
+ return {
38
+ sessionId: s.session_id,
39
+ runId: s.run_id,
40
+ phase: s.phase,
41
+ stepCount: s.step_count,
42
+ budgetRemaining: s.step_budget - s.step_count,
43
+ ticketsCompleted: s.tickets_completed,
44
+ ticketsFailed: s.tickets_failed,
45
+ currentTicketId: s.current_ticket_id,
46
+ timeRemainingMs,
47
+ };
48
+ }
49
+ }
50
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,OAAO,cAAc;IAId;IACA;IACA;IALF,GAAG,CAAa;IAEzB,YACW,EAAmB,EACnB,OAAgB,EAChB,WAAmB;QAFnB,OAAE,GAAF,EAAE,CAAiB;QACnB,YAAO,GAAP,OAAO,CAAS;QAChB,gBAAW,GAAX,WAAW,CAAQ;QAE5B,IAAI,CAAC,GAAG,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAED,8BAA8B;IAC9B,KAAK,CAAC,MAAqB;QACzB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,oCAAoC;IACpC,aAAa;QACX,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC5B,CAAC;IAED,sBAAsB;IACtB,GAAG;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IACxB,CAAC;IAED,iCAAiC;IACjC,SAAS;QAWP,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC7B,MAAM,eAAe,GAAG,CAAC,CAAC,UAAU;YAClC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC5D,CAAC,CAAC,IAAI,CAAC;QAET,OAAO;YACL,SAAS,EAAE,CAAC,CAAC,UAAU;YACvB,KAAK,EAAE,CAAC,CAAC,MAAM;YACf,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,UAAU;YACvB,eAAe,EAAE,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,UAAU;YAC7C,gBAAgB,EAAE,CAAC,CAAC,iBAAiB;YACrC,aAAa,EAAE,CAAC,CAAC,cAAc;YAC/B,eAAe,EAAE,CAAC,CAAC,iBAAiB;YACpC,eAAe;SAChB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Execution tools: next_ticket, validate_scope, complete_ticket, fail_ticket
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { SessionManager } from '../state.js';
6
+ export declare function registerExecuteTools(server: McpServer, getState: () => SessionManager): void;
7
+ //# sourceMappingURL=execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,QAsPrF"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Execution tools: next_ticket, validate_scope, complete_ticket, fail_ticket
3
+ */
4
+ import { z } from 'zod';
5
+ import { repos } from '@blockspool/core';
6
+ import { execSync } from 'node:child_process';
7
+ export function registerExecuteTools(server, getState) {
8
+ server.tool('blockspool_next_ticket', 'Returns the next ticket to work on: title, description, allowed_paths, and execution instructions.', {}, async () => {
9
+ const state = getState();
10
+ const run = state.requireActive();
11
+ // Find next ready ticket
12
+ const readyTickets = await repos.tickets.listByProject(state.db, run.project_id, { status: 'ready', limit: 1 });
13
+ if (readyTickets.length === 0) {
14
+ return {
15
+ content: [{
16
+ type: 'text',
17
+ text: JSON.stringify({
18
+ message: 'No tickets ready for execution. Run blockspool_scout_files to find more work.',
19
+ tickets_completed: run.tickets_completed,
20
+ tickets_failed: run.tickets_failed,
21
+ }),
22
+ }],
23
+ };
24
+ }
25
+ const ticket = readyTickets[0];
26
+ // Mark as in_progress
27
+ await repos.tickets.updateStatus(state.db, ticket.id, 'in_progress');
28
+ state.run.assignTicket(ticket.id);
29
+ // Create a worker run record
30
+ const dbRun = await repos.runs.create(state.db, {
31
+ projectId: run.project_id,
32
+ type: 'worker',
33
+ ticketId: ticket.id,
34
+ });
35
+ return {
36
+ content: [{
37
+ type: 'text',
38
+ text: JSON.stringify({
39
+ ticketId: ticket.id,
40
+ runId: dbRun.id,
41
+ title: ticket.title,
42
+ description: ticket.description,
43
+ allowedPaths: ticket.allowedPaths,
44
+ verificationCommands: ticket.verificationCommands,
45
+ category: ticket.category,
46
+ instructions: buildExecutionPrompt(ticket),
47
+ }, null, 2),
48
+ }],
49
+ };
50
+ });
51
+ server.tool('blockspool_validate_scope', 'Before committing, send the list of changed files. BlockSpool checks scope enforcement.', {
52
+ ticketId: z.string().describe('The ticket ID being worked on.'),
53
+ changedFiles: z.array(z.string()).describe('List of file paths that were modified.'),
54
+ }, async (params) => {
55
+ const state = getState();
56
+ state.requireActive();
57
+ const ticket = await repos.tickets.getById(state.db, params.ticketId);
58
+ if (!ticket) {
59
+ return {
60
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Ticket not found.' }) }],
61
+ isError: true,
62
+ };
63
+ }
64
+ // If no allowed_paths, everything is allowed
65
+ if (ticket.allowedPaths.length === 0) {
66
+ state.run.appendEvent('SCOPE_ALLOWED', { ticket_id: params.ticketId, files: params.changedFiles });
67
+ return {
68
+ content: [{
69
+ type: 'text',
70
+ text: JSON.stringify({ valid: true, message: 'No scope restrictions.' }),
71
+ }],
72
+ };
73
+ }
74
+ const violations = [];
75
+ for (const file of params.changedFiles) {
76
+ const allowed = ticket.allowedPaths.some(pattern => {
77
+ if (file === pattern)
78
+ return true;
79
+ if (file.startsWith(pattern.replace(/\*\*$/, '').replace(/\*$/, '')))
80
+ return true;
81
+ if (pattern.endsWith('/**') && file.startsWith(pattern.slice(0, -3)))
82
+ return true;
83
+ return false;
84
+ });
85
+ if (!allowed) {
86
+ violations.push(file);
87
+ }
88
+ }
89
+ if (violations.length > 0) {
90
+ state.run.appendEvent('SCOPE_BLOCKED', {
91
+ ticket_id: params.ticketId,
92
+ violations,
93
+ allowed_paths: ticket.allowedPaths,
94
+ });
95
+ return {
96
+ content: [{
97
+ type: 'text',
98
+ text: JSON.stringify({
99
+ valid: false,
100
+ violations,
101
+ allowedPaths: ticket.allowedPaths,
102
+ message: 'Some changed files are outside the allowed scope. Revert those changes before completing.',
103
+ }, null, 2),
104
+ }],
105
+ };
106
+ }
107
+ state.run.appendEvent('SCOPE_ALLOWED', { ticket_id: params.ticketId, files: params.changedFiles });
108
+ return {
109
+ content: [{
110
+ type: 'text',
111
+ text: JSON.stringify({ valid: true, message: 'All changes within allowed scope.' }),
112
+ }],
113
+ };
114
+ });
115
+ server.tool('blockspool_complete_ticket', 'Mark a ticket as done. BlockSpool runs QA commands to verify, then records success.', {
116
+ ticketId: z.string().describe('The ticket ID to complete.'),
117
+ runId: z.string().describe('The run ID from next_ticket.'),
118
+ summary: z.string().optional().describe('Brief summary of changes made.'),
119
+ }, async (params) => {
120
+ const state = getState();
121
+ state.requireActive();
122
+ const ticket = await repos.tickets.getById(state.db, params.ticketId);
123
+ if (!ticket) {
124
+ return {
125
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Ticket not found.' }) }],
126
+ isError: true,
127
+ };
128
+ }
129
+ state.run.appendEvent('QA_STARTED', { ticket_id: params.ticketId });
130
+ // Run QA commands
131
+ const qaResults = [];
132
+ for (const cmd of ticket.verificationCommands) {
133
+ try {
134
+ const output = execSync(cmd, {
135
+ cwd: state.project.rootPath,
136
+ timeout: 120_000,
137
+ encoding: 'utf-8',
138
+ stdio: ['pipe', 'pipe', 'pipe'],
139
+ });
140
+ qaResults.push({ command: cmd, success: true, output: output.slice(-2000) });
141
+ state.run.appendEvent('QA_COMMAND_RESULT', { command: cmd, success: true });
142
+ }
143
+ catch (e) {
144
+ const err = e;
145
+ const output = (err.stderr || err.stdout || err.message).slice(-2000);
146
+ qaResults.push({ command: cmd, success: false, output });
147
+ state.run.appendEvent('QA_COMMAND_RESULT', { command: cmd, success: false });
148
+ }
149
+ }
150
+ const allPassed = qaResults.every(r => r.success);
151
+ if (allPassed) {
152
+ await repos.tickets.updateStatus(state.db, params.ticketId, 'done');
153
+ await repos.runs.markSuccess(state.db, params.runId, {
154
+ summary: params.summary,
155
+ qaResults,
156
+ });
157
+ state.run.appendEvent('QA_PASSED', { ticket_id: params.ticketId });
158
+ state.run.setPhase('PR');
159
+ // Save QA artifact
160
+ state.run.saveArtifact(`${state.run.require().step_count}-qa-stdout.log`, qaResults.map(r => `$ ${r.command}\n${r.output}`).join('\n\n'));
161
+ return {
162
+ content: [{
163
+ type: 'text',
164
+ text: JSON.stringify({
165
+ success: true,
166
+ ticketId: params.ticketId,
167
+ qaResults: qaResults.map(r => ({ command: r.command, success: r.success })),
168
+ message: 'QA passed. Call blockspool_advance to create a PR for this ticket.',
169
+ }, null, 2),
170
+ }],
171
+ };
172
+ }
173
+ else {
174
+ state.run.appendEvent('QA_FAILED', { ticket_id: params.ticketId, results: qaResults });
175
+ return {
176
+ content: [{
177
+ type: 'text',
178
+ text: JSON.stringify({
179
+ success: false,
180
+ ticketId: params.ticketId,
181
+ qaResults,
182
+ message: 'QA failed. Fix the issues and try again, or call blockspool_fail_ticket.',
183
+ }, null, 2),
184
+ }],
185
+ };
186
+ }
187
+ });
188
+ server.tool('blockspool_fail_ticket', 'Mark a ticket as failed with a reason.', {
189
+ ticketId: z.string().describe('The ticket ID that failed.'),
190
+ runId: z.string().describe('The run ID from next_ticket.'),
191
+ reason: z.string().describe('Why the ticket failed.'),
192
+ }, async (params) => {
193
+ const state = getState();
194
+ state.requireActive();
195
+ await repos.tickets.updateStatus(state.db, params.ticketId, 'blocked');
196
+ await repos.runs.markFailure(state.db, params.runId, params.reason);
197
+ state.run.failTicket(params.reason);
198
+ return {
199
+ content: [{
200
+ type: 'text',
201
+ text: JSON.stringify({
202
+ ticketId: params.ticketId,
203
+ status: 'blocked',
204
+ reason: params.reason,
205
+ message: 'Ticket marked as failed. Use blockspool_next_ticket for the next one.',
206
+ }, null, 2),
207
+ }],
208
+ };
209
+ });
210
+ }
211
+ function buildExecutionPrompt(ticket) {
212
+ const parts = [
213
+ `# Task: ${ticket.title}`,
214
+ '',
215
+ ticket.description ?? '',
216
+ '',
217
+ '## Constraints',
218
+ '',
219
+ `- Only modify files in: ${ticket.allowedPaths.length > 0 ? ticket.allowedPaths.join(', ') : 'any files'}`,
220
+ '- Make minimal, focused changes',
221
+ '- Do not introduce new dependencies unless necessary',
222
+ '',
223
+ '## Verification',
224
+ '',
225
+ 'After making changes, these commands must pass:',
226
+ ...ticket.verificationCommands.map(c => `- \`${c}\``),
227
+ '',
228
+ '## Workflow',
229
+ '',
230
+ '1. Read the relevant files',
231
+ '2. Make the changes described above',
232
+ '3. Call blockspool_validate_scope with the list of changed files',
233
+ '4. If valid, call blockspool_complete_ticket',
234
+ '5. If QA fails, fix and retry or call blockspool_fail_ticket',
235
+ ];
236
+ return parts.join('\n');
237
+ }
238
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Git operations tool: git_setup
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { SessionManager } from '../state.js';
6
+ export declare function registerGitTools(server: McpServer, getState: () => SessionManager): void;
7
+ //# sourceMappingURL=git.d.ts.map