opencode-swarm 7.167.1 → 7.168.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 (126) 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/agents/project-context.d.ts +12 -8
  4. package/dist/cli/{coder-settlement-2ye4s5xr.js → coder-settlement-a35acvj1.js} +16 -16
  5. package/dist/cli/{config-doctor-b0k8eyd6.js → config-doctor-9csx775x.js} +3 -3
  6. package/dist/cli/{core-xgzgjk8s.js → core-agk5s7dm.js} +4 -4
  7. package/dist/cli/{curation-policy-bvxf5pxv.js → curation-policy-mgwv8h2k.js} +7 -7
  8. package/dist/cli/{curator-jpvzrxcv.js → curator-2fcagjyk.js} +45 -45
  9. package/dist/cli/{curator-drift-20m2ab5w.js → curator-drift-k0zrnm09.js} +8 -8
  10. package/dist/cli/curator-llm-factory-qaxmyy46.js +71 -0
  11. package/dist/cli/{dispatch-tmb929w8.js → dispatch-8ks9dyk5.js} +244 -70
  12. package/dist/cli/{evidence-summary-service-74az43cb.js → evidence-summary-service-4s6cje60.js} +22 -22
  13. package/dist/cli/{explorer-zvk5kbcb.js → explorer-2cv64zfj.js} +1 -1
  14. package/dist/cli/{gate-evidence-f26h2gn3.js → gate-evidence-saja4dan.js} +11 -11
  15. package/dist/cli/guardrail-explain-z41q6sf0.js +72 -0
  16. package/dist/cli/{guardrail-log-pnye3xw8.js → guardrail-log-0h24spq0.js} +9 -9
  17. package/dist/cli/{guardrail-reset-0da7q8ap.js → guardrail-reset-cwbe47k5.js} +44 -44
  18. package/dist/cli/hive-promoter-esxtcvr1.js +86 -0
  19. package/dist/cli/{index-bv8ha57q.js → index-00zx94vn.js} +6 -6
  20. package/dist/cli/{index-9e6fdz2h.js → index-0mhftbpp.js} +1 -1
  21. package/dist/cli/{index-7qefgq4j.js → index-1xnse449.js} +11 -1
  22. package/dist/cli/{index-qyr17fbz.js → index-21ree67h.js} +62 -106
  23. package/dist/cli/{index-q265ytw6.js → index-30h1pk05.js} +4 -4
  24. package/dist/cli/{index-f8xk5q5j.js → index-3dywbkyr.js} +4 -4
  25. package/dist/cli/{index-2w0beg3s.js → index-4r5pmtvk.js} +5 -5
  26. package/dist/cli/{index-69y9p6dh.js → index-54w1564x.js} +2 -2
  27. package/dist/cli/{index-251vrmge.js → index-5zqakgp4.js} +4 -4
  28. package/dist/cli/{index-bzdc4b7t.js → index-64phnth4.js} +6 -6
  29. package/dist/cli/{index-fmzz6aw7.js → index-8f0kscpg.js} +4 -4
  30. package/dist/cli/{index-t8tw1bhs.js → index-8ybjqg51.js} +2 -2
  31. package/dist/cli/{index-9ss2m4rs.js → index-9br68j86.js} +1 -1
  32. package/dist/cli/{index-4rhhvd1a.js → index-a1w58b47.js} +1 -1
  33. package/dist/cli/{index-qd619x3r.js → index-a8xbvsse.js} +2 -2
  34. package/dist/cli/{index-mgc3c483.js → index-an8b5gda.js} +10 -10
  35. package/dist/cli/{index-9wv6a3jx.js → index-bvqqwx84.js} +2 -2
  36. package/dist/cli/{index-bf6zx8cq.js → index-cyenn3pf.js} +6 -2
  37. package/dist/cli/{index-8x4zwk0t.js → index-ddr97ram.js} +47 -47
  38. package/dist/cli/{index-3nm1b3t2.js → index-dfyv3xkd.js} +8 -8
  39. package/dist/cli/{index-87agfprq.js → index-exatbqwj.js} +13 -4
  40. package/dist/cli/{index-70ha9e09.js → index-fyfbpz4f.js} +1 -1
  41. package/dist/cli/{index-5bd84nxc.js → index-gp9yzr1v.js} +1 -1
  42. package/dist/cli/{index-es13aqdb.js → index-h0e2e3h1.js} +1 -1
  43. package/dist/cli/{index-6d4dc99f.js → index-h439y187.js} +1 -1
  44. package/dist/cli/{index-9bhzbwa4.js → index-j950hqmq.js} +9 -9
  45. package/dist/cli/{index-sahf5yz3.js → index-kear8gb7.js} +11 -6
  46. package/dist/cli/{index-qww0h314.js → index-m35hybf0.js} +1 -1
  47. package/dist/cli/{index-qtd3hrk8.js → index-mr0wn36f.js} +5 -5
  48. package/dist/cli/{index-zwsbegc1.js → index-nprngf8p.js} +7 -7
  49. package/dist/cli/{index-z5gdgdkp.js → index-nsyxj57e.js} +12 -12
  50. package/dist/cli/{index-1aex5zd9.js → index-nwwk3dej.js} +2 -2
  51. package/dist/cli/{index-75f9jj3h.js → index-pyf517sz.js} +2 -2
  52. package/dist/cli/{index-m3tx1q9v.js → index-qhey6vc3.js} +1 -1
  53. package/dist/cli/{index-qd726agw.js → index-qwsh0h2g.js} +3 -3
  54. package/dist/cli/{index-n4fzmqz8.js → index-rdm3px0g.js} +4 -2
  55. package/dist/cli/index-rxcgrgkc.js +116 -0
  56. package/dist/cli/{index-54vzqy47.js → index-s0d5xter.js} +6 -6
  57. package/dist/cli/{index-emwezg3y.js → index-seetnhpx.js} +3 -3
  58. package/dist/cli/{index-0tc0pcmh.js → index-sxt7fgcw.js} +38 -2
  59. package/dist/cli/{index-m21x1bkx.js → index-v3xc4sde.js} +11 -8
  60. package/dist/cli/{index-79wnzc8q.js → index-wnzxcr0z.js} +3 -3
  61. package/dist/cli/{index-rk10x4zr.js → index-wst6n478.js} +106 -6
  62. package/dist/cli/{index-hdsg7yf6.js → index-x7k3dps5.js} +4 -3
  63. package/dist/cli/{index-32bxwzw0.js → index-yevn4jpe.js} +92908 -90093
  64. package/dist/cli/index-yv76j77m.js +2008 -0
  65. package/dist/cli/{index-f6zgz02s.js → index-z6qreakh.js} +7 -7
  66. package/dist/cli/{index-eretcr6t.js → index-ze520xw1.js} +11 -11
  67. package/dist/cli/index.js +44 -44
  68. package/dist/cli/{knowledge-escalator-p2a8xh8x.js → knowledge-escalator-b2tf3sd1.js} +17 -17
  69. package/dist/cli/{knowledge-events-jmh28m8d.js → knowledge-events-bgs2kxe0.js} +15 -15
  70. package/dist/cli/{knowledge-link-w1fwqts4.js → knowledge-link-dr3xnwyd.js} +6 -6
  71. package/dist/cli/{knowledge-store-8gmabtsn.js → knowledge-store-stbmb1b9.js} +7 -7
  72. package/dist/cli/{knowledge-validator-yk579vs4.js → knowledge-validator-zykgnsag.js} +9 -9
  73. package/dist/cli/{model-preflight-b3b5pgsc.js → model-preflight-1ycat9jz.js} +1 -1
  74. package/dist/cli/{pending-delegations-nw7ph53z.js → pending-delegations-n5qavj20.js} +14 -14
  75. package/dist/cli/{pr-subscriptions-9815fxbc.js → pr-subscriptions-gnvmyrng.js} +14 -14
  76. package/dist/cli/{pr-workflow-gate-98a7b6py.js → pr-workflow-gate-cf3ybrws.js} +44 -44
  77. package/dist/cli/{runner-nmrjv7te.js → runner-k0ycgv8x.js} +7 -7
  78. package/dist/cli/{scan-cursor-6zcs0frg.js → scan-cursor-b3mcrx23.js} +10 -10
  79. package/dist/cli/{schema-warvhy9h.js → schema-08049cjb.js} +4 -2
  80. package/dist/cli/{scope-persistence-c2ck77cv.js → scope-persistence-a493gv51.js} +20 -20
  81. package/dist/cli/{skill-generator-jamm1cna.js → skill-generator-2qqzkdpv.js} +19 -19
  82. package/dist/cli/{snapshot-coordination-init-st0xsn3f.js → snapshot-coordination-init-8yt8p7q0.js} +44 -44
  83. package/dist/cli/{sqlite-loader-xrnf6bq8.js → sqlite-loader-amp9z7ty.js} +1 -1
  84. package/dist/cli/{telemetry-ce0tx41h.js → telemetry-2wzapf11.js} +2 -2
  85. package/dist/cli/{workspace-snapshot-0kxj2grt.js → workspace-snapshot-rkgxhj9b.js} +6 -6
  86. package/dist/cli/{worktree-collision-ownership-qra7r8pw.js → worktree-collision-ownership-xttafc4h.js} +17 -17
  87. package/dist/cli/{worktree-isolation-yr9gnf64.js → worktree-isolation-e5q5rewk.js} +45 -45
  88. package/dist/commands/close/align-stage.d.ts +10 -0
  89. package/dist/commands/close/archive-stage.d.ts +34 -0
  90. package/dist/commands/close/clean-stage.d.ts +2 -0
  91. package/dist/commands/close/constants.d.ts +122 -0
  92. package/dist/commands/close/context.d.ts +129 -0
  93. package/dist/commands/close/db-helpers.d.ts +10 -0
  94. package/dist/commands/close/dry-run.d.ts +12 -0
  95. package/dist/commands/close/finalize-stage.d.ts +44 -0
  96. package/dist/commands/close/fs-helpers.d.ts +17 -0
  97. package/dist/commands/close/internals.d.ts +55 -0
  98. package/dist/commands/close/orchestrator.d.ts +32 -0
  99. package/dist/commands/close/wiring.d.ts +2 -0
  100. package/dist/commands/close.d.ts +10 -402
  101. package/dist/commands/reset.d.ts +10 -0
  102. package/dist/commands/rollback.d.ts +9 -0
  103. package/dist/config/schema.d.ts +29 -0
  104. package/dist/db/project-db.d.ts +8 -0
  105. package/dist/db/sqlite-loader.d.ts +2 -1
  106. package/dist/dispatch/spawn-circuit.d.ts +121 -0
  107. package/dist/dispatch/token-bucket.d.ts +46 -0
  108. package/dist/hooks/delegation-gate/dead-lane-reclaim.d.ts +61 -0
  109. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +22 -0
  110. package/dist/hooks/issue-trace.d.ts +3 -0
  111. package/dist/hooks/utils.d.ts +1 -1
  112. package/dist/index.js +811 -726
  113. package/dist/lang/dispatch.d.ts +6 -6
  114. package/dist/plan/ledger-sqlite.d.ts +226 -0
  115. package/dist/plan/ledger.d.ts +24 -0
  116. package/dist/plan/manager.d.ts +19 -0
  117. package/dist/retention/sweep.d.ts +2 -0
  118. package/dist/services/spec-drift-recovery.d.ts +2 -1
  119. package/dist/utils/canonical-root.d.ts +19 -0
  120. package/dist/utils/ephemeral-session-teardown.d.ts +55 -2
  121. package/opencode-swarm.schema.json +41 -0
  122. package/package.json +1 -1
  123. package/dist/cli/curator-llm-factory-zeb0pe2j.js +0 -71
  124. package/dist/cli/guardrail-explain-5vhveypz.js +0 -72
  125. package/dist/cli/hive-promoter-2vj54xc4.js +0 -86
  126. package/dist/cli/index-fenasyvr.js +0 -967
