opencode-swarm 7.13.2 → 7.15.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 +2 -1
- package/dist/cli/index.js +950 -269
- package/dist/commands/deep-dive.d.ts +5 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/commands/turbo.d.ts +4 -4
- package/dist/config/constants.d.ts +12 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/schema.d.ts +116 -0
- package/dist/index.js +4504 -1266
- package/dist/parallel/file-locks.d.ts +50 -2
- package/dist/services/status-service.d.ts +29 -0
- package/dist/state.d.ts +17 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/lean-turbo-acquire-locks.d.ts +36 -0
- package/dist/tools/lean-turbo-plan-lanes.d.ts +35 -0
- package/dist/tools/lean-turbo-review.d.ts +34 -0
- package/dist/tools/lean-turbo-run-phase.d.ts +44 -0
- package/dist/tools/lean-turbo-runner-status.d.ts +36 -0
- package/dist/tools/lean-turbo-status.d.ts +44 -0
- package/dist/tools/tool-names.d.ts +1 -1
- package/dist/tools/update-task-status.d.ts +7 -4
- package/dist/turbo/lean/conflicts.d.ts +100 -0
- package/dist/turbo/lean/evidence.d.ts +91 -0
- package/dist/turbo/lean/index.d.ts +27 -0
- package/dist/turbo/lean/integration.d.ts +137 -0
- package/dist/turbo/lean/phase-ready.d.ts +105 -0
- package/dist/turbo/lean/planner.d.ts +115 -0
- package/dist/turbo/lean/reviewer.d.ts +124 -0
- package/dist/turbo/lean/risk.d.ts +47 -0
- package/dist/turbo/lean/runner.d.ts +322 -0
- package/dist/turbo/lean/state.d.ts +61 -0
- package/dist/turbo/lean/task-completion.d.ts +53 -0
- package/package.json +1 -1
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lean Turbo Lane Runner.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates parallel lane execution for Lean Turbo:
|
|
5
|
+
* - Reads plan.json for a given phase
|
|
6
|
+
* - Plans lane distribution via planLeanTurboLanes()
|
|
7
|
+
* - Acquires file locks for each lane (all-or-nothing per lane)
|
|
8
|
+
* - Dispatches coder agents via OpencodeClient session API
|
|
9
|
+
* - Tracks lane status in memory and updates durable state
|
|
10
|
+
* - Releases locks on cleanup
|
|
11
|
+
*
|
|
12
|
+
* ## Fail-Closed Design
|
|
13
|
+
*
|
|
14
|
+
* - If opencodeClient is null at construction, runPhase() returns error immediately
|
|
15
|
+
* - If lock acquisition fails for a lane, the lane is marked 'blocked'
|
|
16
|
+
* - If dispatch fails, locks for that lane are released and lane is marked 'failed'
|
|
17
|
+
*/
|
|
18
|
+
import type { OpencodeClient } from '@opencode-ai/sdk';
|
|
19
|
+
import type { LeanTurboConfig } from '../../config/schema';
|
|
20
|
+
import { loadFullAutoRunState } from '../../full-auto/state';
|
|
21
|
+
import { acquireLaneLocks, releaseLaneLocks } from '../../parallel/file-locks';
|
|
22
|
+
import { loadPlanJsonOnly } from '../../plan/manager';
|
|
23
|
+
import { hasActiveFullAuto } from '../../state';
|
|
24
|
+
import { writeLaneEvidence } from './evidence';
|
|
25
|
+
import { planLeanTurboLanes } from './planner';
|
|
26
|
+
import type { LeanTurboLane } from './state';
|
|
27
|
+
import { loadLeanTurboRunState, saveLeanTurboRunState } from './state';
|
|
28
|
+
/**
|
|
29
|
+
* Shape of the OpencodeClient session API used by the runner.
|
|
30
|
+
* Extracted into an interface so tests can inject a mock without
|
|
31
|
+
* requiring the full SDK type.
|
|
32
|
+
*/
|
|
33
|
+
interface SessionClient {
|
|
34
|
+
create(options: {
|
|
35
|
+
query: {
|
|
36
|
+
directory: string;
|
|
37
|
+
};
|
|
38
|
+
}): Promise<{
|
|
39
|
+
data: {
|
|
40
|
+
id: string;
|
|
41
|
+
} | null;
|
|
42
|
+
error: unknown;
|
|
43
|
+
}>;
|
|
44
|
+
prompt(options: {
|
|
45
|
+
path: {
|
|
46
|
+
id: string;
|
|
47
|
+
};
|
|
48
|
+
body: {
|
|
49
|
+
agent: string;
|
|
50
|
+
tools: {
|
|
51
|
+
write: boolean;
|
|
52
|
+
edit: boolean;
|
|
53
|
+
patch: boolean;
|
|
54
|
+
};
|
|
55
|
+
parts: Array<{
|
|
56
|
+
type: 'text';
|
|
57
|
+
text: string;
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
}): Promise<{
|
|
61
|
+
data: {
|
|
62
|
+
parts: Array<{
|
|
63
|
+
type: string;
|
|
64
|
+
text?: string;
|
|
65
|
+
}>;
|
|
66
|
+
} | null;
|
|
67
|
+
error: unknown;
|
|
68
|
+
}>;
|
|
69
|
+
delete(options: {
|
|
70
|
+
path: {
|
|
71
|
+
id: string;
|
|
72
|
+
};
|
|
73
|
+
}): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Result of a single lane dispatch (session creation + prompt).
|
|
77
|
+
*/
|
|
78
|
+
export interface LaneDispatchResult {
|
|
79
|
+
/** Whether dispatch succeeded */
|
|
80
|
+
ok: boolean;
|
|
81
|
+
/** Session ID if ok === true */
|
|
82
|
+
sessionId?: string;
|
|
83
|
+
/** Error message if ok === false */
|
|
84
|
+
error?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Result of a single lane's processing.
|
|
88
|
+
*/
|
|
89
|
+
export interface LaneResult {
|
|
90
|
+
/** Lane identifier */
|
|
91
|
+
laneId: string;
|
|
92
|
+
/** Current status */
|
|
93
|
+
status: 'pending' | 'running' | 'completed' | 'failed' | 'blocked';
|
|
94
|
+
/** Task IDs assigned to this lane */
|
|
95
|
+
taskIds: string[];
|
|
96
|
+
/** Agent name that was dispatched */
|
|
97
|
+
agent?: string;
|
|
98
|
+
/** Session ID for this lane (set after successful dispatch) */
|
|
99
|
+
sessionId?: string;
|
|
100
|
+
/** Error message if status is 'failed' or 'blocked' */
|
|
101
|
+
error?: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Result of a full phase run.
|
|
105
|
+
*/
|
|
106
|
+
export interface LeanTurboPhaseResult {
|
|
107
|
+
/** Whether the phase ran (at least one lane attempted) */
|
|
108
|
+
ok: boolean;
|
|
109
|
+
/** Human-readable reason when ok === false */
|
|
110
|
+
reason?: string;
|
|
111
|
+
/** Per-lane results */
|
|
112
|
+
lanes: LaneResult[];
|
|
113
|
+
/** Task IDs that were degraded (risk conditions) */
|
|
114
|
+
degradedTasks: string[];
|
|
115
|
+
/** Task IDs excluded from parallel lanes, must complete via standard serial flow */
|
|
116
|
+
serializedTasks: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Orchestrates Lean Turbo lane execution.
|
|
120
|
+
*
|
|
121
|
+
* ## Usage
|
|
122
|
+
*
|
|
123
|
+
* ```ts
|
|
124
|
+
* const runner = new LeanTurboRunner({
|
|
125
|
+
* directory: projectRoot,
|
|
126
|
+
* sessionID: 'sess-abc123',
|
|
127
|
+
* opencodeClient: swarmState.opencodeClient,
|
|
128
|
+
* generatedAgentNames: swarmState.generatedAgentNames,
|
|
129
|
+
* });
|
|
130
|
+
*
|
|
131
|
+
* const result = await runner.runPhase(1);
|
|
132
|
+
* // ... monitor lanes ...
|
|
133
|
+
* await runner.cleanup();
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare class LeanTurboRunner {
|
|
137
|
+
/**
|
|
138
|
+
* Test-only dependency-injection seam.
|
|
139
|
+
* Allows tests to intercept plan/lock/state operations without mock.module leakage.
|
|
140
|
+
* Production code assigns real functions here at module load.
|
|
141
|
+
*/
|
|
142
|
+
static _internals: {
|
|
143
|
+
loadPlanJsonOnly: typeof loadPlanJsonOnly;
|
|
144
|
+
planLeanTurboLanes: typeof planLeanTurboLanes;
|
|
145
|
+
acquireLaneLocks: typeof acquireLaneLocks;
|
|
146
|
+
releaseLaneLocks: typeof releaseLaneLocks;
|
|
147
|
+
loadLeanTurboRunState: typeof loadLeanTurboRunState;
|
|
148
|
+
saveLeanTurboRunState: typeof saveLeanTurboRunState;
|
|
149
|
+
hasActiveFullAuto: typeof hasActiveFullAuto;
|
|
150
|
+
loadFullAutoRunState: typeof loadFullAutoRunState;
|
|
151
|
+
writeLaneEvidence: typeof writeLaneEvidence;
|
|
152
|
+
/** Timeout for lane dispatch (session.create + session.prompt) in ms. Undefined = no timeout. */
|
|
153
|
+
laneDispatchTimeoutMs: number | undefined;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Test-only dependency-injection seam for session operations.
|
|
157
|
+
* Allows tests to intercept client.session calls without mock.module leakage.
|
|
158
|
+
*
|
|
159
|
+
* Default: uses real OpencodeClient session API from the injected client.
|
|
160
|
+
* Tests: replace by assigning a mock SessionClient directly to this field
|
|
161
|
+
* on the runner instance.
|
|
162
|
+
*
|
|
163
|
+
* Example:
|
|
164
|
+
* ```ts
|
|
165
|
+
* const runner = new LeanTurboRunner({ directory, sessionID });
|
|
166
|
+
* (runner as unknown as { _sessionOps: SessionClient })._sessionOps = mockSessionOps;
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* NB: The fail-closed check uses `opencodeClient === null` (strict equality)
|
|
170
|
+
* so omitting `opencodeClient` (undefined) does NOT trigger fail-closed,
|
|
171
|
+
* allowing test mock injection to proceed.
|
|
172
|
+
*/
|
|
173
|
+
_sessionOps: SessionClient | null;
|
|
174
|
+
private readonly _directory;
|
|
175
|
+
private readonly _sessionID;
|
|
176
|
+
private readonly _client;
|
|
177
|
+
private readonly _availableAgents;
|
|
178
|
+
/** Tracks which files are locked per lane (for cleanup) */
|
|
179
|
+
private _laneLockMap;
|
|
180
|
+
/** Current lane statuses (updated after each dispatch) */
|
|
181
|
+
private _laneStatuses;
|
|
182
|
+
/** Round-robin index for agent selection */
|
|
183
|
+
private _agentIndex;
|
|
184
|
+
/**
|
|
185
|
+
* Tracks lanes that timed out so that when their _doDispatch completes,
|
|
186
|
+
* we can clean up the orphan session.
|
|
187
|
+
*/
|
|
188
|
+
private _timedOutLanes;
|
|
189
|
+
/** Chains durable state updates to prevent race conditions on concurrent lanes. */
|
|
190
|
+
private _stateLock;
|
|
191
|
+
/** Lean-mode configuration passed at construction. Undefined means use defaults. */
|
|
192
|
+
private readonly _leanConfig?;
|
|
193
|
+
constructor(options: {
|
|
194
|
+
/** Project root directory */
|
|
195
|
+
directory: string;
|
|
196
|
+
/** Current session ID */
|
|
197
|
+
sessionID: string;
|
|
198
|
+
/** OpenCode SDK client. Pass null to stay fail-closed. Omit to allow test mock injection. */
|
|
199
|
+
opencodeClient?: OpencodeClient | null;
|
|
200
|
+
/** Pre-registered generated agent names */
|
|
201
|
+
generatedAgentNames?: string[];
|
|
202
|
+
/** Lean-mode configuration. Falls back to hardcoded defaults if omitted. */
|
|
203
|
+
leanConfig?: LeanTurboConfig;
|
|
204
|
+
});
|
|
205
|
+
/**
|
|
206
|
+
* Run a single phase: plan lanes, acquire locks, dispatch coders.
|
|
207
|
+
*
|
|
208
|
+
* @param phaseNumber - Phase number to execute
|
|
209
|
+
* @returns Result with per-lane statuses and degraded task list
|
|
210
|
+
*/
|
|
211
|
+
runPhase(phaseNumber: number): Promise<LeanTurboPhaseResult>;
|
|
212
|
+
/**
|
|
213
|
+
* Dispatch a single lane to a named agent.
|
|
214
|
+
*
|
|
215
|
+
* Creates an ephemeral session, sends a task prompt, and returns
|
|
216
|
+
* the session ID for later status polling.
|
|
217
|
+
*
|
|
218
|
+
* @param lane - Lane to dispatch
|
|
219
|
+
* @param agentName - Agent name to dispatch to
|
|
220
|
+
*/
|
|
221
|
+
dispatchLane(lane: LeanTurboLane, agentName: string): Promise<LaneDispatchResult>;
|
|
222
|
+
/**
|
|
223
|
+
* Internal dispatch implementation (separated for timeout wrapping).
|
|
224
|
+
*/
|
|
225
|
+
private _doDispatch;
|
|
226
|
+
/**
|
|
227
|
+
* Get current status of all lanes tracked by this runner.
|
|
228
|
+
*
|
|
229
|
+
* Note: This returns in-memory status only. Lane sessions are
|
|
230
|
+
* managed by the OpenCode runtime and cannot be directly polled
|
|
231
|
+
* through the SDK. External status tracking (e.g., via session
|
|
232
|
+
* list) should be used for production status polling.
|
|
233
|
+
*/
|
|
234
|
+
waitForLanes(): Promise<LaneStatus[]>;
|
|
235
|
+
/**
|
|
236
|
+
* Release all lane locks and mark unresolved lanes as blocked.
|
|
237
|
+
*
|
|
238
|
+
* Call this on error exit or when shutting down a phase early.
|
|
239
|
+
* Releases ALL locks and transitions ALL running/pending lanes to blocked.
|
|
240
|
+
*/
|
|
241
|
+
cleanup(): Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* Cleanup after a successful phase run.
|
|
244
|
+
*
|
|
245
|
+
* Only releases locks for lanes that reached a terminal state (completed,
|
|
246
|
+
* failed, blocked). Does NOT change lane statuses — running lanes stay running.
|
|
247
|
+
*/
|
|
248
|
+
cleanupAfterSuccess(): Promise<void>;
|
|
249
|
+
/**
|
|
250
|
+
* Cleanup after a failed phase run.
|
|
251
|
+
*
|
|
252
|
+
* Current behavior: releases ALL locks, marks all unresolved lanes blocked.
|
|
253
|
+
*/
|
|
254
|
+
cleanupAfterFailure(): Promise<void>;
|
|
255
|
+
/**
|
|
256
|
+
* Resolve the list of available coder agent names.
|
|
257
|
+
*
|
|
258
|
+
* Prefers agents matching swarm prefix patterns (e.g. `mega_coder`)
|
|
259
|
+
* over bare `coder`. Falls back to `['coder']` if no coder agents found.
|
|
260
|
+
*/
|
|
261
|
+
private _resolveCoderAgents;
|
|
262
|
+
/**
|
|
263
|
+
* Get the Lean Turbo configuration.
|
|
264
|
+
*
|
|
265
|
+
* The config is passed to runPhase (from plugin config or caller).
|
|
266
|
+
* If not provided, sensible defaults are used.
|
|
267
|
+
*/
|
|
268
|
+
private _getLeanConfig;
|
|
269
|
+
/**
|
|
270
|
+
* Process a single lane: acquire locks, dispatch, track status.
|
|
271
|
+
*
|
|
272
|
+
* On successful dispatch completion (session.prompt resolves), the lane
|
|
273
|
+
* is transitioned to 'completed', locks are released, evidence is written,
|
|
274
|
+
* and the lane counter is incremented.
|
|
275
|
+
*
|
|
276
|
+
* On lock acquisition failure (Bug #4), the lane's tasks are routed to
|
|
277
|
+
* the serialized tasks set for standard serial fallback.
|
|
278
|
+
*/
|
|
279
|
+
private _processLane;
|
|
280
|
+
/**
|
|
281
|
+
* Select the next available agent using round-robin.
|
|
282
|
+
*/
|
|
283
|
+
private _selectNextAgent;
|
|
284
|
+
/**
|
|
285
|
+
* Safely write lane evidence, catching errors to prevent evidence write
|
|
286
|
+
* failure from blocking lane processing.
|
|
287
|
+
*/
|
|
288
|
+
private _writeLaneEvidenceSafely;
|
|
289
|
+
/**
|
|
290
|
+
* Build a human-readable prompt describing a lane's tasks.
|
|
291
|
+
*/
|
|
292
|
+
private _buildLanePrompt;
|
|
293
|
+
/**
|
|
294
|
+
* Serializes access to durable state via a promise chain.
|
|
295
|
+
* Prevents concurrent lane updates from racing on turbo-state.json writes.
|
|
296
|
+
*
|
|
297
|
+
* Includes a 10-second timeout: if state persistence hangs, the lock is
|
|
298
|
+
* released so subsequent updates are not blocked indefinitely.
|
|
299
|
+
*/
|
|
300
|
+
private _withStateLock;
|
|
301
|
+
/**
|
|
302
|
+
* Update durable state with the full lane plan (called once per phase).
|
|
303
|
+
*/
|
|
304
|
+
private _updateDurableState;
|
|
305
|
+
/**
|
|
306
|
+
* Update a single lane's status in durable state.
|
|
307
|
+
* Serialized through _withStateLock to prevent race conditions with concurrent lanes.
|
|
308
|
+
*/
|
|
309
|
+
private _updateDurableStateLaneStatus;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Current status of a lane (returned by waitForLanes).
|
|
313
|
+
*/
|
|
314
|
+
export interface LaneStatus {
|
|
315
|
+
laneId: string;
|
|
316
|
+
status: LeanTurboLane['status'];
|
|
317
|
+
taskIds: string[];
|
|
318
|
+
agent?: string;
|
|
319
|
+
sessionId?: string;
|
|
320
|
+
error?: string;
|
|
321
|
+
}
|
|
322
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type LeanTurboStatus = 'idle' | 'running' | 'paused' | 'terminated';
|
|
2
|
+
export interface LeanTurboLane {
|
|
3
|
+
laneId: string;
|
|
4
|
+
taskIds: string[];
|
|
5
|
+
files: string[];
|
|
6
|
+
status: 'pending' | 'running' | 'completed' | 'failed' | 'blocked';
|
|
7
|
+
startedAt?: string;
|
|
8
|
+
completedAt?: string;
|
|
9
|
+
error?: string;
|
|
10
|
+
agent?: string;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface LeanTurboDegradedTask {
|
|
14
|
+
taskId: string;
|
|
15
|
+
reason: string;
|
|
16
|
+
files: string[];
|
|
17
|
+
requiredMode: 'standard' | 'balanced';
|
|
18
|
+
}
|
|
19
|
+
export interface LeanTurboCounters {
|
|
20
|
+
lanesPlanned: number;
|
|
21
|
+
lanesStarted: number;
|
|
22
|
+
lanesCompleted: number;
|
|
23
|
+
lanesFailed: number;
|
|
24
|
+
tasksSerialized: number;
|
|
25
|
+
tasksDegraded: number;
|
|
26
|
+
}
|
|
27
|
+
export interface LeanTurboRunState {
|
|
28
|
+
status: LeanTurboStatus;
|
|
29
|
+
sessionID: string;
|
|
30
|
+
strategy: 'lean';
|
|
31
|
+
phase?: number;
|
|
32
|
+
maxParallelCoders: number;
|
|
33
|
+
planId?: string;
|
|
34
|
+
activeLanePlanId?: string;
|
|
35
|
+
lanes: LeanTurboLane[];
|
|
36
|
+
degradedTasks: LeanTurboDegradedTask[];
|
|
37
|
+
/** Task IDs excluded from parallel lanes, must complete via standard serial flow */
|
|
38
|
+
serializedTasks: string[];
|
|
39
|
+
lastReviewerVerdict?: 'APPROVED' | 'NEEDS_REVISION' | 'REJECTED';
|
|
40
|
+
lastCriticVerdict?: string;
|
|
41
|
+
pauseReason?: string;
|
|
42
|
+
terminateReason?: string;
|
|
43
|
+
counters: LeanTurboCounters;
|
|
44
|
+
}
|
|
45
|
+
export interface LeanTurboPersistedState {
|
|
46
|
+
version: 1;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
sessions: Record<string, LeanTurboRunState>;
|
|
49
|
+
}
|
|
50
|
+
export declare function emptyCounters(): LeanTurboCounters;
|
|
51
|
+
export declare function emptyRunState(sessionID: string, maxParallelCoders: number): LeanTurboRunState;
|
|
52
|
+
export declare function emptyPersisted(): LeanTurboPersistedState;
|
|
53
|
+
export declare function isStateUnreadable(directory: string): boolean;
|
|
54
|
+
export declare function repairStateUnreadable(directory: string): void;
|
|
55
|
+
export declare function readPersisted(directory: string): LeanTurboPersistedState | null;
|
|
56
|
+
export declare function writePersisted(directory: string, persisted: LeanTurboPersistedState): void;
|
|
57
|
+
export declare function loadLeanTurboRunState(directory: string, sessionID: string): LeanTurboRunState | null;
|
|
58
|
+
export declare function saveLeanTurboRunState(directory: string, runState: LeanTurboRunState): void;
|
|
59
|
+
export declare function isLeanTurboRunActive(directory: string, sessionID: string): boolean;
|
|
60
|
+
export declare function pauseLeanTurboRun(directory: string, sessionID: string, reason: string): void;
|
|
61
|
+
export declare function resetLeanTurboRun(directory: string, sessionID: string): void;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lean Turbo Stage B bypass verification.
|
|
3
|
+
*
|
|
4
|
+
* Provides a synchronous helper to check whether a task is eligible for
|
|
5
|
+
* Lean Turbo Stage B bypass — i.e., whether it can be marked completed
|
|
6
|
+
* without running the full reviewer + test_engineer gate.
|
|
7
|
+
*/
|
|
8
|
+
import { listActiveLocks } from '../../parallel/file-locks';
|
|
9
|
+
/**
|
|
10
|
+
* Test-only seam. Replaces the lock-list function so tests can inject
|
|
11
|
+
* mock results without touching the real `file-locks` module.
|
|
12
|
+
*/
|
|
13
|
+
export declare const _internals: {
|
|
14
|
+
listActiveLocks: typeof listActiveLocks;
|
|
15
|
+
verifyLeanTurboTaskCompletion: typeof verifyLeanTurboTaskCompletion;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Result of the Lean Turbo task completion eligibility check.
|
|
19
|
+
*/
|
|
20
|
+
export interface LeanTurboTaskCompletionResult {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
reason: string;
|
|
23
|
+
laneFound?: boolean;
|
|
24
|
+
evidence?: {
|
|
25
|
+
laneId: string;
|
|
26
|
+
laneStatus: string;
|
|
27
|
+
taskIds: string[];
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Synchronously verify whether a task is eligible for Lean Turbo Stage B bypass.
|
|
32
|
+
*
|
|
33
|
+
* Checks are performed in fail-fast order:
|
|
34
|
+
* 1. Read `.swarm/turbo-state.json` — missing/unreadable → ok: false
|
|
35
|
+
* 2. Find a Lean Turbo run state (strategy === 'lean' AND status === 'running')
|
|
36
|
+
* → none found → ok: false
|
|
37
|
+
* If sessionID is provided, also require sessionID to match
|
|
38
|
+
* 3. Find the lane containing taskId in runState.lanes → none → ok: false
|
|
39
|
+
* 4. Check if task is in runState.degradedTasks → yes → ok: false with degradation reason
|
|
40
|
+
* 5. Check lane.status === 'completed' → not completed → ok: false
|
|
41
|
+
* 6. Check lane evidence file exists at `.swarm/evidence/{phase}/lean-turbo/{laneId}.json`
|
|
42
|
+
* → missing → ok: false
|
|
43
|
+
* 7. Check for active file locks on this lane → any active → ok: false
|
|
44
|
+
* 8. Read plan.json to get task's files_touched and check Tier-3 patterns → matched → ok: false
|
|
45
|
+
* 9. All checks pass → ok: true
|
|
46
|
+
*
|
|
47
|
+
* @param directory - Project root directory
|
|
48
|
+
* @param taskId - Task ID to verify
|
|
49
|
+
* @param sessionID - Optional session ID to scope which Lean Turbo session may grant bypass.
|
|
50
|
+
* When provided, only a running Lean Turbo session with a matching sessionID
|
|
51
|
+
* can grant bypass — preventing cross-session Stage B bypass.
|
|
52
|
+
*/
|
|
53
|
+
export declare function verifyLeanTurboTaskCompletion(directory: string, taskId: string, sessionID?: string): LeanTurboTaskCompletionResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.15.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|