opencode-swarm 7.125.0 → 7.125.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 (47) hide show
  1. package/.opencode/skills/swarm-pr-feedback/SKILL.md +11 -127
  2. package/.opencode/skills/swarm-pr-feedback/references/bot-claim-verification.md +71 -0
  3. package/.opencode/skills/swarm-pr-feedback/references/operational-gotchas.md +49 -0
  4. package/.opencode/skills/swarm-pr-review/SKILL.md +6 -346
  5. package/.opencode/skills/swarm-pr-review/references/parser-dry-run.md +235 -0
  6. package/.opencode/skills/swarm-pr-review/references/prompt-templates.md +103 -0
  7. package/.opencode/skills/writing-tests/SKILL.md +4 -123
  8. package/.opencode/skills/writing-tests/references/mock-and-seam-inventory.md +43 -0
  9. package/dist/cli/{config-doctor-be9sxqx8.js → config-doctor-g3m2q646.js} +2 -2
  10. package/dist/cli/{curation-policy-52kt6d7t.js → curation-policy-vgbx8530.js} +2 -2
  11. package/dist/cli/{curator-llm-factory-frde1955.js → curator-llm-factory-7pvqy94w.js} +13 -13
  12. package/dist/cli/{curator-hbst8nbc.js → curator-xk4g1nx2.js} +13 -13
  13. package/dist/cli/{evidence-summary-service-9hq7n9k9.js → evidence-summary-service-v4h2w487.js} +1 -1
  14. package/dist/cli/{guardrail-explain-112kqmbc.js → guardrail-explain-wfk16bpr.js} +14 -14
  15. package/dist/cli/{guardrail-log-c8zcab91.js → guardrail-log-5zz9xx6z.js} +3 -3
  16. package/dist/cli/{hive-promoter-448xs2tp.js → hive-promoter-njwc5rt0.js} +13 -13
  17. package/dist/cli/{index-kt0awv1n.js → index-3k8pg467.js} +1 -1
  18. package/dist/cli/{index-n6chz2g8.js → index-83rwq7pb.js} +1 -1
  19. package/dist/cli/{index-xattnmyb.js → index-8yvqkbw7.js} +3 -1
  20. package/dist/cli/{index-99ed0h32.js → index-93cq8t5b.js} +5 -5
  21. package/dist/cli/{index-9hbwa5x1.js → index-cz6fv84h.js} +15 -15
  22. package/dist/cli/{index-amspa811.js → index-dsf1yv4s.js} +119 -44
  23. package/dist/cli/{index-4rzzzjtg.js → index-fs02c7tz.js} +277 -16
  24. package/dist/cli/{index-dx2c2wjt.js → index-ghteqdy1.js} +2 -2
  25. package/dist/cli/{index-67hqr2zv.js → index-kvrk3h8p.js} +1 -1
  26. package/dist/cli/{index-09vd53pz.js → index-kws8zn6y.js} +1 -1
  27. package/dist/cli/{index-7j3sm7h8.js → index-mhhmecsw.js} +2 -2
  28. package/dist/cli/{index-yt1v62pv.js → index-mwdcvh0e.js} +4 -4
  29. package/dist/cli/{index-6vfvc36k.js → index-pbjenws7.js} +1 -1
  30. package/dist/cli/{index-958hf0yr.js → index-rpg8qqjs.js} +2 -2
  31. package/dist/cli/{index-vtwqjr4z.js → index-tn3shyqj.js} +3 -3
  32. package/dist/cli/{index-jh6s75f6.js → index-txragda9.js} +1 -1
  33. package/dist/cli/{index-0y6tmm9v.js → index-z4sc6yxc.js} +1 -1
  34. package/dist/cli/index.js +13 -13
  35. package/dist/cli/{knowledge-escalator-htafbhxg.js → knowledge-escalator-jtyykzqc.js} +3 -3
  36. package/dist/cli/{knowledge-events-havw8c4t.js → knowledge-events-qhr97sy9.js} +1 -1
  37. package/dist/cli/{knowledge-store-hqngpt2v.js → knowledge-store-332x3pjv.js} +1 -1
  38. package/dist/cli/{knowledge-validator-g7mpnazh.js → knowledge-validator-3t8tgzsz.js} +4 -4
  39. package/dist/cli/{scan-cursor-sx7cvh8v.js → scan-cursor-q21c9k9q.js} +2 -2
  40. package/dist/cli/{schema-2418eqy3.js → schema-y2d7j2jk.js} +1 -1
  41. package/dist/cli/{skill-generator-zggy797r.js → skill-generator-3gkxx98d.js} +5 -5
  42. package/dist/commands/close.d.ts +4 -2
  43. package/dist/config/schema.d.ts +4 -0
  44. package/dist/evidence/documents-retention.d.ts +116 -0
  45. package/dist/evidence/manager.d.ts +17 -0
  46. package/dist/index.js +374 -366
  47. package/package.json +1 -1
