opencode-swarm 7.166.2 → 7.166.4

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 (106) hide show
  1. package/.opencode/skills/council/SKILL.md +4 -1
  2. package/.opencode/skills/deep-dive/SKILL.md +1 -1
  3. package/.opencode/skills/deep-research/SKILL.md +4 -1
  4. package/.opencode/skills/gate-attribution/SKILL.md +3 -0
  5. package/.opencode/skills/pre-phase-briefing/SKILL.md +8 -0
  6. package/.opencode/skills/swarm-pr-review/SKILL.md +30 -30
  7. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  8. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  9. package/dist/cli/{coder-settlement-pv86n7n4.js → coder-settlement-yynntj5j.js} +11 -11
  10. package/dist/cli/{config-doctor-fy1aytwt.js → config-doctor-8asc35km.js} +2 -2
  11. package/dist/cli/{core-1d9vqbt4.js → core-qrbhs2q4.js} +1 -1
  12. package/dist/cli/{curation-policy-gnpgc3z7.js → curation-policy-bvxf5pxv.js} +9 -6
  13. package/dist/cli/{curator-drift-efmgp1v2.js → curator-drift-20m2ab5w.js} +4 -4
  14. package/dist/cli/curator-llm-factory-rs4921ks.js +71 -0
  15. package/dist/cli/{curator-a4rbehfr.js → curator-qk4xmkv4.js} +37 -36
  16. package/dist/cli/{evidence-summary-service-dvp1kbm4.js → evidence-summary-service-rktcp3s4.js} +15 -15
  17. package/dist/cli/{gate-evidence-qf27gdfx.js → gate-evidence-k6nzqca1.js} +6 -6
  18. package/dist/cli/guardrail-explain-jdspxzjr.js +72 -0
  19. package/dist/cli/{guardrail-log-qhw3knjt.js → guardrail-log-962pzjev.js} +7 -7
  20. package/dist/cli/{guardrail-reset-84ydxdg3.js → guardrail-reset-dv02t0bm.js} +37 -36
  21. package/dist/cli/{hive-promoter-y2daybf6.js → hive-promoter-9zzr28p2.js} +37 -36
  22. package/dist/cli/{index-ytsts0zj.js → index-0v6bf0j9.js} +1 -1
  23. package/dist/cli/{index-bysyj3z4.js → index-1aex5zd9.js} +1 -1
  24. package/dist/cli/{index-p0r5fn7y.js → index-251vrmge.js} +2 -2
  25. package/dist/cli/{index-sxe3t040.js → index-2w0beg3s.js} +2 -2
  26. package/dist/cli/{index-sxsyd7kf.js → index-3ct7fd75.js} +6 -6
  27. package/dist/cli/{index-jr6tppv9.js → index-3nm1b3t2.js} +7 -7
  28. package/dist/cli/{index-22sannyk.js → index-3s194swm.js} +36 -10
  29. package/dist/cli/{index-ft1tnx0e.js → index-5bd84nxc.js} +1 -1
  30. package/dist/cli/{index-gy55mc55.js → index-5qws47d4.js} +3369 -2820
  31. package/dist/cli/{index-7pp8fz4j.js → index-6d4dc99f.js} +1 -1
  32. package/dist/cli/{index-nthqfxzz.js → index-75f9jj3h.js} +2 -2
  33. package/dist/cli/{index-x4azb6qj.js → index-7g5kdtvw.js} +2 -2
  34. package/dist/cli/{index-qmp4gxac.js → index-8ewgab6z.js} +1 -1
  35. package/dist/cli/{index-0a0jsbhg.js → index-9eswrdp5.js} +1 -1
  36. package/dist/cli/{index-x8cvbkjs.js → index-9wv6a3jx.js} +2 -2
  37. package/dist/cli/{index-c0eyq4rp.js → index-bxrxqwce.js} +4 -4
  38. package/dist/cli/{index-bks56jbg.js → index-f6zgz02s.js} +3 -3
  39. package/dist/cli/{index-2n1v8ft1.js → index-gccxen4x.js} +5 -1
  40. package/dist/cli/{index-7mxrqy4r.js → index-gr5wg0nj.js} +7 -7
  41. package/dist/cli/{index-st47knj6.js → index-gsftf6c8.js} +3 -3
  42. package/dist/cli/{index-wz258yje.js → index-kwervbv6.js} +11 -11
  43. package/dist/cli/{index-3nww2vnx.js → index-kz44j3qe.js} +8 -8
  44. package/dist/cli/{index-19hjpqsy.js → index-m21x1bkx.js} +17 -9
  45. package/dist/cli/{index-j81kpway.js → index-m3tx1q9v.js} +1 -1
  46. package/dist/cli/{index-z1kmkh72.js → index-m9q6f3ty.js} +2 -2
  47. package/dist/cli/{index-3wtfrjcx.js → index-n189w64j.js} +3 -3
  48. package/dist/cli/{index-ty0wg9yp.js → index-n65x6e1y.js} +5 -5
  49. package/dist/cli/{index-hgphhnrp.js → index-qd619x3r.js} +2 -2
  50. package/dist/cli/{index-fkk7x6sy.js → index-qd726agw.js} +2 -2
  51. package/dist/cli/{index-jgtje76m.js → index-qv4byzwp.js} +94 -29
  52. package/dist/cli/{index-c23w8t46.js → index-qww0h314.js} +11 -6
  53. package/dist/cli/{index-y3dtdn2f.js → index-rk10x4zr.js} +1 -1
  54. package/dist/cli/{index-4kwxpnf8.js → index-sahf5yz3.js} +1 -1
  55. package/dist/cli/{index-e0bjbadr.js → index-shqhq68n.js} +8 -3
  56. package/dist/cli/{index-kd68b6mg.js → index-st1zw5ps.js} +2 -2
  57. package/dist/cli/{index-14z9en94.js → index-t8tw1bhs.js} +1 -1
  58. package/dist/cli/{index-9ccxcjdm.js → index-v5wanchr.js} +4 -4
  59. package/dist/cli/index-vzm6zre7.js +167 -0
  60. package/dist/cli/{index-8nv3bc9h.js → index-wd86yj53.js} +4 -4
  61. package/dist/cli/{index-nrdj94za.js → index-x8c42y8s.js} +39 -38
  62. package/dist/cli/{index-hbjax6hy.js → index-z62gdhkd.js} +8 -8
  63. package/dist/cli/index.js +37 -36
  64. package/dist/cli/{knowledge-escalator-aq7gzhpd.js → knowledge-escalator-w4bfnks3.js} +13 -12
  65. package/dist/cli/{knowledge-events-9z5sskyv.js → knowledge-events-wmnx8m6b.js} +10 -10
  66. package/dist/cli/{knowledge-link-ps2v4s18.js → knowledge-link-w1fwqts4.js} +4 -4
  67. package/dist/cli/{knowledge-store-1hzt2a0t.js → knowledge-store-5442ph4m.js} +8 -5
  68. package/dist/cli/{knowledge-validator-xe1fza7c.js → knowledge-validator-5rmardr4.js} +8 -7
  69. package/dist/cli/{pending-delegations-0nfjg7vp.js → pending-delegations-ea6zpqw2.js} +12 -11
  70. package/dist/cli/{pr-subscriptions-8974hwa0.js → pr-subscriptions-yqxt0avv.js} +12 -11
  71. package/dist/cli/{pr-workflow-gate-xgak5wvz.js → pr-workflow-gate-px36rczj.js} +37 -36
  72. package/dist/cli/{runner-7zqbp81n.js → runner-nmrjv7te.js} +5 -5
  73. package/dist/cli/{scan-cursor-hc4v0c90.js → scan-cursor-efrage98.js} +7 -6
  74. package/dist/cli/{schema-w1hsvw1h.js → schema-w2sds948.js} +3 -1
  75. package/dist/cli/{scope-persistence-k17003v4.js → scope-persistence-dd7p3tdv.js} +15 -14
  76. package/dist/cli/{skill-generator-tbxgpc9x.js → skill-generator-c0720k51.js} +15 -14
  77. package/dist/cli/{snapshot-coordination-init-vaf34wf0.js → snapshot-coordination-init-dp42vvme.js} +37 -36
  78. package/dist/cli/{telemetry-8qn4eag5.js → telemetry-ce0tx41h.js} +1 -1
  79. package/dist/cli/{workspace-snapshot-y85jy6gs.js → workspace-snapshot-0kxj2grt.js} +3 -3
  80. package/dist/cli/{worktree-collision-ownership-r3jdke7h.js → worktree-collision-ownership-emh2yhpx.js} +13 -12
  81. package/dist/cli/{worktree-isolation-sa1tbqff.js → worktree-isolation-a8f1yahq.js} +37 -36
  82. package/dist/commands/close.d.ts +82 -0
  83. package/dist/config/schema.d.ts +9 -0
  84. package/dist/context-map/capsule-persistence.d.ts +13 -8
  85. package/dist/hooks/delegate-ack-collector.d.ts +7 -0
  86. package/dist/hooks/knowledge-store.d.ts +7 -0
  87. package/dist/hooks/review-receipt.d.ts +29 -1
  88. package/dist/index.js +554 -551
  89. package/dist/knowledge/curation-policy.d.ts +7 -0
  90. package/dist/memory/consolidation-log.d.ts +9 -0
  91. package/dist/memory/injector.d.ts +7 -0
  92. package/dist/memory/run-log.d.ts +8 -0
  93. package/dist/retention/caps.d.ts +33 -0
  94. package/dist/retention/dir-prune.d.ts +72 -0
  95. package/dist/retention/jsonl-cap.d.ts +84 -0
  96. package/dist/retention/sweep.d.ts +67 -0
  97. package/dist/services/compaction-service.d.ts +14 -0
  98. package/dist/services/skill-changelog.d.ts +20 -0
  99. package/dist/summaries/manager.d.ts +41 -4
  100. package/dist/test-impact/history-store.d.ts +16 -0
  101. package/dist/turbo/epic/calibration.d.ts +16 -1
  102. package/dist/turbo/epic/divergence-recorder.d.ts +11 -0
  103. package/opencode-swarm.schema.json +15 -0
  104. package/package.json +1 -1
  105. package/dist/cli/curator-llm-factory-cwg62ynw.js +0 -70
  106. package/dist/cli/guardrail-explain-zskpzgsr.js +0 -71
