opencode-swarm 7.58.1 → 7.59.1
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/dist/agents/agent-output-schema.d.ts +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/config/constants.d.ts +1 -1
- package/dist/config/schema.d.ts +42 -0
- package/dist/index.js +968 -318
- package/dist/memory/schema.d.ts +1 -1
- package/dist/tools/lean-turbo-run-phase.d.ts +2 -1
- package/dist/turbo/lean/index.d.ts +4 -1
- package/dist/turbo/lean/merge-back.d.ts +180 -0
- package/dist/turbo/lean/runner.d.ts +47 -1
- package/dist/turbo/lean/state.d.ts +10 -0
- package/dist/turbo/lean/worktree.d.ts +194 -0
- package/package.json +1 -1
package/dist/memory/schema.d.ts
CHANGED
|
@@ -129,10 +129,10 @@ export declare const MemoryProposalSchema: z.ZodObject<{
|
|
|
129
129
|
id: z.ZodString;
|
|
130
130
|
operation: z.ZodEnum<{
|
|
131
131
|
ignore: "ignore";
|
|
132
|
+
merge: "merge";
|
|
132
133
|
add: "add";
|
|
133
134
|
delete: "delete";
|
|
134
135
|
update: "update";
|
|
135
|
-
merge: "merge";
|
|
136
136
|
supersede: "supersede";
|
|
137
137
|
}>;
|
|
138
138
|
proposedRecord: z.ZodOptional<z.ZodObject<{
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { ToolDefinition } from '@opencode-ai/plugin/tool';
|
|
6
6
|
import { loadPluginConfigWithMeta as loadPluginConfigWithMeta_import } from '../config';
|
|
7
|
-
import type { LaneResult } from '../turbo/lean/runner';
|
|
7
|
+
import type { LaneResult, MergeBackFailureInfo } from '../turbo/lean/runner';
|
|
8
8
|
import { LeanTurboRunner as LeanTurboRunner_import } from '../turbo/lean/runner';
|
|
9
9
|
/**
|
|
10
10
|
* Arguments for the lean_turbo_run_phase tool
|
|
@@ -22,6 +22,7 @@ export interface LeanTurboRunPhaseResult {
|
|
|
22
22
|
lanes?: LaneResult[];
|
|
23
23
|
degradedTasks?: string[];
|
|
24
24
|
serializedTasks?: string[];
|
|
25
|
+
mergeBackFailures?: MergeBackFailureInfo[];
|
|
25
26
|
reason?: string;
|
|
26
27
|
errors?: string[];
|
|
27
28
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* import { LeanTurboRunner, planLeanTurboLanes, LeanTurboLane, ... } from './turbo/lean';
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
|
-
export type { LaneDispatchResult, LaneResult, LaneStatus, LeanTurboPhaseResult, } from './runner';
|
|
11
|
+
export type { LaneDispatchResult, LaneResult, LaneStatus, LeanTurboPhaseResult, MergeBackFailureInfo, } from './runner';
|
|
12
12
|
export { LeanTurboRunner } from './runner';
|
|
13
13
|
export type { LeanTurboLanePlan, PlanPhase, PlanTask, } from './planner';
|
|
14
14
|
export { GLOBAL_FILES_LIST, isGlobalFile, isPathSafe, isProtectedPath, normalizePath, PROTECTED_PATTERNS_LIST, pathsConflict, planLeanTurboLanes, readTaskScopes, } from './planner';
|
|
@@ -25,3 +25,6 @@ export type { LeanTurboPhaseCriticConfig, PhaseCriticResult, } from './integrati
|
|
|
25
25
|
export { dispatchPhaseCritic } from './integration';
|
|
26
26
|
export type { LeanTurboPhaseReviewerConfig, PhaseReviewerResult, } from './reviewer';
|
|
27
27
|
export { dispatchPhaseReviewer } from './reviewer';
|
|
28
|
+
export { _internals as worktreeInternals, assertCleanWorkingTree, autoCommitDirty, cleanUntrackedFiles, isCleanWorktree, provisionWorktree, removeWorktree, } from './worktree';
|
|
29
|
+
export type { CleanupFailure, CleanupSuccess, ConflictHandlingError, ConflictInfo, DirtyMergeFailure, DirtyMergePartial, DirtyMergeSuccess, MergeConflict, MergeFailure, MergeSuccess, OrphanCleanupResult, StartupRecoveryResult, } from './merge-back';
|
|
30
|
+
export { _internals as mergeBackInternals, attemptMergeBackFromDirty, cleanupOrphanedBranches, getMergeStrategy, handleMergeConflict, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery, } from './merge-back';
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge-back operations for lean turbo parallel lanes.
|
|
3
|
+
*
|
|
4
|
+
* Provides four public functions for merging lane branches back into
|
|
5
|
+
* the primary worktree, cleaning up lane branches, and handling merge
|
|
6
|
+
* conflicts. All subprocess calls go through the `_internals` DI seam
|
|
7
|
+
* so tests can replace the real `bunSpawn` without leaking across Bun's
|
|
8
|
+
* shared test-runner process.
|
|
9
|
+
*
|
|
10
|
+
* @module merge-back
|
|
11
|
+
*/
|
|
12
|
+
import type { LeanTurboConfig } from '../../config/schema';
|
|
13
|
+
import { bunSpawn } from '../../utils/bun-compat';
|
|
14
|
+
/**
|
|
15
|
+
* Test-only dependency-injection seam. Production code calls
|
|
16
|
+
* `_internals.bunSpawn(...)` so tests can replace the function on this object
|
|
17
|
+
* without touching the real `../../utils/bun-compat` module — `mock.module`
|
|
18
|
+
* from `bun:test` leaks across files in Bun's shared test-runner process,
|
|
19
|
+
* which would corrupt unrelated suites that import `bun-compat`. Mutating this
|
|
20
|
+
* local object is file-scoped and trivially restorable via `afterEach`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const _internals: {
|
|
23
|
+
bunSpawn: typeof bunSpawn;
|
|
24
|
+
/** Test seam for process.platform — allows non-Windows CIs to exercise Windows paths. */
|
|
25
|
+
platform: string;
|
|
26
|
+
/** Test seam for sleep — allows tests to skip real delays. */
|
|
27
|
+
sleep: (ms: number) => Promise<void>;
|
|
28
|
+
};
|
|
29
|
+
export interface MergeSuccess {
|
|
30
|
+
merged: true;
|
|
31
|
+
strategy: string;
|
|
32
|
+
}
|
|
33
|
+
export interface MergeConflict {
|
|
34
|
+
conflict: true;
|
|
35
|
+
files: string[];
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
export interface MergeFailure {
|
|
39
|
+
error: string;
|
|
40
|
+
}
|
|
41
|
+
export interface CleanupSuccess {
|
|
42
|
+
cleaned: true;
|
|
43
|
+
}
|
|
44
|
+
export interface CleanupFailure {
|
|
45
|
+
error: string;
|
|
46
|
+
partial?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ConflictInfo {
|
|
49
|
+
files: string[];
|
|
50
|
+
message: string;
|
|
51
|
+
aborted: true;
|
|
52
|
+
}
|
|
53
|
+
export interface ConflictHandlingError {
|
|
54
|
+
error: string;
|
|
55
|
+
aborted: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface DirtyMergeSuccess {
|
|
58
|
+
merged: true;
|
|
59
|
+
strategy: string;
|
|
60
|
+
autoCommitted: boolean;
|
|
61
|
+
cleaned: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface DirtyMergePartial {
|
|
64
|
+
partial: true;
|
|
65
|
+
stage: string;
|
|
66
|
+
autoCommitted: boolean;
|
|
67
|
+
cleaned: boolean;
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
export interface DirtyMergeFailure {
|
|
71
|
+
failed: true;
|
|
72
|
+
stage: string;
|
|
73
|
+
message: string;
|
|
74
|
+
}
|
|
75
|
+
export interface OrphanCleanupResult {
|
|
76
|
+
removed: string[];
|
|
77
|
+
skipped: string[];
|
|
78
|
+
errors: Array<{
|
|
79
|
+
branch: string;
|
|
80
|
+
error: string;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
|
83
|
+
export interface StartupRecoveryResult {
|
|
84
|
+
prunedWorktrees: boolean;
|
|
85
|
+
remainingBranches: string[];
|
|
86
|
+
warnings: string[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Reads the merge strategy from the lean turbo configuration.
|
|
90
|
+
*
|
|
91
|
+
* Returns `config.merge_strategy` if set, otherwise defaults to `'merge'`.
|
|
92
|
+
* This is a pure function — no subprocess calls.
|
|
93
|
+
*
|
|
94
|
+
* @param config - Lean turbo configuration.
|
|
95
|
+
* @returns The merge strategy to use: `'merge'`, `'rebase'`, or `'cherry-pick'`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function getMergeStrategy(config: LeanTurboConfig): 'merge' | 'rebase' | 'cherry-pick';
|
|
98
|
+
/**
|
|
99
|
+
* Merges a lane branch back into the primary worktree using the specified
|
|
100
|
+
* strategy.
|
|
101
|
+
*
|
|
102
|
+
* On conflict, automatically aborts the in-progress merge/rebase/cherry-pick
|
|
103
|
+
* to restore the working tree to a clean state, then returns conflict details.
|
|
104
|
+
*
|
|
105
|
+
* @param primaryDir - The main project root (cwd for all git commands).
|
|
106
|
+
* @param branchName - The lane branch name (e.g. `swarm-lane/<sessionId>/<laneId>`).
|
|
107
|
+
* @param strategy - Merge strategy to use.
|
|
108
|
+
* @returns Discriminated union: success, conflict, or failure.
|
|
109
|
+
*/
|
|
110
|
+
export declare function mergeLaneBranch(primaryDir: string, branchName: string, strategy: 'merge' | 'rebase' | 'cherry-pick'): Promise<MergeSuccess | MergeConflict | MergeFailure>;
|
|
111
|
+
/**
|
|
112
|
+
* Cleans up a lane branch after a successful merge.
|
|
113
|
+
*
|
|
114
|
+
* Deletes the lane branch and prunes stale worktree metadata (DD-9).
|
|
115
|
+
* Reports partial success if branch deletion fails but worktree prune succeeds.
|
|
116
|
+
*
|
|
117
|
+
* @param directory - The project root (cwd for git commands).
|
|
118
|
+
* @param branchName - The lane branch name to delete.
|
|
119
|
+
* @returns Discriminated union: success, partial failure, or full failure.
|
|
120
|
+
*/
|
|
121
|
+
export declare function postMergeCleanup(directory: string, branchName: string): Promise<CleanupSuccess | CleanupFailure>;
|
|
122
|
+
/**
|
|
123
|
+
* Handles a merge conflict by listing conflicted files and aborting the
|
|
124
|
+
* in-progress operation to restore the working tree to a clean state.
|
|
125
|
+
*
|
|
126
|
+
* Uses a strategy-specific abort command so the correct git sub-command
|
|
127
|
+
* is invoked (`merge --abort`, `rebase --abort`, or `cherry-pick --abort`).
|
|
128
|
+
* Using the wrong abort command would leave the repository in a dirty state.
|
|
129
|
+
*
|
|
130
|
+
* @param primaryDir - The main project root (cwd for all git commands).
|
|
131
|
+
* @param branchName - The lane branch name that caused the conflict.
|
|
132
|
+
* Retained for logging and future conflict-reporting use.
|
|
133
|
+
* @param strategy - The merge strategy that is currently in progress.
|
|
134
|
+
* @returns Discriminated union: conflict info or handling error.
|
|
135
|
+
*/
|
|
136
|
+
export declare function handleMergeConflict(primaryDir: string, _branchName: string, strategy: 'merge' | 'rebase' | 'cherry-pick'): Promise<ConflictInfo | ConflictHandlingError>;
|
|
137
|
+
/**
|
|
138
|
+
* Attempts to merge a lane branch back from a potentially dirty worktree
|
|
139
|
+
* using progressive cleanup (DD-7).
|
|
140
|
+
*
|
|
141
|
+
* Pipeline:
|
|
142
|
+
* 1. Auto-commit dirty state in the worktree
|
|
143
|
+
* 2. Clean untracked files
|
|
144
|
+
* 3. Attempt the merge-back
|
|
145
|
+
*
|
|
146
|
+
* Each step is fault-tolerant: failures log a warning and continue.
|
|
147
|
+
* Only when both auto-commit AND clean fail (not just skip) does the
|
|
148
|
+
* pipeline abandon early with `{ failed: true, stage: 'cleanup' }`.
|
|
149
|
+
*
|
|
150
|
+
* @param worktreePath - Absolute path to the lane worktree directory.
|
|
151
|
+
* @param branchName - The lane branch name (e.g. `swarm-lane/<sessionId>/<laneId>`).
|
|
152
|
+
* @param primaryDir - The main project root (cwd for merge commands).
|
|
153
|
+
* @param strategy - Merge strategy to use.
|
|
154
|
+
* @returns Discriminated union: success, partial, or failure.
|
|
155
|
+
*/
|
|
156
|
+
export declare function attemptMergeBackFromDirty(worktreePath: string, branchName: string, primaryDir: string, strategy: 'merge' | 'rebase' | 'cherry-pick'): Promise<DirtyMergeSuccess | DirtyMergePartial | DirtyMergeFailure>;
|
|
157
|
+
/**
|
|
158
|
+
* Cleans up orphaned swarm-lane branches that do not belong to any active session.
|
|
159
|
+
*
|
|
160
|
+
* Lists all branches matching `swarm-lane/*`, identifies orphans (branches whose
|
|
161
|
+
* session ID is not in `activeSessionIds`), force-deletes them, and prunes stale
|
|
162
|
+
* worktree metadata.
|
|
163
|
+
*
|
|
164
|
+
* @param directory - The project root (cwd for all git commands).
|
|
165
|
+
* @param activeSessionIds - Session IDs that are still active; their branches are skipped.
|
|
166
|
+
* @returns Result with arrays of removed, skipped, and errored branch names.
|
|
167
|
+
*/
|
|
168
|
+
export declare function cleanupOrphanedBranches(directory: string, activeSessionIds?: string[]): Promise<OrphanCleanupResult>;
|
|
169
|
+
/**
|
|
170
|
+
* Performs startup orphan recovery: prunes stale worktrees, then identifies
|
|
171
|
+
* any remaining orphaned swarm-lane branches for warning.
|
|
172
|
+
*
|
|
173
|
+
* This is designed to run at session startup (DD-3). It does NOT delete branches —
|
|
174
|
+
* it reports them as warnings so the caller can decide on further action.
|
|
175
|
+
*
|
|
176
|
+
* @param directory - The project root (cwd for all git commands).
|
|
177
|
+
* @param activeSessionIds - Session IDs that are still active; their branches are expected.
|
|
178
|
+
* @returns Result indicating whether pruning happened, orphaned branches, and warnings.
|
|
179
|
+
*/
|
|
180
|
+
export declare function startupOrphanRecovery(directory: string, activeSessionIds?: string[]): Promise<StartupRecoveryResult>;
|
|
@@ -22,9 +22,11 @@ import { acquireLaneLocks, releaseLaneLocks } from '../../parallel/file-locks';
|
|
|
22
22
|
import { loadPlanJsonOnly } from '../../plan/manager';
|
|
23
23
|
import { hasActiveFullAuto } from '../../state';
|
|
24
24
|
import { writeLaneEvidence } from './evidence';
|
|
25
|
+
import { attemptMergeBackFromDirty, getMergeStrategy, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery } from './merge-back';
|
|
25
26
|
import { planLeanTurboLanes } from './planner';
|
|
26
27
|
import type { LeanTurboLane } from './state';
|
|
27
28
|
import { loadLeanTurboRunState, saveLeanTurboRunState } from './state';
|
|
29
|
+
import { assertCleanWorkingTree, provisionWorktree, removeWorktree } from './worktree';
|
|
28
30
|
/**
|
|
29
31
|
* Shape of the OpencodeClient session API used by the runner.
|
|
30
32
|
* Extracted into an interface so tests can inject a mock without
|
|
@@ -83,6 +85,17 @@ export interface LaneDispatchResult {
|
|
|
83
85
|
/** Error message if ok === false */
|
|
84
86
|
error?: string;
|
|
85
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Describes a merge-back failure for a completed lane.
|
|
90
|
+
*/
|
|
91
|
+
export interface MergeBackFailureInfo {
|
|
92
|
+
/** Lane identifier */
|
|
93
|
+
laneId: string;
|
|
94
|
+
/** Human-readable reason for the merge-back failure */
|
|
95
|
+
reason: string;
|
|
96
|
+
/** Conflict files if the failure was a merge conflict */
|
|
97
|
+
conflictFiles?: string[];
|
|
98
|
+
}
|
|
86
99
|
/**
|
|
87
100
|
* Result of a single lane's processing.
|
|
88
101
|
*/
|
|
@@ -99,6 +112,8 @@ export interface LaneResult {
|
|
|
99
112
|
sessionId?: string;
|
|
100
113
|
/** Error message if status is 'failed' or 'blocked' */
|
|
101
114
|
error?: string;
|
|
115
|
+
/** Merge-back failure info if the coder completed but integration back to primary failed */
|
|
116
|
+
mergeBackFailure?: MergeBackFailureInfo;
|
|
102
117
|
}
|
|
103
118
|
/**
|
|
104
119
|
* Result of a full phase run.
|
|
@@ -114,6 +129,8 @@ export interface LeanTurboPhaseResult {
|
|
|
114
129
|
degradedTasks: string[];
|
|
115
130
|
/** Task IDs excluded from parallel lanes, must complete via standard serial flow */
|
|
116
131
|
serializedTasks: string[];
|
|
132
|
+
/** Lanes whose coder completed but merge-back to primary branch failed */
|
|
133
|
+
mergeBackFailures?: MergeBackFailureInfo[];
|
|
117
134
|
}
|
|
118
135
|
/**
|
|
119
136
|
* Orchestrates Lean Turbo lane execution.
|
|
@@ -151,6 +168,14 @@ export declare class LeanTurboRunner {
|
|
|
151
168
|
writeLaneEvidence: typeof writeLaneEvidence;
|
|
152
169
|
/** Timeout for lane dispatch (session.create + session.prompt) in ms. Undefined = no timeout. */
|
|
153
170
|
laneDispatchTimeoutMs: number | undefined;
|
|
171
|
+
provisionWorktree: typeof provisionWorktree;
|
|
172
|
+
removeWorktree: typeof removeWorktree;
|
|
173
|
+
mergeLaneBranch: typeof mergeLaneBranch;
|
|
174
|
+
postMergeCleanup: typeof postMergeCleanup;
|
|
175
|
+
attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
|
|
176
|
+
startupOrphanRecovery: typeof startupOrphanRecovery;
|
|
177
|
+
getMergeStrategy: typeof getMergeStrategy;
|
|
178
|
+
assertCleanWorkingTree: typeof assertCleanWorkingTree;
|
|
154
179
|
};
|
|
155
180
|
/**
|
|
156
181
|
* Test-only dependency-injection seam for session operations.
|
|
@@ -218,7 +243,7 @@ export declare class LeanTurboRunner {
|
|
|
218
243
|
* @param lane - Lane to dispatch
|
|
219
244
|
* @param agentName - Agent name to dispatch to
|
|
220
245
|
*/
|
|
221
|
-
dispatchLane(lane: LeanTurboLane, agentName: string): Promise<LaneDispatchResult>;
|
|
246
|
+
dispatchLane(lane: LeanTurboLane, agentName: string, worktreeDirectory?: string): Promise<LaneDispatchResult>;
|
|
222
247
|
/**
|
|
223
248
|
* Internal dispatch implementation (separated for timeout wrapping).
|
|
224
249
|
*/
|
|
@@ -277,6 +302,20 @@ export declare class LeanTurboRunner {
|
|
|
277
302
|
* the serialized tasks set for standard serial fallback.
|
|
278
303
|
*/
|
|
279
304
|
private _processLane;
|
|
305
|
+
/**
|
|
306
|
+
* Sequential worktree cleanup for completed and failed worktree lanes.
|
|
307
|
+
*
|
|
308
|
+
* Runs AFTER all lanes have been dispatched and completed via Promise.all.
|
|
309
|
+
* Each worktree lane is processed one at a time, preventing concurrent
|
|
310
|
+
* git merge/rebase/cherry-pick from corrupting the shared .git index.
|
|
311
|
+
*
|
|
312
|
+
* - **Success lanes**: mergeLaneBranch → removeWorktree → postMergeCleanup
|
|
313
|
+
* - **Success lanes with merge failure**: log warning, keep worktree, update lane result
|
|
314
|
+
* - **Failed lanes**: attemptMergeBackFromDirty → removeWorktree
|
|
315
|
+
*
|
|
316
|
+
* @returns Array of MergeBackFailureInfo for lanes where merge-back failed
|
|
317
|
+
*/
|
|
318
|
+
private _sequentialWorktreeCleanup;
|
|
280
319
|
/**
|
|
281
320
|
* Select the next available agent using round-robin.
|
|
282
321
|
*/
|
|
@@ -302,6 +341,13 @@ export declare class LeanTurboRunner {
|
|
|
302
341
|
* Update durable state with the full lane plan (called once per phase).
|
|
303
342
|
*/
|
|
304
343
|
private _updateDurableState;
|
|
344
|
+
/**
|
|
345
|
+
* Persist a lane's worktreePath and branchName to durable state.
|
|
346
|
+
*
|
|
347
|
+
* Called after provisioning so that after a crash/restart these fields
|
|
348
|
+
* are recoverable from turbo-state.json.
|
|
349
|
+
*/
|
|
350
|
+
private _persistLaneWorktreeFields;
|
|
305
351
|
/**
|
|
306
352
|
* Update a single lane's status in durable state.
|
|
307
353
|
* Serialized through _withStateLock to prevent race conditions with concurrent lanes.
|
|
@@ -9,6 +9,16 @@ export interface LeanTurboLane {
|
|
|
9
9
|
error?: string;
|
|
10
10
|
agent?: string;
|
|
11
11
|
sessionId?: string;
|
|
12
|
+
/** Worktree path for isolated lane execution (undefined when worktree_isolation is disabled) */
|
|
13
|
+
worktreePath?: string;
|
|
14
|
+
/** Branch name for the lane's worktree (swarm-lane/<sessionId>/<laneId>) */
|
|
15
|
+
branchName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* In-memory-only flag: set when dispatch fails with a provisioned worktree.
|
|
18
|
+
* Signals that _sequentialWorktreeCleanup should run attemptMergeBackFromDirty
|
|
19
|
+
* + removeWorktree for this lane. Never persisted to disk.
|
|
20
|
+
*/
|
|
21
|
+
_failureCleanupPending?: boolean;
|
|
12
22
|
}
|
|
13
23
|
export interface LeanTurboDegradedTask {
|
|
14
24
|
taskId: string;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree lifecycle operations for lean turbo parallel lanes.
|
|
3
|
+
*
|
|
4
|
+
* Provides five public functions for creating, removing, inspecting, and
|
|
5
|
+
* cleaning git worktrees used by parallel coder lanes. All subprocess
|
|
6
|
+
* calls go through the `_internals` DI seam so tests can replace the
|
|
7
|
+
* real `bunSpawn` without leaking across Bun's shared test-runner process.
|
|
8
|
+
*
|
|
9
|
+
* @module worktree
|
|
10
|
+
*/
|
|
11
|
+
import type { LeanTurboConfig } from '../../config/schema';
|
|
12
|
+
import { bunSpawn } from '../../utils/bun-compat';
|
|
13
|
+
/**
|
|
14
|
+
* Test-only dependency-injection seam. Production code calls
|
|
15
|
+
* `_internals.bunSpawn(...)` so tests can replace the function on this object
|
|
16
|
+
* without touching the real `../../utils/bun-compat` module — `mock.module`
|
|
17
|
+
* from `bun:test` leaks across files in Bun's shared test-runner process,
|
|
18
|
+
* which would corrupt unrelated suites that import `bun-compat`. Mutating this
|
|
19
|
+
* local object is file-scoped and trivially restorable via `afterEach`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const _internals: {
|
|
22
|
+
bunSpawn: typeof bunSpawn;
|
|
23
|
+
/** Test seam for process.platform — allows non-Windows CIs to exercise Windows paths. */
|
|
24
|
+
platform: string;
|
|
25
|
+
/** Test seam for sleep — allows tests to skip real delays. */
|
|
26
|
+
sleep: (ms: number) => Promise<void>;
|
|
27
|
+
/** Test seam for os.tmpdir() — allows tests to control temp path. */
|
|
28
|
+
osTmpdir: () => string;
|
|
29
|
+
/**
|
|
30
|
+
* Test seam for querying `git config core.longpaths`.
|
|
31
|
+
* Returns `'true'` | `'false'` | `undefined` (not set or query failed).
|
|
32
|
+
* Production implementation runs `git config core.longpaths` via runGit.
|
|
33
|
+
*/
|
|
34
|
+
getCoreLongPaths: (directory: string) => Promise<string | undefined>;
|
|
35
|
+
};
|
|
36
|
+
interface PathBudgetOk {
|
|
37
|
+
ok: true;
|
|
38
|
+
}
|
|
39
|
+
interface PathBudgetExceeded {
|
|
40
|
+
ok: false;
|
|
41
|
+
error: string;
|
|
42
|
+
suggestion: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Checks whether the total path length for files inside a worktree would
|
|
46
|
+
* exceed the Windows MAX_PATH budget (260 chars).
|
|
47
|
+
*
|
|
48
|
+
* On non-Windows platforms this is a no-op and always returns `{ ok: true }`.
|
|
49
|
+
*
|
|
50
|
+
* If `core.longpaths` is enabled in the git config (`true`), the MAX_PATH
|
|
51
|
+
* limit does not apply (Git 2.35+) and the budget check is skipped entirely.
|
|
52
|
+
* If the config query fails or returns anything other than `true`, the
|
|
53
|
+
* existing budget check proceeds (fail-safe).
|
|
54
|
+
*
|
|
55
|
+
* The check runs `git ls-files` via `_internals.bunSpawn` to discover the
|
|
56
|
+
* longest relative file path in the project, then computes
|
|
57
|
+
* `worktreeRoot.length + 1 + longestRelativePath.length`. If this total is
|
|
58
|
+
* >= 250 (a safety margin under 260), the budget is exceeded.
|
|
59
|
+
*
|
|
60
|
+
* @param worktreeRoot - Absolute path to the worktree root directory.
|
|
61
|
+
* @param directory - Project root (used as `cwd` for `git ls-files`).
|
|
62
|
+
*/
|
|
63
|
+
export declare function checkPathBudget(worktreeRoot: string, directory: string): Promise<PathBudgetOk | PathBudgetExceeded>;
|
|
64
|
+
/**
|
|
65
|
+
* Returns a shortened worktree path under the system temp directory.
|
|
66
|
+
*
|
|
67
|
+
* On non-Windows platforms this is not typically needed but still returns
|
|
68
|
+
* a deterministic path. The returned path is
|
|
69
|
+
* `<os.tmpdir()>/swwt/<sessionId>/<laneId>`.
|
|
70
|
+
*
|
|
71
|
+
* @param directory - Project root (unused but kept for API symmetry).
|
|
72
|
+
* @param sessionId - Lean turbo session identifier.
|
|
73
|
+
* @param laneId - Lane identifier.
|
|
74
|
+
*/
|
|
75
|
+
export declare function shortenWorktreePath(_directory: string, sessionId: string, laneId: string): string;
|
|
76
|
+
interface ProvisionSuccess {
|
|
77
|
+
worktreePath: string;
|
|
78
|
+
branchName: string;
|
|
79
|
+
}
|
|
80
|
+
interface ProvisionFailure {
|
|
81
|
+
error: string;
|
|
82
|
+
}
|
|
83
|
+
interface RemoveSuccess {
|
|
84
|
+
success: true;
|
|
85
|
+
}
|
|
86
|
+
interface RemoveFailure {
|
|
87
|
+
error: string;
|
|
88
|
+
}
|
|
89
|
+
interface AutoCommitSuccess {
|
|
90
|
+
committed: true;
|
|
91
|
+
message: string;
|
|
92
|
+
}
|
|
93
|
+
interface AutoCommitSkip {
|
|
94
|
+
committed: false;
|
|
95
|
+
reason: string;
|
|
96
|
+
}
|
|
97
|
+
interface CleanSuccess {
|
|
98
|
+
cleaned: true;
|
|
99
|
+
}
|
|
100
|
+
interface CleanFailure {
|
|
101
|
+
cleaned: false;
|
|
102
|
+
error: string;
|
|
103
|
+
}
|
|
104
|
+
interface CleanCheckSuccess {
|
|
105
|
+
clean: true;
|
|
106
|
+
}
|
|
107
|
+
interface CleanCheckFailure {
|
|
108
|
+
clean: false;
|
|
109
|
+
error: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Creates a new git worktree for a lean turbo lane.
|
|
113
|
+
*
|
|
114
|
+
* Branch naming follows DD-3: `swarm-lane/<sessionId>/<laneId>`.
|
|
115
|
+
* Worktree path follows DD-6: uses `config.worktree_dir` when set,
|
|
116
|
+
* otherwise defaults to `<project-parent>/.swarm-worktrees/<sessionId>/<laneId>`.
|
|
117
|
+
*
|
|
118
|
+
* Before creating the worktree, checks whether the branch already exists
|
|
119
|
+
* (via `git branch --list`) and returns an error if so.
|
|
120
|
+
*
|
|
121
|
+
* @param directory - Project root (an absolute path to the git working tree).
|
|
122
|
+
* @param laneId - Lane identifier (e.g. "lane-1").
|
|
123
|
+
* @param sessionId - Lean turbo session identifier.
|
|
124
|
+
* @param config - Lean turbo configuration (may contain `worktree_dir`).
|
|
125
|
+
* @returns An object with `worktreePath` and `branchName` on success, or
|
|
126
|
+
* `{ error: string }` on failure.
|
|
127
|
+
*/
|
|
128
|
+
export declare function provisionWorktree(directory: string, laneId: string, sessionId: string, config: LeanTurboConfig): Promise<ProvisionSuccess | ProvisionFailure>;
|
|
129
|
+
/**
|
|
130
|
+
* Removes a git worktree **without** `--force`.
|
|
131
|
+
*
|
|
132
|
+
* On Windows (`process.platform === 'win32'`), retries up to 3 times with a
|
|
133
|
+
* 2-second delay when the error contains `EBUSY` or `EPERM` (DD-10). After
|
|
134
|
+
* exhausting retries the worktree is abandoned — the function returns an
|
|
135
|
+
* error but does NOT throw.
|
|
136
|
+
*
|
|
137
|
+
* @param worktreePath - Absolute path to the worktree directory to remove.
|
|
138
|
+
* @param projectRoot - Absolute path to the project root (a git repository)
|
|
139
|
+
* used as `cwd` for the `git worktree remove` command.
|
|
140
|
+
* Required because the worktree's parent directory may
|
|
141
|
+
* not itself be a git repository.
|
|
142
|
+
* @returns `{ success: true }` on success or `{ error: string }` on failure.
|
|
143
|
+
*/
|
|
144
|
+
export declare function removeWorktree(worktreePath: string, projectRoot: string): Promise<RemoveSuccess | RemoveFailure>;
|
|
145
|
+
/**
|
|
146
|
+
* Checks whether a worktree is clean — no uncommitted changes AND no
|
|
147
|
+
* untracked files.
|
|
148
|
+
*
|
|
149
|
+
* Runs two git commands with `cwd` set to the worktree:
|
|
150
|
+
* 1. `git status --porcelain` — detects staged/unstaged modifications
|
|
151
|
+
* 2. `git ls-files --others --exclude-standard` — detects untracked files
|
|
152
|
+
*
|
|
153
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
154
|
+
* @returns `true` when the worktree is completely clean, `false` otherwise.
|
|
155
|
+
*/
|
|
156
|
+
export declare function isCleanWorktree(worktreePath: string): Promise<boolean>;
|
|
157
|
+
/**
|
|
158
|
+
* Auto-commits dirty state in a worktree before cleanup.
|
|
159
|
+
*
|
|
160
|
+
* Stages all files (`git add -A`) and commits with the message
|
|
161
|
+
* `swarm-lane: auto-commit before cleanup`. If there is nothing to commit,
|
|
162
|
+
* returns `{ committed: false, reason: 'Nothing to commit' }`.
|
|
163
|
+
*
|
|
164
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
165
|
+
* @returns `{ committed: true, message }` on success or `{ committed: false, reason }`
|
|
166
|
+
* if nothing to commit or on failure.
|
|
167
|
+
*/
|
|
168
|
+
export declare function autoCommitDirty(worktreePath: string): Promise<AutoCommitSuccess | AutoCommitSkip>;
|
|
169
|
+
/**
|
|
170
|
+
* Removes untracked files and directories from a worktree (DD-7 amendment).
|
|
171
|
+
*
|
|
172
|
+
* Before running `git clean -fd`, performs a dry-run (`git clean -fdn`) to
|
|
173
|
+
* list what would be deleted. If the list contains anything that is not
|
|
174
|
+
* a known generated/temporary artifact, the clean is **skipped** to prevent
|
|
175
|
+
* accidental deletion of uncommitted source files created by lane coders.
|
|
176
|
+
*
|
|
177
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
178
|
+
* @returns `{ cleaned: true }` on success or `{ cleaned: false, error }`
|
|
179
|
+
* on failure or when untracked source files are detected.
|
|
180
|
+
*/
|
|
181
|
+
export declare function cleanUntrackedFiles(worktreePath: string): Promise<CleanSuccess | CleanFailure>;
|
|
182
|
+
/**
|
|
183
|
+
* Verifies that the working tree at `directory` has no uncommitted or
|
|
184
|
+
* untracked changes before worktree provisioning (DD-2).
|
|
185
|
+
*
|
|
186
|
+
* If the working tree is dirty, returns a descriptive error message
|
|
187
|
+
* instructing the user to commit or stash.
|
|
188
|
+
*
|
|
189
|
+
* @param directory - Project root (an absolute path to the git working tree).
|
|
190
|
+
* @returns `{ clean: true }` when the working tree is clean, or
|
|
191
|
+
* `{ clean: false, error: string }` when dirty or unverifiable.
|
|
192
|
+
*/
|
|
193
|
+
export declare function assertCleanWorkingTree(directory: string): Promise<CleanCheckSuccess | CleanCheckFailure>;
|
|
194
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.59.1",
|
|
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",
|