@@ -88,7 +88,7 @@ import {
88
88
  resolveGeneratedAgentRole,
89
89
  resolveGuardrailsConfig,
90
90
  stripKnownSwarmPrefix
91
- } from "./index-xattnmyb.js";
91
+ } from "./index-8yvqkbw7.js";
92
92
  import"./index-bk5tah7q.js";
93
93
  import"./index-zjygnfay.js";
94
94
  import"./index-bpmtbmy9.js";
@@ -33,12 +33,12 @@ import {
33
33
  sanitizeSlug,
34
34
  selectCandidateEntries,
35
35
  writeEvalStub
36
- } from "./index-vtwqjr4z.js";
37
- import"./index-dx2c2wjt.js";
38
- import"./index-67hqr2zv.js";
36
+ } from "./index-tn3shyqj.js";
37
+ import"./index-ghteqdy1.js";
38
+ import"./index-kvrk3h8p.js";
39
39
  import"./index-rtry5xyf.js";
40
- import"./index-yt1v62pv.js";
41
- import"./index-n6chz2g8.js";
40
+ import"./index-mwdcvh0e.js";
41
+ import"./index-83rwq7pb.js";
42
42
  import"./index-ae75rja9.js";
43
43
  import"./index-q27bajqb.js";
44
44
  import"./index-bk5tah7q.js";
@@ -134,8 +134,10 @@ export declare function runFinalizeStage(ctx: CloseStageContext): Promise<void>;
134
134
  export declare function runArchiveStage(ctx: CloseStageContext): Promise<void>;
135
135
  /**
136
136
  * Runs the evidence-retention sub-logic of STAGE 2 (ARCHIVE).
137
- * Reads max_age_days / max_bundles from config.evidence (FR-016) and
138
- * calls archiveEvidence. Fail-open: pushes a warning on error but never throws.
137
+ * Reads max_age_days / max_bundles / cache_max_bytes / cache_max_records from
138
+ * config.evidence (FR-016, issue #1184) and calls archiveEvidence. The report
139
+ * overload is used so the documents-cache prune runs when cache caps are set.
140
+ * Fail-open: pushes a warning on error but never throws.
139
141
  */
140
142
  export declare function runArchiveEvidenceRetention(ctx: ArchiveStageContext): Promise<void>;