@@ -85,6 +85,13 @@ export interface CohortQuorumConfig {
85
85
  /** Minimum distinct cohort events (e.g. violations) required to authorize. */
86
86
  minCohortEvidence: number;
87
87
  }
88
+ /**
89
+ * Global FIFO cap on the curation-proposals audit stream (issue #2483 §2).
90
+ * Enforcement resolves the effective value through `resolveRetentionCap` so
91
+ * the #2483 acceptance checks can shrink the cap below this default and prove
92
+ * the writer clamps.
93
+ */
94
+ export declare const MAX_CURATION_PROPOSALS = 200;
88
95
  /**
89
96
  * Authorize a destructive curation action against a single entry.
90
97
  *
@@ -31,5 +31,14 @@ export interface ConsolidationLogRecord {
31
31
  errored: number;
32
32
  processedProposalIds: string[];
33
33
  }
34
+ /**
35
+ * Global FIFO cap on the consolidation log (issue #2483 §2). Enforcement and
36
+ * the bounded read both resolve the effective value through
37
+ * `resolveRetentionCap` so the #2483 acceptance checks can shrink the cap
38
+ * below this default and prove the writer clamps. The cap keeps last-N
39
+ * semantics: records are returned oldest-to-newest, so callers that
40
+ * `slice(-limit)` for the CLI's last-N view keep working.
41
+ */
42
+ export declare const MAX_CONSOLIDATION_LOG_ENTRIES = 500;
34
43
  export declare function readConsolidationLog(target: string | VettedMemoryRoot): Promise<ConsolidationLogRecord[]>;
