opencode-swarm 7.184.0 → 7.184.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.
Files changed (112) hide show
  1. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  2. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  3. package/dist/background/delegation-health.d.ts +1 -1
  4. package/dist/background/index.d.ts +1 -0
  5. package/dist/background/pr-event-delivery.d.ts +29 -14
  6. package/dist/background/pr-event-subscribers.d.ts +6 -5
  7. package/dist/background/pr-feedback-event-queue.d.ts +19 -2
  8. package/dist/background/pr-feedback-loop-runtime.d.ts +75 -0
  9. package/dist/background/pr-feedback-loop.d.ts +47 -12
  10. package/dist/cli/{coder-settlement-vrc5zxvv.js → coder-settlement-yvpewr52.js} +15 -12
  11. package/dist/cli/{config-doctor-y0bpap07.js → config-doctor-qgwpvrbz.js} +2 -2
  12. package/dist/cli/{core-7f955h2f.js → core-9qt388hq.js} +4 -4
  13. package/dist/cli/{curation-policy-fa2h82c4.js → curation-policy-49f8jx48.js} +7 -6
  14. package/dist/cli/{curator-drift-48x02n2m.js → curator-drift-wf0sm2te.js} +9 -9
  15. package/dist/cli/{curator-m7enwwz2.js → curator-ffz5pxgc.js} +40 -39
  16. package/dist/cli/curator-llm-factory-drs36v1q.js +75 -0
  17. package/dist/cli/{dispatch-p5zjg5e6.js → dispatch-cv89p2y1.js} +1 -1
  18. package/dist/cli/{evidence-summary-service-k8a5vkfk.js → evidence-summary-service-8dfzjnxe.js} +21 -20
  19. package/dist/cli/{gate-evidence-nktrs0w2.js → gate-evidence-aa5q30f4.js} +14 -7
  20. package/dist/cli/guardrail-explain-9g5y2gjm.js +76 -0
  21. package/dist/cli/{guardrail-log-dppv6tgn.js → guardrail-log-0g51p94w.js} +8 -8
  22. package/dist/cli/{guardrail-reset-btzq4ses.js → guardrail-reset-dcbmt2wr.js} +40 -39
  23. package/dist/cli/{hive-promoter-yp1baj9z.js → hive-promoter-2g8nga0y.js} +40 -39
  24. package/dist/cli/{index-r30xs0wp.js → index-046psajf.js} +1 -1
  25. package/dist/cli/{index-ysr6n4ca.js → index-0874kghs.js} +1 -1
  26. package/dist/cli/{index-6h81yvyc.js → index-131ay7x1.js} +3 -3
  27. package/dist/cli/{index-4gr9pj67.js → index-2c91cxdv.js} +4 -4
  28. package/dist/cli/{index-pq6vr26z.js → index-32vszgv0.js} +3 -3
  29. package/dist/cli/{index-0bpr8vag.js → index-3n5zsp31.js} +2 -2
  30. package/dist/cli/{index-152b9c6m.js → index-3skvygca.js} +5 -5
  31. package/dist/cli/{index-w81jmdkt.js → index-456awy1p.js} +2 -2
  32. package/dist/cli/{index-74x26wyj.js → index-475bkab8.js} +2 -2
  33. package/dist/cli/{index-t1swv35d.js → index-49ptc9xx.js} +1 -1
  34. package/dist/cli/{index-nm8ma9xb.js → index-57swfxyp.js} +8 -8
  35. package/dist/cli/{index-me39468k.js → index-5ppx86w1.js} +38 -18
  36. package/dist/cli/{index-njf5pbkm.js → index-6b427dy8.js} +6 -6
  37. package/dist/cli/{index-edrgc139.js → index-6cvdk98y.js} +2 -2
  38. package/dist/cli/{index-4t0wd9sv.js → index-6g664sy8.js} +1 -1
  39. package/dist/cli/{index-t26gj2fh.js → index-76abqm8d.js} +2 -2
  40. package/dist/cli/{index-nvm6mxep.js → index-7hvy33gc.js} +271 -80
  41. package/dist/cli/{index-6b4vkz6q.js → index-7p4ym4q3.js} +1 -1
  42. package/dist/cli/{index-rwfmx7vn.js → index-aghd9kcx.js} +2 -2
  43. package/dist/cli/{index-e90m050y.js → index-ar2gsn6b.js} +8 -8
  44. package/dist/cli/{index-fs9y88h1.js → index-dbshccrr.js} +3 -3
  45. package/dist/cli/{index-ad3yskxy.js → index-depfky1j.js} +158 -27
  46. package/dist/cli/{index-v3hpsxvd.js → index-earq3mda.js} +1 -1
  47. package/dist/cli/{index-b5mkznms.js → index-ejb7ejhd.js} +1 -1
  48. package/dist/cli/{index-3rb5gs4w.js → index-f0nj3d8z.js} +1 -1
  49. package/dist/cli/{index-5wk0etp8.js → index-gsgy1psq.js} +4 -4
  50. package/dist/cli/{index-qyx53xrz.js → index-jc8pcf0r.js} +7 -7
  51. package/dist/cli/{index-3fhg7pqf.js → index-jkxef52n.js} +2 -2
  52. package/dist/cli/{index-mn5zzmqx.js → index-jvk95e6y.js} +2 -2
  53. package/dist/cli/{index-5cve9g2b.js → index-k53a69vb.js} +6 -6
  54. package/dist/cli/{index-1xnse449.js → index-mc72pk74.js} +1 -1
  55. package/dist/cli/{index-bf1726rj.js → index-mz4zz59c.js} +42 -41
  56. package/dist/cli/{index-j40czc9v.js → index-n107956q.js} +5 -5
  57. package/dist/cli/{index-z3b157ew.js → index-qczxr0wh.js} +12 -10
  58. package/dist/cli/{index-9yvjwfay.js → index-s7bseqza.js} +3156 -1887
  59. package/dist/cli/{index-01wt209s.js → index-t7hmqgjy.js} +90 -141
  60. package/dist/cli/{index-08x7gsnf.js → index-w9hxzcz4.js} +2 -2
  61. package/dist/cli/{index-51xtrf7g.js → index-wfdx7yw2.js} +39 -15
  62. package/dist/cli/{index-079xzcxb.js → index-wsb0wbw6.js} +40 -39
  63. package/dist/cli/{index-nmh0s6dg.js → index-wy3zpwjy.js} +1 -1
  64. package/dist/cli/{index-fbhtb6f5.js → index-x1gyqgze.js} +7 -7
  65. package/dist/cli/index-xf69xty9.js +105 -0
  66. package/dist/cli/{index-z8smhv7k.js → index-ya32wfkp.js} +4 -2
  67. package/dist/cli/{index-46z4c89b.js → index-yk0r42nr.js} +4 -4
  68. package/dist/cli/{index-1d6ssjcj.js → index-zzvxj02e.js} +3 -3
  69. package/dist/cli/index.js +41 -40
  70. package/dist/cli/{knowledge-escalator-4296y1h2.js → knowledge-escalator-pt21q3eh.js} +14 -13
  71. package/dist/cli/{knowledge-events-31nga9yt.js → knowledge-events-hp96b55k.js} +12 -11
  72. package/dist/cli/{knowledge-link-ydpvzam8.js → knowledge-link-ap2274vm.js} +6 -5
  73. package/dist/cli/{knowledge-store-0qz3zmq3.js → knowledge-store-rnw1e7zp.js} +7 -6
  74. package/dist/cli/{knowledge-validator-vndnwdj6.js → knowledge-validator-xy7r6eyx.js} +9 -8
  75. package/dist/cli/{mcp-taace90a.js → mcp-3nd85kww.js} +15 -1
  76. package/dist/cli/mcp.d.ts +1 -0
  77. package/dist/cli/{model-preflight-bv8nvjjx.js → model-preflight-xe0chjad.js} +40 -39
  78. package/dist/cli/{pending-delegations-kwdk8j9d.js → pending-delegations-2pdngdzq.js} +13 -12
  79. package/dist/cli/{pr-subscriptions-w2fwdpkk.js → pr-subscriptions-hxxwszyr.js} +13 -12
  80. package/dist/cli/{pr-workflow-gate-sqjc6jmd.js → pr-workflow-gate-m37ynr6h.js} +40 -39
  81. package/dist/cli/{runner-r6gxq7m1.js → runner-yz3ysehf.js} +7 -6
  82. package/dist/cli/{scan-cursor-f74b9b4k.js → scan-cursor-be9hbq1v.js} +8 -7
  83. package/dist/cli/{schema-cyet68tw.js → schema-j17hv98z.js} +1 -1
  84. package/dist/cli/{scope-persistence-rg8v0r8q.js → scope-persistence-rmt56rma.js} +16 -15
  85. package/dist/cli/{server-765s4stz.js → server-wzrb59mh.js} +40 -39
  86. package/dist/cli/{skill-generator-qg5m18k7.js → skill-generator-vsfya55z.js} +16 -15
  87. package/dist/cli/{snapshot-coordination-init-zzs4bkmj.js → snapshot-coordination-init-pc8ykvh8.js} +40 -39
  88. package/dist/cli/{speckit-checkoff-2bsm6p0c.js → speckit-checkoff-j407j8ew.js} +4 -4
  89. package/dist/cli/{telemetry-rzvcp2n9.js → telemetry-39zmx4fp.js} +2 -2
  90. package/dist/cli/{workspace-snapshot-t22m6gbd.js → workspace-snapshot-0q1n1xq5.js} +4 -4
  91. package/dist/cli/{worktree-collision-ownership-qf2shp2n.js → worktree-collision-ownership-je4fb407.js} +14 -13
  92. package/dist/cli/{worktree-isolation-0b0jy6dt.js → worktree-isolation-27rt584e.js} +40 -39
  93. package/dist/db/qa-gate-session-override.d.ts +12 -12
  94. package/dist/gate-evidence.d.ts +43 -1
  95. package/dist/hooks/guardrails/index.d.ts +13 -7
  96. package/dist/index.js +507 -503
  97. package/dist/plan/ledger.d.ts +20 -4
  98. package/dist/plan/manager.d.ts +20 -2
  99. package/dist/session/hydration-ownership.d.ts +39 -12
  100. package/dist/session/snapshot-coordination-init.d.ts +11 -4
  101. package/dist/session/snapshot-reader.d.ts +9 -4
  102. package/dist/session/snapshot-writer.d.ts +2 -3
  103. package/dist/state.d.ts +35 -5
  104. package/dist/tools/phase-complete.d.ts +1 -0
  105. package/dist/tools/update-task-status.d.ts +1 -1
  106. package/dist/utils/project-boundary.d.ts +32 -1
  107. package/dist/workflow/coder-settlement.d.ts +8 -0
  108. package/dist/workflow/task-terminal.d.ts +2 -1
  109. package/dist/workflow/workflow-wal-schema.d.ts +2 -0
  110. package/package.json +1 -1
  111. package/dist/cli/curator-llm-factory-g6at4hn6.js +0 -74
  112. package/dist/cli/guardrail-explain-1ccchxdr.js +0 -75