141
143
  /**
@@ -262,6 +262,8 @@ export declare const EvidenceConfigSchema: z.ZodObject<{
262
262
  max_age_days: z.ZodDefault<z.ZodNumber>;
263
263
  max_bundles: z.ZodDefault<z.ZodNumber>;
264
264
  auto_archive: z.ZodDefault<z.ZodBoolean>;
265
+ cache_max_bytes: z.ZodOptional<z.ZodNumber>;
266
+ cache_max_records: z.ZodOptional<z.ZodNumber>;
265
267
  }, z.core.$strip>;
266
268
  export type EvidenceConfig = z.infer<typeof EvidenceConfigSchema>;
267
269
  export declare const GateFeatureSchema: z.ZodObject<{
@@ -1805,6 +1807,8 @@ export declare const PluginConfigSchema: z.ZodObject<{
1805
1807
  max_age_days: z.ZodDefault<z.ZodNumber>;
1806
1808
  max_bundles: z.ZodDefault<z.ZodNumber>;
1807
1809
  auto_archive: z.ZodDefault<z.ZodBoolean>;
1810
+ cache_max_bytes: z.ZodOptional<z.ZodNumber>;
1811
+ cache_max_records: z.ZodOptional<z.ZodNumber>;
1808
1812
  }, z.core.$strip>>;
1809
1813
  summaries: z.ZodOptional<z.ZodObject<{
1810
1814
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Retention for the web_search / web_fetch documents cache at
3
+ * `.swarm/evidence-cache/documents.jsonl`.
4
+ *
5
+ * Background (issue #1184): `writeEvidenceDocuments` in `./documents.ts` is
6
+ * purely append-only. Without this module the cache grows without bound.
7
+ * This module provides a bounded, project-root-contained, atomic-rewrite
8
+ * prune that is invoked only via `/swarm archive` and `/swarm finalize`
9
+ * (never on the plugin init path — AGENTS.md invariant #1).
10
+ *
11
+ * Design contract (mirrors `archiveEvaluationArtifacts` in
12
+ * `../evaluation/retention.ts` where applicable):
13
+ * - Optional byte cap and optional record-count cap. When both are unset the
14
+ * prune is a no-op (current append-only behavior preserved exactly).
15
+ * - Corrupt rows (failed `JSON.parse`) are dropped from the rewrite and
16
+ * reported via `corrupt` count. They are NOT relocated to a sidecar —
17
+ * matches the "report, don't relocate" precedent in
18
+ * `archiveEvaluationArtifacts` (retention.ts:246-254), while still
19
+ * preserving the bounded-growth contract (a corrupt row otherwise counts
20
+ * toward caps forever).
21
+ * - Atomic rewrite via temp file + fsync + rename. NOT under
22
+ * `withEvidenceLock`: web_search/web_fetch are hot paths and forcing a
23
+ * lockfile round-trip on every capture is an unjustified latency tax
24
+ * (issue-tracer critic item #2). The append-vs-rewrite race is a known,
25
+ * accepted data-loss window: a concurrent `appendFile` whose write is in
26
+ * flight when the prune renames the temp over the target will, on POSIX,
27
+ * complete against the now-unlinked old inode (the appended row is
28
+ * silently lost from the cache). This is accepted because refs are
29
+ * content-addressed (`evd_<sha256[:16]>`) so a lost row's ref
30
+ * re-materializes on the next capture of the same content, and because
31
+ * the prune runs only via explicit `/swarm archive` / `/swarm finalize`,
32
+ * not on every write.
33
+ * - Read is streamed line-by-line via `node:readline` with a hard 100 MiB
34
+ * cap. On cap breach the prune aborts, writes nothing, and leaves the
35
+ * file byte-identical.
36
+ * - Windows-safe rename: `EPERM`/`EBUSY`/`ENOTEMPTY`/`EACCES` are retried
37
+ * with bounded backoff (5× / 10ms). On final failure the temp file is
38
+ * removed and the original is left untouched (fail-safe).
39
+ *
40
+ * Memory tradeoff (L6-002): valid rows are parsed into a `ParsedRow[]` and
41
+ * retained in memory (raw string + parsed object per row) before selection.
42
+ * The 100 MiB read cap bounds input bytes, but the in-process heap footprint
43
+ * is higher (V8 string + object overhead). This is an accepted tradeoff: the
44
+ * prune runs once per explicit `/swarm archive` / `/swarm finalize` (never on
45
+ * a hot path), the input is bounded, and a streaming rewrite would be a
46
+ * materially larger refactor. If the cache ever needs to scale beyond the
47
+ * current cap, switch `readCacheRows` + `selectSurvivors` to a streaming
48
+ * selection (single pass, write survivors directly to the temp file).
49
+ */
50
+ import * as fs from 'node:fs';
51
+ export interface DocumentsRetentionResult {
52
+ /** Total valid (parseable) rows read before pruning. Excludes corrupt rows. */
53
+ inventory: number;
54
+ /** Rows marked for deletion by the policy (same as `inventory - surviving`). */
55
+ selected: number;
56
+ /** Rows actually removed from the file. Always 0 when `dryRun` or `aborted`. */
57
+ archived: number;
58
+ /** Unparseable rows dropped from the rewrite (count only; not preserved). */
59
+ corrupt: number;
60
+ /** File size in bytes before the prune (0 if the file did not exist). */
61
+ bytesBefore: number;
62
+ /** File size in bytes after the prune. Equal to `bytesBefore` on no-op. */
63
+ bytesAfter: number;
64
+ /** True when the prune produced no file mutation. */
65
+ dryRun: boolean;
66
+ /**
67
+ * True when the read cap (`MAX_READ_BYTES`) was exceeded. On abort the file
68
+ * is left byte-identical — no temp file, no rewrite, no sidecar.
69
+ */
70
+ aborted: boolean;
71
+ }
72
+ export interface PruneEvidenceDocumentsArgs {
73
+ directory: string;
74
+ /** Optional byte cap. When omitted, no byte-based pruning. */
75
+ maxBytes?: number;
76
+ /** Optional record-count cap. When omitted, no count-based pruning. */
77
+ maxRecords?: number;
78
+ /** When true, compute the plan but write nothing. */
79
+ dryRun?: boolean;
80
+ }
81
+ /** Internal DI seam (AGENTS.md invariant #7 — preferred over mock.module). */
82
+ export declare const _internals: {
83
+ stat: (path: string) => Promise<fs.Stats>;
84
+ createReadStream: (path: string, options: {
85
+ encoding: BufferEncoding;
86
+ highWaterMark: number;
87
+ }) => fs.ReadStream;
88
+ openSync: (path: string, flags: fs.OpenMode) => number;
89
+ writeSync: (fd: number, data: string, position?: number | null) => number;
90
+ fsyncSync: (fd: number) => void;
91
+ closeSync: (fd: number) => void;
92
+ renameWithRetry: (src: string, dst: string) => Promise<void>;
93
+ unlink: (path: string) => Promise<void>;
94
+ };
95
+ /**
96
+ * Atomic rename with bounded retry for Windows.
97
+ *
98
+ * On Windows, `fs.rename` over an existing file can fail with `EPERM` when
99
+ * another handle (e.g. a concurrent `appendFile` from web_search) holds the
100
+ * target. We retry the rename a bounded number of times with a short backoff
101
+ * (the `readSwarmFileAsync` precedent in `hooks/utils.ts:263` uses the same
102
+ * 5× / 10ms shape for the macOS rename-visibility race). On final failure we
103
+ * rethrow — the caller is responsible for cleaning up the temp file.
104
+ *
105
+ * The optional `renameFn` is a test seam (defaults to `fsp.rename`) so the
106
+ * retry loop can be exercised deterministically on non-Windows hosts.
107
+ */
108
+ export declare function atomicRenameWithRetry(src: string, dst: string, renameFn?: (s: string, d: string) => Promise<void>): Promise<void>;
109
+ /**
110
+ * Apply the configured byte/count retention policy to the documents cache.
111
+ *
112
+ * Safe to call on a missing file (returns an idempotent zeroed result) and
113
+ * safe to call with both caps unset (no-op). Never throws for routine cases;
114
+ * surfaces unexpected I/O errors to the caller (archive command fails open).
115
+ */
116
+ export declare function pruneEvidenceDocuments(args: PruneEvidenceDocumentsArgs): Promise<DocumentsRetentionResult>;
@@ -1,5 +1,6 @@
1
1
  import { type BuildEvidence, type Evidence, type EvidenceBundle, type PlaceholderEvidence, type QualityBudgetEvidence, type SastEvidence, type SbomEvidence, type SecretscanEvidence, type SyntaxEvidence } from '../config/evidence-schema';