35
44
  export declare function appendConsolidationLog(target: string | VettedMemoryRoot, record: ConsolidationLogRecord): Promise<void>;
@@ -33,6 +33,13 @@ export interface MemoryLifecycleHooks {
33
33
  toolAfter(input: unknown, output: unknown): Promise<void>;
34
34
  }
35
35
  export declare function createMemoryLifecycleHooks(options: MemoryLifecycleHookOptions): MemoryLifecycleHooks;
36
+ /**
37
+ * Global FIFO cap on the (env-gated) unitid-probe audit stream (issue #2483
38
+ * §2). Enforcement resolves the effective value through
39
+ * `resolveRetentionCap` so the #2483 acceptance checks can shrink the cap
40
+ * below this default and prove the writer clamps.
41
+ */
42
+ export declare const MAX_UNITID_PROBE_ENTRIES = 2000;
36
43
  declare function messagesContainRecall(messages: unknown[]): boolean;
37
44
  declare function recallMessageInsertIndex(messages: unknown[]): number;
38
45
  declare function compactText(text: string): string;
@@ -20,5 +20,13 @@ export interface MemoryRunLogEvent {
20
20
  memoriesDecayed?: number;
21
21
  metadata?: Record<string, unknown>;
22
22
  }
23
+ /**
24
+ * Global FIFO cap on each run's `memory.jsonl` run log (issue #2483 §2).
25
+ * Enforcement resolves the effective value through `resolveRetentionCap` so
26
+ * the #2483 acceptance checks can shrink the cap below this default and
27
+ * prove the writer clamps. Keyspace (run directories) is handled by the
28
+ * retention sweep and close lifecycle.
29
+ */
30
+ export declare const MAX_RUN_LOG_ENTRIES = 2000;
23
31
  export declare function appendMemoryRunLog(directory: string, runId: string | undefined, event: MemoryRunLogEvent): Promise<void>;
24
32
  export declare function sanitizeRunId(runId: string | undefined): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Test-visible cap seam for every #2483 retention bound (issue #2483 §0).