@@ -226,7 +226,9 @@ export declare function readLedgerEvents(directory: string): Promise<LedgerEvent
226
226
  * @param directory - The working directory
227
227
  * @param planId - Unique identifier for the plan
228
228
  */
229
- export declare function initLedger(directory: string, planId: string, initialPlanHash?: string, initialPlan?: Plan): Promise<void>;
229
+ export declare function initLedger(directory: string, planId: string, initialPlanHash?: string, initialPlan?: Plan, options?: {
230
+ preCommitCheck?: () => void;
231
+ }): Promise<void>;
230
232
  /**
231
233
  * Read and validate the current plan epoch identity without creating,
232
234
  * adopting, or appending any ledger state.
@@ -264,6 +266,8 @@ export declare function appendLedgerEvent(directory: string, eventInput: LedgerE
264
266
  */
265
267
  expectedLedgerHash?: string;
266
268
  planHashAfter?: string;
269
+ /** Synchronous authority fence inside the evidence lock. */
270
+ preCommitCheck?: () => void;
267
271
  }): Promise<LedgerEvent>;
268
272
  /**
269
273
  * Append a ledger event with optimistic retry on stale-writer conflicts.
@@ -303,6 +307,7 @@ export declare function appendLedgerEventWithRetry(directory: string, eventInput
303
307
  maxRetries?: number;
304
308
  backoffMs?: number;
305
309
  verifyValid?: () => Promise<boolean> | boolean;
310
+ preCommitCheck?: () => void;
306
311
  }): Promise<LedgerEvent | null>;
307
312
  /**
308
313
  * Take a snapshot with bounded retry and always-visible warning logging (FR-004).
@@ -351,6 +356,8 @@ export declare function takeSnapshotEvent(directory: string, plan: Plan, options
351
356
  expectedSeq?: number;
352
357
  /** Previous durable hash used to preserve the ledger hash chain. */
