@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.
- package/README.md +174 -0
- package/dist/advance.d.ts +30 -0
- package/dist/advance.d.ts.map +1 -0
- package/dist/advance.js +514 -0
- package/dist/advance.js.map +1 -0
- package/dist/direct-client.d.ts +57 -0
- package/dist/direct-client.d.ts.map +1 -0
- package/dist/direct-client.js +92 -0
- package/dist/direct-client.js.map +1 -0
- package/dist/event-processor.d.ts +17 -0
- package/dist/event-processor.d.ts.map +1 -0
- package/dist/event-processor.js +360 -0
- package/dist/event-processor.js.map +1 -0
- package/dist/formulas.d.ts +37 -0
- package/dist/formulas.d.ts.map +1 -0
- package/dist/formulas.js +245 -0
- package/dist/formulas.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/proposals.d.ts +51 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/proposals.js +207 -0
- package/dist/proposals.js.map +1 -0
- package/dist/run-manager.d.ts +69 -0
- package/dist/run-manager.d.ts.map +1 -0
- package/dist/run-manager.js +315 -0
- package/dist/run-manager.js.map +1 -0
- package/dist/scope-policy.d.ts +34 -0
- package/dist/scope-policy.d.ts.map +1 -0
- package/dist/scope-policy.js +145 -0
- package/dist/scope-policy.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +31 -0
- package/dist/server.js.map +1 -0
- package/dist/spindle.d.ts +41 -0
- package/dist/spindle.d.ts.map +1 -0
- package/dist/spindle.js +279 -0
- package/dist/spindle.js.map +1 -0
- package/dist/state.d.ts +36 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +50 -0
- package/dist/state.js.map +1 -0
- package/dist/tools/execute.d.ts +7 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +238 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/git.d.ts +7 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +67 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/scout.d.ts +7 -0
- package/dist/tools/scout.d.ts.map +1 -0
- package/dist/tools/scout.js +199 -0
- package/dist/tools/scout.js.map +1 -0
- package/dist/tools/session.d.ts +7 -0
- package/dist/tools/session.d.ts.map +1 -0
- package/dist/tools/session.js +296 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct Client — programmatic adapter for the BlockSpool canonical loop.
|
|
3
|
+
*
|
|
4
|
+
* Proves the MCP tools work without Claude Code or stdio transport.
|
|
5
|
+
* Any LLM (or test harness) can drive the loop:
|
|
6
|
+
*
|
|
7
|
+
* const client = await DirectClient.create({ projectPath });
|
|
8
|
+
* const session = client.startSession({ scope: 'src/**' });
|
|
9
|
+
* while (true) {
|
|
10
|
+
* const resp = await client.advance();
|
|
11
|
+
* if (resp.next_action === 'STOP') break;
|
|
12
|
+
* // ... call LLM with resp.prompt ...
|
|
13
|
+
* await client.ingestEvent(type, payload);
|
|
14
|
+
* }
|
|
15
|
+
* client.endSession();
|
|
16
|
+
* await client.close();
|
|
17
|
+
*/
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import { createSQLiteAdapter } from '@blockspool/sqlite';
|
|
21
|
+
import { repos } from '@blockspool/core';
|
|
22
|
+
import { RunManager } from './run-manager.js';
|
|
23
|
+
import { advance } from './advance.js';
|
|
24
|
+
import { processEvent } from './event-processor.js';
|
|
25
|
+
export class DirectClient {
|
|
26
|
+
run;
|
|
27
|
+
db;
|
|
28
|
+
project;
|
|
29
|
+
ownsDb;
|
|
30
|
+
constructor(run, db, project, ownsDb) {
|
|
31
|
+
this.run = run;
|
|
32
|
+
this.db = db;
|
|
33
|
+
this.project = project;
|
|
34
|
+
this.ownsDb = ownsDb;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a DirectClient. Initializes SQLite and ensures the project exists.
|
|
38
|
+
*/
|
|
39
|
+
static async create(options) {
|
|
40
|
+
const { projectPath, projectName } = options;
|
|
41
|
+
let db = options.db;
|
|
42
|
+
let ownsDb = false;
|
|
43
|
+
if (!db) {
|
|
44
|
+
const bsDir = path.join(projectPath, '.blockspool');
|
|
45
|
+
if (!fs.existsSync(bsDir)) {
|
|
46
|
+
fs.mkdirSync(bsDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
db = await createSQLiteAdapter({ url: path.join(bsDir, 'state.sqlite') });
|
|
49
|
+
ownsDb = true;
|
|
50
|
+
}
|
|
51
|
+
const project = await repos.projects.ensureForRepo(db, {
|
|
52
|
+
name: projectName ?? path.basename(projectPath),
|
|
53
|
+
rootPath: projectPath,
|
|
54
|
+
});
|
|
55
|
+
const run = new RunManager(projectPath);
|
|
56
|
+
return new DirectClient(run, db, project, ownsDb);
|
|
57
|
+
}
|
|
58
|
+
/** Start a new session. Returns the initial RunState. */
|
|
59
|
+
startSession(config = {}) {
|
|
60
|
+
return this.run.create(this.project.id, config);
|
|
61
|
+
}
|
|
62
|
+
/** Get the next action. This is the core loop driver. */
|
|
63
|
+
async advance() {
|
|
64
|
+
return advance({ run: this.run, db: this.db, project: this.project });
|
|
65
|
+
}
|
|
66
|
+
/** Report an event back. Triggers state transitions. */
|
|
67
|
+
async ingestEvent(type, payload) {
|
|
68
|
+
// Log the raw event (matches what blockspool_ingest_event tool does)
|
|
69
|
+
this.run.appendEvent(type, payload);
|
|
70
|
+
const result = await processEvent(this.run, this.db, type, payload);
|
|
71
|
+
return { processed: result.processed, message: result.message };
|
|
72
|
+
}
|
|
73
|
+
/** Get current run state. */
|
|
74
|
+
getState() {
|
|
75
|
+
return this.run.require();
|
|
76
|
+
}
|
|
77
|
+
/** End the session. */
|
|
78
|
+
endSession() {
|
|
79
|
+
return this.run.end();
|
|
80
|
+
}
|
|
81
|
+
/** Clean up resources. */
|
|
82
|
+
async close() {
|
|
83
|
+
if (this.ownsDb) {
|
|
84
|
+
await this.db.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Expose internals for testing */
|
|
88
|
+
get _run() { return this.run; }
|
|
89
|
+
get _db() { return this.db; }
|
|
90
|
+
get _project() { return this.project; }
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=direct-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct-client.js","sourceRoot":"","sources":["../src/direct-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Processor — handles ingested events and triggers state transitions.
|
|
3
|
+
*
|
|
4
|
+
* When the client calls `blockspool_ingest_event`, this module processes
|
|
5
|
+
* the event and updates RunState accordingly (phase transitions, counters, etc).
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseAdapter } from '@blockspool/core';
|
|
8
|
+
import { RunManager } from './run-manager.js';
|
|
9
|
+
import type { EventType } from './types.js';
|
|
10
|
+
export interface ProcessResult {
|
|
11
|
+
processed: boolean;
|
|
12
|
+
phase_changed: boolean;
|
|
13
|
+
new_phase?: string;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function processEvent(run: RunManager, db: DatabaseAdapter, type: EventType, payload: Record<string, unknown>): Promise<ProcessResult>;
|
|
17
|
+
//# sourceMappingURL=event-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-processor.d.ts","sourceRoot":"","sources":["../src/event-processor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,YAAY,CAAC;AAMxD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,UAAU,EACf,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,aAAa,CAAC,CAiaxB"}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Processor — handles ingested events and triggers state transitions.
|
|
3
|
+
*
|
|
4
|
+
* When the client calls `blockspool_ingest_event`, this module processes
|
|
5
|
+
* the event and updates RunState accordingly (phase transitions, counters, etc).
|
|
6
|
+
*/
|
|
7
|
+
import { repos } from '@blockspool/core';
|
|
8
|
+
import { filterAndCreateTickets } from './proposals.js';
|
|
9
|
+
import { deriveScopePolicy, validatePlanScope } from './scope-policy.js';
|
|
10
|
+
import { recordDiff, recordCommandFailure, recordPlanHash } from './spindle.js';
|
|
11
|
+
export async function processEvent(run, db, type, payload) {
|
|
12
|
+
const s = run.require();
|
|
13
|
+
switch (type) {
|
|
14
|
+
// -----------------------------------------------------------------
|
|
15
|
+
// Scout events
|
|
16
|
+
// -----------------------------------------------------------------
|
|
17
|
+
case 'SCOUT_OUTPUT': {
|
|
18
|
+
if (s.phase !== 'SCOUT') {
|
|
19
|
+
return { processed: true, phase_changed: false, message: 'Scout output outside SCOUT phase, ignored' };
|
|
20
|
+
}
|
|
21
|
+
// Extract proposals from payload
|
|
22
|
+
const rawProposals = (payload['proposals'] ?? []);
|
|
23
|
+
if (rawProposals.length === 0) {
|
|
24
|
+
// No proposals found — done
|
|
25
|
+
run.setPhase('DONE');
|
|
26
|
+
return {
|
|
27
|
+
processed: true,
|
|
28
|
+
phase_changed: true,
|
|
29
|
+
new_phase: 'DONE',
|
|
30
|
+
message: 'No proposals in scout output, transitioning to DONE',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Filter, dedup, score, create tickets
|
|
34
|
+
const result = await filterAndCreateTickets(run, db, rawProposals);
|
|
35
|
+
// Save proposals artifact
|
|
36
|
+
run.saveArtifact(`${s.step_count}-scout-proposals.json`, JSON.stringify({ raw: rawProposals, result }, null, 2));
|
|
37
|
+
if (result.created_ticket_ids.length > 0) {
|
|
38
|
+
run.setPhase('NEXT_TICKET');
|
|
39
|
+
return {
|
|
40
|
+
processed: true,
|
|
41
|
+
phase_changed: true,
|
|
42
|
+
new_phase: 'NEXT_TICKET',
|
|
43
|
+
message: `Created ${result.created_ticket_ids.length} tickets from ${rawProposals.length} proposals (${result.rejected.length} rejected)`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// All proposals rejected — done
|
|
47
|
+
run.setPhase('DONE');
|
|
48
|
+
return {
|
|
49
|
+
processed: true,
|
|
50
|
+
phase_changed: true,
|
|
51
|
+
new_phase: 'DONE',
|
|
52
|
+
message: `All ${rawProposals.length} proposals rejected: ${result.rejected.map(r => r.reason).join('; ')}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
case 'PROPOSALS_FILTERED': {
|
|
56
|
+
// Legacy event from blockspool_submit_proposals tool.
|
|
57
|
+
// Check if we have ready tickets now.
|
|
58
|
+
const readyCount = await repos.tickets.countByStatus(db, s.project_id);
|
|
59
|
+
const ready = readyCount['ready'] ?? 0;
|
|
60
|
+
if (ready > 0 && s.phase === 'SCOUT') {
|
|
61
|
+
run.setPhase('NEXT_TICKET');
|
|
62
|
+
return {
|
|
63
|
+
processed: true,
|
|
64
|
+
phase_changed: true,
|
|
65
|
+
new_phase: 'NEXT_TICKET',
|
|
66
|
+
message: `${ready} tickets ready, transitioning to NEXT_TICKET`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (ready === 0 && s.phase === 'SCOUT') {
|
|
70
|
+
run.setPhase('DONE');
|
|
71
|
+
return {
|
|
72
|
+
processed: true,
|
|
73
|
+
phase_changed: true,
|
|
74
|
+
new_phase: 'DONE',
|
|
75
|
+
message: 'No proposals accepted, transitioning to DONE',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { processed: true, phase_changed: false, message: 'Proposals filtered' };
|
|
79
|
+
}
|
|
80
|
+
// -----------------------------------------------------------------
|
|
81
|
+
// Plan events
|
|
82
|
+
// -----------------------------------------------------------------
|
|
83
|
+
case 'PLAN_SUBMITTED': {
|
|
84
|
+
if (s.phase !== 'PLAN') {
|
|
85
|
+
return { processed: true, phase_changed: false, message: 'Plan submitted outside PLAN phase, ignored' };
|
|
86
|
+
}
|
|
87
|
+
const raw = payload;
|
|
88
|
+
// Coerce files_to_touch if Claude sends plain strings instead of objects
|
|
89
|
+
const rawFiles = Array.isArray(raw.files_to_touch) ? raw.files_to_touch : [];
|
|
90
|
+
const files_to_touch = rawFiles.map((f) => {
|
|
91
|
+
if (typeof f === 'string')
|
|
92
|
+
return { path: f, action: 'modify', reason: '' };
|
|
93
|
+
if (f && typeof f === 'object' && 'path' in f)
|
|
94
|
+
return f;
|
|
95
|
+
return { path: String(f), action: 'modify', reason: '' };
|
|
96
|
+
});
|
|
97
|
+
const plan = {
|
|
98
|
+
ticket_id: String(raw.ticket_id ?? s.current_ticket_id ?? ''),
|
|
99
|
+
files_to_touch,
|
|
100
|
+
expected_tests: Array.isArray(raw.expected_tests) ? raw.expected_tests.map(String) : [],
|
|
101
|
+
risk_level: (raw.risk_level === 'low' || raw.risk_level === 'medium' || raw.risk_level === 'high')
|
|
102
|
+
? raw.risk_level : 'low',
|
|
103
|
+
estimated_lines: typeof raw.estimated_lines === 'number' ? raw.estimated_lines : 50,
|
|
104
|
+
};
|
|
105
|
+
// Derive scope policy for the current ticket
|
|
106
|
+
const ticket = s.current_ticket_id
|
|
107
|
+
? await repos.tickets.getById(db, s.current_ticket_id)
|
|
108
|
+
: null;
|
|
109
|
+
const policy = deriveScopePolicy({
|
|
110
|
+
allowedPaths: ticket?.allowedPaths ?? [],
|
|
111
|
+
category: ticket?.category ?? 'refactor',
|
|
112
|
+
maxLinesPerTicket: s.max_lines_per_ticket,
|
|
113
|
+
});
|
|
114
|
+
// Validate plan against scope policy
|
|
115
|
+
const scopeResult = validatePlanScope(plan.files_to_touch, plan.estimated_lines, plan.risk_level, policy);
|
|
116
|
+
if (!scopeResult.valid) {
|
|
117
|
+
s.plan_rejections++;
|
|
118
|
+
run.appendEvent('PLAN_REJECTED', { reason: scopeResult.reason, attempt: s.plan_rejections });
|
|
119
|
+
return {
|
|
120
|
+
processed: true,
|
|
121
|
+
phase_changed: false,
|
|
122
|
+
message: `Plan rejected: ${scopeResult.reason} (attempt ${s.plan_rejections}/${3})`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Plan passed validation
|
|
126
|
+
s.current_ticket_plan = plan;
|
|
127
|
+
recordPlanHash(s.spindle, plan);
|
|
128
|
+
// High-risk plans → BLOCKED_NEEDS_HUMAN
|
|
129
|
+
if (plan.risk_level === 'high') {
|
|
130
|
+
run.appendEvent('PLAN_REJECTED', { reason: 'High-risk plan requires human approval', risk_level: 'high' });
|
|
131
|
+
run.setPhase('BLOCKED_NEEDS_HUMAN');
|
|
132
|
+
return {
|
|
133
|
+
processed: true,
|
|
134
|
+
phase_changed: true,
|
|
135
|
+
new_phase: 'BLOCKED_NEEDS_HUMAN',
|
|
136
|
+
message: 'High-risk plan requires human approval',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Low/medium risk — auto-approve
|
|
140
|
+
s.plan_approved = true;
|
|
141
|
+
run.appendEvent('PLAN_APPROVED', { risk_level: plan.risk_level, auto: true });
|
|
142
|
+
run.setPhase('EXECUTE');
|
|
143
|
+
return {
|
|
144
|
+
processed: true,
|
|
145
|
+
phase_changed: true,
|
|
146
|
+
new_phase: 'EXECUTE',
|
|
147
|
+
message: `${plan.risk_level}-risk plan auto-approved, moving to EXECUTE`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// -----------------------------------------------------------------
|
|
151
|
+
// Execution events
|
|
152
|
+
// -----------------------------------------------------------------
|
|
153
|
+
case 'TICKET_RESULT': {
|
|
154
|
+
if (s.phase !== 'EXECUTE') {
|
|
155
|
+
return { processed: true, phase_changed: false, message: 'Ticket result outside EXECUTE phase' };
|
|
156
|
+
}
|
|
157
|
+
const status = payload['status'];
|
|
158
|
+
if (status === 'done') {
|
|
159
|
+
// Validate changed_files against plan (if plan exists)
|
|
160
|
+
const changedFiles = (payload['changed_files'] ?? []);
|
|
161
|
+
const linesAdded = (payload['lines_added'] ?? 0);
|
|
162
|
+
const linesRemoved = (payload['lines_removed'] ?? 0);
|
|
163
|
+
const totalLines = linesAdded + linesRemoved;
|
|
164
|
+
// Save ticket result artifact
|
|
165
|
+
run.saveArtifact(`${s.step_count}-ticket-result.json`, JSON.stringify({
|
|
166
|
+
status,
|
|
167
|
+
changed_files: changedFiles,
|
|
168
|
+
lines_added: linesAdded,
|
|
169
|
+
lines_removed: linesRemoved,
|
|
170
|
+
summary: payload['summary'],
|
|
171
|
+
}, null, 2));
|
|
172
|
+
// Validate changed files against approved plan
|
|
173
|
+
if (s.current_ticket_plan) {
|
|
174
|
+
const plannedPaths = new Set(s.current_ticket_plan.files_to_touch.map(f => f.path));
|
|
175
|
+
const surpriseFiles = changedFiles.filter(f => !plannedPaths.has(f));
|
|
176
|
+
if (surpriseFiles.length > 0) {
|
|
177
|
+
run.appendEvent('SCOPE_BLOCKED', {
|
|
178
|
+
ticket_id: s.current_ticket_id,
|
|
179
|
+
surprise_files: surpriseFiles,
|
|
180
|
+
planned_files: [...plannedPaths],
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
processed: true,
|
|
184
|
+
phase_changed: false,
|
|
185
|
+
message: `Changed files not in plan: ${surpriseFiles.join(', ')}. Revert those changes and re-submit.`,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// Validate lines against budget
|
|
189
|
+
if (totalLines > s.max_lines_per_ticket) {
|
|
190
|
+
return {
|
|
191
|
+
processed: true,
|
|
192
|
+
phase_changed: false,
|
|
193
|
+
message: `Lines changed (${totalLines}) exceeds budget (${s.max_lines_per_ticket}). Reduce changes.`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Track lines
|
|
198
|
+
s.total_lines_changed += totalLines;
|
|
199
|
+
// Update spindle state with diff info
|
|
200
|
+
const diff = (payload['diff'] ?? null);
|
|
201
|
+
recordDiff(s.spindle, diff ?? (changedFiles.length > 0 ? changedFiles.join('\n') : null));
|
|
202
|
+
// Move to QA
|
|
203
|
+
run.setPhase('QA');
|
|
204
|
+
return {
|
|
205
|
+
processed: true,
|
|
206
|
+
phase_changed: true,
|
|
207
|
+
new_phase: 'QA',
|
|
208
|
+
message: `Ticket result accepted (${changedFiles.length} files, ${totalLines} lines), moving to QA`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (status === 'failed') {
|
|
212
|
+
// Fail the ticket, move to next
|
|
213
|
+
if (s.current_ticket_id) {
|
|
214
|
+
await repos.tickets.updateStatus(db, s.current_ticket_id, 'blocked');
|
|
215
|
+
run.failTicket(payload['reason'] ?? 'Execution failed');
|
|
216
|
+
}
|
|
217
|
+
run.setPhase('NEXT_TICKET');
|
|
218
|
+
return {
|
|
219
|
+
processed: true,
|
|
220
|
+
phase_changed: true,
|
|
221
|
+
new_phase: 'NEXT_TICKET',
|
|
222
|
+
message: 'Ticket failed, moving to NEXT_TICKET',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return { processed: true, phase_changed: false, message: `Ticket result: ${status}` };
|
|
226
|
+
}
|
|
227
|
+
// -----------------------------------------------------------------
|
|
228
|
+
// QA events
|
|
229
|
+
// -----------------------------------------------------------------
|
|
230
|
+
case 'QA_COMMAND_RESULT': {
|
|
231
|
+
if (s.phase !== 'QA') {
|
|
232
|
+
return { processed: true, phase_changed: false, message: 'QA command result outside QA phase' };
|
|
233
|
+
}
|
|
234
|
+
const command = payload['command'];
|
|
235
|
+
const success = payload['success'];
|
|
236
|
+
const output = (payload['output'] ?? '');
|
|
237
|
+
// Record command failure in spindle state
|
|
238
|
+
if (!success) {
|
|
239
|
+
recordCommandFailure(s.spindle, command, output);
|
|
240
|
+
}
|
|
241
|
+
// Save command output as artifact
|
|
242
|
+
const cmdSlug = command.replace(/[^a-z0-9]/gi, '-').slice(0, 30);
|
|
243
|
+
run.saveArtifact(`${s.step_count}-qa-${cmdSlug}-${success ? 'pass' : 'fail'}.log`, `$ ${command}\n\n${output}`);
|
|
244
|
+
return {
|
|
245
|
+
processed: true,
|
|
246
|
+
phase_changed: false,
|
|
247
|
+
message: `QA command ${success ? 'passed' : 'failed'}: ${command}`,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
case 'QA_PASSED': {
|
|
251
|
+
if (s.phase !== 'QA') {
|
|
252
|
+
return { processed: true, phase_changed: false, message: 'QA passed outside QA phase' };
|
|
253
|
+
}
|
|
254
|
+
// Mark ticket done in DB
|
|
255
|
+
if (s.current_ticket_id) {
|
|
256
|
+
await repos.tickets.updateStatus(db, s.current_ticket_id, 'done');
|
|
257
|
+
}
|
|
258
|
+
// Save QA summary artifact
|
|
259
|
+
run.saveArtifact(`${s.step_count}-qa-summary.json`, JSON.stringify({
|
|
260
|
+
ticket_id: s.current_ticket_id,
|
|
261
|
+
status: 'passed',
|
|
262
|
+
attempt: s.qa_retries + 1,
|
|
263
|
+
...payload,
|
|
264
|
+
}, null, 2));
|
|
265
|
+
// Move to PR
|
|
266
|
+
run.setPhase('PR');
|
|
267
|
+
return {
|
|
268
|
+
processed: true,
|
|
269
|
+
phase_changed: true,
|
|
270
|
+
new_phase: 'PR',
|
|
271
|
+
message: 'QA passed, moving to PR',
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
case 'QA_FAILED': {
|
|
275
|
+
if (s.phase !== 'QA') {
|
|
276
|
+
return { processed: true, phase_changed: false, message: 'QA failed outside QA phase' };
|
|
277
|
+
}
|
|
278
|
+
// Record QA failure in spindle (for stall detection — no progress)
|
|
279
|
+
recordDiff(s.spindle, null);
|
|
280
|
+
// Save failure artifact
|
|
281
|
+
run.saveArtifact(`${s.step_count}-qa-failed-attempt-${s.qa_retries + 1}.json`, JSON.stringify({
|
|
282
|
+
ticket_id: s.current_ticket_id,
|
|
283
|
+
attempt: s.qa_retries + 1,
|
|
284
|
+
...payload,
|
|
285
|
+
}, null, 2));
|
|
286
|
+
s.qa_retries++;
|
|
287
|
+
if (s.qa_retries >= 3) {
|
|
288
|
+
// Give up on this ticket
|
|
289
|
+
if (s.current_ticket_id) {
|
|
290
|
+
await repos.tickets.updateStatus(db, s.current_ticket_id, 'blocked');
|
|
291
|
+
run.failTicket(`QA failed ${s.qa_retries} times`);
|
|
292
|
+
}
|
|
293
|
+
run.setPhase('NEXT_TICKET');
|
|
294
|
+
return {
|
|
295
|
+
processed: true,
|
|
296
|
+
phase_changed: true,
|
|
297
|
+
new_phase: 'NEXT_TICKET',
|
|
298
|
+
message: `QA failed ${s.qa_retries} times, giving up on ticket`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// Retry: go back to EXECUTE to fix
|
|
302
|
+
run.setPhase('EXECUTE');
|
|
303
|
+
return {
|
|
304
|
+
processed: true,
|
|
305
|
+
phase_changed: true,
|
|
306
|
+
new_phase: 'EXECUTE',
|
|
307
|
+
message: `QA failed (attempt ${s.qa_retries}/3), retrying execution`,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
// -----------------------------------------------------------------
|
|
311
|
+
// PR events
|
|
312
|
+
// -----------------------------------------------------------------
|
|
313
|
+
case 'PR_CREATED': {
|
|
314
|
+
if (s.phase !== 'PR') {
|
|
315
|
+
return { processed: true, phase_changed: false, message: 'PR created outside PR phase' };
|
|
316
|
+
}
|
|
317
|
+
// Save PR artifact
|
|
318
|
+
run.saveArtifact(`${s.step_count}-pr-created.json`, JSON.stringify({
|
|
319
|
+
ticket_id: s.current_ticket_id,
|
|
320
|
+
pr_number: s.prs_created + 1,
|
|
321
|
+
...payload,
|
|
322
|
+
}, null, 2));
|
|
323
|
+
s.prs_created++;
|
|
324
|
+
run.completeTicket();
|
|
325
|
+
run.appendEvent('PR_CREATED', payload);
|
|
326
|
+
run.setPhase('NEXT_TICKET');
|
|
327
|
+
return {
|
|
328
|
+
processed: true,
|
|
329
|
+
phase_changed: true,
|
|
330
|
+
new_phase: 'NEXT_TICKET',
|
|
331
|
+
message: `PR created (${s.prs_created}/${s.max_prs}), moving to NEXT_TICKET`,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// -----------------------------------------------------------------
|
|
335
|
+
// User overrides
|
|
336
|
+
// -----------------------------------------------------------------
|
|
337
|
+
case 'USER_OVERRIDE': {
|
|
338
|
+
if (typeof payload['hint'] === 'string') {
|
|
339
|
+
run.addHint(payload['hint']);
|
|
340
|
+
return { processed: true, phase_changed: false, message: 'Hint added' };
|
|
341
|
+
}
|
|
342
|
+
if (payload['cancel'] === true) {
|
|
343
|
+
run.setPhase('DONE');
|
|
344
|
+
return {
|
|
345
|
+
processed: true,
|
|
346
|
+
phase_changed: true,
|
|
347
|
+
new_phase: 'DONE',
|
|
348
|
+
message: 'Session cancelled by user',
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return { processed: true, phase_changed: false, message: 'User override recorded' };
|
|
352
|
+
}
|
|
353
|
+
// -----------------------------------------------------------------
|
|
354
|
+
// Default: just record
|
|
355
|
+
// -----------------------------------------------------------------
|
|
356
|
+
default:
|
|
357
|
+
return { processed: true, phase_changed: false, message: `Event ${type} recorded` };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=event-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-processor.js","sourceRoot":"","sources":["../src/event-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formulas — typed, versioned, testable sweep recipes.
|
|
3
|
+
*
|
|
4
|
+
* A formula configures what a scout session looks for and how strictly
|
|
5
|
+
* it gates execution. Built-in formulas mirror the CLI's set; users can
|
|
6
|
+
* add custom formulas in `.blockspool/formulas/` as simple YAML files.
|
|
7
|
+
*/
|
|
8
|
+
import type { SessionConfig } from './types.js';
|
|
9
|
+
export interface Formula {
|
|
10
|
+
name: string;
|
|
11
|
+
version: number;
|
|
12
|
+
description: string;
|
|
13
|
+
scope?: string;
|
|
14
|
+
categories?: string[];
|
|
15
|
+
min_confidence?: number;
|
|
16
|
+
prompt?: string;
|
|
17
|
+
max_prs?: number;
|
|
18
|
+
model?: string;
|
|
19
|
+
risk_tolerance?: 'low' | 'medium' | 'high';
|
|
20
|
+
tags?: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare const BUILTIN_FORMULAS: Formula[];
|
|
23
|
+
/**
|
|
24
|
+
* Load a formula by name.
|
|
25
|
+
* Search order: user formulas in `.blockspool/formulas/`, then built-ins.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadFormula(name: string, projectPath?: string): Formula | null;
|
|
28
|
+
/**
|
|
29
|
+
* List all available formulas (user + built-in, user overrides built-in).
|
|
30
|
+
*/
|
|
31
|
+
export declare function listFormulas(projectPath?: string): Formula[];
|
|
32
|
+
/**
|
|
33
|
+
* Apply a formula's settings to a SessionConfig.
|
|
34
|
+
* Formula values are defaults — explicit config values take precedence.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyFormula(formula: Formula, config: SessionConfig): SessionConfig;
|
|
37
|
+
//# sourceMappingURL=formulas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formulas.d.ts","sourceRoot":"","sources":["../src/formulas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMhD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD,eAAO,MAAM,gBAAgB,EAAE,OAAO,EA8FrC,CAAC;AAMF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAI9E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAK5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,aAAa,CAUnF"}
|