opencode-swarm 7.137.2 → 7.137.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 (65) hide show
  1. package/.opencode/skills/test-file-split/SKILL.md +2 -2
  2. package/.opencode/skills/writing-tests/SKILL.md +15 -1
  3. package/dist/cli/{config-doctor-xrbzq4r0.js → config-doctor-5qymy0bp.js} +2 -2
  4. package/dist/cli/{core-6w5sd5bc.js → core-v6bte964.js} +1 -1
  5. package/dist/cli/{curation-policy-xyradeax.js → curation-policy-788qbgwk.js} +6 -6
  6. package/dist/cli/{curator-h1ea9skz.js → curator-0zebvv5q.js} +25 -25
  7. package/dist/cli/{curator-llm-factory-rk7pccwc.js → curator-llm-factory-6w7hpfb0.js} +25 -25
  8. package/dist/cli/{evidence-summary-service-85gw9p2m.js → evidence-summary-service-1azhyeft.js} +7 -7
  9. package/dist/cli/{gate-evidence-s2kytsrj.js → gate-evidence-ecx4djaw.js} +4 -4
  10. package/dist/cli/{guardrail-explain-sq1kcah3.js → guardrail-explain-k1a7mwq9.js} +26 -26
  11. package/dist/cli/{guardrail-log-7anp1z1n.js → guardrail-log-wqsg11xd.js} +3 -3
  12. package/dist/cli/{hive-promoter-qsymj94z.js → hive-promoter-kxcm4n0n.js} +25 -25
  13. package/dist/cli/{index-s9at02fn.js → index-01dpavd4.js} +2 -2
  14. package/dist/cli/{index-h5sbn1zr.js → index-10mz5js6.js} +75 -34
  15. package/dist/cli/{index-pwx989sa.js → index-2qr7twf5.js} +3 -3
  16. package/dist/cli/{index-gv00q5gc.js → index-2y4jy0de.js} +1 -1
  17. package/dist/cli/{index-5r6kkhd7.js → index-39k6y018.js} +2 -2
  18. package/dist/cli/{index-s3j9fsab.js → index-4fmztnrq.js} +2 -2
  19. package/dist/cli/{index-9casmxdt.js → index-b2khb7xx.js} +6 -6
  20. package/dist/cli/{index-02jqxmh8.js → index-b9pgq0fk.js} +5 -5
  21. package/dist/cli/{index-4t39wzzg.js → index-bma4nwts.js} +3 -3
  22. package/dist/cli/{index-877ah4kx.js → index-c2v79596.js} +1 -1
  23. package/dist/cli/{index-ysh3a2nb.js → index-csneb2ph.js} +2 -2
  24. package/dist/cli/{index-vft1pg34.js → index-en4fb04r.js} +1 -1
  25. package/dist/cli/{index-kakb2jm0.js → index-eq564d4t.js} +2 -2
  26. package/dist/cli/{index-jdqayy7h.js → index-fetnv58w.js} +4 -4
  27. package/dist/cli/{index-1zrb3vt2.js → index-fmh15wxb.js} +5 -5
  28. package/dist/cli/{index-1da1tvtn.js → index-h353c1xz.js} +1 -1
  29. package/dist/cli/{index-dxatvs3f.js → index-j0xx9wpj.js} +1 -1
  30. package/dist/cli/{index-aygnzd04.js → index-m09k3dpz.js} +1 -1
  31. package/dist/cli/{index-5k0csd2m.js → index-mrwr3kac.js} +2 -2
  32. package/dist/cli/{index-5wjw05dy.js → index-ngqxzkqm.js} +2 -2
  33. package/dist/cli/{index-d735dzm7.js → index-nnf41ca1.js} +1409 -1112
  34. package/dist/cli/{index-gey6qegb.js → index-p9shqpbc.js} +1 -1
  35. package/dist/cli/{index-vyh2prxv.js → index-pzkn7d2k.js} +4 -2
  36. package/dist/cli/{index-rfrkt29c.js → index-q9eqty52.js} +1 -1
  37. package/dist/cli/{index-p0kez6cn.js → index-rdg1tkz4.js} +27 -27
  38. package/dist/cli/{index-b2s3t517.js → index-rrxcfxrd.js} +1 -1
  39. package/dist/cli/{index-n3h6rmbe.js → index-tqshdzaw.js} +1 -1
  40. package/dist/cli/{index-8ehyt3rx.js → index-xybtaph7.js} +1 -1
  41. package/dist/cli/{index-qy3rgmkc.js → index-z7jgvm9b.js} +1 -1
  42. package/dist/cli/index.js +25 -25
  43. package/dist/cli/{knowledge-escalator-e9zk371p.js → knowledge-escalator-dna6s7qy.js} +7 -7
  44. package/dist/cli/{knowledge-events-dnyc1k78.js → knowledge-events-shy8wgb3.js} +5 -5
  45. package/dist/cli/{knowledge-link-t94b79qe.js → knowledge-link-xc6yhxmz.js} +4 -4
  46. package/dist/cli/{knowledge-store-x4vqyhbz.js → knowledge-store-j7xtx4dd.js} +5 -5
  47. package/dist/cli/{knowledge-validator-72jdx5ze.js → knowledge-validator-zfweje73.js} +8 -8
  48. package/dist/cli/{pending-delegations-kshh66s2.js → pending-delegations-gee019ec.js} +3 -3
  49. package/dist/cli/{pr-subscriptions-5fpzz4f3.js → pr-subscriptions-m943zn6g.js} +3 -3
  50. package/dist/cli/{runner-9rqc8y3m.js → runner-x1hy047y.js} +5 -5
  51. package/dist/cli/{scan-cursor-z4xpes5f.js → scan-cursor-fessrenj.js} +6 -6
  52. package/dist/cli/{schema-2dkw18zz.js → schema-36b6sv6b.js} +1 -1
  53. package/dist/cli/{scope-persistence-sjz200dt.js → scope-persistence-n1bryhzf.js} +4 -4
  54. package/dist/cli/{skill-generator-0q1jk6xd.js → skill-generator-0ghcwxeb.js} +9 -9
  55. package/dist/cli/{telemetry-h7h7f0ez.js → telemetry-0yqed3jv.js} +3 -1
  56. package/dist/cli/{worktree-collision-ownership-xzwab4xt.js → worktree-collision-ownership-y1c7yx14.js} +3 -3
  57. package/dist/commands/archive-sqlite.d.ts +106 -0
  58. package/dist/commands/close.d.ts +33 -11
  59. package/dist/context/role-filter.d.ts +21 -2
  60. package/dist/db/project-db.d.ts +3 -1
  61. package/dist/index.d.ts +1 -0
  62. package/dist/index.js +322 -322
  63. package/dist/observability/catalog.d.ts +8 -9
  64. package/dist/telemetry.d.ts +58 -3
  65. package/package.json +4 -2
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Transactionally-consistent SQLite snapshot for `/swarm close` archival.
3
+ *
4
+ * Why this exists (issue #2030): the legacy `copySqliteSafe` in `close.ts`
5
+ * copied ONLY the main `swarm.db` file, either via an external `sqlite3` CLI
6
+ * (forbidden external dependency — AGENTS.md invariant 2/3) or, when that CLI
7
+ * was absent (common on Windows), via a raw `fs.copyFile` of the main file with
8
+ * NO checkpoint at all. For a WAL-mode database (`PRAGMA journal_mode = WAL`,
9
+ * set in `src/db/project-db.ts`), committed rows live in `swarm.db-wal` while
10
+ * the main file is a stale shell — so the archived copy silently lost every
11
+ * committed row.
12
+ *
13
+ * The fix is an in-process `VACUUM INTO` snapshot taken from a dedicated
14
+ * connection created through the shared, runtime-portable loader
15
+ * (`src/db/sqlite-loader.ts`). Verified under both Bun — native bun:sqlite —
16
+ * and Node — the loader's node:sqlite `DatabaseSync` adapter — by the issue #2030
17
+ * spike (`.zcode/issue-traces/2030/spike-vacuum-into.mjs`): the destination is
18
+ * a single self-contained file (journal_mode=delete, no WAL sidecars) that
19
+ * contains ALL committed rows and EXCLUDES a concurrent uncommitted writer's
20
+ * row, with `PRAGMA integrity_check = ok`.
21
+ *
22
+ * Contract: the source `main`/`wal`/`shm` are preserved on EVERY failure path.
23
+ * This function never deletes the source. `source_disposition` is `retained`
24
+ * (or `absent` when the source does not exist); the `'removed'` disposition is
25
+ * reserved for the clean stage's archive-first guard, which is the only place
26
+ * authorized to delete an archived source.
27
+ */
28
+ import type { Database } from 'bun:sqlite';
29
+ import * as fsSync from 'node:fs';
30
+ export type ArchiveSqliteMethod = 'vacuum_into';
31
+ export type ArchiveSqliteReasonCode = 'ok' | 'source_absent' | 'source_over_budget' | 'snapshot_failed' | 'validation_failed' | 'schema_mismatch' | 'publish_failed';
32
+ /**
33
+ * Domain row counts captured during validation. Counts ONLY — no row content
34
+ * is ever read into memory or logged, per issue #2030 item 4 ("without logging
35
+ * row content"). A missing domain table (legacy schema) reports count 0 rather
36
+ * than failing validation, because integrity + schema_migrations presence is the
37
+ * real health signal.
38
+ */
39
+ export interface SqliteRowCounts {
40
+ schema_migrations_max_version: number | null;
41
+ project_constraints: number;
42
+ qa_gate_profile: number;
43
+ }
44
+ export interface ArchiveSqliteOptions {
45
+ /** Absolute path to the live source DB, e.g. `.swarm/swarm.db`. */
46
+ sourcePath: string;
47
+ /** Absolute path to the archive bundle directory (must exist). */
48
+ destDir: string;
49
+ /** Filename to publish in the bundle, e.g. `swarm.db`. */
50
+ destName: string;
51
+ /**
52
+ * Hard byte-budget preflight: sum of source `main` + `wal` + `shm` sizes.
53
+ * If exceeded, the snapshot is not attempted (no expensive work). The
54
+ * default 2 GiB ceiling is generous for project DBs while still catching
55
+ * the pathological "archived the wrong 66 GB host DB" failure mode.
56
+ */
57
+ maxSourceBytes?: number;
58
+ /** `PRAGMA busy_timeout` on the snapshot connection. Default 5000 ms. */
59
+ busyTimeoutMs?: number;
60
+ }
61
+ export interface ArchiveSqliteResult {
62
+ requiredness: 'required';
63
+ attempt: 'not_attempted' | 'succeeded' | 'failed';
64
+ validation: 'not_applicable' | 'passed' | 'failed';
65
+ source_disposition: 'absent' | 'retained';
66
+ method: ArchiveSqliteMethod | 'none';
67
+ reason_code: ArchiveSqliteReasonCode;
68
+ /** Absolute, only on success. */
69
+ destPath?: string;
70
+ /** Counts only, present when validation runs. */
71
+ rowCounts?: SqliteRowCounts;
72
+ /** Non-sensitive diagnostic (errno / short message). No row content. */
73
+ detail?: string;
74
+ }
75
+ /**
76
+ * Test-only dependency-injection seam. `loadDatabaseCtor` is imported directly
77
+ * (it is a stable public API) and is NOT part of this seam. The fields here are
78
+ * only those tests genuinely substitute: `DatabaseCtor` lets a failure-injection
79
+ * test swap the constructor without touching the real loader; the fs/time
80
+ * helpers let deterministic tests control temp-path generation and filesystem
81
+ * behavior. Mutate this object in `beforeEach` and restore in `afterEach`
82
+ * (AGENTS.md invariant 7 — prefer `_internals` DI over `mock.module`).
83
+ */
84
+ export declare const _internals: {
85
+ existsSync: typeof fsSync.existsSync;
86
+ statSync: typeof fsSync.statSync;
87
+ renameSync: typeof fsSync.renameSync;
88
+ rmSync: typeof fsSync.rmSync;
89
+ now: () => number;
90
+ randomSuffix: () => string;
91
+ /**
92
+ * When non-null, overrides `loadDatabaseCtor()` for failure injection
93
+ * (e.g. a fake ctor whose `VACUUM INTO` throws). Leave null in production
94
+ * and in tests that exercise the real driver.
95
+ */
96
+ DatabaseCtor: typeof Database | null;
97
+ };
98
+ /**
99
+ * Produce a transactionally-consistent single-file snapshot of the source WAL
100
+ * database via in-process `VACUUM INTO`, validate it read-only through the
101
+ * shared loader, then atomically publish it into the archive bundle.
102
+ *
103
+ * Non-destructive: on every error path the source `main`/`wal`/`shm` are left
104
+ * untouched and `source_disposition` is `retained` (or `absent`).
105
+ */
106
+ export declare function archiveSqliteSnapshot(opts: ArchiveSqliteOptions): Promise<ArchiveSqliteResult>;
@@ -1,4 +1,3 @@
1
- import * as child_process from 'node:child_process';
2
1
  import { loadPluginConfigWithMeta } from '../config';
3
2
  import { type KnowledgeConfig, type PluginConfig } from '../config/schema';
4
3
  import { archiveEvidence } from '../evidence/manager';
@@ -11,6 +10,7 @@ import { runFinalizeRewardSweep } from '../memory/finalize-reward-sweep';
11
10
  import { closePlanTerminalState } from '../plan/manager';
12
11
  import { type SessionReflectionResult } from '../services/session-reflection';
13
12
  import { endAgentSession, resetSwarmStatePreservingSingletons } from '../state';
13
+ import { type SqliteRowCounts } from './archive-sqlite';
14
14
  interface PlanPhase {
15
15
  id: number;
16
16
  name: string;
@@ -38,6 +38,23 @@ interface CurationCounts {
38
38
  interface CloseKnowledgeEntry {
39
39
  created_at?: string;
40
40
  }
41
+ export type ArchiveRequiredness = 'required' | 'optional';
42
+ export type ArchiveAttempt = 'not_attempted' | 'succeeded' | 'failed';
43
+ export type ArchiveValidation = 'not_applicable' | 'passed' | 'failed';
44
+ export type ArchiveSourceDisposition = 'absent' | 'retained' | 'removed';
45
+ export interface ArtifactArchiveResult {
46
+ artifact: string;
47
+ requiredness: ArchiveRequiredness;
48
+ attempt: ArchiveAttempt;
49
+ validation: ArchiveValidation;
50
+ source_disposition: ArchiveSourceDisposition;
51
+ method: string;
52
+ reason_code: string;
53
+ /** Counts only (no row content), present for validated sqlite snapshots. */
54
+ row_counts?: SqliteRowCounts;
55
+ /** Non-sensitive diagnostic. */
56
+ detail?: string;
57
+ }
41
58
  export interface ArchiveStageContext {
42
59
  directory: string;
43
60
  swarmDir: string;
@@ -83,6 +100,10 @@ export interface CloseStageContext {
83
100
  archivedActiveStateFiles: Set<string>;
84
101
  archivedActiveStateDirs: Set<string>;
85
102
  archiveFailureReasons: Map<string, string>;
103
+ /** Structured per-artifact results — single source of truth (issue #2030). */
104
+ archiveResults: ArtifactArchiveResult[];
105
+ /** True when the archive STAGE threw wholesale (e.g. mkdir EACCES/ENOSPC). */
106
+ archiveStageFailed: boolean;
86
107
  timestamp: string;
87
108
  archiveDir: string;
88
109
  archiveSuffix: string;
@@ -114,6 +135,16 @@ export interface CleanStageResult {
114
135
  swarmPlanFilesRemoved: number;
115
136
  tmpFilesRemoved: number;
116
137
  }
138
+ /**
139
+ * Emit the single `close_archive_result` telemetry event whose payload is the
140
+ * SAME `ctx.archiveResults` array the user-facing prose derives from, so the
141
+ * two cannot disagree (issue #2030 item 6). Called AFTER `runCleanStage` so
142
+ * `source_disposition` can be finalized truthfully: artifacts that were
143
+ * successfully archived AND then unlinked by the clean stage report `'removed'`;
144
+ * artifacts preserved (absent, or failed/retained) keep their archive-time
145
+ * disposition. Counts only — no row content (issue items 4/9).
146
+ */
147
+ export declare function emitCloseArchiveResult(ctx: CloseStageContext, cleanResult: CleanStageResult): void;
117
148
  /**
118
149
  * STAGE 1: FINALIZE
119
150
  *
@@ -215,15 +246,6 @@ export declare const _internals: {
215
246
  archiveEvidence: typeof archiveEvidence;
216
247
  closePlanTerminalState: typeof closePlanTerminalState;
217
248
  endAgentSession: typeof endAgentSession;
218
- spawnSync: (cmd: string, args: string[], options?: {
219
- cwd?: string;
220
- encoding?: BufferEncoding;
221
- timeout?: number;
222
- maxBuffer?: number;
223
- windowsHide?: boolean;
224
- stdio?: "pipe" | "ignore" | "inherit" | Array<"pipe" | "ignore" | "inherit">;
225
- env?: Record<string, string | undefined>;
226
- envOverrides?: Record<string, string | null>;
227
- }) => child_process.SpawnSyncReturns<string | NonSharedBuffer>;
249
+ flushAndDrainTelemetry: () => Promise<void>;
228
250
  };
229
251
  export {};
@@ -10,6 +10,10 @@ export interface ContextEntry {
10
10
  content: string;
11
11
  name?: string;
12
12
  }
13
+ export interface FilterByRoleOptions {
14
+ /** Allow valid leading [FOR: ...] tags to route otherwise-protected system entries. */
15
+ filterTaggedSystem?: boolean;
16
+ }
13
17
  /**
14
18
  * Filter context entries based on target role and [FOR: ...] tags.
15
19
  *
@@ -21,7 +25,22 @@ export interface ContextEntry {
21
25
  *
22
26
  * @param entries - Array of context entries to filter
23
27
  * @param targetRole - The target agent role to filter for
24
- * @param directory - Optional project directory for metrics logging (defaults to cwd)
28
+ * @param directory - Optional project directory for metrics logging
29
+ * @param options - Optional routing behavior; defaults preserve historical semantics
25
30
  * @returns Filtered array of context entries
26
31
  */
27
- export declare function filterByRole(entries: ContextEntry[], targetRole: string, directory?: string): ContextEntry[];
32
+ export declare function filterByRole(entries: ContextEntry[], targetRole: string, directory?: string, options?: FilterByRoleOptions): ContextEntry[];
33
+ /**
34
+ * Create the production adapter for role-scoped system fragments.
35
+ *
36
+ * The adapter intentionally has no directory parameter: chat-system filtering
37
+ * must stay free of synchronous metrics I/O. Missing session or agent identity
38
+ * fails open so critical system context is never dropped speculatively.
39
+ */
40
+ export declare function createRoleFilterSystemHook(getActiveAgentName: (sessionID: string) => string | undefined): {
41
+ 'experimental.chat.system.transform': (input: {
42
+ sessionID?: string;
43
+ }, output: {
44
+ system?: string[];
45
+ }) => Promise<void>;
46
+ };
@@ -30,7 +30,9 @@ export declare function projectDbExists(directory: string): boolean;
30
30
  export declare function getProjectDb(directory: string): Database;
31
31
  /**
32
32
  * Close and remove the cached project database for the given directory.
33
- * Test-only.
33
+ * Called by the `/swarm close` clean stage before unlinking `swarm.db` (so a
34
+ * long-lived WAL-mode connection releases its file lock and Windows `unlink`
35
+ * does not fail with EBUSY), and from tests.
34
36
  */
35
37
  export declare function closeProjectDb(directory: string): void;
36
38
  /**
package/dist/index.d.ts CHANGED
@@ -47,6 +47,7 @@ declare const _default: {
47
47
  };
48
48
  export default _default;
49
49
  export type { AgentDefinition } from './agents';
50
+ export { archiveSqliteSnapshot } from './commands/archive-sqlite.js';
50
51
  export type { AgentName, AutomationCapabilities, AutomationConfig, AutomationMode, PipelineAgentName, PluginConfig, QAAgentName, } from './config';
51
52
  export { loadTier1EvaluationTasks } from './evaluation/fixtures.js';
52
53
  export { recordTestImpactGateGroundTruth } from './evaluation/gate-ground-truth.js';