353
358
  expectedLedgerHash?: string;
359
+ /** Synchronous authority fence immediately before ledger append. */
360
+ preCommitCheck?: () => void;
354
361
  }): Promise<LedgerEvent>;
355
362
  export interface TruncatedLedgerRecoveryResult {
356
363
  archivePath: string;
@@ -379,13 +386,17 @@ export declare function clearPlanLedgerForReset(directory: string): Promise<void
379
386
  * Existing JSONL bytes are content-addressed before the SQLite transaction;
380
387
  * the portable export is published only after the new SQLite root commits.
381
388
  */
382
- export declare function replacePlanLedgerWithRoot(directory: string, plan: Plan, source: string): Promise<void>;
389
+ export declare function replacePlanLedgerWithRoot(directory: string, plan: Plan, source: string, options?: {
390
+ preCommitCheck?: () => void;
391
+ }): Promise<void>;
383
392
  /**
384
393
  * Options for replayFromLedger
385
394
  */
386
395
  interface ReplayOptions {
387
396
  /** If true, use the latest snapshot to speed up replay */
388
397
  useSnapshot?: boolean;
398
+ /** Optional authority fence for recovery-side durable publications. */
399
+ preCommitCheck?: () => void;
389
400
  }
390
401
  /**
391
402
  * Result of a status-aware ledger replay.
@@ -449,7 +460,8 @@ export declare function peekPlanFromLedger(directory: string, _options?: ReplayO
449
460
  * `replayWithIntegrity`'s bug — it hid genuine replay failures).
450
461
  *
451
462
  * @param directory - The working directory
452
- * @param _options - Optional replay options (reserved)
463
+ * @param _options - Optional replay options, including an authority fence for
464
+ * recovery-side quarantine publications
453
465
  * @returns {@link ReplayStatusResult} with plan, truncated flag, and bad suffix
454
466
  */
455
467
  export declare function replayFromLedgerWithStatus(directory: string, _options?: ReplayOptions): Promise<ReplayStatusResult>;
@@ -526,10 +538,14 @@ export interface QuarantineResult {
526
538
  *
527
539
  * @param directory - The working directory
528
540
  * @param badSuffix - The corrupted content to quarantine
541
+ * @param options - Optional authority fence checked immediately before writing
542
+ * the quarantine side file
529
543
  * @returns {@link QuarantineResult} with the written path (or null) and the
530
544
  * number of parseable lines salvaged from the suffix
531
545
  */
532
- export declare function quarantineLedgerSuffix(directory: string, badSuffix: string): Promise<QuarantineResult>;
546
+ export declare function quarantineLedgerSuffix(directory: string, badSuffix: string, options?: {
547
+ preCommitCheck?: () => void;
548
+ }): Promise<QuarantineResult>;
533
549
  /**
534
550
  * Metadata describing an approved snapshot recovered from the ledger.
535
551
  */
@@ -6,6 +6,15 @@
6
6
  export declare class PlanConcurrentModificationError extends Error {
7
7
  constructor(message: string);
8
8
  }
9
+ /**
10
+ * Internal control-flow error used to stop every recovery rung when the
11
+ * coordinator's captured hydration generation is no longer authoritative.
12
+ * Broad availability catches must rethrow this instead of trying a fallback
13
+ * that could publish stale durable state.
14
+ */
15
+ export declare class PlanRecoverySupersededError extends Error {
16
+ constructor(message?: string);
17
+ }
9
18
  /**
10
19
  * Thrown when savePlan detects that the incoming plan would silently drop one
11
20
  * or more tasks from the prior plan without the caller acknowledging the
@@ -61,6 +70,7 @@ export declare const _internals: {
61
70
  readPlanJsonUtf8: typeof readPlanJsonUtf8;
62
71
  readPlanFileUtf8: typeof readPlanFileUtf8;
63
72
  verifyWrittenPlanJson: typeof verifyWrittenPlanJson;
73
+ writeRebuildPlanMarkdown: typeof writeRebuildPlanMarkdown;
64
74
  ledgerExists: typeof ledgerExists;
65
75
  replayFromLedger: typeof replayFromLedger;
66
76
  loadLastApprovedPlan: typeof loadLastApprovedPlan;
@@ -91,6 +101,7 @@ export declare function retryCasWithBackoff(directory: string, eventInput: Ledge
91
101
  planHashAfter?: string;
92
102
  verifyValid?: () => Promise<boolean> | boolean;
93
103
  maxRetries?: number;
104
+ preCommitCheck?: () => void;
94
105
  }): Promise<LedgerEvent | null>;
95
106
  /**
96
107
  * Load plan.json ONLY without auto-migration from plan.md.
@@ -114,7 +125,9 @@ export declare function isPlanMdInSync(directory: string, plan: Plan, cache?: Ma
114
125
  /**
115
126
  * Regenerate plan.md from valid plan.json (auto-heal case 1).
116
127
  */
117
- export declare function regeneratePlanMarkdown(directory: string, plan: Plan): Promise<void>;
128
+ export declare function regeneratePlanMarkdown(directory: string, plan: Plan, options?: {
129
+ preCommitCheck?: () => void;
130
+ }): Promise<void>;
118
131
  /**
119
132
  * Load and validate plan from .swarm/plan.json with auto-heal sync.
120
133
  *
@@ -128,7 +141,9 @@ export declare function regeneratePlanMarkdown(directory: string, plan: Plan): P
128
141
  * 3. .swarm/plan.md exists only -> migrate from plan.md, save both files, return Plan
129
142
  * 4. Neither exists -> return null
130
143
  */
131
- export declare function loadPlan(directory: string, cache?: Map<string, Promise<string | null>>): Promise<RuntimePlan | null>;
144
+ export declare function loadPlan(directory: string, cache?: Map<string, Promise<string | null>>, options?: {
145
+ preCommitCheck?: () => void;
146
+ }): Promise<RuntimePlan | null>;
132
147
  /**
133
148
  * Recovery-path helper for callers that legitimately need to replace the
134
149
  * plan task set without explicit per-id acknowledgement (e.g. rebuilding
@@ -146,6 +161,7 @@ export declare function loadPlan(directory: string, cache?: Map<string, Promise<
146
161
  export declare function savePlanWithAutoAcknowledgedRemovals(directory: string, plan: Plan, source: string, reason: string, options?: {
147
162
  preserveCompletedStatuses?: boolean;
148
163
  planLockAlreadyHeld?: boolean;
164
+ preCommitCheck?: () => void;
149
165
  }): Promise<{
150
166
  removedCount: number;
151
167
  }>;
@@ -216,6 +232,7 @@ export declare function savePlan(directory: string, plan: Plan, options?: {
216
232
  */
217
233
  preCommitCheck?: () => void;
218
234
  }): Promise<PlanSaveDurability>;
