opencode-swarm 7.131.0 → 7.132.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 -2
- package/dist/cli/{config-doctor-rjvb0hhn.js → config-doctor-3rssa871.js} +2 -2
- package/dist/cli/{curation-policy-f5bybzmh.js → curation-policy-3914h3g9.js} +2 -2
- package/dist/cli/{curator-kjzqa5m7.js → curator-1e77dq6x.js} +12 -12
- package/dist/cli/{curator-llm-factory-ezq4fakt.js → curator-llm-factory-41c17ybs.js} +12 -12
- package/dist/cli/{guardrail-explain-n93qh8k6.js → guardrail-explain-624brj1y.js} +13 -13
- package/dist/cli/{guardrail-log-h4tmcjwx.js → guardrail-log-vfka4tcn.js} +3 -3
- package/dist/cli/{hive-promoter-mammxe5p.js → hive-promoter-mw5prfy2.js} +12 -12
- package/dist/cli/{index-1atz85c8.js → index-2dtwjx39.js} +1 -1
- package/dist/cli/{index-hynbzh7s.js → index-5x3g1q91.js} +4 -0
- package/dist/cli/{index-cnwh164k.js → index-64z5dvam.js} +1 -1
- package/dist/cli/{index-q68sprcy.js → index-6mcx76j9.js} +4 -4
- package/dist/cli/{index-d2tgc580.js → index-8w3sp149.js} +1420 -1313
- package/dist/cli/{index-6vg0qczz.js → index-99tq1zd5.js} +2 -2
- package/dist/cli/{index-01nyrk95.js → index-e630fw43.js} +3 -3
- package/dist/cli/{index-tw33v84d.js → index-exs5bt14.js} +1 -1
- package/dist/cli/{index-cq22pnd2.js → index-fegng5pv.js} +1 -1
- package/dist/cli/{index-fepakwhp.js → index-nsxchdx0.js} +1 -1
- package/dist/cli/{index-m6zfm7cm.js → index-ppkp20fp.js} +5 -5
- package/dist/cli/{index-kbfhyxtv.js → index-q0ysv66x.js} +1 -1
- package/dist/cli/{index-xhd797bz.js → index-qg1cj1ev.js} +14 -14
- package/dist/cli/{index-pft1qxqh.js → index-sbq3gbjs.js} +1 -1
- package/dist/cli/{index-xv2ydncg.js → index-zah4qws8.js} +2 -2
- package/dist/cli/{index-szkswbqf.js → index-zrh07ykv.js} +2 -2
- package/dist/cli/index.js +12 -12
- package/dist/cli/{knowledge-escalator-cf1kkmfe.js → knowledge-escalator-5hv2dwhz.js} +3 -3
- package/dist/cli/{knowledge-events-p8t5ev44.js → knowledge-events-434663dp.js} +1 -1
- package/dist/cli/{knowledge-store-vpdmcwem.js → knowledge-store-73ykq5j3.js} +1 -1
- package/dist/cli/{knowledge-validator-w1t0sw5f.js → knowledge-validator-tnadtt1h.js} +4 -4
- package/dist/cli/{scan-cursor-z4c51902.js → scan-cursor-e33n9pej.js} +2 -2
- package/dist/cli/{schema-yqzzfavj.js → schema-1kwmcayk.js} +1 -1
- package/dist/cli/{skill-generator-aaabj00n.js → skill-generator-k111qfdw.js} +5 -5
- package/dist/index.js +348 -348
- package/dist/parallel/index.d.ts +0 -2
- package/dist/plan/parallel-verdict.d.ts +94 -0
- package/dist/services/status-service.d.ts +14 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/lean-turbo-run-phase.d.ts +7 -0
- package/dist/tools/manifest.d.ts +1 -0
- package/dist/tools/plan-conflict-check.d.ts +61 -0
- package/dist/tools/tool-metadata.d.ts +4 -0
- package/dist/turbo/lean/recovery.d.ts +90 -0
- package/dist/turbo/lean/runner.d.ts +16 -1
- package/dist/worktree/merge.d.ts +5 -0
- package/package.json +1 -1
- package/dist/parallel/dependency-graph.d.ts +0 -34
- package/dist/parallel/meta-indexer.d.ts +0 -32
package/dist/parallel/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
export { EvidenceLockTimeoutError, withEvidenceLock, } from '../evidence/lock.js';
|
|
2
|
-
export { type DependencyGraph, getDependencyChain, getExecutionOrder, getRunnableTasks, isTaskBlocked, parseDependencyGraph, type TaskNode, } from './dependency-graph.js';
|
|
3
2
|
export { cleanupExpiredLocks, type FileLock, isLocked, listActiveLocks, releaseLock, tryAcquireLock, } from './file-locks.js';
|
|
4
|
-
export { extractMetaSummaries, getLatestTaskSummary, indexMetaSummaries, type MetaSummaryEntry, querySummaries, } from './meta-indexer.js';
|
|
5
3
|
export { type ComplexityMetrics, computeComplexity, type ReviewDepth, type ReviewRouting, routeReview, routeReviewForChanges, shouldParallelizeReview, } from './review-router.js';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan-time parallel-execution verdict helper (#1656 / #1674 v8 flagship).
|
|
3
|
+
*
|
|
4
|
+
* Pure, synchronous, side-effect-free pairwise conflict analysis for N proposed
|
|
5
|
+
* parallel task groups. Used by BOTH:
|
|
6
|
+
* - the `plan_conflict_check` tool (architect-facing advisory — see
|
|
7
|
+
* `src/tools/plan-conflict-check.ts`), and
|
|
8
|
+
* - the delegation gate (`src/hooks/delegation-gate.ts`) which recomputes the
|
|
9
|
+
* verdict INLINE at coder-dispatch time to enforce the v8 "serial fallback
|
|
10
|
+
* when scopes overlap or are unknown" contract (acceptance criterion 4).
|
|
11
|
+
*
|
|
12
|
+
* Single source of truth: one helper, two call sites, so the architect's
|
|
13
|
+
* advisory and the gate's enforcement can never disagree on what "disjoint"
|
|
14
|
+
* means.
|
|
15
|
+
*
|
|
16
|
+
* Design notes:
|
|
17
|
+
* - Sync by design: it reads only `.swarm/scopes/scope-<taskId>.json` via
|
|
18
|
+
* the hardened persisted-scope reader (sync + fail-closed). The gate runs in
|
|
19
|
+
* `toolBefore` on every tool call and must stay bounded; an async/gitten
|
|
20
|
+
* helper would violate the bounded-gate spirit.
|
|
21
|
+
* - The helper itself NEVER calls `getCoChangePairs` (async + `git log`).
|
|
22
|
+
* Co-change signal is opt-in and supplied by the caller (the tool) via
|
|
23
|
+
* `options.cochangePairs`. The gate never supplies it, keeping the
|
|
24
|
+
* enforcement path git-free and fast.
|
|
25
|
+
* - Fail-closed: a missing/malformed scope → `unknown_scope`, which conflicts
|
|
26
|
+
* with everything, so `verdict` can never be `all_disjoint` while any task
|
|
27
|
+
* lacks a declared scope. This is the v8 safety guarantee.
|
|
28
|
+
* - Writes nothing. Honors issue #1656's "read-only (writes nothing)" tool
|
|
29
|
+
* acceptance criterion.
|
|
30
|
+
*/
|
|
31
|
+
import type { CoChangeEntry } from '../tools/co-change-analyzer.js';
|
|
32
|
+
import { type CoChangeThreshold } from '../turbo/epic/cochange-conflict.js';
|
|
33
|
+
import { normalizePath, pathsConflict, readTaskScopes } from '../turbo/lean/conflicts.js';
|
|
34
|
+
/**
|
|
35
|
+
* Per-pair conflict classification. Mirrors `EpicPairVerdict`'s signal
|
|
36
|
+
* decomposition but flattens `none` into `disjoint` for the plan-level view.
|
|
37
|
+
*/
|
|
38
|
+
export interface ParallelVerdictPair {
|
|
39
|
+
/** First task id (input order). */
|
|
40
|
+
a: string;
|
|
41
|
+
/** Second task id (input order). */
|
|
42
|
+
b: string;
|
|
43
|
+
/** `conflict` = path or co-change overlap; `disjoint` = provably no overlap; `unknown` = ≥1 task has no usable scope. */
|
|
44
|
+
verdict: 'conflict' | 'disjoint' | 'unknown';
|
|
45
|
+
/** Human-readable evidence lines (path pairs, co-change pairs). Empty for `disjoint`/`unknown`. */
|
|
46
|
+
evidence: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whole-plan verdict. The gate keys off `verdict === 'all_disjoint'` to allow
|
|
50
|
+
* parallel execution; anything else forces serial.
|
|
51
|
+
*/
|
|
52
|
+
export interface ParallelVerdict {
|
|
53
|
+
/** `all_disjoint` iff every pair is `disjoint` (no conflicts, no unknowns). */
|
|
54
|
+
verdict: 'all_disjoint' | 'conflicts_present' | 'unknown_scopes';
|
|
55
|
+
/** Pairwise results, one per input task pair (i < j). */
|
|
56
|
+
pairs: ParallelVerdictPair[];
|
|
57
|
+
/** Suggested serialization order (topological sort over the conflict graph). Input order preserved when no conflicts. */
|
|
58
|
+
suggestedSerialOrder: string[];
|
|
59
|
+
/** Task ids whose scope could not be resolved (missing/malformed). */
|
|
60
|
+
unknownScopeTasks: string[];
|
|
61
|
+
}
|
|
62
|
+
/** Default co-change threshold when the caller opts into co-change but omits one. */
|
|
63
|
+
export declare const DEFAULT_PARALLEL_COCHANGE_THRESHOLD: CoChangeThreshold;
|
|
64
|
+
/** Hard cap for the synchronous O(N²) verdict path (F-005). */
|
|
65
|
+
export declare const MAX_PARALLEL_VERDICT_TASKS = 64;
|
|
66
|
+
export interface ComputeParallelVerdictOptions {
|
|
67
|
+
/** When true AND `cochangePairs` is supplied, fold co-change signal into each pair. Off by default. */
|
|
68
|
+
useCochange?: boolean;
|
|
69
|
+
/** Caller-supplied co-change data (e.g. from `getCoChangePairs`). The helper never fetches it. */
|
|
70
|
+
cochangePairs?: CoChangeEntry[];
|
|
71
|
+
/** Override the co-change threshold. Defaults to `DEFAULT_PARALLEL_COCHANGE_THRESHOLD`. */
|
|
72
|
+
cochangeThreshold?: CoChangeThreshold;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compute a pairwise conflict verdict for the given task ids.
|
|
76
|
+
*
|
|
77
|
+
* Pure + synchronous. Reads only `.swarm/scopes/`. Writes nothing. Fail-closed
|
|
78
|
+
* on any read/parse error (treats the task as `unknown`).
|
|
79
|
+
*
|
|
80
|
+
* @param directory Project root (for `.swarm/scopes/` reads).
|
|
81
|
+
* @param taskIds Task ids to analyze. Caller is responsible for min-length
|
|
82
|
+
* validation (the tool requires ≥2; the gate only calls this
|
|
83
|
+
* with ≥2 pending tasks).
|
|
84
|
+
* @param options Optional co-change signal + threshold.
|
|
85
|
+
*/
|
|
86
|
+
export declare function computeParallelVerdict(directory: string, taskIds: string[], options?: ComputeParallelVerdictOptions): ParallelVerdict;
|
|
87
|
+
/**
|
|
88
|
+
* Quick pairwise check used by the gate: are these task ids provably disjoint?
|
|
89
|
+
*
|
|
90
|
+
* Equivalent to `computeParallelVerdict(...).verdict === 'all_disjoint'` but
|
|
91
|
+
* exposed as a named predicate so the gate reads as intent.
|
|
92
|
+
*/
|
|
93
|
+
export declare function isProvablyDisjoint(directory: string, taskIds: string[]): boolean;
|
|
94
|
+
export { normalizePath, pathsConflict, readTaskScopes };
|
|
@@ -40,6 +40,20 @@ export interface StatusData {
|
|
|
40
40
|
leanDegradedTasks?: number;
|
|
41
41
|
/** Human-readable degradation summary */
|
|
42
42
|
leanDegradationSummary?: string;
|
|
43
|
+
/**
|
|
44
|
+
* #1657: merge-back conflict recovery worktrees preserved for manual
|
|
45
|
+
* recovery (durable records under `.swarm/recovery/`). Surfaced so the
|
|
46
|
+
* architect/operator can see pending recovery work in `/swarm status`
|
|
47
|
+
* rather than having to re-read a prior tool result. `undefined`/empty when
|
|
48
|
+
* no lanes are preserved.
|
|
49
|
+
*/
|
|
50
|
+
leanPreservedRecoveryWorktrees?: Array<{
|
|
51
|
+
laneId: string;
|
|
52
|
+
status: string;
|
|
53
|
+
worktreePath: string;
|
|
54
|
+
reason: string;
|
|
55
|
+
replayHint: string;
|
|
56
|
+
}>;
|
|
43
57
|
/** Whether Full-Auto mode is currently active */
|
|
44
58
|
fullAutoActive?: boolean;
|
|
45
59
|
/**
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export { parse_lane_candidates } from './parse-lane-candidates';
|
|
|
49
49
|
export { phase_complete } from './phase-complete';
|
|
50
50
|
export { pkg_audit } from './pkg-audit';
|
|
51
51
|
export { type PlaceholderFinding, type PlaceholderScanInput, type PlaceholderScanResult, placeholder_scan, placeholderScan, } from './placeholder-scan';
|
|
52
|
+
export { plan_conflict_check } from './plan-conflict-check';
|
|
52
53
|
export { pr_workflow_status } from './pr-workflow-status';
|
|
53
54
|
export { type PreCheckBatchInput, type PreCheckBatchResult, pre_check_batch, runPreCheckBatch, type ToolResult, } from './pre-check-batch';
|
|
54
55
|
export { executePreparePrFeedbackScope, prepare_pr_feedback_scope, } from './prepare-pr-feedback-scope';
|
|
@@ -6,6 +6,7 @@ import type { ToolDefinition } from '@opencode-ai/plugin/tool';
|
|
|
6
6
|
import { loadPluginConfigWithMeta as loadPluginConfigWithMeta_import } from '../config';
|
|
7
7
|
import type { LaneResult, MergeBackFailureInfo } from '../turbo/lean/runner';
|
|
8
8
|
import { LeanTurboRunner as LeanTurboRunner_import } from '../turbo/lean/runner';
|
|
9
|
+
import type { LeanTurboDegradedTask } from '../turbo/lean/state';
|
|
9
10
|
/**
|
|
10
11
|
* Arguments for the lean_turbo_run_phase tool
|
|
11
12
|
*/
|
|
@@ -21,6 +22,12 @@ export interface LeanTurboRunPhaseResult {
|
|
|
21
22
|
success: boolean;
|
|
22
23
|
lanes?: LaneResult[];
|
|
23
24
|
degradedTasks?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* #1657: full degraded-task details (reason/files/requiredMode), additive
|
|
27
|
+
* alongside `degradedTasks`. Lets the architect see per-task degradation
|
|
28
|
+
* reasons in the tool result without reading /swarm status separately.
|
|
29
|
+
*/
|
|
30
|
+
degradedDetails?: LeanTurboDegradedTask[];
|
|
24
31
|
serializedTasks?: string[];
|
|
25
32
|
mergeBackFailures?: MergeBackFailureInfo[];
|
|
26
33
|
reason?: string;
|
package/dist/tools/manifest.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare const TOOL_MANIFEST: {
|
|
|
53
53
|
checkpoint: () => ToolDefinition;
|
|
54
54
|
pkg_audit: () => ToolDefinition;
|
|
55
55
|
parse_lane_candidates: () => ToolDefinition;
|
|
56
|
+
plan_conflict_check: () => ToolDefinition;
|
|
56
57
|
prepare_pr_feedback_scope: () => ToolDefinition;
|
|
57
58
|
write_pr_review_artifact: () => ToolDefinition;
|
|
58
59
|
write_pr_review_trigger_eval: () => ToolDefinition;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `plan_conflict_check` tool (#1656 — v8 parallel-first execution prerequisite).
|
|
3
|
+
*
|
|
4
|
+
* Read-only advisory: compute a pairwise file-conflict matrix for N proposed
|
|
5
|
+
* parallel task groups using declared scopes (and optional git co-change),
|
|
6
|
+
* returning a verdict and suggested serialization order.
|
|
7
|
+
*
|
|
8
|
+
* READ-ONLY CONTRACT (issue #1656 acceptance): this tool writes NOTHING — not
|
|
9
|
+
* to `.swarm/`, not to the source tree. It calls no other tools. The only I/O
|
|
10
|
+
* is reading `.swarm/plan.json` (via `loadPlanJsonOnly`) and
|
|
11
|
+
* `.swarm/scopes/scope-<taskId>.json` (via `readTaskScopes` inside
|
|
12
|
+
* `computeParallelVerdict`), plus an optional `git log` (only when the caller
|
|
13
|
+
* opts in via `use_cochange: true`).
|
|
14
|
+
*
|
|
15
|
+
* Why this tool exists alongside the gate: the gate (`delegation-gate.ts`)
|
|
16
|
+
* independently recomputes the verdict INLINE at coder-dispatch time via the
|
|
17
|
+
* same shared `computeParallelVerdict` helper. The tool gives the architect a
|
|
18
|
+
* way to inspect the conflict matrix BEFORE attempting parallel dispatch, so it
|
|
19
|
+
* can choose disjoint task groups and understand why the gate will (or won't)
|
|
20
|
+
* permit parallelism. Single source of truth (the helper), two call sites.
|
|
21
|
+
*/
|
|
22
|
+
import type { tool } from '@opencode-ai/plugin';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
export declare const plan_conflict_check_args: {
|
|
25
|
+
task_ids: z.ZodArray<z.ZodString>;
|
|
26
|
+
use_cochange: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
phase_id: z.ZodOptional<z.ZodString>;
|
|
28
|
+
};
|
|
29
|
+
export interface PlanConflictCheckResult {
|
|
30
|
+
/** Summary verdict. `all_disjoint` ⇒ safe to parallelize. */
|
|
31
|
+
verdict: 'all_disjoint' | 'conflicts_present' | 'unknown_scopes';
|
|
32
|
+
/** Pairwise results. */
|
|
33
|
+
pairs: Array<{
|
|
34
|
+
a: string;
|
|
35
|
+
b: string;
|
|
36
|
+
verdict: 'conflict' | 'disjoint' | 'unknown';
|
|
37
|
+
evidence: string[];
|
|
38
|
+
}>;
|
|
39
|
+
/** Suggested serialization order (topological sort over the conflict graph). */
|
|
40
|
+
suggested_serial_order: string[];
|
|
41
|
+
/** Tasks whose declared scope could not be resolved. */
|
|
42
|
+
unknown_scope_tasks: string[];
|
|
43
|
+
/** Whether co-change signal was used. */
|
|
44
|
+
used_cochange: boolean;
|
|
45
|
+
/** Diagnostic: did plan.json load successfully? */
|
|
46
|
+
plan_loaded: boolean;
|
|
47
|
+
/** Task ids requested by the caller but absent from the loaded plan. */
|
|
48
|
+
unknown_to_plan?: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pure executor (no createSwarmTool wrapper) so it is directly unit-testable.
|
|
52
|
+
*
|
|
53
|
+
* Reads `.swarm/plan.json` (to confirm the task ids exist) and
|
|
54
|
+
* `.swarm/scopes/scope-*.json` (via `computeParallelVerdict`). Writes nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function executePlanConflictCheck(args: {
|
|
57
|
+
task_ids: string[];
|
|
58
|
+
use_cochange?: boolean;
|
|
59
|
+
phase_id?: string;
|
|
60
|
+
}, directory: string): Promise<PlanConflictCheckResult>;
|
|
61
|
+
export declare const plan_conflict_check: ReturnType<typeof tool>;
|
|
@@ -196,6 +196,10 @@ export declare const TOOL_METADATA: {
|
|
|
196
196
|
description: string;
|
|
197
197
|
agents: "architect"[];
|
|
198
198
|
};
|
|
199
|
+
plan_conflict_check: {
|
|
200
|
+
description: string;
|
|
201
|
+
agents: "architect"[];
|
|
202
|
+
};
|
|
199
203
|
write_pr_review_trigger_eval: {
|
|
200
204
|
description: string;
|
|
201
205
|
agents: "architect"[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable merge-back conflict recovery records (#1657).
|
|
3
|
+
*
|
|
4
|
+
* When a lean-turbo lane's merge-back fails (conflict / partial / error), the
|
|
5
|
+
* runner preserves the lane's worktree + branch for manual recovery but —
|
|
6
|
+
* before this module — that information lived only in:
|
|
7
|
+
* - the in-memory `LeanTurboLane` state (lost when the session ends), and
|
|
8
|
+
* - a scrolled-away log line.
|
|
9
|
+
*
|
|
10
|
+
* Problem #1: `cleanupOrphanedBranches` (`src/worktree/merge.ts`) force-deletes
|
|
11
|
+
* any lane branch whose session isn't active, including a branch just preserved
|
|
12
|
+
* for recovery. The only copy of unmerged lane work could be deleted by routine
|
|
13
|
+
* init-time cleanup before a human ever sees the recovery message.
|
|
14
|
+
*
|
|
15
|
+
* Problem #2: `/swarm status` had no concept of preserved worktrees, so the
|
|
16
|
+
* architect was blind to pending recovery work unless it re-read the tool
|
|
17
|
+
* result inline.
|
|
18
|
+
*
|
|
19
|
+
* This module writes a durable record under `.swarm/recovery/` on every
|
|
20
|
+
* merge-back failure, lets `cleanupOrphanedBranches` EXEMPT recovery branches
|
|
21
|
+
* (fail-safe on read error), and lets `/swarm status` surface them. Records are
|
|
22
|
+
* auto-cleared when the lane later merges back successfully (no accumulation).
|
|
23
|
+
*
|
|
24
|
+
* Records live ONLY under `.swarm/recovery/` (AGENTS.md invariant 4 — `.swarm/`
|
|
25
|
+
* containment). They are intentionally NOT part of the plan ledger or
|
|
26
|
+
* turbo-state: recovery is a side-channel safety net, not authoritative plan
|
|
27
|
+
* or run state.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* A durable merge-back recovery record. Mirrors `MergeBackFailureInfo` plus
|
|
31
|
+
* the session/bookkeeping fields needed for orphan-cleanup exemption and
|
|
32
|
+
* status surfacing.
|
|
33
|
+
*/
|
|
34
|
+
export interface RecoveryRecord {
|
|
35
|
+
/** Lane identifier (e.g. "lane-1"). */
|
|
36
|
+
laneId: string;
|
|
37
|
+
/** Session that created the record (for scoping/status). */
|
|
38
|
+
sessionId: string;
|
|
39
|
+
/** Lane branch preserved for recovery (e.g. "swarm-lane/<sid>/<laneId>"). */
|
|
40
|
+
branchName?: string;
|
|
41
|
+
/** Lane worktree filesystem path preserved for recovery. */
|
|
42
|
+
worktreePath: string;
|
|
43
|
+
/** Merge-back failure class. */
|
|
44
|
+
status: 'failed' | 'partial' | 'conflict';
|
|
45
|
+
/** Human-readable reason for the merge-back failure. */
|
|
46
|
+
reason: string;
|
|
47
|
+
/** Conflict files (when status === 'conflict'). */
|
|
48
|
+
conflictFiles?: string[];
|
|
49
|
+
/** Epoch ms when the record was written. */
|
|
50
|
+
recordedAt: number;
|
|
51
|
+
/** Portable human guidance for inspecting the preserved worktree. */
|
|
52
|
+
replayHint: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write a recovery record atomically (temp file + rename, mirroring the
|
|
56
|
+
* `turbo-state.json` pattern in `src/turbo/lean/state.ts`). Best-effort:
|
|
57
|
+
* swallows errors so a recovery-write failure can never break the merge-back
|
|
58
|
+
* path that called it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function writeRecoveryRecord(directory: string, record: Omit<RecoveryRecord, 'recordedAt'> & {
|
|
61
|
+
recordedAt?: number;
|
|
62
|
+
}): void;
|
|
63
|
+
/**
|
|
64
|
+
* List all recovery records under `.swarm/recovery/`. Tolerates malformed
|
|
65
|
+
* files (skips + continues). Returns `[]` if the directory is absent or
|
|
66
|
+
* unreadable.
|
|
67
|
+
*/
|
|
68
|
+
export declare function listRecoveryRecords(directory: string): RecoveryRecord[];
|
|
69
|
+
/**
|
|
70
|
+
* Fast check: does any recovery record reference the given branch name?
|
|
71
|
+
* Used by `cleanupOrphanedBranches` to exempt recovery branches. Returns
|
|
72
|
+
* `false` on any read error (the caller decides fail-open vs fail-safe —
|
|
73
|
+
* see `cleanupOrphanedBranches`).
|
|
74
|
+
*/
|
|
75
|
+
export declare function hasRecoveryRecordForBranch(directory: string, branchName: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Remove the recovery record for a specific lane + session. Called on
|
|
78
|
+
* SUCCESSFUL merge-back so records don't accumulate (a record exists only
|
|
79
|
+
* while a lane is in a failed/preserved state). Best-effort.
|
|
80
|
+
*/
|
|
81
|
+
export declare function clearRecoveryRecord(directory: string, laneId: string, sessionId: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Did the recovery-directory read itself throw (vs simply being empty)?
|
|
84
|
+
* `cleanupOrphanedBranches` uses this to decide fail-safe behavior: on a
|
|
85
|
+
* genuine read error it skips ALL lane-branch deletions for that pass
|
|
86
|
+
* (recovery safety trumps orphan cleanliness). Returns `true` if the
|
|
87
|
+
* directory exists but could not be read, OR if any record file exists but
|
|
88
|
+
* is unreadable.
|
|
89
|
+
*/
|
|
90
|
+
export declare function recoveryReadErrored(directory: string): boolean;
|
|
@@ -25,7 +25,7 @@ import { type ModelOverride } from '../../utils/model-dispatch-fallback';
|
|
|
25
25
|
import { writeLaneEvidence, writePhaseEvidence } from './evidence';
|
|
26
26
|
import { attemptMergeBackFromDirty, getMergeStrategy, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery } from './merge-back';
|
|
27
27
|
import { planLeanTurboLanes } from './planner';
|
|
28
|
-
import type { LeanTurboLane } from './state';
|
|
28
|
+
import type { LeanTurboDegradedTask, LeanTurboLane } from './state';
|
|
29
29
|
import { loadLeanTurboRunState, saveLeanTurboRunState } from './state';
|
|
30
30
|
import { assertCleanWorkingTree, provisionWorktree, removeLaneProfileFromDiskReal, removeWorktree } from './worktree';
|
|
31
31
|
/**
|
|
@@ -152,6 +152,12 @@ export interface LeanTurboPhaseResult {
|
|
|
152
152
|
lanes: LaneResult[];
|
|
153
153
|
/** Task IDs that were degraded (risk conditions) */
|
|
154
154
|
degradedTasks: string[];
|
|
155
|
+
/**
|
|
156
|
+
* #1657: full degraded-task details (reason/files/requiredMode) so the
|
|
157
|
+
* architect sees per-task degradation reasons in the tool result, not
|
|
158
|
+
* just task IDs. Additive alongside `degradedTasks` (kept for back-compat).
|
|
159
|
+
*/
|
|
160
|
+
degradedDetails?: LeanTurboDegradedTask[];
|
|
155
161
|
/**
|
|
156
162
|
* Task IDs excluded from parallel lanes due to lock conflicts.
|
|
157
163
|
* Caller must complete these via standard serial flow before phase can advance.
|
|
@@ -323,6 +329,15 @@ export declare class LeanTurboRunner {
|
|
|
323
329
|
* the serialized tasks set for standard serial fallback.
|
|
324
330
|
*/
|
|
325
331
|
private _processLane;
|
|
332
|
+
/**
|
|
333
|
+
* Persist a durable recovery record for a merge-back / dispatch failure (#1657).
|
|
334
|
+
*
|
|
335
|
+
* Wraps `writeRecoveryRecord` (best-effort, non-fatal) with this session's
|
|
336
|
+
* id and portable human recovery guidance. Called from every failure branch of
|
|
337
|
+
* `_sequentialWorktreeCleanup`. Records are auto-cleared on successful
|
|
338
|
+
* merge-back so they exist only while a lane is preserved.
|
|
339
|
+
*/
|
|
340
|
+
private _persistRecovery;
|
|
326
341
|
/**
|
|
327
342
|
* Sequential worktree cleanup for completed and failed worktree lanes.
|
|
328
343
|
*
|
package/dist/worktree/merge.d.ts
CHANGED
|
@@ -86,6 +86,11 @@ export interface OrphanCleanupResult {
|
|
|
86
86
|
branch: string;
|
|
87
87
|
error: string;
|
|
88
88
|
}>;
|
|
89
|
+
/** #1657: lane branches skipped because a recovery record references them. */
|
|
90
|
+
skippedRecoveryBranches: string[];
|
|
91
|
+
/** #1657: set when the recovery-directory read errored and ALL lane-branch
|
|
92
|
+
* deletions were skipped this pass (fail-safe). */
|
|
93
|
+
recoveryReadError?: boolean;
|
|
89
94
|
}
|
|
90
95
|
export interface StartupRecoveryResult {
|
|
91
96
|
prunedWorktrees: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.132.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",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export interface TaskNode {
|
|
2
|
-
id: string;
|
|
3
|
-
phase: number;
|
|
4
|
-
description: string;
|
|
5
|
-
depends: string[];
|
|
6
|
-
dependents: string[];
|
|
7
|
-
status: 'pending' | 'in_progress' | 'complete' | 'blocked';
|
|
8
|
-
}
|
|
9
|
-
export interface DependencyGraph {
|
|
10
|
-
tasks: Map<string, TaskNode>;
|
|
11
|
-
phases: Map<number, string[]>;
|
|
12
|
-
roots: string[];
|
|
13
|
-
leaves: string[];
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Parse plan.json and build dependency graph
|
|
17
|
-
*/
|
|
18
|
-
export declare function parseDependencyGraph(planPath: string): DependencyGraph;
|
|
19
|
-
/**
|
|
20
|
-
* Get tasks that can run in parallel (no unresolved dependencies)
|
|
21
|
-
*/
|
|
22
|
-
export declare function getRunnableTasks(graph: DependencyGraph): string[];
|
|
23
|
-
/**
|
|
24
|
-
* Check if a task is blocked (has incomplete dependencies)
|
|
25
|
-
*/
|
|
26
|
-
export declare function isTaskBlocked(graph: DependencyGraph, taskId: string): boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Get execution order (topological sort)
|
|
29
|
-
*/
|
|
30
|
-
export declare function getExecutionOrder(graph: DependencyGraph): string[];
|
|
31
|
-
/**
|
|
32
|
-
* Find all paths from root to a task
|
|
33
|
-
*/
|
|
34
|
-
export declare function getDependencyChain(graph: DependencyGraph, taskId: string): string[];
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export interface MetaSummaryEntry {
|
|
2
|
-
timestamp: string;
|
|
3
|
-
phase?: number;
|
|
4
|
-
taskId?: string;
|
|
5
|
-
agent?: string;
|
|
6
|
-
summary: string;
|
|
7
|
-
source?: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Extract meta.summary from event JSONL files
|
|
11
|
-
*/
|
|
12
|
-
export declare function extractMetaSummaries(eventsPath: string): MetaSummaryEntry[];
|
|
13
|
-
/**
|
|
14
|
-
* Index meta summaries to external knowledge store
|
|
15
|
-
*/
|
|
16
|
-
export declare function indexMetaSummaries(directory: string, externalKnowledgeDir?: string): Promise<{
|
|
17
|
-
indexed: number;
|
|
18
|
-
path: string;
|
|
19
|
-
}>;
|
|
20
|
-
/**
|
|
21
|
-
* Query indexed summaries
|
|
22
|
-
*/
|
|
23
|
-
export declare function querySummaries(directory: string, options?: {
|
|
24
|
-
phase?: number;
|
|
25
|
-
taskId?: string;
|
|
26
|
-
agent?: string;
|
|
27
|
-
since?: string;
|
|
28
|
-
}): MetaSummaryEntry[];
|
|
29
|
-
/**
|
|
30
|
-
* Get latest summary for a task
|
|
31
|
-
*/
|
|
32
|
-
export declare function getLatestTaskSummary(directory: string, taskId: string): MetaSummaryEntry | undefined;
|