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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/{config-doctor-rjvb0hhn.js → config-doctor-3rssa871.js} +2 -2
  3. package/dist/cli/{curation-policy-f5bybzmh.js → curation-policy-3914h3g9.js} +2 -2
  4. package/dist/cli/{curator-kjzqa5m7.js → curator-1e77dq6x.js} +12 -12
  5. package/dist/cli/{curator-llm-factory-ezq4fakt.js → curator-llm-factory-41c17ybs.js} +12 -12
  6. package/dist/cli/{guardrail-explain-n93qh8k6.js → guardrail-explain-624brj1y.js} +13 -13
  7. package/dist/cli/{guardrail-log-h4tmcjwx.js → guardrail-log-vfka4tcn.js} +3 -3
  8. package/dist/cli/{hive-promoter-mammxe5p.js → hive-promoter-mw5prfy2.js} +12 -12
  9. package/dist/cli/{index-1atz85c8.js → index-2dtwjx39.js} +1 -1
  10. package/dist/cli/{index-hynbzh7s.js → index-5x3g1q91.js} +4 -0
  11. package/dist/cli/{index-cnwh164k.js → index-64z5dvam.js} +1 -1
  12. package/dist/cli/{index-q68sprcy.js → index-6mcx76j9.js} +4 -4
  13. package/dist/cli/{index-d2tgc580.js → index-8w3sp149.js} +1420 -1313
  14. package/dist/cli/{index-6vg0qczz.js → index-99tq1zd5.js} +2 -2
  15. package/dist/cli/{index-01nyrk95.js → index-e630fw43.js} +3 -3
  16. package/dist/cli/{index-tw33v84d.js → index-exs5bt14.js} +1 -1
  17. package/dist/cli/{index-cq22pnd2.js → index-fegng5pv.js} +1 -1
  18. package/dist/cli/{index-fepakwhp.js → index-nsxchdx0.js} +1 -1
  19. package/dist/cli/{index-m6zfm7cm.js → index-ppkp20fp.js} +5 -5
  20. package/dist/cli/{index-kbfhyxtv.js → index-q0ysv66x.js} +1 -1
  21. package/dist/cli/{index-xhd797bz.js → index-qg1cj1ev.js} +14 -14
  22. package/dist/cli/{index-pft1qxqh.js → index-sbq3gbjs.js} +1 -1
  23. package/dist/cli/{index-xv2ydncg.js → index-zah4qws8.js} +2 -2
  24. package/dist/cli/{index-szkswbqf.js → index-zrh07ykv.js} +2 -2
  25. package/dist/cli/index.js +12 -12
  26. package/dist/cli/{knowledge-escalator-cf1kkmfe.js → knowledge-escalator-5hv2dwhz.js} +3 -3
  27. package/dist/cli/{knowledge-events-p8t5ev44.js → knowledge-events-434663dp.js} +1 -1
  28. package/dist/cli/{knowledge-store-vpdmcwem.js → knowledge-store-73ykq5j3.js} +1 -1
  29. package/dist/cli/{knowledge-validator-w1t0sw5f.js → knowledge-validator-tnadtt1h.js} +4 -4
  30. package/dist/cli/{scan-cursor-z4c51902.js → scan-cursor-e33n9pej.js} +2 -2
  31. package/dist/cli/{schema-yqzzfavj.js → schema-1kwmcayk.js} +1 -1
  32. package/dist/cli/{skill-generator-aaabj00n.js → skill-generator-k111qfdw.js} +5 -5
  33. package/dist/index.js +348 -348
  34. package/dist/parallel/index.d.ts +0 -2
  35. package/dist/plan/parallel-verdict.d.ts +94 -0
  36. package/dist/services/status-service.d.ts +14 -0
  37. package/dist/tools/index.d.ts +1 -0
  38. package/dist/tools/lean-turbo-run-phase.d.ts +7 -0
  39. package/dist/tools/manifest.d.ts +1 -0
  40. package/dist/tools/plan-conflict-check.d.ts +61 -0
  41. package/dist/tools/tool-metadata.d.ts +4 -0
  42. package/dist/turbo/lean/recovery.d.ts +90 -0
  43. package/dist/turbo/lean/runner.d.ts +16 -1
  44. package/dist/worktree/merge.d.ts +5 -0
  45. package/package.json +1 -1
  46. package/dist/parallel/dependency-graph.d.ts +0 -34
  47. package/dist/parallel/meta-indexer.d.ts +0 -32
@@ -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
  /**
@@ -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;
@@ -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
  *
@@ -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.131.0",
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;