235
+ declare function writeRebuildPlanMarkdown(tempPath: string, content: string): Promise<void>;
219
236
  /**
220
237
  * Rebuild plan from ledger events.
221
238
  * Replays the ledger to reconstruct plan state, then writes the result.
@@ -226,6 +243,7 @@ export declare function savePlan(directory: string, plan: Plan, options?: {
226
243
  */
227
244
  export declare function rebuildPlan(directory: string, plan?: Plan, options?: {
228
245
  reason?: string;
246
+ preCommitCheck?: () => void;
229
247
  }): Promise<Plan | null>;
230
248
  /**
231
249
  * Write terminal plan state through the managed write path (FR-002, FR-005, FR-006).
@@ -1,13 +1,15 @@
1
1
  /**
2
- * Project-owned, generation-fenced hydration state (issue #2667).
2
+ * Project-owned, authority-fenced hydration state (issues #2667/#2668).
3
3
  *
4
4
  * The live maps on `swarmState` are process-resident and keyed by sessionID;
5
5
  * hydration is a per-PROJECT operation. This module owns the per-project
6
6
  * registries that scope a hydration's blast radius to the project that
7
7
  * initiated it and fence stale generations from publishing over newer state:
8
8
  *
9
- * - `projectHydrationGenerations` — monotonic counter per canonical project
10
- * key, bumped ONLY when a hydration is initiated (`beginHydrationScope`).
9
+ * - `projectHydrationAuthorities` — bounded records containing a per-project
10
+ * generation and a process-monotonic authority epoch. The generation is
11
+ * bumped ONLY when a hydration is initiated (`beginHydrationScope`), while
12
+ * the epoch changes whenever an evicted/reset project is reintroduced.
11
13
  * Session creation NEVER bumps it; new sessions stamp `current + 1` so a
12
14
  * session created while generation `g` is latest survives any later apply
13
15
  * at `g`.
@@ -16,10 +18,12 @@
16
18
  * - `hydratedAggregateKeys` — the toolAggregates keys each project's last
17
19
  * hydration published, so a re-hydration replaces only its own keys.
18
20
  *
19
- * Fence rule: a hydration whose scope generation `g` satisfies
20
- * `projectHydrationGenerations[K] > g` is REJECTED before any mutation
21
- * some newer hydration began for that project. Stamp rule: an accepted
22
- * hydration at `g` evicts only sessions owned by `K` with
21
+ * Fence rule: a hydration is current only while both its generation and its
22
+ * authority epoch match the bounded record for its project. This prevents an
23
+ * evicted project entry from being reintroduced with a numerically reused
24
+ * generation and accidentally reviving an old scope (ABA). Session stamp
25
+ * rule: an accepted hydration at `{ generation: g, authorityEpoch: e }`
26
+ * evicts owned sessions from an older epoch, or sessions in epoch `e` with
23
27
  * `hydrationStamp <= g`.
24
28
  *
25
29
  * All maps are bounded (FIFO) with an explicit reset path
@@ -32,10 +36,17 @@ export declare const MAX_TRACKED_PROJECTS = 32;
32
36
  export declare const MAX_DIRECTORY_KEY_MEMO = 64;
33
37
  /** Opaque cache payload owned by state.ts; opaque here by design. */
34
38
  export type ProjectRehydrationCache = unknown;
39
+ /** Opaque process-local authority token for a project's current record. */
40
+ export interface HydrationAuthorityToken {
41
+ projectKey: string;
42
+ generation: number;
43
+ authorityEpoch: number;
44
+ }
35
45
  /** Fence token captured when a hydration is initiated; see beginHydrationScope. */
36
46
  export interface HydrationScope {
37
47
  projectKey: string;
38
48
  generation: number;
49
+ authorityEpoch: number;
39
50
  }
40
51
  /**
41
52
  * Resolve the canonical project key for a directory spelling through a
@@ -58,8 +69,8 @@ export interface HydrationScope {
58
69
  */
59
70
  export declare function hydrationProjectKey(directory: string): string;
60
71
  /**
61
- * Begin a hydration scope: bump the project's generation counter and return
62
- * the fence token. The token must be captured when the hydration is
72
+ * Begin a hydration scope: bump the project's generation, mint a non-reusable
73
+ * authority, and return the fence token. The token must be captured when the hydration is
63
74
  * INITIATED (e.g. at `loadSnapshot` entry) and carried into
64
75
  * `rehydrateState`, which refuses to apply it once any newer generation has
65
76
  * begun.
@@ -67,6 +78,22 @@ export declare function hydrationProjectKey(directory: string): string;
67
78
  export declare function beginHydrationScope(directory: string): HydrationScope;
68
79
  /** Latest initiated hydration generation for a project (0 when never). */