3
+ *
4
+ * Writers keep their cap constants exported on their own modules (registry
5
+ * citations point there), but ENFORCEMENT must resolve the effective value
6
+ * through {@link resolveRetentionCap} so tests and acceptance checks can
7
+ * shrink a cap below its production default and prove the writer actually
8
+ * clamps. A writer that reads only its own constant is unfalsifiable at cap+1
9
+ * test widths that are impractical to write (10 000 entries / 8 MiB).
10
+ *
11
+ * Pure module: no filesystem, no imports — safe on the init path and under
12
+ * both the Bun and Node hosts (AGENTS.md invariant 2).
13
+ */
14
+ /** Canonical cap names (frozen by the #2483 acceptance checks). */
15
+ export type RetentionCapName = 'MAX_RETRACTION_RECORDS' | 'MAX_UNACKNOWLEDGED_CRITICALS' | 'MAX_CURATION_PROPOSALS' | 'MAX_CONSOLIDATION_LOG_ENTRIES' | 'MAX_CONTEXT_SNAPSHOT_BYTES' | 'MAX_CONTEXT_SNAPSHOT_ENTRIES' | 'MAX_CALIBRATION_MODULES' | 'MAX_DIVERGENCE_BYTES' | 'MAX_TEST_HISTORY_ENTRIES' | 'MAX_TEST_HISTORY_KEYS' | 'MAX_SKILL_CHANGELOG_ENTRIES_PER_SKILL' | 'MAX_SKILL_CHANGELOG_GLOBAL_ENTRIES' | 'MAX_RECEIPTS_READ' | 'MAX_CAPSULES_LISTED' | 'MAX_SUMMARIES_LISTED' | 'MAX_RUN_LOG_ENTRIES' | 'MAX_UNITID_PROBE_ENTRIES';
16
+ /**
17
+ * Install test cap overrides (partial). Production code never calls this;
18
+ * tests and the #2483 acceptance checks do. Values are validated to be
19
+ * positive finite numbers so a bad fixture fails loudly at install time.
20
+ */
21
+ export declare function setRetentionCapOverrides(partial: Partial<Record<RetentionCapName, number>>): void;
22
+ /** Clear every override (test teardown). */
23
+ export declare function clearRetentionCapOverrides(): void;
24
+ /**
25
+ * Resolve the effective cap for {@link name}: the installed override when
26
+ * present, otherwise {@link defaultValue}. Every capped writer routes its
27
+ * enforcement through this function.
28
+ */
29
+ export declare function resolveRetentionCap(name: RetentionCapName, defaultValue: number): number;
30
+ /** Test/inspection seam. */
31
+ export declare const _internals: {
32
+ overrides: Map<string, number>;
33
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Age/count directory pruner (issue #2483 §1).
3
+ *
4
+ * Deletes the OLDEST entries (mtime ascending, deterministic code-unit name
5
+ * tie-break — never localeCompare) until the directory is within its caps.
6
+ *
7
+ * A DIRECTORY entry is aged by its CONTENT, not by the directory node's own
8
+ * mtime: the effective mtime is the newest regular-file mtime anywhere in the
9
+ * subtree (bounded, symlink-refusing). A directory's own mtime only reflects
10
+ * metadata churn (entry creates/deletes/renames — e.g. another pruner
11
+ * deleting a sibling refreshes the parent), so content age is the honest
12
+ * "last write activity" signal. An empty subtree falls back to the
13
+ * directory's own mtime; an unreadable or scan-budget-exhausted subtree is
14
+ * treated as unprunable (effective mtime +Infinity — never a victim).
15
+ *
16
+ * Containment properties (issue #2483 edge cases):
17
+ * - symlink/junction entries are NEVER traversed or deleted (lstat check —
18
+ * the #2127 marker-symlink precedent), including inside subtrees;
19
+ * - entries with future mtimes (clock skew) are NEVER pruned;
20
+ * - enumeration is bounded (`maxScan`, per directory level AND per subtree
21
+ * walk) so a huge directory cannot turn the pruner into an unbounded scan
22
+ * on a cold Windows filesystem;
23
+ * - per-entry failures are swallowed (fail-open): one unreadable entry
24
+ * never aborts the family.
25
+ */
26
+ export interface PruneDirectoryOptions {
27
+ /** Keep at most this many entries (newest by mtime). */
28
+ maxEntries?: number;
29
+ /** Delete entries strictly older than this (ms before `now`). */
30
+ maxAgeMs?: number;
31
+ /** Clock injection point for tests/checks. */
32
+ now?: number;
33
+ /**
34
+ * Enumeration bound (default 100000 — review FB-12: 20000 stat ops could
35
+ * exhaust before a legitimately large keyspace finished enumerating,
36
+ * silently skipping stale tail entries; the budget is stats, not
37
+ * deletions, so the higher ceiling stays bounded).
38
+ */
39
+ maxScan?: number;
40
+ /** Count victims without deleting (blast-radius rehearsal / dry_run). */
41
+ dryRun?: boolean;
42
+ }
43
+ export interface PruneCandidate {
44
+ name: string;
45
+ mtimeMs: number;
46
+ }
47
+ /**
48
+ * Effective mtime of a subtree: the newest regular-file mtime found inside
49
+ * (never traversing symlinks), or `null` when the subtree contains no files.
50
+ * `POSITIVE_INFINITY` signals "could not verify within budget" — callers must
51
+ * treat that as unprunable. The walk is bounded by `maxScan` stat operations
52
+ * total, so a pathological subtree degrades to keep, never to an unbounded
53
+ * scan.
54
+ */
55
+ export declare function subtreeNewestFileMtime(root: string, maxScan: number): number | null;
56
+ /**
57
+ * Per-subtree walk budget. Deliberately NOT the caller's `maxScan`: the
58
+ * top-level enumeration bound must not multiply into every child subtree.
59
+ * Run/batch/candidate directories hold a handful of files each; 2000 stat
60
+ * operations per subtree is generous, and exhausting it degrades to keep.
61
+ */
62
+ export declare const SUBTREE_SCAN_CAP = 2000;
63
+ /** List bounded entries with effective mtimes; symlinked entries are collected separately and refused. */
64
+ export declare function listPruneCandidates(dir: string, maxScan: number): {
65
+ candidates: PruneCandidate[];
66
+ refusedSymlinks: string[];
67
+ };
68
+ /**
69
+ * Prune `dir` down to its caps. Returns the number of entries deleted. A
70
+ * missing directory is a no-op (0). `dryRun` counts without deleting.
71
+ */
72
+ export declare function pruneDirectory(dir: string, opts: PruneDirectoryOptions): Promise<number>;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Capped JSONL append + bounded tail read (issue #2483 §1).
3
+ *
4
+ * `appendCappedJsonl` enforces the entry/byte caps on EVERY completed state:
5
+ * when an append would push the file past its caps, the compacted prefix
6
+ * (newest whole records that fit, minus the incoming record) is first
7
+ * swapped in crash-atomically (temp file + rename with a Windows
8
+ * transient-error retry), then the new record is appended — so an
9
+ * interleaved reader never observes more than the caps. Compaction has a
10
+ * whole-record floor: a non-empty stream is never emptied by compaction —
11
+ * at least the newest single record always survives, whatever the effective
12
+ * cap (the #2483 acceptance contract).
13
+ *
14
+ * Concurrency: all calls for the same `filePath` serialize through a
15
+ * per-file async mutex, so in-process concurrent appenders can never lose a
16
+ * line to the compaction rename (review finding FB-4). Cross-process
17
+ * writers remain best-effort by the documented fail-open contract (audit
18
+ * streams; the one lockfile-guarded writer predates this module).
19
+ *
20
+ * `readTailJsonl` reads only the last `maxBytes` bytes (newline-aligned) and
21
+ * parses at most `maxEntries` records from the end, so every reader that
22
+ * routes through it is O(cap), not O(history). `readTailJsonlDetailed`
23
+ * additionally reports whether a torn trailing line was skipped, for
24
+ * callers whose conservative decisions depend on tail completeness.
25
+ *
26
+ * Plumbing module: callers own their streams (retention-registry exemption;
27
+ * callers' rows carry the citations).
28
+ */
29
+ export interface CappedJsonlOptions {
30
+ maxEntries: number;
31
+ /** Optional byte cap for the compacted file. */
32
+ maxBytes?: number;
33
+ /**
34
+ * Invoked when compaction drops `droppedCount` oldest records to enforce
35
+ * the caps. Lets stream owners surface truncation (review finding FB-5)
36
+ * instead of failing silently; failures thrown here are swallowed.
37
+ */
38
+ onPrune?: (droppedCount: number) => void;
39
+ }
40
+ declare function withFileLock<T>(filePath: string, task: () => Promise<T>): Promise<T>;
41
+ /**
42
+ * Test/inspection seam (review round 2): exposes the mutex so the
43
+ * concurrent-append test can assert the chain fully drains instead of
44
+ * reasoning about the self-deletion logic.
45
+ */
46
+ export declare const _internals: {
47
+ appendChains: Map<string, Promise<void>>;
48
+ withFileLock: typeof withFileLock;
49
+ };
50
+ /**
51
+ * Append `line` (a bare JSON record without the trailing newline) to
52
+ * `filePath`, enforcing the caps with a crash-atomic compaction when
53
+ * exceeded. Calls for the same file serialize through a per-file async
54
+ * mutex (in-process writers never lose lines to the compaction rename);
55
+ * the compaction rewrite is temp+rename, so a crash mid-compaction leaves
56
+ * either the old complete file or the new complete file — never a torn one.
57
+ */
58
+ export declare function appendCappedJsonl(filePath: string, line: string, opts: CappedJsonlOptions): Promise<void>;
59
+ export interface TailJsonlOptions {
60
+ maxEntries?: number;
61
+ maxBytes?: number;
62
+ }
63
+ export interface TailJsonlResult<T> {
64
+ records: T[];
65
+ /**
66
+ * True when a torn (unterminated) trailing line was skipped by the
67
+ * newline-alignment or whole-line filter. Conservative callers (e.g.
68
+ * evolution terminal detection) treat this as "state uncertain".
69
+ */
70
+ tailTruncated: boolean;
71
+ }
72
+ /**
73
+ * Bounded tail read: returns at most `maxEntries` records parsed from the
74
+ * end of the file, reading no more than `maxBytes` bytes. Malformed lines
75
+ * are skipped (they can be a torn final write); a missing file is `[]`.
76
+ */
77
+ export declare function readTailJsonl<T>(filePath: string, opts: TailJsonlOptions): Promise<T[]>;
78
+ /**
79
+ * Bounded tail read that also reports whether a torn trailing line was
80
+ * skipped, so conservative callers can distinguish "no record" from
81
+ * "state uncertain" (review FB-11).
82
+ */
83
+ export declare function readTailJsonlDetailed<T>(filePath: string, opts: TailJsonlOptions): Promise<TailJsonlResult<T>>;
84
+ export {};
@@ -0,0 +1,67 @@
1
+ /**
2
+ * One bounded, fail-open retention sweep over the residual keyspace families
3
+ * under `<projectRoot>/.swarm/` (issue #2483 §3).
4
+ *
5
+ * Production triggers: the wrapper-owned post-resolution task registered in
6
+ * `src/index.ts` (withTimeout-bounded, off the `server()`-resolution path —
7
+ * AGENTS.md invariant 1) and one pass before the `/swarm close` clean stage.
8
+ *
9
+ * Safety properties (tested in tests/unit/retention/sweep-2483.test.ts and
10
+ * edge-cases-2483.test.ts):
11
+ * - only ever touches paths under `<projectRoot>/.swarm/`; nothing outside
12
+ * survives-or-dies by accident (containment asserted by test);
13
+ * - fail-open per family — one family's error never aborts the others and
14
+ * never throws to the caller;
15
+ * - future-mtime entries are never pruned; symlinked entries are never
16
+ * traversed (dir-prune guards);
17
+ * - `dryRun` reports what WOULD be pruned without deleting (the blast-
18
+ * radius rehearsal mode; also the `retention.dry_run` config surface);
19
+ * - the summaries family honors `summaries.retention_days` (default 7) by
20
+ * delegating to `cleanupSummaries` (content-timestamp with mtime
21
+ * fallback), which this sweep is the first production caller of — the
22
+ * previously-dead `retention_days` setting becomes live.
23
+ * - authoritative streams (plan ledger, knowledge store, council, evidence,
24
+ * scopes, swarm.db, telemetry) are NOT in any family and are never
25
+ * touched (negative test).
26
+ */
27
+ /** Default age horizon for keyspace families (30 days). */
28
+ export declare const DEFAULT_FAMILY_AGE_DAYS = 30;
29
+ /** Summaries horizon comes from summaries.retention_days (default 7). */
30
+ export declare const DEFAULT_SUMMARIES_RETENTION_DAYS = 7;
31
+ /** Age-only backstop for evolution candidates whose state is unreadable. */
32
+ export declare const EVOLUTION_BACKSTOP_AGE_DAYS = 90;
33
+ /** Keep-newest caps layered on top of age for high-churn run/batch dirs. */
34
+ export declare const PR_REVIEW_KEEP_NEWEST_RUNS = 50;
35
+ export declare const LANE_RESULTS_KEEP_NEWEST_BATCHES = 100;
36
+ export declare const REVIEW_RECEIPTS_KEEP_NEWEST = 1000;
37
+ export interface RetentionSweepOptions {
38
+ /** Clock injection point for tests/checks. */
39
+ now?: number;
40
+ /** Count-and-report without deleting (blast-radius rehearsal / config). */
41
+ dryRun?: boolean;
42
+ /** Honored from `retention.enabled`; when false the sweep is a no-op. */
43
+ enabled?: boolean;
44
+ /** Honored from `summaries.retention_days`. */
45
+ summariesRetentionDays?: number;
46
+ /**
47
+ * Cooperative stop token, polled between families/passes (review FB-10).
48
+ * The post-init scheduler flips it when the outer `withTimeout` budget
49
+ * expires so an in-flight sweep abandons the remaining families instead
50
+ * of finishing its full pass after the awaiter already moved on.
51
+ */
52
+ shouldContinue?: () => boolean;
53
+ }
54
+ export interface RetentionSweepResult {
55
+ pruned: Record<string, number>;
56
+ disabled?: boolean;
57
+ dryRun?: boolean;
58
+ errors: Record<string, string>;
59
+ }
60
+ /**
61
+ * Prune stale keyspace families under `.swarm/`, age-delete the rebuildable
62
+ * epic diagnostics, expire legacy `.imported` doc-drift cold archives, run
63
+ * the summaries retention pass, and prune evolution candidates that reached
64
+ * a terminal lifecycle state (with an age-only backstop). Every family is
65
+ * individually fail-open; the function itself never throws.
66
+ */
67
+ export declare function runRetentionSweep(projectRoot: string, options?: RetentionSweepOptions): Promise<RetentionSweepResult>;
@@ -20,6 +20,20 @@
20
20
  import type { CompactionConfig } from '../config/schema';
21
21
  export type { CompactionConfig };
22
22
  export declare const MAX_TRACKED_COMPACTION_SESSIONS = 500;
23
+ /**
24
+ * Global byte cap on `.swarm/context-snapshot.md` (issue #2483 §2). Enforced
25
+ * via `appendCappedJsonl` with a high entry count so only the byte budget
26
+ * binds; compaction keeps the newest whole records that fit and never empties
27
+ * a non-empty snapshot (whole-record floor ≥ 1 entry).
28
+ */
29
+ export declare const MAX_CONTEXT_SNAPSHOT_BYTES = 65536;
30
+ /**
31
+ * Whole-record ceiling for the snapshot file (review FB-8). Only the byte
32
+ * budget binds in practice; this entry cap is a pure defense-in-depth bound
33
+ * and resolves through the seam like every other #2483 cap so tests can
34
+ * shrink it.
35
+ */
36
+ export declare const MAX_CONTEXT_SNAPSHOT_ENTRIES = 100000;
23
37
  export interface CompactionServiceHook {
24
38
  toolAfter: (input: {
25
39
  tool: string;
@@ -1,4 +1,24 @@
1
+ /**
2
+ * Per-skill FIFO cap (issue #2483 §2). Enforcement routes the append through
3
+ * `appendCappedJsonl`, so the trim is crash-atomic (temp + rename), and
4
+ * resolves the effective value through `resolveRetentionCap` so the #2483
5
+ * acceptance checks can shrink the cap below this default and prove the
6
+ * writer clamps.
7
+ */
8
+ export declare const MAX_SKILL_CHANGELOG_ENTRIES_PER_SKILL = 200;
9
+ /**
10
+ * Legacy alias for {@link MAX_SKILL_CHANGELOG_ENTRIES_PER_SKILL} — retained
11
+ * for existing citations (`scripts/retention-registry.data.ts`) and tests.
12
+ */
1
13
  export declare const MAX_CHANGELOG_ENTRIES_PER_SKILL = 200;
14
+ /**
15
+ * Global ceiling on TOTAL changelog entries across every per-skill file
16
+ * (issue #2483 §2). Enforced on EVERY append (critic N3 — deliberately no
17
+ * cadence) by scanning the changelog directory; the scan is bounded by the
18
+ * ceiling itself (one entry per slug ⇒ at most `cap` files / `cap` entries
19
+ * to enumerate). Appends are rare, so the per-append scan cost is accepted.
20
+ */
21
+ export declare const MAX_SKILL_CHANGELOG_GLOBAL_ENTRIES = 10000;
2
22
  export interface SkillChangelogEntry {
3
23
  version: number;
4
24
  timestamp: string;
@@ -17,13 +17,50 @@ export declare function storeSummary(directory: string, id: string, fullOutput:
17
17
  */
18
18
  export declare function loadFullOutput(directory: string, id: string): Promise<string | null>;
19
19
  /**
20
- * List all summary IDs that have summary entries.
21
- * Returns sorted array of valid summary IDs.
22
- * Returns empty array if summaries directory doesn't exist.
20
+ * Listing cap for `.swarm/summaries/` enumeration (issue #2483 §2, R12): the
21
+ * public list returns NEWEST-first (mtime descending, code-unit filename
22
+ * tie-break never localeCompare) and is capped, so every listing read is
23
+ * O(cap), not O(unbounded summary history). The effective value resolves
24
+ * through `resolveRetentionCap` so the #2483 acceptance checks can shrink it.
25
+ * Retention cleanup does NOT go through this capped view — it enumerates the
26
+ * directory directly so stale files beyond the newest N are still pruned.
27
+ */
28
+ export declare const MAX_SUMMARIES_LISTED = 500;
29
+ /**
30
+ * List summary IDs that have summary entries, newest-first (mtime
31
+ * descending, code-unit filename tie-break), capped at
32
+ * {@link MAX_SUMMARIES_LISTED} entries. Returns an empty array if the
33
+ * summaries directory doesn't exist.
23
34
  */
24
35
  export declare function listSummaries(directory: string): Promise<string[]>;
36
+ /**
37
+ * List summary IDs past the retention horizon WITHOUT deleting them (review
38
+ * FB-9: the single detection predicate shared by `cleanupSummaries` and the
39
+ * sweep's dry-run counter, so rehearsal and deletion can never diverge).
40
+ *
41
+ * Retention cleanup enumerates the directory DIRECTLY (uncapped): the
42
+ * public listSummaries is capped to the newest MAX_SUMMARIES_LISTED, and
43
+ * routing cleanup through it would skip stale files beyond that window
44
+ * (issue #2483).
45
+ *
46
+ * Retention also enumerates LENIENTLY: `enumerateSummaryIds` applies the
47
+ * strict write-side `^S\d+$` id grammar, but retention's job is to bound
48
+ * the keyspace — ANY `S*.json` occupant past the horizon is stale
49
+ * regardless of whether its id would pass write validation (legacy or
50
+ * foreign producers included).
51
+ *
52
+ * Detection is content-timestamp-first: a numeric `timestamp` older than the
53
+ * cutoff marks the entry stale; a missing/unparsable timestamp falls back to
54
+ * the file mtime (issue #2483); unreadable content or a parse failure is
55
+ * never stale (a `warn` is emitted for the latter, as deletion does).
56
+ */
57
+ export declare function listStaleSummaryIds(directory: string, retentionDays: number, options?: {
58
+ now?: number;
59
+ }): Promise<string[]>;
25
60
  /**
26
61
  * Delete summaries older than retentionDays.
27
62
  * Returns array of deleted summary IDs.
28
63
  */
29
- export declare function cleanupSummaries(directory: string, retentionDays: number): Promise<string[]>;
64
+ export declare function cleanupSummaries(directory: string, retentionDays: number, options?: {
65
+ now?: number;
66
+ }): Promise<string[]>;
@@ -11,6 +11,22 @@ export interface TestRunRecord {
11
11
  stackPrefix?: string;
12
12
  changedFiles: string[];
13
13
  }
14
+ /**
15
+ * Global cap on TOTAL entries in `.swarm/cache/test-history.jsonl` (issue
16
+ * #2483 §2). Enforced inside the existing read-prune-write pass on EVERY
17
+ * append — deliberately no amortized cadence (critic N3): a cadence like
18
+ * every-512-appends would never fire inside a shrunken test override width
19
+ * and silently fail the #2483 acceptance check. The effective value resolves
20
+ * through `resolveRetentionCap`.
21
+ */
22
+ export declare const MAX_TEST_HISTORY_ENTRIES = 5000;
23
+ /**
24
+ * Global cap on DISTINCT (testFile, testName) keys in the history file
25
+ * (issue #2483 §2): when distinct keys exceed the cap, the oldest-key records
26
+ * are dropped entirely (keyspace prune). Enforced on every append alongside
27
+ * {@link MAX_TEST_HISTORY_ENTRIES}.
28
+ */
29
+ export declare const MAX_TEST_HISTORY_KEYS = 1000;
14
30
  export declare function batchAppendTestRuns(records: TestRunRecord[], workingDir?: string): void;
15
31
  export declare function appendTestRun(record: TestRunRecord, workingDir?: string): void;
16
32
  export declare function getTestHistory(testFile: string, workingDir?: string): TestRunRecord[];
@@ -27,7 +27,11 @@ export interface CalibrationState {
27
27
  * Modules promoted to the hot-module list by observed divergence.
28
28
  * Monotonically grows — never auto-shrinks (loosening the hot-module
29
29
  * list requires manual intervention; the calibration loop only adds).
30
- * Sorted lexicographically for stable diffs.
30
+ * Sorted lexicographically for stable diffs. Bounded at
31
+ * {@link MAX_CALIBRATION_MODULES} on every save and load (issue #2483):
32
+ * once the cap binds, late-alphabet module paths are PERMANENTLY
33
+ * excluded from the list and — because additions are monotonic — can
34
+ * never re-enter (critic N5).
31
35
  */
32
36
  hotModuleAdditions: string[];
33
37
  /**
@@ -42,6 +46,17 @@ export interface CalibrationState {
42
46
  /** Number of divergence records processed by the engine so far. */
43
47
  processedRecords: number;
44
48
  }
49
+ /**
50
+ * Global cap on the persisted `hotModuleAdditions` list (issue #2483 §2).
51
+ * Enforcement (save AND load) keeps the lexicographically SMALLEST prefix of
52
+ * the sorted list — deterministic and order-respecting, with no invented
53
+ * score. N5 bias, stated plainly: once the cap binds, late-alphabet module
54
+ * paths are permanently excluded from the list and — because additions are
55
+ * monotonic — can never re-enter. The effective value resolves through
56
+ * `resolveRetentionCap` so the #2483 acceptance checks can shrink the cap
57
+ * below this default and prove the truncation clamps.
58
+ */
59
+ export declare const MAX_CALIBRATION_MODULES = 500;
45
60
  export declare function emptyCalibrationState(): CalibrationState;
46
61
  export declare function isCalibrationStateUnreadable(directory: string): boolean;
47
62
  export declare function repairCalibrationUnreadable(directory: string): void;
@@ -40,6 +40,17 @@ export interface DivergenceRecord {
40
40
  /** True when divergenceRatio === 0 (no undeclared writes). */
41
41
  isClean: boolean;
42
42
  }
43
+ /**
44
+ * Global byte cap on `.swarm/epic/divergence.jsonl` (issue #2483 §2).
45
+ * Byte-cap contract (critic N2): compaction retains the newest WHOLE records
46
+ * that fit within the effective cap, with a floor of at least one record — a
47
+ * non-empty stream is never emptied by compaction (one record ≈ 320 B; under
48
+ * any smaller effective cap the file keeps the newest single record). The
49
+ * effective value resolves through `resolveRetentionCap` so the #2483
50
+ * acceptance checks can shrink the cap below this default and prove the
51
+ * writer clamps.
52
+ */
53
+ export declare const MAX_DIVERGENCE_BYTES: number;
43
54
  /**
44
55
  * Compute the divergence between a declared scope and the files actually
45
56
  * modified. Pure — no I/O, no side effects. Returns the diff sets plus the
@@ -1524,6 +1524,21 @@
1524
1524
  }
1525
1525
  }
1526
1526
  },
1527
+ "retention": {
1528
+ "description": "Retention sweep settings (issue #2483).",
1529
+ "default": {},
1530
+ "type": "object",
1531
+ "properties": {
1532
+ "enabled": {
1533
+ "default": true,
1534
+ "type": "boolean"
1535
+ },
1536
+ "dry_run": {
1537
+ "default": false,
1538
+ "type": "boolean"
1539
+ }
1540
+ }
1541
+ },
1527
1542
  "review_passes": {
1528
1543
  "description": "Dual-pass security review settings.",
1529
1544
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.166.2",
3
+ "version": "7.166.4",
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,70 +0,0 @@
1
- // @bun
2
- import {
3
- createCuratorLLMDelegate
4
- } from "./index-gy55mc55.js";
5
- import"./index-d5qf7hvh.js";
6
- import"./index-j81kpway.js";
7
- import"./index-3wtfrjcx.js";
8
- import"./index-2n1v8ft1.js";
9
- import"./index-wz258yje.js";
10
- import"./index-ft1tnx0e.js";
11
- import"./index-txdagbh7.js";
12
- import"./index-cw912re7.js";
13
- import"./index-jgtje76m.js";
14
- import"./index-ty0wg9yp.js";
15
- import"./index-x4azb6qj.js";
16
- import"./index-70ha9e09.js";
17
- import"./index-bysyj3z4.js";
18
- import"./index-9ss2m4rs.js";
19
- import"./index-jr6tppv9.js";
20
- import"./index-zsrtt42s.js";
21
- import"./index-hbjax6hy.js";
22
- import"./index-p0r5fn7y.js";
23
- import"./index-x8cvbkjs.js";
24
- import"./index-b43rt5ph.js";
25
- import"./index-q7sjgr1y.js";
26
- import"./index-c0eyq4rp.js";
27
- import"./index-qmp4gxac.js";
28
- import"./index-sxsyd7kf.js";
29
- import"./index-3nww2vnx.js";
30
- import"./index-4kwxpnf8.js";
31
- import"./index-p612v1mv.js";
32
- import"./index-8nv3bc9h.js";
33
- import"./index-c23w8t46.js";
34
- import"./index-rtry5xyf.js";
35
- import"./index-kd68b6mg.js";
36
- import"./index-3qf1vxtb.js";
37
- import"./index-n832052r.js";
38
- import"./index-7mxrqy4r.js";
39
- import"./index-9ccxcjdm.js";
40
- import"./index-hgphhnrp.js";
41
- import"./index-nthqfxzz.js";
42
- import"./index-7pp8fz4j.js";
43
- import"./index-y3dtdn2f.js";
44
- import"./index-ry16d01s.js";
45
- import"./index-n4fzmqz8.js";
46
- import"./index-fkk7x6sy.js";
47
- import"./index-22sannyk.js";
48
- import"./index-ae75rja9.js";
49
- import"./index-14z9en94.js";
50
- import"./index-sxe3t040.js";
51
- import"./index-19hjpqsy.js";
52
- import"./index-bks56jbg.js";
53
- import"./index-7qefgq4j.js";
54
- import"./index-ee6ydtfe.js";
55
- import"./index-7g4c7s5r.js";
56
- import"./index-0a0jsbhg.js";
57
- import"./index-9e6fdz2h.js";
58
- import"./index-4rhhvd1a.js";
59
- import"./index-e0bjbadr.js";
60
- import"./index-0tc0pcmh.js";
61
- import"./index-bk5tah7q.js";
62
- import"./index-bpmtbmy9.js";
63
- import"./index-zpsr8rpc.js";
64
- import"./index-q1r1cfww.js";
65
- import"./index-yzjaj53h.js";
66
- import"./index-zgwm4ryv.js";
67
- import"./index-a76rekgs.js";
68
- export {
69
- createCuratorLLMDelegate
70
- };