2
2
  import { type EvaluationRetentionResult } from '../evaluation/retention.js';
3
+ import { type DocumentsRetentionResult, pruneEvidenceDocuments } from './documents-retention.js';
3
4
  /**
4
5
  * Discriminated union returned by loadEvidence.
5
6
  * - 'found': file exists and passed Zod schema validation
@@ -101,11 +102,26 @@ export type EvidenceArchiveReport = {
101
102
  archivedEvidence: string[];
102
103
  failedEvidence: string[];
103
104
  evaluation: EvaluationRetentionResult;
105
+ /**
106
+ * Documents-cache retention result (issue #1184). Always present in the
107
+ * report shape — a zeroed result ({ inventory: 0, selected: 0, ... })
108
+ * indicates the cache was not pruned (no caps configured, file missing,
109
+ * or prune disabled).
110
+ */
111
+ documentsCache: DocumentsRetentionResult;
104
112
  };
105
113
  export type EvidenceArchiveReportOptions = {
106
114
  report: true;
107
115
  dryRun?: boolean;
108
116
  now?: Date;
117
+ /**
118
+ * Optional documents-cache retention caps (issue #1184). When either is a
119
+ * positive number, `archiveEvidence` also prunes
120
+ * `.swarm/evidence-cache/documents.jsonl` after the bundle/evaluation
121
+ * sweep. When both are unset, the cache is left untouched (append-only).
122
+ */
123
+ cacheMaxBytes?: number;
124
+ cacheMaxRecords?: number;
109
125
  };
110
126
  export declare function archiveEvidence(directory: string, maxAgeDays: number, maxBundles?: number): Promise<string[]>;
111
127
  export declare function archiveEvidence(directory: string, maxAgeDays: number, maxBundles: number | undefined, options: EvidenceArchiveReportOptions): Promise<EvidenceArchiveReport>;
@@ -125,6 +141,7 @@ export declare const _internals: {
125
141
  validateEvidence: typeof validateEvidence;
126
142
  saveEvidence: typeof saveEvidence;
127
143
  deleteEvidence: typeof deleteEvidence;
144
+ pruneEvidenceDocuments: typeof pruneEvidenceDocuments;
128
145
  now: () => Date;
129
146
  };
130
147
  export {};