69
80
  export declare function currentHydrationGeneration(projectKey: string): number;
81
+ /**
82
+ * Capture the current project authority without beginning a hydration. This
83
+ * is used by direct session rehydration, which needs an exact record to fence
84
+ * across awaits but must preserve the session-creation/no-generation-bump
85
+ * contract.
86
+ */
87
+ export declare function captureCurrentHydrationAuthority(projectKey: string): HydrationAuthorityToken;
88
+ /** Return whether an exact authority token still names the current record. */
89
+ export declare function isHydrationAuthorityCurrent(authority: HydrationAuthorityToken): boolean;
90
+ /**
91
+ * Return whether a captured hydration scope is still the latest initiated
92
+ * scope for its project. Exact generation+epoch equality is intentional: a
93
+ * scope whose project registry entry was evicted or reset is no longer current
94
+ * either, even if a numerically equal generation is visible at the check.
95
+ */
96
+ export declare function isHydrationScopeCurrent(scope: HydrationScope): boolean;
70
97
  /**
71
98
  * Stamp value for a session created NOW under `projectKey`:
72
99
  * `current + 1`, i.e. newer than any already-initiated hydration, so an
@@ -74,10 +101,10 @@ export declare function currentHydrationGeneration(projectKey: string): number;
74
101
  */
75
102
  export declare function nextSessionHydrationStamp(projectKey: string): number;
76
103
  export declare function getRehydrationCache(projectKey: string): ProjectRehydrationCache | undefined;
77
- export declare function setRehydrationCache(projectKey: string, cache: ProjectRehydrationCache): void;
104
+ export declare function setRehydrationCache(projectKey: string, cache: ProjectRehydrationCache, authority?: HydrationAuthorityToken): boolean;
78
105
  /** Record the aggregate keys a project's hydration published (replace set). */
79
- export declare function recordHydratedAggregateKeys(projectKey: string, keys: Set<string>): void;
106
+ export declare function recordHydratedAggregateKeys(projectKey: string, keys: Set<string>, authority?: HydrationAuthorityToken): boolean;
80
107
  /** The aggregate keys the project's last hydration published (empty if none). */
81
- export declare function hydratedAggregateKeysFor(projectKey: string): Set<string>;
108
+ export declare function hydratedAggregateKeysFor(projectKey: string, authority?: HydrationAuthorityToken): Set<string>;
82
109
  /** Reset every registry (invariant 8: bounded state with an explicit reset). */
83
110
  export declare function clearHydrationOwnershipState(): void;
@@ -1,7 +1,11 @@
1
1
  /** Post-resolution SQLite snapshot import/readiness lifecycle (#2481). */
2
+ import { loadPlan } from '../plan/manager.js';
2
3
  import { type HydrationScope } from './hydration-ownership.js';