@@ -1,402 +1,10 @@
1
- import * as fsSync from 'node:fs';
2
- import { loadPluginConfigWithMeta } from '../config';
3
- import type { Plan } from '../config/plan-schema';
4
- import { type KnowledgeConfig, type PluginConfig } from '../config/schema';
5
- import { archiveEvidence } from '../evidence/manager';
6
- import { getGitRepositoryStatus, resetToMainAfterMerge, resetToRemoteBranch } from '../git/branch';
7
- import { createCuratorLLMDelegate } from '../hooks/curator-llm-factory';
8
- import { runCuratorPostMortem } from '../hooks/curator-postmortem';
9
- import { checkHivePromotions } from '../hooks/hive-promoter';
10
- import { curateAndStoreSwarm } from '../hooks/knowledge-curator';
11
- import { reconcilePhaseClose } from '../hooks/knowledge-receipt-ledger.js';
12
- import { closeSnapshotCoordinationInitialization } from '../session/snapshot-coordination-init.js';
13
- import { closeRepoMemory } from '../tools/repo-graph/indexed-storage';
14
- /** Narrow seam for receipt/plan ordering tests. */
15
- export declare const closeReceiptLifecycleInternals: {
16
- recordPhaseCloseIntent: (directory: string, phase: string, sessionId?: string, taskId?: string) => Promise<import("../hooks/knowledge-receipt-ledger.js").ReceiptLedgerResult<{
17
- event_id: string;
18
- }>>;
19
- reconcilePhaseClose: typeof reconcilePhaseClose;
20
- };
21
- import { runFinalizeRewardSweep } from '../memory/finalize-reward-sweep';
22
- import { type SessionReflectionResult } from '../services/session-reflection';
23
- import { endAgentSession, resetSwarmStatePreservingSingletons } from '../state';
24
- import { collectGarbageBestEffort, sleep } from '../utils/bun-compat.js';
25
- import { type CloseTerminalResult } from '../workflow/close-terminal.js';
26
- import { type SqliteRowCounts } from './archive-sqlite';
27
- interface PlanPhase {
28
- id: number;
29
- name: string;
30
- status: string;
31
- tasks: Array<{
32
- id: string;
33
- status: string;
34
- close_reason?: string;
35
- }>;
36
- }
37
- interface PlanData {
38
- title: string;
39
- phases: PlanPhase[];
40
- }
41
- /**
42
- * Close-command wrapper around the exact-task terminal reconciliation service.
43
- *
44
- * Deliberately NOT named `closePlanTerminalState`: `src/plan/manager.ts` exports a
45
- * distinct function by that name (ledger-first phase/projection persistence), which
46
- * `reconcileCloseTerminalState` itself calls downstream. Keeping the two identifiers
47
- * distinct avoids a same-name collision across close.ts / close-terminal.ts /
48
- * plan/manager.ts. The `_internals` key below stays `closePlanTerminalState` so the
49
- * existing test seam is unchanged.
50
- */
51
- declare function reconcileCloseTerminalStateForPlan(directory: string, targetPlan: Plan, options: {
52
- actor: string;
53
- requestedClosedTaskIds: string[];
54
- closedPhaseIds: number[];
55
- originalStatuses?: Map<string, string>;
56
- }): Promise<CloseTerminalResult | undefined>;
57
- interface CloseCommandOptions {
58
- sessionID?: string;
59
- skillReviewTimeoutMs?: number;
60
- }
61
- interface CurationCounts {
62
- stored: number;
63
- /** Issue #2077: surfaced for the reflection knowledge-delta report. */
64
- reinforced: number;
65
- skipped: number;
66
- rejected: number;
67
- quarantined: number;
68
- }
69
- interface CloseKnowledgeEntry {
70
- created_at?: string;
71
- }
72
- export type ArchiveRequiredness = 'required' | 'optional';
73
- export type ArchiveAttempt = 'not_attempted' | 'succeeded' | 'failed';
74
- export type ArchiveValidation = 'not_applicable' | 'passed' | 'failed';
75
- export type ArchiveSourceDisposition = 'absent' | 'retained' | 'removed';
76
- export interface ArtifactArchiveResult {
77
- artifact: string;
78
- requiredness: ArchiveRequiredness;
79
- attempt: ArchiveAttempt;
80
- validation: ArchiveValidation;
81
- source_disposition: ArchiveSourceDisposition;
82
- method: string;
83
- reason_code: string;
84
- /** Counts only (no row content), present for validated sqlite snapshots. */
85
- row_counts?: SqliteRowCounts;
86
- /** Non-sensitive diagnostic. */
87
- detail?: string;
88
- }
89
- export interface ArchiveStageContext {
90
- directory: string;
91
- swarmDir: string;
92
- config: PluginConfig;
93
- warnings: string[];
94
- }
95
- export interface CloseStageContext {
96
- directory: string;
97
- swarmDir: string;
98
- planData: PlanData;
99
- planExists: boolean;
100
- planAlreadyDone: boolean;
101
- config: KnowledgeConfig;
102
- projectName: string;
103
- warnings: string[];
104
- closedPhases: number[];
105
- closedTasks: string[];
106
- sessionStart: string | undefined;
107
- isForced: boolean;
108
- runSkillReview: boolean;
109
- options: CloseCommandOptions;
110
- phases: PlanPhase[];
111
- inProgressPhases: PlanPhase[];
112
- curationSucceeded: boolean;
113
- curationResult: CurationCounts | undefined;
114
- allLessons: string[];
115
- explicitLessons: string[];
116
- retroLessons: string[];
117
- knowledgeSkillHint: string;
118
- skillReviewSummary: string;
119
- postMortemSummary: string;
120
- sessionReflection: SessionReflectionResult | undefined;
121
- hivePromoted: number;
122
- sessionKnowledgeCreated: number;
123
- fallbackKnowledgeCreated: number;
124
- /** Issue #2077: FR-015 dedup drop count (retro lessons dropped as already-known). */
125
- dedupDropped: number;
126
- /** Issue #2077: false when the dedup knowledge read failed (fail-open). */
127
- dedupAvailable: boolean;
128
- /** Issue #2077: total retro lessons before dedup. */
129
- retroLessonTotal: number;
130
- /** Issue #2077: full-auto state computed once, reused at reflection + menu render. */
131
- fullAuto: boolean;
132
- originalStatuses: Map<string, string>;
133
- guaranteeResult: {
134
- closedPhaseIds: number[];
135
- closedTaskIds: string[];
136
- };
137
- terminalizationError?: string;
138
- archiveResult: string;
139
- archivedFileCount: number;
140
- archivedActiveStateFiles: Set<string>;
141
- archivedActiveStateDirs: Set<string>;
142
- archiveFailureReasons: Map<string, string>;
143
- /** Structured per-artifact results — single source of truth (issue #2030). */
144
- archiveResults: ArtifactArchiveResult[];
145
- /** True when the archive STAGE threw wholesale (e.g. mkdir EACCES/ENOSPC). */
146
- archiveStageFailed: boolean;
147
- timestamp: string;
148
- archiveDir: string;
149
- archiveSuffix: string;
150
- args: string[];
151
- }
152
- declare function archiveCloseSummary(ctx: Pick<CloseStageContext, 'archiveStageFailed' | 'archiveDir' | 'warnings'>, closeSummaryPath: string, summaryWritten: boolean): Promise<void>;
153
- declare function countSessionKnowledgeEntries(entries: CloseKnowledgeEntry[], sessionStart: string | undefined, fallbackCount: number): number;
154
- /**
155
- * Backward-compatible wrapper that returns only the copied count.
156
- * Direct callers (including tests) that expect a number continue to work.
157
- * Use copyDirRecursiveWithFailures when per-file failure tracking is needed.
158
- */
159
- declare function copyDirRecursive(src: string, dest: string): Promise<number>;
160
- /**
161
- * Flat-file artifacts to include in the archive bundle.
162
- * Each entry is a relative path under .swarm/.
163
- *
164
- * plan-ledger.jsonl is included so the archive bundle is a self-contained
165
- * forensic snapshot of the session: the ledger holds the full audit trail of
166
- * task state transitions and snapshot events that plan.json/plan.md don't
167
- * preserve.
168
- */
169
- export declare const ARCHIVE_ARTIFACTS: string[];
170
- /**
171
- * Active-state flat files to clean after archiving so future swarms start clean.
172
- *
173
- * plan.json, plan.md, and plan-ledger.jsonl are all removed so the next /swarm
174
- * session starts with a clean slate. The user's original ask for /swarm close
175
- * was to "archive plan files so future swarms aren't confused" — leaving a
176
- * terminal-state plan.json in place violates that invariant because the next
177
- * session's loadPlan() would pick it up as if it were still active.
178
- *
179
- * CRITICAL: the ledger must also be removed. Without this, loadPlan()'s Step 4
180
- * would see no plan.json but a surviving ledger, call replayFromLedger(), and
181
- * materialize the CLOSED plan back into plan.json on the next session. The
182
- * ledger is a second backing store for the same "terminal-state plan" and
183
- * leaving it behind re-enables the exact bug this cleanup is meant to fix.
184
- * The archive-first guard below ensures we only delete files we successfully
185
- * copied to the archive bundle, so the audit trail is preserved in the bundle.
186
- *
187
- * knowledge-rejected.jsonl, repo-graph.json, doc-manifest.json,
188
- * dark-matter.md, telemetry.jsonl, and swarm.db are
189
- * session-generated artifacts that do not persist meaningfully across sessions —
190
- * they are recreated on next session init and must be removed to avoid stale-state
191
- * interference.
192
- *
193
- * The SQLite WAL sidecars swarm.db-shm and swarm.db-wal are deliberately NOT in
194
- * either list (the archive-first guard would preserve them anyway): since #2483
195
- * they are removed immediately AFTER the swarm.db unlink by
196
- * removeSqliteSidecarsAfterClose, deliberately reversing #1692. Post-unlink the
197
- * sidecar paths are meaningless for future opens (no new opener can attach),
198
- * live processes keep their already-open fds so deleting the PATH cannot
199
- * corrupt them, and a Windows open-handle collision yields EBUSY which the
200
- * helper skips fail-open.
201
- *
202
- * Note: knowledge.jsonl is intentionally NOT cleaned because it contains cumulative
203
- * project knowledge (lessons learned) that should persist across sessions and finalize
204
- * cycles. The archive step still creates a backup for safety.
205
- * close-summary.md is NOT cleaned because it is written as the final close output
206
- * AFTER the clean stage runs. spec.md IS cleaned: it is single-session state coupled
207
- * to the plan lifecycle (the plan it produced is removed above), so leaving it behind
208
- * makes the next session pick up a stale spec via readEffectiveSpecSync and mis-route
209
- * the architect into CLARIFY-SPEC/overwrite prompts. It is archived first (archive-first
210
- * guard), so the forensic copy is preserved in the bundle. The earlier "spec.md may not
211
- * exist" rationale was wrong — handoff.md is equally optional and is cleaned the same way.
212
- * session-reflection.md is a single-session snapshot (not cumulative like
213
- * knowledge.jsonl) so it IS cleaned to maintain the clean-slate invariant.
214
- * spec-staleness.json and spec-snapshot.md are the same class of single-session
215
- * spec-drift state as spec.md. spec-staleness.json is an existence-only gate
216
- * checked unconditionally by enforceSpecDriftGate, which hard-blocks the core
217
- * write tools (save_plan, update_task_status, phase_complete,
218
- * lean_turbo_run_phase, lean_turbo_acquire_locks) with SPEC_DRIFT_BLOCK — a
219
- * survivor would block the NEXT session against drift that no longer applies.
220
- * spec-snapshot.md is its companion diff source, feeding the mismatch shown in
221
- * the SPEC_DRIFT_BLOCK message. Both are archived first (archive-first guard),
222
- * then cleaned so the next session starts drift-free.
223
- */
224
- export declare const ACTIVE_STATE_TO_CLEAN: string[];
225
- /**
226
- * Active-state directories to archive and clean after archiving.
227
- * These contain session-generated data that must be removed so future
228
- * swarms start clean. Each entry is a relative path under .swarm/.
229
- */
230
- export declare const ACTIVE_STATE_DIRS_TO_CLEAN: string[];
231
- /**
232
- * Guarantee all phases and tasks in a plan are marked complete/closed.
233
- * Mutates planData in place. Returns actual IDs of newly closed phases and
234
- * tasks so the caller can track only genuinely new closures (idempotent).
235
- */
236
- declare function guaranteeAllPlansComplete(planData: PlanData): {
237
- closedPhaseIds: number[];
238
- closedTaskIds: string[];
239
- };
240
- export interface GitAlignResult {
241
- gitAlignResult: string;
242
- prunedBranches: string[];
243
- }
244
- export interface CleanStageResult {
245
- cleanedFiles: string[];
246
- configBackupsRemoved: number;
247
- swarmPlanFilesRemoved: number;
248
- /**
249
- * Stale atomic-write temp files MOVED into `.swarm/quarantine/<batch>/`
250
- * (issue #2035). Quarantine is a recoverable move with a manifest — the
251
- * pre-#2035 blind `.tmp.*` unlink sweep is gone; preserved candidates
252
- * (recent/active/tracked/ambiguous) are counted in `residuePreserved`.
253
- */
254
- residueQuarantined: number;
255
- residuePreserved: number;
256
- }
257
- /**
258
- * Emit the single `close_archive_result` telemetry event whose payload is the
259
- * SAME `ctx.archiveResults` array the user-facing prose derives from, so the
260
- * two cannot disagree (issue #2030 item 6). Called AFTER `runCleanStage` so
261
- * `source_disposition` can be finalized truthfully: artifacts that were
262
- * successfully archived AND then unlinked by the clean stage report `'removed'`;
263
- * artifacts preserved (absent, or failed/retained) keep their archive-time
264
- * disposition. Counts only — no row content (issue items 4/9).
265
- */
266
- export declare function emitCloseArchiveResult(ctx: CloseStageContext, cleanResult: CleanStageResult): void;
267
- /**
268
- * STAGE 1: FINALIZE
269
- *
270
- * Writes retrospectives for in-progress phases (or a session-level retro for
271
- * plan-free closes), curates lessons, promotes to hive, runs skill review,
272
- * persists terminal plan state, and runs post-mortem. All state mutations are
273
- * written back to ctx so the caller can build the close summary.
274
- */
275
- export declare function runFinalizeStage(ctx: CloseStageContext): Promise<void>;
276
- /**
277
- * STAGE 2: ARCHIVE
278
- *
279
- * Creates a timestamped archive bundle under .swarm/archive/, copies flat-file
280
- * artifacts and active-state directories, then runs the evidence retention
281
- * policy. All state mutations (archive path, counts, success sets) are written
282
- * back to ctx so the caller can build the close summary.
283
- */
284
- export declare function runArchiveStage(ctx: CloseStageContext): Promise<void>;
285
- /**
286
- * Runs the evidence-retention sub-logic of STAGE 2 (ARCHIVE).
287
- * Reads max_age_days / max_bundles / cache_max_bytes / cache_max_records from
288
- * config.evidence (FR-016, issue #1184) and calls archiveEvidence. The report
289
- * overload is used so the documents-cache prune runs when cache caps are set.
290
- * Fail-open: pushes a warning on error but never throws.
291
- */
292
- export declare function runArchiveEvidenceRetention(ctx: ArchiveStageContext): Promise<void>;
293
- /**
294
- * Delete one archived active-state artifact, tolerating the short-lived file
295
- * locks Windows antivirus and SQLite sidecars can retain after handle close.
296
- * Non-transient errors fail immediately; the retry budget is bounded to
297
- * 375 ms so `/swarm close` remains responsive.
298
- */
299
- declare function unlinkActiveStateFileWithRetry(filePath: string): Promise<void>;
300
- /**
301
- * Remove the SQLite WAL sidecars (swarm.db-wal / swarm.db-shm) immediately
302
- * after the clean stage unlinks swarm.db (#2483, deliberately reversing the
303
- * #1692 preserve decision): once the main db is unlinked the sidecar paths
304
- * are meaningless for future opens — no new opener can attach — and live
305
- * processes keep their already-open fds, so deleting the PATH cannot corrupt
306
- * them. Best-effort and per-file fail-open: ENOENT (already gone) and EBUSY
307
- * (Windows open-handle collision) are skipped silently.
308
- */
309
- export declare function removeSqliteSidecarsAfterClose(swarmDir: string): void;
310
- export declare function runCleanStage(ctx: CloseStageContext): Promise<CleanStageResult>;
311
- /**
312
- * STAGE 4: ALIGN
313
- *
314
- * Performs safe git alignment to main (resetToMainAfterMerge / resetToRemoteBranch
315
- * via _internals), handling post-merge scenarios and non-git directories.
316
- * Returns { gitAlignResult, prunedBranches } so the orchestrator can build
317
- * the close summary. All warnings are pushed into ctx.warnings.
318
- */
319
- export declare function runAlignStage(ctx: CloseStageContext): Promise<GitAlignResult>;
320
- /**
321
- * Builds the `/swarm finalize --dry-run` report. Purely READ-ONLY: inspects the
322
- * plan and the filesystem and describes what a real finalize WOULD do, without
323
- * acquiring the finalize lock, creating an archive bundle, deleting any file,
324
- * running git, or tearing down session state. (#1692)
325
- *
326
- * The archive-first guard means the clean stage only removes files it first
327
- * archived successfully; this report approximates that by listing existing
328
- * clean-set members as "would remove" and notes the approximation.
329
- */
330
- export declare function runFinalizeDryRun(directory: string, swarmDir: string, planData: PlanData, planExists: boolean): Promise<string>;
331
- /**
332
- * Handles /swarm close command - performs full terminal session finalization:
333
- * 0. Guarantee: mark all incomplete phases/tasks as closed
334
- * 1. Finalize: write retrospectives, produce terminal summary
335
- * 2. Archive: create timestamped bundle of swarm artifacts
336
- * 3. Clean: clear active-state files that confuse future swarms
337
- * 4. Align: safe git alignment to main
338
- *
339
- * Must be idempotent - safe to run multiple times.
340
- */
341
- export declare function handleCloseCommand(directory: string, args: string[], options?: CloseCommandOptions): Promise<string>;
342
- /**
343
- * Acquire the finalize lock for the close command (FR-012).
344
- * Wraps tryAcquireLock with a directory-only API.
345
- */
346
- declare function acquireFinalizeLock(directory: string): Promise<{
347
- acquired: boolean;
348
- release?: () => Promise<void>;
349
- }>;
350
- /**
351
- * Issue #2077: detect full-auto state for the action-menu prompt suppression.
352
- * Combines the in-memory session flag (hasActiveFullAuto) with the durable
353
- * run state (isFullAutoRunActive reads .swarm/full-auto-state.json) so a
354
- * process restart mid-run does not silently re-enable the interactive menu
355
- * prompt. The durable check is sync and takes a state lock; if it throws,
356
- * fall back to the in-memory flag alone. Caller MUST guard with a defined
357
- * sessionID to avoid the cross-session leak (hasActiveFullAuto(undefined)
358
- * scans all sessions).
359
- */
360
- declare function detectFullAuto(directory: string, sessionID: string): boolean;
361
- export declare const _internals: {
362
- closeSnapshotCoordinationInitialization: typeof closeSnapshotCoordinationInitialization;
363
- closeRepoMemory: typeof closeRepoMemory;
364
- unlinkActiveStateFileWithRetry: typeof unlinkActiveStateFileWithRetry;
365
- unlink: typeof fsSync.promises.unlink;
366
- unlinkSidecarSync: typeof fsSync.unlinkSync;
367
- sleep: typeof sleep;
368
- collectGarbageBestEffort: typeof collectGarbageBestEffort;
369
- ACTIVE_STATE_DIRS_TO_CLEAN: string[];
370
- countSessionKnowledgeEntries: typeof countSessionKnowledgeEntries;
371
- CLOSE_SKILL_REVIEW_TIMEOUT_MS: number;
372
- CLOSE_REFLECTION_TIMEOUT_MS: number;
373
- detectFullAuto: typeof detectFullAuto;
374
- guaranteeAllPlansComplete: typeof guaranteeAllPlansComplete;
375
- getGitRepositoryStatus: typeof getGitRepositoryStatus;
376
- resetToMainAfterMerge: typeof resetToMainAfterMerge;
377
- resetToRemoteBranch: typeof resetToRemoteBranch;
378
- copyDirRecursive: typeof copyDirRecursive;
379
- loadPluginConfigWithMeta: typeof loadPluginConfigWithMeta;
380
- curateAndStoreSwarm: typeof curateAndStoreSwarm;
381
- checkHivePromotions: typeof checkHivePromotions;
382
- runCuratorPostMortem: typeof runCuratorPostMortem;
383
- createCuratorLLMDelegate: typeof createCuratorLLMDelegate;
384
- resetSwarmStatePreservingSingletons: typeof resetSwarmStatePreservingSingletons;
385
- runFinalizeStage: typeof runFinalizeStage;
386
- runFinalizeRewardSweep: typeof runFinalizeRewardSweep;
387
- acquireFinalizeLock: typeof acquireFinalizeLock;
388
- runArchiveStage: typeof runArchiveStage;
389
- archiveCloseSummary: typeof archiveCloseSummary;
390
- runArchiveEvidenceRetention: typeof runArchiveEvidenceRetention;
391
- runCleanStage: typeof runCleanStage;
392
- runAlignStage: typeof runAlignStage;
393
- runFinalizeDryRun: typeof runFinalizeDryRun;
394
- archiveEvidence: typeof archiveEvidence;
395
- closePlanTerminalState: typeof reconcileCloseTerminalStateForPlan;
396
- endAgentSession: typeof endAgentSession;
397
- flushAndDrainTelemetry: () => Promise<void>;
398
- finalizeContextTelemetry: (directory: string) => void;
399
- finalizeCoreEvents: (directory: string) => void;
400
- finalizeShellAudit: (directory: string) => void;
401
- };
402
- export {};
1
+ export { runAlignStage } from './close/align-stage.js';
2
+ export { emitCloseArchiveResult, runArchiveEvidenceRetention, runArchiveStage, } from './close/archive-stage.js';
3
+ export { runCleanStage } from './close/clean-stage.js';
4
+ export { ACTIVE_STATE_DIRS_TO_CLEAN, ACTIVE_STATE_TO_CLEAN, ARCHIVE_ARTIFACTS, } from './close/constants.js';
5
+ export type { ArchiveAttempt, ArchiveRequiredness, ArchiveSourceDisposition, ArchiveStageContext, ArchiveValidation, ArtifactArchiveResult, CleanStageResult, CloseStageContext, GitAlignResult, } from './close/context.js';
6
+ export { removeSqliteSidecarsAfterClose } from './close/db-helpers.js';
7
+ export { runFinalizeDryRun } from './close/dry-run.js';
8
+ export { runFinalizeStage } from './close/finalize-stage.js';
9
+ export { _internals, closeReceiptLifecycleInternals, } from './close/internals.js';
10
+ export { handleCloseCommand } from './close/orchestrator.js';
@@ -1,3 +1,6 @@
1
+ import * as fs from 'node:fs';
2
+ import { clearPlanLedgerForReset } from '../plan/ledger.js';
3
+ import { withPlanLifecycleLock } from '../plan/manager.js';
1
4
  import { type ResetBackupResult } from './reset-backup';
2
5
  /**
3
6
  * _internals DI seam so tests can stub the pre-deletion backup without touching
@@ -6,6 +9,13 @@ import { type ResetBackupResult } from './reset-backup';
6
9
  */
7
10
  export declare const _internals: {
8
11
  backupSwarmStateBeforeReset: (directory: string, kind: 'reset' | 'reset-session', relEntries: string[]) => ResetBackupResult;
12
+ clearPlanLedgerForReset: typeof clearPlanLedgerForReset;
13
+ withPlanLifecycleLock: typeof withPlanLifecycleLock;
14
+ existsSync: typeof fs.existsSync;
15
+ readFileSync: typeof fs.readFileSync;
16
+ unlinkSync: typeof fs.unlinkSync;
17
+ writeFileSync: typeof fs.writeFileSync;
18
+ rmSync: typeof fs.rmSync;
9
19
  };
10
20
  /**
11
21
  * Handles the /swarm reset command.
@@ -1,3 +1,12 @@
1
+ import { clearPlanLedgerForReset, peekPlanFromLedger, replacePlanLedgerWithRoot } from '../plan/ledger';
2
+ import { withPlanLifecycleLock } from '../plan/manager';
3
+ /** Test-only seam for the atomic ledger re-root lifecycle transition. */
4
+ export declare const _internals: {
5
+ replacePlanLedgerWithRoot: typeof replacePlanLedgerWithRoot;
6
+ clearPlanLedgerForReset: typeof clearPlanLedgerForReset;
7
+ peekPlanFromLedger: typeof peekPlanFromLedger;
8
+ withPlanLifecycleLock: typeof withPlanLifecycleLock;
9
+ };
1
10
  /**
2
11
  * Handle /swarm rollback command
3
12
  * Restores .swarm/ state from a checkpoint using direct overwrite
@@ -1395,6 +1395,7 @@ export declare const WorktreeIsolationConfigSchema: z.ZodObject<{
1395
1395
  }>>;
1396
1396
  serialization_release_after_dispatches: z.ZodDefault<z.ZodNumber>;
1397
1397
  serialization_release_after_ms: z.ZodDefault<z.ZodNumber>;
1398
+ session_create_timeout_ms: z.ZodDefault<z.ZodNumber>;
1398
1399
  runtime_isolation: z.ZodOptional<z.ZodObject<{
1399
1400
  enabled: z.ZodDefault<z.ZodBoolean>;
1400
1401
  port_base: z.ZodOptional<z.ZodNumber>;
@@ -1889,6 +1890,26 @@ export declare const LaneLivenessWatchdogConfigSchema: z.ZodObject<{
1889
1890
  stall_token_threshold: z.ZodDefault<z.ZodNumber>;
1890
1891
  }, z.core.$strict>;
1891
1892
  export type LaneLivenessWatchdogConfig = z.infer<typeof LaneLivenessWatchdogConfigSchema>;
1893
+ /**
1894
+ * Issue #2507 dispatch protection: an action-local spawn-protection circuit
1895
+ * plus a token-bucket dispatch rate limit for native task delegations.
1896
+ *
1897
+ * Default-ON follows the guardrails family (`guardrails.enabled` defaults
1898
+ * true): the numbers are deliberately conservative (10 dispatches per second
1899
+ * with a burst of 10 never waits in normal use), and every knob is
1900
+ * user-overridable — set `enabled: false` to opt out entirely, or
1901
+ * `rate_per_second: 0` to disable only the limiter. Parameter surface
1902
+ * adopted with credit from opencode-ensemble (reimplemented per ADR 0002 —
1903
+ * no upstream code is ported).
1904
+ */
1905
+ export declare const DispatchProtectionConfigSchema: z.ZodObject<{
1906
+ enabled: z.ZodDefault<z.ZodBoolean>;
1907
+ spawn_failure_threshold: z.ZodDefault<z.ZodNumber>;
1908
+ half_open_after_ms: z.ZodDefault<z.ZodNumber>;
1909
+ rate_per_second: z.ZodDefault<z.ZodNumber>;
1910
+ burst_capacity: z.ZodDefault<z.ZodNumber>;
1911
+ }, z.core.$strict>;
1912
+ export type DispatchProtectionConfig = z.infer<typeof DispatchProtectionConfigSchema>;
1892
1913
  /**
1893
1914
  * Issue #2384: deprecated transcript-row settlement for Profile A PR-review
1894
1915
  * base/micro discovery lanes is an explicit compatibility opt-in. Omitted
@@ -2001,6 +2022,13 @@ export declare const PluginConfigSchema: z.ZodObject<{
2001
2022
  stall_min_steps: z.ZodDefault<z.ZodNumber>;
2002
2023
  stall_token_threshold: z.ZodDefault<z.ZodNumber>;
2003
2024
  }, z.core.$strict>>;
2025
+ dispatch_protection: z.ZodOptional<z.ZodObject<{
2026
+ enabled: z.ZodDefault<z.ZodBoolean>;
2027
+ spawn_failure_threshold: z.ZodDefault<z.ZodNumber>;
2028
+ half_open_after_ms: z.ZodDefault<z.ZodNumber>;
2029
+ rate_per_second: z.ZodDefault<z.ZodNumber>;
2030
+ burst_capacity: z.ZodDefault<z.ZodNumber>;
2031
+ }, z.core.$strict>>;
2004
2032
  pr_review_legacy_transcript_compatibility: z.ZodOptional<z.ZodBoolean>;
2005
2033
  gates: z.ZodOptional<z.ZodObject<{
2006
2034
  syntax_check: z.ZodDefault<z.ZodObject<{
@@ -2801,6 +2829,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
2801
2829
  }>>;
2802
2830
  serialization_release_after_dispatches: z.ZodDefault<z.ZodNumber>;
2803
2831
  serialization_release_after_ms: z.ZodDefault<z.ZodNumber>;
2832
+ session_create_timeout_ms: z.ZodDefault<z.ZodNumber>;
2804
2833
  runtime_isolation: z.ZodOptional<z.ZodObject<{
2805
2834
  enabled: z.ZodDefault<z.ZodBoolean>;
2806
2835
  port_base: z.ZodOptional<z.ZodNumber>;
@@ -39,6 +39,14 @@ export declare function projectDbPath(directory: string): string;
39
39
  * workspace just to check for a missing record.
40
40
  */