3
- import type { SnapshotData } from './snapshot-writer.js';
4
- type ReadinessState = 'running' | 'succeeded' | 'failed' | 'timed_out' | 'closing';
4
+ import { readSnapshotFileStrict } from './snapshot-reader.js';
5
+ import { importSnapshotRowsOnce } from './snapshot-store.js';
6
+ import { writeSnapshotProjection } from './snapshot-writer.js';
7
+ type ReadinessState = 'running' | 'succeeded' | 'superseded' | 'failed' | 'timed_out' | 'closing';
8
+ export type SnapshotCoordinationInitializationOutcome = 'succeeded' | 'superseded';
5
9
  interface ReadinessEntry {
6
10
  attemptId: number;
7
11
  generation: number;
@@ -42,9 +46,12 @@ export declare function closeSnapshotCoordinationInitialization(directory: strin
42
46
  export declare function markSnapshotCoordinationClosing(directory: string): void;
43
47
  export declare const _snapshotCoordinationInternals: {
44
48
  entries: Map<string, ReadinessEntry>;
45
- initialize: (directory: string, scope?: HydrationScope) => Promise<void>;
49
+ initialize: (directory: string, scope?: HydrationScope) => Promise<SnapshotCoordinationInitializationOutcome>;
50
+ loadPlan: typeof loadPlan;
51
+ readSnapshotFileStrict: typeof readSnapshotFileStrict;
52
+ importSnapshotRowsOnce: typeof importSnapshotRowsOnce;
46
53
  renameLegacySnapshot: (from: string, to: string) => void;
47
- writeProjection: (directory: string, snapshot: SnapshotData) => Promise<void>;
54
+ writeProjection: typeof writeSnapshotProjection;
48
55
  timeoutMs: number;
49
56
  };
50
57
  export {};
@@ -4,7 +4,11 @@
4
4
  */
5
5
  import type { AgentSessionState } from '../state';
6
6
  import { type HydrationScope } from './hydration-ownership.js';
7
+ import { recordInterruptedExecution } from './restart-reconciliation.js';
7
8
  import type { SerializedAgentSession, SnapshotData } from './snapshot-writer';
9
+ export declare const _internals: {
10
+ recordInterruptedExecution: typeof recordInterruptedExecution;
11
+ };
8
12
  /**
9
13
  * Transient session fields that must be reset on rehydration.
10
14
  * Centralised here to keep the reset logic DRY and auditable.
@@ -35,9 +39,10 @@ export declare function readSnapshotFileStrict(directory: string, relativePath:
35
39
  /**
36
40
  * Rehydrate swarmState from a SnapshotData object.
37
41
  *
38
- * Issue #2667 — project-owned and generation-fenced:
42
+ * Issues #2667/#2668 — project-owned and authority-fenced:
39
43
  * - With a `directory`, this replaces ONLY the state owned by that project
40
- * (sessions whose `owningProjectKey` matches and whose `hydrationStamp` is
44
+ * (sessions whose `owningProjectKey` matches and whose authority epoch is
45
+ * older than the applying epoch, or whose current-epoch `hydrationStamp` is
41
46
  * at or below the applying generation). Other projects' live state — and
42
47
  * this project's sessions created after the hydration began — survive.
43
48
  * - With an explicit `scope` captured at initiation, the apply is refused
@@ -66,8 +71,8 @@ export declare function rehydrateState(snapshot: SnapshotData, directory?: strin
66
71
  * Called on plugin init to restore state from previous session.
67
72
  * NEVER throws - swallows any errors silently.
68
73
  *
69
- * Issue #2667: a hydration scope is captured at entry so the eventual
70
- * rehydrateState apply is generation-fenced — a loadSnapshot whose 5 s init
74
+ * Issues #2667/#2668: a hydration scope is captured at entry so the eventual
75
+ * rehydrateState apply is authority-fenced — a loadSnapshot whose 5 s init
71
76
  * timeout (src/index.ts) abandoned the await is refused once any newer
72
77
  * hydration for the same project has begun.
73
78
  */
@@ -3,7 +3,6 @@
3
3
  * Persists swarmState as independently keyed SQLite coordination rows and a
4
4
  * non-authoritative, versioned file projection.
5
5
  */
6
- import { rename as fsRename } from 'node:fs/promises';
7
6
  import { TASK_WORKFLOW_SCHEMA_MARKER } from '../gate-evidence.js';
8
7
  import type { AgentSessionState, DelegationEntry, ToolAggregate } from '../state';
9
8
  import { swarmState } from '../state';
@@ -190,7 +189,7 @@ export declare function serializeAgentSession(s: AgentSessionState): SerializedA
190
189
  * Silently swallows errors (non-fatal — never crash the plugin).
191
190
  */
192
191
  export declare function writeSnapshot(directory: string, state: typeof swarmState): Promise<void>;
193
- export declare function writeSnapshotProjection(directory: string, snapshot: SnapshotData): Promise<void>;
192
+ export declare function writeSnapshotProjection(directory: string, snapshot: SnapshotData, shouldCommit?: () => boolean): Promise<void>;
194
193
  /**
195
194
  * Create a snapshot writer hook suitable for use in tool.execute.after.
196
195
  * Writes state immediately on every call. Concurrent calls are serialised so
@@ -211,5 +210,5 @@ export declare const _internals: {
211
210
  writeSnapshot: typeof writeSnapshot;
212
211
  createSnapshotWriterHook: typeof createSnapshotWriterHook;
213
212
  flushPendingSnapshot: typeof flushPendingSnapshot;
214
- rename: typeof fsRename;
213
+ rename: (from: string, to: string, shouldCommit?: () => boolean) => void | Promise<void>;
215
214
  };
package/dist/state.d.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  * and delegation chains.
8
8
  */
9
9
  import type { OpencodeClient } from '@opencode-ai/sdk';
10
+ import { type Plan } from './config/plan-schema';
10
11
  import type { CouncilAgent } from './council/types';
11
12
  import { type QaGates } from './db/qa-gate-profile.js';
12
13
  import { type EnvironmentProfile } from './environment/profile.js';
@@ -14,8 +15,26 @@ import { type TaskWorkflowMetadata } from './gate-evidence';
14
15
  import type { EscalationTracker } from './prm/escalation.js';
15
16
  import type { PatternMatch, PrmEpisodeState } from './prm/types.js';
16
17
  import type { ReviewRouteEvidence } from './review/routing-enforcement.js';
18
+ import { getRehydrationCache } from './session/hydration-ownership.js';
17
19
  import { AgentRunContext } from './state/agent-run-context.js';
20
+ export { getRehydrationCache };
18
21
  export { AgentRunContext } from './state/agent-run-context.js';
22
+ /** Optional controls for rebuilding the project-owned rehydration cache. */
23
+ export interface RehydrationCacheBuildOptions {
24
+ /**
25
+ * Explicitly recovered plan state. Presence of this property, including a
26
+ * null value, means the caller already resolved the authoritative plan and
27
+ * the builder must not fall back to the derived plan.json projection.
28
+ */
29
+ planOverride?: Plan | null;
30
+ /** Return false when the captured hydration scope was superseded mid-read. */
31
+ shouldCommit?: () => boolean;
32
+ }
33
+ /** Result of a cache rebuild, including whether its publication committed. */
34
+ export interface RehydrationCacheBuildResult {
35
+ committed: boolean;
36
+ reason?: 'superseded';
37
+ }
19
38
  /**
20
39
  * Represents a single tool call entry for tracking purposes
21
40
  */
@@ -470,11 +489,21 @@ export interface AgentSessionState {
470
489
  * Hydration generation this session was created/restored AT.
471
490
  * `startAgentSession` stamps `currentGeneration + 1` (newer than any
472
491
  * in-flight hydration); `rehydrateState` stamps its applying generation.
473
- * A hydration at generation `g` evicts only owned sessions with
474
- * `hydrationStamp <= g`, so live sessions created after `g` began always
475
- * survive. Also never snapshotted.
492
+ * A hydration at authority `{ generation: g, epoch: e }` evicts owned
493
+ * sessions from another epoch and same-epoch sessions with
494
+ * `hydrationStamp <= g`, so sessions created after `g` began survive only
495
+ * within the same authority incarnation.
496
+ * `hydrationAuthorityEpoch` disambiguates a numerically reused generation
497
+ * after bounded project-authority eviction or reset. Also never snapshotted.
476
498
  */
477
499
  hydrationStamp?: number;
500
+ /**
501
+ * Process-local authority epoch paired with `hydrationStamp`. A session from
502
+ * an older project-authority incarnation is stale even when its numeric
503
+ * generation is larger than the current generation (issue #2668 ABA guard).
504
+ * Deliberately omitted from snapshots with the other ownership fields.
505
+ */
506
+ hydrationAuthorityEpoch?: number;
478
507
  /** Pattern type to detection count mapping */
479
508
  prmPatternCounts: Map<string, number>;
480
509
  /** Current escalation level (0=none, 1=guidance, 2=strong guidance, 3=hard stop) */
@@ -1378,7 +1407,7 @@ export declare function _resetCouncilDisagreementWarnings(): void;
1378
1407
  * refreshed after compaction by the compaction hook (src/hooks/compaction-customizer.ts).
1379
1408
  * Non-fatal: missing/malformed files leave an empty cache.
1380
1409
  */
1381
- export declare function buildRehydrationCache(directory: string): Promise<void>;
1410
+ export declare function buildRehydrationCache(directory: string, options?: RehydrationCacheBuildOptions): Promise<RehydrationCacheBuildResult>;
1382
1411
  /**
1383
1412
  * Synchronously applies the cached plan+evidence data to a session.
1384
1413
  * Merge rules:
@@ -1398,7 +1427,7 @@ export declare function applyRehydrationCache(session: AgentSessionState, projec
1398
1427
  * Builds (or refreshes) the rehydration cache from disk, then applies it
1399
1428
  * to the target session.
1400
1429
  */
1401
- export declare function rehydrateSessionFromDisk(directory: string, session: AgentSessionState): Promise<void>;
1430
+ export declare function rehydrateSessionFromDisk(directory: string, session: AgentSessionState, shouldCommit?: () => boolean): Promise<void>;
1402
1431
  /**
1403
1432
  * Check if Turbo Mode is enabled for a specific session or ANY session.
1404
1433
  * @param sessionID - Optional session ID to check. If provided, checks only that session.
@@ -1615,6 +1644,7 @@ export declare const _internals: {
1615
1644
  buildRehydrationCache: typeof buildRehydrationCache;
1616
1645
  applyRehydrationCache: typeof applyRehydrationCache;
1617
1646
  rehydrateSessionFromDisk: typeof rehydrateSessionFromDisk;
1647
+ rehydratePrSubscriptions: typeof rehydratePrSubscriptions;
1618
1648
  isCouncilGateActive: typeof isCouncilGateActive;
1619
1649
  defaultRunContext: typeof defaultRunContext;
1620
1650
  };
@@ -150,6 +150,7 @@ export declare const MAX_OUTPUT_BYTES = 512000;
150
150
  declare function allCompletedTasksHavePassedGateEvidence(directory: string, tasks: Array<{
151
151
  id: string;
152
152
  status: string;
153
+ files_touched?: string[];
153
154
  }>): Promise<boolean>;
154
155
  /**
155
156
  * Execute the phase_complete tool
@@ -84,7 +84,7 @@ export interface ReviewerGateResult {
84
84
  nextAction?: string;
85
85
  }
86
86
  declare function hasPassedDurableGateEvidence(workingDirectory: string, taskId: string): boolean;
87
- export declare function checkReviewerGate(taskId: string, workingDirectory?: string, stageBParallelEnabled?: boolean, sessionID?: string, fallbackDir?: string): ReviewerGateResult;
87
+ export declare function checkReviewerGate(taskId: string, workingDirectory?: string, stageBParallelEnabled?: boolean, sessionID?: string, fallbackDir?: string, currentDeclaredFiles?: readonly string[] | null): ReviewerGateResult;
88
88
  /**
89
89
  * Wrapper around checkReviewerGate that appends a diff-scope advisory warning.
90
90
  * Keeps checkReviewerGate synchronous for backward compatibility.
@@ -19,6 +19,7 @@ export declare function hasExplicitProjectBoundary(directory: unknown): boolean;
19
19
  */
20
20
  export declare function isStrictPathDescendant(candidate: unknown, root: unknown): boolean;
21
21
  type ProjectRootProbeDependencies = Pick<typeof fs, 'realpathSync' | 'statSync'>;
22
+ export type { ProjectRootProbeDependencies };
22
23
  /**
23
24
  * Authoritative write-time project-root assertion shared by persistence sinks.
24
25
  *
@@ -27,8 +28,38 @@ type ProjectRootProbeDependencies = Pick<typeof fs, 'realpathSync' | 'statSync'>
27
28
  * project indicator. Ambiguous ancestor state fails closed.
28
29
  */
29
30
  export declare function assertProjectRoot(directory: string, dependencies?: ProjectRootProbeDependencies, artifactLabel?: string): void;
31
+ /**
32
+ * Decision form of the same boundary policy (#2679): non-throwing, for the
33
+ * bootstrap path where the outcome must (a) name the owning project root for an
34
+ * ordinary child so every init/first-write consumer can target it, and
35
+ * (b) fail closed (no runtime-state writes) when ownership cannot be
36
+ * determined, while the plugin manifest stays fail-open.
37
+ *
38
+ * - `root`: the directory is a standalone root or declares its own boundary
39
+ * (`.git` file/dir, `.opencode` dir) — use it verbatim (canonicalized).
40
+ * - `redirect`: an ancestor owns `.swarm/` plus a project indicator — use
41
+ * `owningRoot` for all project-surface reads/writes and surface an
42
+ * actionable hint naming it.
43
+ * - `fail-closed`: ownership is indeterminable (inaccessible ancestor probes
44
+ * or depth exhaustion) — write no runtime state anywhere.
45
+ *
46
+ * Silent by design: messaging is the caller's job (`assertProjectRoot` keeps
47
+ * its warn/throw contract; bootstrap emits one bounded operational hint).
48
+ */
49
+ export type ProjectRootDecision = {
50
+ kind: 'root';
51
+ directory: string;
52
+ } | {
53
+ kind: 'redirect';
54
+ directory: string;
55
+ owningRoot: string;
56
+ } | {
57
+ kind: 'fail-closed';
58
+ directory: string;
59
+ reason: string;
60
+ };
61
+ export declare function resolveProjectRootDecision(directory: string, dependencies?: ProjectRootProbeDependencies): ProjectRootDecision;
30
62
  /** Narrow filesystem seam for deterministic marker error tests. */
31
63
  export declare const _internals: {
32
64
  lstatSync: typeof fs.lstatSync;
33
65
  };
34
- export {};
@@ -8,6 +8,12 @@ export interface CoderSettlementResult {
8
8
  accepted: boolean;
9
9
  alreadyApplied: boolean;
10
10
  }
11
+ /**
12
+ * An empty declared scope cannot distinguish a coder mutation from an
13
+ * out-of-scope workspace change. Such a change must not be reduced to the
14
+ * empty scoped observation that powers the generation-0 read-only exception.
15
+ */
16
+ export declare function hasUnattributedEmptyScopeMutation(declaredFiles: readonly string[] | null | undefined, rawObservedFiles: readonly string[] | null | undefined): boolean;
11
17
  export declare function beginCoderSettlement(options: {
12
18
  directory: string;
13
19
  taskId: string;
@@ -24,6 +30,8 @@ export declare function settleCoderDispatch(options: {
24
30
  accepted: boolean;
25
31
  testEngineerExempt: boolean;
26
32
  settlementFailed?: boolean;
33
+ /** Raw workspace changes used to prevent empty-scope no-mutation proofs. */
34
+ observedFiles?: readonly string[] | null;
27
35
  /** #2508: landed via squash-unstaged — retain the lane branch at cleanup. */
28
36
  landedUnstaged?: boolean;
29
37
  }): Promise<CoderSettlementResult>;
@@ -1,4 +1,4 @@
1
- import type { Plan } from '../config/plan-schema.js';
1
+ import { type Plan } from '../config/plan-schema.js';
2
2
  import { type TaskEvidence, withTaskEvidenceTransaction } from '../gate-evidence.js';
3
3
  import type { TaskTerminalWal, TerminalPlanStatus } from './workflow-wal-schema.js';
4
4
  export interface TaskTerminalResult<TPlan> {
@@ -37,6 +37,7 @@ export declare function commitTaskTerminalUnderPlanLock<TPlan>(options: {
37
37
  targetStatus: TerminalPlanStatus;
38
38
  qaExempt: boolean;
39
39
  preserveEvidence?: boolean;
40
+ readOnlyNoMutation?: boolean;
40
41
  };
41
42
  planIdentityHash?: string;
42
43
  planEpoch?: string;
@@ -54,6 +54,8 @@ export interface TaskTerminalWalV1 {
54
54
  newWorkflowState: 'blocked' | 'complete';
55
55
  generation: number;
56
56
  qaExempt: boolean;
57
+ /** Completion used the trusted generation-0 empty-scope settlement path. */
58
+ readOnlyNoMutation?: boolean;
57
59
  recordedAt: string;
58
60
  }
59
61
  export interface TaskTerminalWalV2 extends Omit<TaskTerminalWalV1, 'version' | 'newPlanStatus' | 'newWorkflowState'> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.184.0",
3
+ "version": "7.184.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",
@@ -1,74 +0,0 @@
1
- // @bun
2
- import {
3
- createCuratorLLMDelegate
4
- } from "./index-9yvjwfay.js";
5
- import"./index-pq6vr26z.js";
6
- import"./index-hamqvzqn.js";
7
- import"./index-4t0wd9sv.js";
8
- import"./index-46z4c89b.js";
9
- import"./index-r30xs0wp.js";
10
- import"./index-nvm6mxep.js";
11
- import"./index-z8smhv7k.js";
12
- import"./index-txdagbh7.js";
13
- import"./index-6b4vkz6q.js";
14
- import"./index-6b295cas.js";
15
- import"./index-j40czc9v.js";
16
- import"./index-152b9c6m.js";
17
- import"./index-3fhg7pqf.js";
18
- import"./index-rdec0y3z.js";
19
- import"./index-e90m050y.js";
20
- import"./index-cjapb4hy.js";
21
- import"./index-zsrtt42s.js";
22
- import"./index-me39468k.js";
23
- import"./index-6h81yvyc.js";
24
- import"./index-0bpr8vag.js";
25
- import"./index-pt7h91zc.js";
26
- import"./index-q7sjgr1y.js";
27
- import"./index-t26gj2fh.js";
28
- import"./index-ad3yskxy.js";
29
- import"./index-4gr9pj67.js";
30
- import"./index-nm8ma9xb.js";
31
- import"./index-z3b157ew.js";
32
- import"./index-nmh0s6dg.js";
33
- import"./index-2s7dvzff.js";
34
- import"./index-5wk0etp8.js";
35
- import"./index-v3hpsxvd.js";
36
- import"./index-rtry5xyf.js";
37
- import"./index-edrgc139.js";
38
- import"./index-frcemc0b.js";
39
- import"./index-0725jpp7.js";
40
- import"./index-njf5pbkm.js";
41
- import"./index-51xtrf7g.js";
42
- import"./index-mn5zzmqx.js";
43
- import"./index-w81jmdkt.js";
44
- import"./index-3rb5gs4w.js";
45
- import"./index-08x7gsnf.js";
46
- import"./index-rdm3px0g.js";
47
- import"./index-ry16d01s.js";
48
- import"./index-1d6ssjcj.js";
49
- import"./index-qyx53xrz.js";
50
- import"./index-vzm6zre7.js";
51
- import"./index-ae75rja9.js";
52
- import"./index-74x26wyj.js";
53
- import"./index-01wt209s.js";
54
- import"./index-fbhtb6f5.js";
55
- import"./index-1xnse449.js";
56
- import"./index-c1ggtmpm.js";
57
- import"./index-ejhxgyvm.js";
58
- import"./index-7g4c7s5r.js";
59
- import"./index-5cve9g2b.js";
60
- import"./index-gx2vp8gx.js";
61
- import"./index-t1swv35d.js";
62
- import"./index-zxdawwc7.js";
63
- import"./index-ysr6n4ca.js";
64
- import"./index-wzec3c4g.js";
65
- import"./index-bk5tah7q.js";
66
- import"./index-gknz3bv1.js";
67
- import"./index-zpsr8rpc.js";
68
- import"./index-wvghb3x6.js";
69
- import"./index-9rwhas09.js";
70
- import"./index-zgwm4ryv.js";
71
- import"./index-a76rekgs.js";
72
- export {
73
- createCuratorLLMDelegate
74
- };