41
41
  export declare function projectDbExists(directory: string): boolean;
42
+ /**
43
+ * Open the existing project database for one observational callback.
44
+ *
45
+ * Unlike `getProjectDb`, this never creates directories, negotiates WAL, runs
46
+ * migrations, or enters the shared connection cache. It is the only suitable
47
+ * path for lifecycle previews such as `/swarm close --dry-run`.
48
+ */
49
+ export declare function withProjectDbReadOnly<T>(directory: string, read: (db: Database) => T): T | null;
42
50
  /**
43
51
  * Best-effort WAL checkpoint before close (issue #2480 checkpoint policy).
44
52
  *
@@ -51,8 +51,9 @@ interface NodeDatabaseSync {
51
51
  loadExtension(path: string): void;
52
52
  close(): void;
53
53
  }
54
- type NodeDatabaseSyncCtor = new (filename: string, options?: {
54
+ type NodeDatabaseSyncCtor = new (filename: string | URL, options?: {
55
55
  allowExtension?: boolean;
56
+ readOnly?: boolean;
56
57
  }) => NodeDatabaseSync;
57
58
  /**
58
59
  * Build a `bun:sqlite`-`Database`-compatible constructor backed by `node:sqlite`'s
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Action-local spawn-protection circuit for native task delegations
3
+ * (issue #2507 / ADR 0002 G3 — reimplemented, no upstream code ported).
4
+ *
5
+ * Ownership boundary (one accounting owner per failure category,
6
+ * docs/invocation-failures.md): this circuit owns repeated ACTUAL dispatch
7
+ * failures of the SAME semantic action on the native `task` route. Policy
8
+ * denials stay with the gate-denial tracker, shell-structural failures with
9
+ * the non-transient circuit, PR-review lane provider-terminal with the
10
+ * PR-review resilience circuit, provable-non-acceptance launch retry with
11
+ * #2473, and lane liveness with #2506.
12
+ *
13
+ * State machine (the src/pr-review/circuit.ts timed HALF_OPEN precedent):
14
+ * CLOSED -> (threshold failures) -> OPEN -> (denyUntil elapses, next dispatch
15
+ * admitted) -> HALF_OPEN (exactly one probe) -> completed probe closes |
16
+ * failed probe re-opens with a fresh interval.
17
+ *
18
+ * The state is process-local, invocation-owned, and bounded — the
19
+ * docs/invocation-failures.md contract for action circuits (only the
20
+ * PR-review resilience circuit is durable).
21
+ */
22
+ /** Bounded memory: same discipline as MAX_TRACKED_ACTION_CIRCUITS. */
23
+ export declare const MAX_TRACKED_SPAWN_CIRCUITS = 500;
24
+ export declare const SPAWN_CIRCUIT_TTL_MS: number;
25
+ /** Bounded armed-digest map (late toolAfter results must not grow it). */
26
+ export declare const MAX_ARMED_DISPATCH_IDENTITIES = 500;
27
+ /** Frozen denial code — gate-denial-tracker exempts exactly this code. */
28
+ export declare const SPAWN_CIRCUIT_DENIAL_CODE = "SPAWN PROTECTION CIRCUIT OPEN";
29
+ export interface SpawnCircuitEntry {
30
+ state: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
31
+ sessionID: string;
32
+ invocationID: string;
33
+ actionDigest: string;
34
+ failureCount: number;
35
+ openedAt: number;
36
+ denyUntil: number;
37
+ /** Denials issued in the current OPEN episode (reset on each OPEN). */
38
+ denialsInEpisode: number;
39
+ updatedAt: number;
40
+ }
41
+ export declare function invocationIdForSession(sessionID: string): string;
42
+ /**
43
+ * Compute the dispatch identity for a tool + args WITHOUT storing anything.
44
+ * Shared by armDispatchIdentity (before-hook step 0) and by the after-hook
45
+ * recorder's fallback (which must not re-insert into the bounded armed map
46
+ * — a stored-but-never-consumed entry would evict legitimate pending
47
+ * identities under review feedback WD-1).
48
+ */
49
+ export declare function dispatchIdentityFor(tool: string, args: unknown): {
50
+ digest: string;
51
+ pattern: string;
52
+ };
53
+ /**
54
+ * Arm the pre-mutation dispatch identity for a callID. Step 0 of the
55
+ * fail-closed tool.execute.before region calls this BEFORE any hook can
56
+ * mutate `output.args` (skill / delegate-directive injection), so the
57
+ * toolAfter recorder consumes the SAME digest the circuit was keyed with —
58
+ * a corrected success can never clear a phantom key (plan Round 1
59
+ * revision 2).
60
+ */
61
+ export declare function armDispatchIdentity(callID: string, tool: string, args: unknown): {
62
+ digest: string;
63
+ pattern: string;
64
+ };
65
+ /** Consume the armed identity for a callID (fallback: undefined). */
66
+ export declare function takeArmedDispatchIdentity(callID: string): {
67
+ digest: string;
68
+ pattern: string;
69
+ } | undefined;
70
+ /**
71
+ * Record one ACTUAL dispatch failure for the matching action. Returns the
72
+ * entry and whether this call performed the CLOSED->OPEN transition (the
73
+ * caller emits exactly one bounded telemetry event on that transition).
74
+ */
75
+ export declare function noteDispatchSpawnFailure(input: {
76
+ sessionID: string;
77
+ invocationID: string;
78
+ actionDigest: string;
79
+ threshold: number;
80
+ halfOpenAfterMs: number;
81
+ now?: number;
82
+ }): {
83
+ entry: SpawnCircuitEntry;
84
+ opened: boolean;
85
+ };
86
+ /**
87
+ * Deny when the matching action's circuit is OPEN (before its interval
88
+ * elapses) or when a half-open probe is already in flight. When the open
89
+ * interval has elapsed, this call is ADMITTED as the single probe.
90
+ * Throws an Error whose leading token is the frozen
91
+ * SPAWN_CIRCUIT_DENIAL_CODE so the gate-denial tracker can exempt it.
92
+ */
93
+ export declare function assertDispatchSpawnCircuitAdmits(input: {
94
+ sessionID: string;
95
+ invocationID: string;
96
+ actionDigest: string;
97
+ threshold: number;
98
+ halfOpenAfterMs: number;
99
+ now?: number;
100
+ }): void;
101
+ /**
102
+ * A corrected successful execution clears ONLY the matching action's entry
103
+ * (and closes an in-flight half-open probe). Failures of other actions are
104
+ * never touched.
105
+ */
106
+ export declare function noteDispatchSpawnSuccess(input: {
107
+ sessionID: string;
108
+ invocationID: string;
109
+ actionDigest: string;
110
+ }): void;
111
+ export declare function getSpawnCircuitEntry(input: {
112
+ sessionID: string;
113
+ invocationID: string;
114
+ actionDigest: string;
115
+ }): SpawnCircuitEntry | undefined;
116
+ export declare function spawnCircuitIsTaskTool(tool: string): boolean;
117
+ /** Test seam: reset all circuits + armed identities between test files. */
118
+ export declare function _clearAllSpawnCircuits(): void;
119
+ export declare const _internals: {
120
+ now: () => number;
121
+ };