opencode-swarm 7.163.1 → 7.164.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.
- package/README.md +1 -1
- package/dist/cli/{coder-settlement-f1gtvcy8.js → coder-settlement-84je6bza.js} +8 -8
- package/dist/cli/{config-doctor-0fnqzqz1.js → config-doctor-vfze38e1.js} +2 -2
- package/dist/cli/{core-w81fk5sc.js → core-q5hv8e2w.js} +1 -1
- package/dist/cli/{curation-policy-j12j2gvc.js → curation-policy-a2zty4br.js} +5 -5
- package/dist/cli/{curator-as495r18.js → curator-4pckmmyf.js} +32 -32
- package/dist/cli/{curator-drift-g6w4ga1q.js → curator-drift-wy7ejcvw.js} +105 -37
- package/dist/cli/{curator-llm-factory-v8vwz20c.js → curator-llm-factory-msbj3hpn.js} +32 -32
- package/dist/cli/{evidence-summary-service-51dxfcn5.js → evidence-summary-service-b15yes21.js} +14 -14
- package/dist/cli/{gate-evidence-nb1e8hz0.js → gate-evidence-70h0w4tb.js} +5 -5
- package/dist/cli/{guardrail-explain-z2qb6v67.js → guardrail-explain-kksdy032.js} +33 -33
- package/dist/cli/{guardrail-log-2kwntcqw.js → guardrail-log-7rxbd20p.js} +6 -6
- package/dist/cli/{guardrail-reset-mrxrc56j.js → guardrail-reset-3b4gs357.js} +32 -32
- package/dist/cli/{hive-promoter-c62x2ncb.js → hive-promoter-s80g1gwb.js} +32 -32
- package/dist/cli/index-0515j0cz.js +403 -0
- package/dist/cli/{index-ma52g2pq.js → index-12f1tsn2.js} +3 -3
- package/dist/cli/{index-2zgjcmmc.js → index-1b1h770t.js} +3 -3
- package/dist/cli/{index-9ss2m4rs.js → index-1hpjwz3s.js} +410 -1
- package/dist/cli/{index-kvra3nv1.js → index-1z4jzwja.js} +3 -3
- package/dist/cli/{index-0103w5pf.js → index-2s4s9n82.js} +2 -2
- package/dist/cli/{index-9crtmnqg.js → index-36nt17m8.js} +1 -1
- package/dist/cli/{index-g3znh2yd.js → index-4afh2cz7.js} +5 -5
- package/dist/cli/{index-2n1ym7jb.js → index-4jersar8.js} +4 -4
- package/dist/cli/{index-n67vx5zw.js → index-70bfj3v1.js} +1 -1
- package/dist/cli/{index-zjme8atd.js → index-7r9vpkwa.js} +4 -4
- package/dist/cli/{index-8ada7ag7.js → index-93sepnc9.js} +2 -2
- package/dist/cli/{index-qynqyfgj.js → index-9sy65e94.js} +3 -3
- package/dist/cli/{index-f923njwh.js → index-bm73pych.js} +6 -6
- package/dist/cli/{index-xyhmt813.js → index-c4pynht5.js} +1 -1
- package/dist/cli/{index-m1fvbah1.js → index-c69jbpex.js} +2 -2
- package/dist/cli/{index-t34daffb.js → index-e3hwzcjv.js} +2 -2
- package/dist/cli/{index-r56f3f81.js → index-g64154pd.js} +1 -1
- package/dist/cli/{index-08y8pccg.js → index-gxd8fwyt.js} +4 -4
- package/dist/cli/{index-d3azve4r.js → index-hyq20s2v.js} +118 -296
- package/dist/cli/{index-7n9jznv0.js → index-ma8w6pfp.js} +3 -3
- package/dist/cli/{index-tnpf9wwv.js → index-nhxaa9j5.js} +1 -1
- package/dist/cli/{index-d9gdwh34.js → index-nzrhw31r.js} +1 -1
- package/dist/cli/{index-n985274d.js → index-pvgcex0d.js} +3 -3
- package/dist/cli/{index-etvq73mp.js → index-qkk2skff.js} +34 -34
- package/dist/cli/{index-2v06a1yh.js → index-t5t82jy8.js} +5 -5
- package/dist/cli/{index-5056zmpt.js → index-t90gjc0k.js} +1 -1
- package/dist/cli/{index-66073kej.js → index-t9rhtvy9.js} +2 -2
- package/dist/cli/{index-hm239n1p.js → index-tb1k8jya.js} +1 -1
- package/dist/cli/{index-x2f1f011.js → index-td6n935w.js} +3 -2
- package/dist/cli/{index-swgy9xvk.js → index-v3a9rmyh.js} +3 -3
- package/dist/cli/{index-cqgpvx2d.js → index-wdtckfnf.js} +1 -1
- package/dist/cli/{index-0tervb1m.js → index-xk0kc1py.js} +522 -358
- package/dist/cli/{index-n2mhyect.js → index-ynqp3jb6.js} +1 -1
- package/dist/cli/{index-n249fbw7.js → index-zaab1wz9.js} +5 -0
- package/dist/cli/{index-4p0wyz5p.js → index-zbpcpsk0.js} +8 -8
- package/dist/cli/index.js +32 -32
- package/dist/cli/{knowledge-escalator-fq7dm2g4.js → knowledge-escalator-sttdnwf8.js} +11 -11
- package/dist/cli/{knowledge-events-3zanyfkr.js → knowledge-events-4h88stj7.js} +9 -9
- package/dist/cli/{knowledge-link-vmdj5e5d.js → knowledge-link-yykmxdyw.js} +4 -4
- package/dist/cli/{knowledge-store-vhehnw52.js → knowledge-store-j832fxpx.js} +5 -5
- package/dist/cli/{knowledge-validator-0tt0pe6b.js → knowledge-validator-edbg761g.js} +7 -7
- package/dist/cli/{pending-delegations-b92pecbj.js → pending-delegations-sphntrs0.js} +4 -4
- package/dist/cli/{pr-subscriptions-2mkdt0ak.js → pr-subscriptions-1a4gcnzv.js} +4 -4
- package/dist/cli/{runner-3gw2njnx.js → runner-d294h1by.js} +5 -5
- package/dist/cli/{scan-cursor-1c8a3b0m.js → scan-cursor-5frvp7nb.js} +6 -6
- package/dist/cli/{schema-c554j5c8.js → schema-9xkt5hvd.js} +1 -1
- package/dist/cli/{scope-persistence-vtbcszvv.js → scope-persistence-gk55h3sp.js} +8 -8
- package/dist/cli/{skill-generator-0es21fck.js → skill-generator-sxxf7jbb.js} +13 -13
- package/dist/cli/{sqlite-loader-c92413n7.js → sqlite-loader-8zefc142.js} +1 -1
- package/dist/cli/{telemetry-x4zggfd7.js → telemetry-q51s6tyt.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-043dg8gg.js → worktree-collision-ownership-7kj2ryt1.js} +4 -4
- package/dist/cli/{worktree-isolation-hk42yxw7.js → worktree-isolation-67fs6rz9.js} +32 -32
- package/dist/db/canonical-project.d.ts +31 -0
- package/dist/db/db-errors.d.ts +24 -0
- package/dist/db/driver-parity.d.ts +31 -0
- package/dist/db/durability.d.ts +40 -0
- package/dist/db/group-commit-writer.d.ts +117 -0
- package/dist/db/health.d.ts +35 -0
- package/dist/db/insight-candidate-store.d.ts +61 -0
- package/dist/db/legacy-import.d.ts +77 -0
- package/dist/db/phase-report-store.d.ts +45 -0
- package/dist/db/project-db.d.ts +35 -8
- package/dist/db/qa-gate-profile.d.ts +2 -0
- package/dist/hooks/curator-drift.d.ts +9 -5
- package/dist/hooks/curator-types.d.ts +1 -0
- package/dist/hooks/knowledge-curator.d.ts +5 -3
- package/dist/hooks/micro-reflector.d.ts +12 -7
- package/dist/index.js +619 -567
- package/dist/memory/schema.d.ts +4 -4
- package/dist/prm/index.d.ts +3 -1
- package/package.json +3 -2
- package/dist/cli/index-c8s9a3zh.js +0 -73
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical project identity for the SQLite durable-state foundation (issue #2480).
|
|
3
|
+
*
|
|
4
|
+
* Policy (docs/sqlite-durable-state.md §Identity):
|
|
5
|
+
* - This helper answers ONE question: "are these two directory spellings the same project
|
|
6
|
+
* root, so they must share ONE `.swarm/swarm.db` connection?" It is project-root
|
|
7
|
+
* IDENTITY, not security-sensitive file equivalence — those are different threat models
|
|
8
|
+
* and deliberately different helpers (issue #2474 / Workstream B1 owns the repo-wide
|
|
9
|
+
* identity rollout; this is the DB-layer-scoped implementation D1 builds on).
|
|
10
|
+
* - Resolution: `path.resolve` (lexical cleanup) → best-effort `fs.realpathSync`
|
|
11
|
+
* (collapses symlinks/junctions and, on Windows, expands 8.3 short names) →
|
|
12
|
+
* case-fold the WHOLE key on win32 only. On POSIX, case is significant: `/a/B` and
|
|
13
|
+
* `/a/b` are different roots and must stay isolated.
|
|
14
|
+
* - Never throws: if `realpathSync` fails (broken symlink, permission, race), the
|
|
15
|
+
* lexically-resolved path is used as-is. A canonicalization failure must not prevent
|
|
16
|
+
* the project DB from opening; it only risks a duplicate handle for exotic spellings,
|
|
17
|
+
* which is the pre-existing behavior.
|
|
18
|
+
*/
|
|
19
|
+
import { realpathSync } from 'node:fs';
|
|
20
|
+
/** DI seam for tests (fault-injected realpath failures). */
|
|
21
|
+
export declare const _internals: {
|
|
22
|
+
realpathSync: typeof realpathSync;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Return the canonical cache key for a project directory.
|
|
26
|
+
*
|
|
27
|
+
* - `C:\Proj` and `c:\proj\` map to one key on Windows (one DB handle).
|
|
28
|
+
* - A symlink or junction to the same directory maps to one key on every platform.
|
|
29
|
+
* - Distinct POSIX casings remain distinct roots.
|
|
30
|
+
*/
|
|
31
|
+
export declare function canonicalProjectKey(directory: string): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors for the SQLite durable-state foundation (issue #2480).
|
|
3
|
+
*
|
|
4
|
+
* Callers use `category` to make fail-open decisions and to emit ONE coalesced
|
|
5
|
+
* advisory per condition instead of repeating raw SQLite errors. Messages never
|
|
6
|
+
* contain SQL text or user file contents; at most the `.swarm/swarm.db` artifact
|
|
7
|
+
* name appears.
|
|
8
|
+
*/
|
|
9
|
+
export type ProjectDbErrorCategory = 'mkdir_failed' | 'driver_unavailable' | 'open_failed' | 'migration_failed';
|
|
10
|
+
export type DbWriteErrorCategory = 'disk_full' | 'read_only' | 'corrupt' | 'busy' | 'unknown';
|
|
11
|
+
export declare class ProjectDbError extends Error {
|
|
12
|
+
readonly category: ProjectDbErrorCategory;
|
|
13
|
+
constructor(category: ProjectDbErrorCategory, message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class DbWriteError extends Error {
|
|
16
|
+
readonly category: DbWriteErrorCategory;
|
|
17
|
+
constructor(category: DbWriteErrorCategory, message: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Classify a write/open failure into a `DbWriteErrorCategory` from errno and
|
|
21
|
+
* SQLite error text. Used by the group-commit writer to decide retry/degrade
|
|
22
|
+
* behavior (issue #2480 disk-full / read-only / corrupt handling).
|
|
23
|
+
*/
|
|
24
|
+
export declare function classifyDbWriteError(err: unknown): DbWriteErrorCategory;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun ↔ Node driver-parity contract for `.swarm/swarm.db` (issue #2480
|
|
3
|
+
* obligation 2).
|
|
4
|
+
*
|
|
5
|
+
* A single suite, run against WHATEVER driver the shared sqlite loader
|
|
6
|
+
* resolved:
|
|
7
|
+
* - under `bun test`: the real `bun:sqlite` driver (and the node adapter
|
|
8
|
+
* against the strict fake in `sqlite-loader.test.ts`);
|
|
9
|
+
* - under the merge-queue smoke job (`scripts/repro-1873.mjs`, 3-OS, real
|
|
10
|
+
* Node 22): the real `node:sqlite` driver through the adapter.
|
|
11
|
+
*
|
|
12
|
+
* The contract pins the behavioral deltas documented for #1873/#2480:
|
|
13
|
+
* - EXACT parameter counts: every bound-parameter call must pass exactly as
|
|
14
|
+
* many values as the statement has placeholders. `node:sqlite` rejects a
|
|
15
|
+
* mismatched count (`SQLITE_RANGE`); `bun:sqlite` tolerates some lax forms.
|
|
16
|
+
* Portable code never relies on the lax form.
|
|
17
|
+
* - Multi-statement strings only through the no-parameter `run(sql)` path
|
|
18
|
+
* (which routes to `exec` on both drivers).
|
|
19
|
+
* - Transaction + SAVEPOINT nesting round trip.
|
|
20
|
+
* - WAL / busy_timeout / synchronous pragma reads.
|
|
21
|
+
*/
|
|
22
|
+
import type { Database } from 'bun:sqlite';
|
|
23
|
+
export interface DriverParityProbe {
|
|
24
|
+
/** True when the resolved driver is the node:sqlite adapter. */
|
|
25
|
+
isNodeAdapter: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Assert the driver-parity contract on a FRESH database (the caller owns its
|
|
29
|
+
* lifecycle and closes it). Throws on the first violation.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runDriverParityContract(db: Database, probe?: DriverParityProbe): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-table durability classes for `.swarm/swarm.db` (issue #2480 obligation 4).
|
|
3
|
+
*
|
|
4
|
+
* SQLite's `synchronous` pragma is connection-scoped and takes effect at the next
|
|
5
|
+
* commit, so "per-table durability classes" are implemented by escalating the
|
|
6
|
+
* pragma around write transactions whose target table demands it:
|
|
7
|
+
*
|
|
8
|
+
* - `full` — terminal-state streams (authoritative rows whose loss changes an
|
|
9
|
+
* outcome): `synchronous = FULL` for the wrapping transaction. Authoritative
|
|
10
|
+
* state must never inherit the rebuildable-index durability setting.
|
|
11
|
+
* - `normal` — telemetry/operational/diagnostic rows: `synchronous = NORMAL`
|
|
12
|
+
* (WAL + NORMAL is durable across application crashes; only an OS/power
|
|
13
|
+
* failure can lose the tail — acceptable for rebuildable streams).
|
|
14
|
+
*
|
|
15
|
+
* A batch that contains ANY `full`-class write runs the WHOLE transaction at
|
|
16
|
+
* FULL (escalation rule, group-commit writer consults `batchDurabilityClass`).
|
|
17
|
+
*/
|
|
18
|
+
import type { Database } from 'bun:sqlite';
|
|
19
|
+
/** The durability class of every table in `.swarm/swarm.db`. */
|
|
20
|
+
export declare const DURABILITY_CLASSES: Readonly<Record<string, 'full' | 'normal'>>;
|
|
21
|
+
/** Escalation rule: any full-class op makes the whole batch full-class. */
|
|
22
|
+
export declare function batchDurabilityClass(classes: Iterable<'full' | 'normal'>): 'full' | 'normal';
|
|
23
|
+
/** Apply the `synchronous` pragma for a durability class. Cheap and idempotent. */
|
|
24
|
+
export declare function applySynchronousForClass(db: Database, cls: 'full' | 'normal'): void;
|
|
25
|
+
/**
|
|
26
|
+
* Run `fn` with the connection's `synchronous` pragma set for `cls`, restoring
|
|
27
|
+
* NORMAL afterwards. `fn` is expected to complete its own transaction (or be
|
|
28
|
+
* composed inside one); the pragma takes effect at commit time.
|
|
29
|
+
*
|
|
30
|
+
* The connection default is NORMAL (telemetry class), so restoring NORMAL — not
|
|
31
|
+
* "the previous value" — is the correct post-condition: nothing outside the
|
|
32
|
+
* foundation ever sets a different value on this connection.
|
|
33
|
+
*
|
|
34
|
+
* NESTING CAVEAT (final-critic note): nesting a normal-class helper inside an
|
|
35
|
+
* open full-class transaction would restore NORMAL before the OUTER commit.
|
|
36
|
+
* No production path nests these helpers today (group-commit ops never call
|
|
37
|
+
* the qa-gate/receipt writers); if nesting is ever introduced, restore the
|
|
38
|
+
* pre-call value instead.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withDurabilityClass<T>(db: Database, cls: 'full' | 'normal', fn: () => T): T;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group-commit writer for `.swarm/swarm.db` low-risk stores (issue #2480
|
|
3
|
+
* obligation 8: "queue -> one txn per flush").
|
|
4
|
+
*
|
|
5
|
+
* Design:
|
|
6
|
+
* - One writer per canonical project root, created lazily on first use and
|
|
7
|
+
* closed with the DB handle (`closeGroupCommitWriter`). Nothing here runs at
|
|
8
|
+
* plugin init.
|
|
9
|
+
* - `enqueue(op)` queues a write op. A flush applies EVERY queued op inside
|
|
10
|
+
* ONE `BEGIN IMMEDIATE` transaction (the qa-gate-profile lock precedent —
|
|
11
|
+
* plain `db.transaction()` issues a deferred BEGIN that lets two writers
|
|
12
|
+
* deadlock-escalate to SQLITE_BUSY under two-windows contention).
|
|
13
|
+
* - Durability escalation: if any op in the batch is `full`-class, the whole
|
|
14
|
+
* transaction runs with `PRAGMA synchronous = FULL` (authoritative state
|
|
15
|
+
* never inherits the rebuildable-index setting); otherwise NORMAL.
|
|
16
|
+
* - Backpressure: the queue is bounded; overflow forces a synchronous flush
|
|
17
|
+
* rather than dropping writes.
|
|
18
|
+
* - Failure handling: a `BEGIN IMMEDIATE` busy or a disk-full/read-only
|
|
19
|
+
* failure keeps the queue intact, classifies the error (`db-errors.ts`),
|
|
20
|
+
* and coalesces to ONE advisory/telemetry signal per degradation episode
|
|
21
|
+
* (cooldown); the next flush retries. Ops themselves throwing rolls the
|
|
22
|
+
* transaction back and rethrows (the enqueuing store decides fail-open).
|
|
23
|
+
*/
|
|
24
|
+
import type { Database } from 'bun:sqlite';
|
|
25
|
+
import { type DbWriteErrorCategory } from './db-errors.js';
|
|
26
|
+
import { getProjectDb } from './project-db.js';
|
|
27
|
+
/** A single durable write, applied inside a flush transaction. */
|
|
28
|
+
export interface GroupCommitOp {
|
|
29
|
+
/** Durability class of the target table/stream (escalation input). */
|
|
30
|
+
durability: 'full' | 'normal';
|
|
31
|
+
/** Apply the write. Must only touch `.swarm/swarm.db` via the given handle. */
|
|
32
|
+
run: (db: Database) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Detect "the underlying handle was closed" failures across BOTH drivers:
|
|
36
|
+
* bun:sqlite says "database has closed"; node:sqlite raises
|
|
37
|
+
* ERR_INVALID_STATE "database is not open".
|
|
38
|
+
*/
|
|
39
|
+
declare function isClosedHandleError(err: unknown): boolean;
|
|
40
|
+
/** Queue bound — overflow forces a synchronous flush (never a silent drop). */
|
|
41
|
+
export declare const MAX_QUEUED_OPS = 1024;
|
|
42
|
+
/** Ops at or above this count trigger an immediate synchronous flush. */
|
|
43
|
+
export declare const FLUSH_THRESHOLD_OPS = 64;
|
|
44
|
+
/**
|
|
45
|
+
* Test seam (repo `_internals` convention): the self-heal rebind's handle
|
|
46
|
+
* acquisition, injectable so tests can deterministically exercise the
|
|
47
|
+
* eviction-on-double-closed-handle path (a rebind that returns an ALREADY
|
|
48
|
+
* closed handle).
|
|
49
|
+
*/
|
|
50
|
+
export declare const _internals: {
|
|
51
|
+
getProjectDb: typeof getProjectDb;
|
|
52
|
+
isClosedHandleError: typeof isClosedHandleError;
|
|
53
|
+
};
|
|
54
|
+
export declare class GroupCommitWriter {
|
|
55
|
+
private db;
|
|
56
|
+
private queue;
|
|
57
|
+
private flushing;
|
|
58
|
+
private degraded;
|
|
59
|
+
private lastAdvisoryAt;
|
|
60
|
+
private closed;
|
|
61
|
+
/**
|
|
62
|
+
* Canonical cache key this writer was registered under (set by
|
|
63
|
+
* getGroupCommitWriter). A flush against a CLOSED underlying handle —
|
|
64
|
+
* possible when a close site evicted the DB handle without closing the
|
|
65
|
+
* writer — evicts the writer from the registry so the next store call
|
|
66
|
+
* rebinds to the fresh handle instead of failing forever.
|
|
67
|
+
*/
|
|
68
|
+
private registryKey;
|
|
69
|
+
constructor(db: Database);
|
|
70
|
+
get queuedOpCount(): number;
|
|
71
|
+
/** #2480: record the registry key for self-healing eviction. */
|
|
72
|
+
bindRegistryKey(key: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Queue a write op. A synchronous flush runs immediately when the queue
|
|
75
|
+
* reaches the flush threshold (backpressure), and again at the hard
|
|
76
|
+
* `MAX_QUEUED_OPS` bound. Throws `DbWriteError` from an inline flush
|
|
77
|
+
* (threshold or hard bound) when the flush fails — the op is then NOT
|
|
78
|
+
* accepted; the caller's fail-open handling owns the loss.
|
|
79
|
+
*/
|
|
80
|
+
enqueue(op: GroupCommitOp): void;
|
|
81
|
+
/**
|
|
82
|
+
* Apply every queued op in ONE immediate transaction. On op failure the
|
|
83
|
+
* transaction rolls back and the error rethrows (queue emptied — the ops
|
|
84
|
+
* are not idempotently retryable by this layer). On busy/disk-full/
|
|
85
|
+
* read-only the queue is RETAINED and a typed `DbWriteError` throws.
|
|
86
|
+
*
|
|
87
|
+
* Self-healing (#2480): if the underlying handle was CLOSED underneath
|
|
88
|
+
* this writer (a close site evicted the DB handle without closing the
|
|
89
|
+
* writer — the pre-fix /swarm close shape), the flush rebinds to a fresh
|
|
90
|
+
* handle ONCE and re-applies the batch, so post-close writes complete
|
|
91
|
+
* transparently instead of failing until restart.
|
|
92
|
+
*/
|
|
93
|
+
flushSync(): void;
|
|
94
|
+
/** Async facade over the synchronous flush (callers `await` durability). */
|
|
95
|
+
flush(): Promise<void>;
|
|
96
|
+
/** Close the writer and drop any unflushed queue. */
|
|
97
|
+
close(): void;
|
|
98
|
+
private applyBatch;
|
|
99
|
+
private noteDegraded;
|
|
100
|
+
/** Test/observability access to the degradation state. */
|
|
101
|
+
get degradation(): {
|
|
102
|
+
category: DbWriteErrorCategory;
|
|
103
|
+
until: number;
|
|
104
|
+
} | null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Return the group-commit writer for a project root, creating it (and the DB
|
|
108
|
+
* handle) lazily on first use. Never runs at plugin init.
|
|
109
|
+
*/
|
|
110
|
+
export declare function getGroupCommitWriter(directory: string): GroupCommitWriter;
|
|
111
|
+
/** Flush + close the writer for a root (dispose/exit/close paths). */
|
|
112
|
+
export declare function closeGroupCommitWriter(directory: string): void;
|
|
113
|
+
/** Flush + close every writer, then close every DB handle. Test/close use. */
|
|
114
|
+
export declare function closeAllGroupCommitWriters(): void;
|
|
115
|
+
/** Number of open writers (tests/observability). */
|
|
116
|
+
export declare function getOpenGroupCommitWriterCount(): number;
|
|
117
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swarm.db health probe (issue #2480 obligation 5).
|
|
3
|
+
*
|
|
4
|
+
* The one sanctioned read-only surface for diagnose-style health checks: runs
|
|
5
|
+
* the size-capped quick_check + pragma/migration-failure probes and returns a
|
|
6
|
+
* structured snapshot. Keeping the SQL here (inside `src/db/**`) means the
|
|
7
|
+
* raw-handle confinement and writer-registry seams stay honest — callers like
|
|
8
|
+
* `diagnose-service` consume a plain object.
|
|
9
|
+
*/
|
|
10
|
+
/** quick_check size cap: an oversized DB reports `too_large` instead of scanning inline. */
|
|
11
|
+
export declare const SWARM_DB_QUICK_CHECK_MAX_BYTES: number;
|
|
12
|
+
export type SwarmDbHealthSnapshot = {
|
|
13
|
+
kind: 'absent';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'too_large';
|
|
16
|
+
sizeBytes: number;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'open';
|
|
19
|
+
quickCheck: string;
|
|
20
|
+
journalMode: string;
|
|
21
|
+
pageCount: number;
|
|
22
|
+
migrationFailures: number;
|
|
23
|
+
/** #2480 review F-07: stale marker file present (a recorded
|
|
24
|
+
* failure whose cleanup could not run — surfaced for diagnosis). */
|
|
25
|
+
staleMarker: boolean;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'error';
|
|
28
|
+
category: string;
|
|
29
|
+
message: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Probe `.swarm/swarm.db` health. Never opens-for-create (an absent DB is
|
|
33
|
+
* `absent`, which callers render as healthy) and never throws.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getSwarmDbHealthSnapshot(directory: string): SwarmDbHealthSnapshot;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swarm.db store for insight candidates (issue #2480 D1 migration).
|
|
3
|
+
*
|
|
4
|
+
* Replaces `.swarm/insight-candidates.jsonl` (locked read-modify-write JSONL
|
|
5
|
+
* queue) with the append-only event-stream pattern:
|
|
6
|
+
*
|
|
7
|
+
* - Table `insight_candidate` — PK (stream_id, version) is the
|
|
8
|
+
* UNIQUE(stream_id, version) stream contract; versions are assigned
|
|
9
|
+
* MAX(version)+1 inside the appending transaction.
|
|
10
|
+
* - `appendInsightCandidatesDb` batches appends through the group-commit
|
|
11
|
+
* writer (queue -> one txn per flush).
|
|
12
|
+
* - `consumeInsightCandidatesDb` is the dual-contract transaction: SELECT the
|
|
13
|
+
* pending batch + UPDATE consumed_at for exactly those versions in ONE
|
|
14
|
+
* `BEGIN IMMEDIATE` transaction, so concurrent appends and consumes can
|
|
15
|
+
* never lose or double-take a candidate.
|
|
16
|
+
* - Telemetry-sink retention: consumed rows are DELETE-pruned after 7 days,
|
|
17
|
+
* and the pending queue is FIFO-capped at 500 (both bounds carried over
|
|
18
|
+
* from the legacy store's limits).
|
|
19
|
+
*
|
|
20
|
+
* Payloads are opaque serialized JSON strings; the hook layer owns parsing,
|
|
21
|
+
* validation, and identity (`resolveInsightCandidateId` recomputes identity
|
|
22
|
+
* from content, so no id column exists).
|
|
23
|
+
*/
|
|
24
|
+
/** The single stream id used by this store (table is stream-shaped for D2+). */
|
|
25
|
+
export declare const INSIGHT_CANDIDATE_STREAM_ID = "insight-candidates";
|
|
26
|
+
/** Legacy queue filename (imported then cold-archived as `.jsonl.imported`). */
|
|
27
|
+
export declare const INSIGHT_CANDIDATES_LEGACY_FILE = "insight-candidates.jsonl";
|
|
28
|
+
/** FIFO cap on pending (unconsumed) candidates — carried over from the file store. */
|
|
29
|
+
export declare const INSIGHT_PENDING_CAP = 500;
|
|
30
|
+
/** Consumed-row retention window (telemetry-sink DELETE-based retention). */
|
|
31
|
+
export declare const INSIGHT_CONSUMED_RETENTION_DAYS = 7;
|
|
32
|
+
export interface InsightCandidateRow {
|
|
33
|
+
payload: string;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One-time (per process, per canonical root) lazy import of the legacy
|
|
38
|
+
* `.swarm/insight-candidates.jsonl` queue. Never runs at plugin init.
|
|
39
|
+
*/
|
|
40
|
+
export declare function ensureInsightLegacyImported(directory: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Append candidates to the stream via the group-commit writer and await the
|
|
43
|
+
* flush (the legacy store's append was awaited too — durability semantics
|
|
44
|
+
* are preserved; batching coalesces concurrent callers and multi-candidate
|
|
45
|
+
* calls into one transaction).
|
|
46
|
+
*/
|
|
47
|
+
export declare function appendInsightCandidatesDb(directory: string, rows: InsightCandidateRow[]): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Atomically consume up to `limit` pending candidates: the SELECT and the
|
|
50
|
+
* consumed_at UPDATE happen in ONE immediate transaction (dual-contract
|
|
51
|
+
* event+state transition). Consumed rows older than the retention window are
|
|
52
|
+
* DELETE-pruned in the same transaction. Returns the consumed payloads,
|
|
53
|
+
* oldest first.
|
|
54
|
+
*/
|
|
55
|
+
export declare function consumeInsightCandidatesDb(directory: string, limit: number): string[];
|
|
56
|
+
/** Count pending (unconsumed) candidates — status/diagnostics surface. */
|
|
57
|
+
export declare function countPendingInsightCandidatesDb(directory: string): number;
|
|
58
|
+
/** List pending payloads, oldest first (postmortem raw-content surface). */
|
|
59
|
+
export declare function listPendingInsightCandidatesDb(directory: string, max: number): string[];
|
|
60
|
+
/** Test hook: reset the per-process import guards. */
|
|
61
|
+
export declare function _resetInsightImportGuards(): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotent legacy file → swarm.db import (issue #2480 obligation 3).
|
|
3
|
+
*
|
|
4
|
+
* Contract (docs/sqlite-durable-state.md §Legacy import):
|
|
5
|
+
* - Legacy artifact PRESENT + target table/stream EMPTY → import every record
|
|
6
|
+
* in ONE `BEGIN IMMEDIATE` transaction (emptiness re-checked inside the
|
|
7
|
+
* transaction so a concurrent importer cannot double-import) → on commit,
|
|
8
|
+
* rename the artifact to `<name>.imported` (bounded Windows rename retry).
|
|
9
|
+
* - Crash before commit → nothing imported; the next run retries (idempotent).
|
|
10
|
+
* - Crash after commit before rename → the next run sees a NON-empty table;
|
|
11
|
+
* the stale file is left in place (never re-imported, never silently
|
|
12
|
+
* deleted) with a once-per-process warning. This also covers a file that
|
|
13
|
+
* reappeared because an older plugin version wrote it again: those lines
|
|
14
|
+
* are preserved on disk rather than destroyed.
|
|
15
|
+
* - Artifact absent, or table already populated → no-op.
|
|
16
|
+
*
|
|
17
|
+
* Import runs lazily on first store use, never at plugin init (the
|
|
18
|
+
* knowledge-receipts migration precedent).
|
|
19
|
+
*/
|
|
20
|
+
import { renameSync } from 'node:fs';
|
|
21
|
+
import { getProjectDb } from './project-db.js';
|
|
22
|
+
/**
|
|
23
|
+
* Size cap for a single legacy artifact import (#2480 review F-02 — same
|
|
24
|
+
* guard convention as MAX_TRACEABILITY_BYTES in design-doc-drift). The live
|
|
25
|
+
* stores were FIFO/entry-bounded when they were files, so anything beyond
|
|
26
|
+
* this is pathological; it is skipped inert (never imported, never renamed)
|
|
27
|
+
* rather than loaded into memory.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MAX_LEGACY_IMPORT_BYTES: number;
|
|
30
|
+
export interface LegacyImportResult {
|
|
31
|
+
/** Rows imported (0 when the import conditions were not met). */
|
|
32
|
+
imported: number;
|
|
33
|
+
/** Lines/files skipped because they failed validation. */
|
|
34
|
+
skipped: number;
|
|
35
|
+
/** True when the legacy artifact was renamed to `.imported`. */
|
|
36
|
+
archived: boolean;
|
|
37
|
+
}
|
|
38
|
+
declare function warnStaleLegacyOnce(key: string, fileName: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* DI seam for tests: the LOW-LEVEL rename is fault-injectable so the retry
|
|
41
|
+
* loop itself stays under test (replacing the loop would test nothing).
|
|
42
|
+
*/
|
|
43
|
+
export declare const _internals: {
|
|
44
|
+
renameSync: typeof renameSync;
|
|
45
|
+
warnStaleLegacyOnce: typeof warnStaleLegacyOnce;
|
|
46
|
+
maxLegacyImportBytes: () => number;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Import a legacy `.jsonl` file into an append-only stream table.
|
|
50
|
+
*
|
|
51
|
+
* `parseLine` returns the row payload string for a valid line or null to skip
|
|
52
|
+
* (corrupt line). Rows are inserted with versions 1..n in file order. The
|
|
53
|
+
* emptiness probe is `streamCount(db)` (e.g. rows for the stream).
|
|
54
|
+
*/
|
|
55
|
+
export declare function importLegacyJsonl(directory: string, opts: {
|
|
56
|
+
fileName: string;
|
|
57
|
+
/** Count existing rows for the target stream (inside the txn). */
|
|
58
|
+
streamCount: (db: ReturnType<typeof getProjectDb>) => number;
|
|
59
|
+
/** Insert one row at the given version; payload from the parsed line. */
|
|
60
|
+
insertRow: (db: ReturnType<typeof getProjectDb>, version: number, payload: string) => void;
|
|
61
|
+
parseLine: (line: string) => string | null;
|
|
62
|
+
}): LegacyImportResult;
|
|
63
|
+
/**
|
|
64
|
+
* Import a family of legacy `.json` files into an entity table keyed by
|
|
65
|
+
* `(kind, phase)`. Files are discovered by exact prefix/suffix match in
|
|
66
|
+
* `.swarm/` (readdir — no user-supplied paths), the phase is parsed from the
|
|
67
|
+
* filename, and each file's parsed+validated object becomes the row payload.
|
|
68
|
+
*/
|
|
69
|
+
export declare function importLegacyJsonFiles(directory: string, opts: {
|
|
70
|
+
filePrefix: string;
|
|
71
|
+
kind: string;
|
|
72
|
+
/** Count existing rows for the kind (inside the txn). */
|
|
73
|
+
kindCount: (db: ReturnType<typeof getProjectDb>) => number;
|
|
74
|
+
/** Upsert one row; payload is the serialized JSON file content. */
|
|
75
|
+
upsertRow: (db: ReturnType<typeof getProjectDb>, phase: number, payload: string) => void;
|
|
76
|
+
}): LegacyImportResult;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swarm.db store for per-phase reports (issue #2480 D1 migration).
|
|
3
|
+
*
|
|
4
|
+
* Replaces two legacy file families with the entity/KV pattern — one row per
|
|
5
|
+
* (kind, phase), last-write-wins on a same-phase re-run:
|
|
6
|
+
* - `.swarm/drift-report-phase-{N}.json` (curator drift, kind
|
|
7
|
+
* `curator_drift`) — written by `src/hooks/curator-drift.ts`, read back by
|
|
8
|
+
* `readPriorDriftReports` and the curator postmortem.
|
|
9
|
+
* - `.swarm/doc-drift-phase-{N}.json` (design-doc drift, kind
|
|
10
|
+
* `design_doc_drift`) — written by `src/hooks/design-doc-drift.ts` (whose
|
|
11
|
+
* legacy bare `writeFile` was non-atomic; the store fixes that).
|
|
12
|
+
*
|
|
13
|
+
* Payloads are opaque serialized JSON strings; readers own validation
|
|
14
|
+
* (skip-corrupt on read, mirroring the legacy readers).
|
|
15
|
+
*/
|
|
16
|
+
export type PhaseReportKind = 'curator_drift' | 'design_doc_drift';
|
|
17
|
+
/** Legacy filename prefixes, one per report kind. */
|
|
18
|
+
export declare const PHASE_REPORT_LEGACY_PREFIXES: Readonly<Record<PhaseReportKind, string>>;
|
|
19
|
+
/**
|
|
20
|
+
* One-time (per process, per canonical root) lazy import of both legacy
|
|
21
|
+
* report families. Never runs at plugin init.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ensurePhaseReportsImported(directory: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Upsert one phase report via the group-commit writer and await the flush.
|
|
26
|
+
* A same-phase re-run overwrites the row (the legacy file rewrite semantic)
|
|
27
|
+
* and `updated_at` moves.
|
|
28
|
+
*/
|
|
29
|
+
export declare function upsertPhaseReportDb(directory: string, kind: PhaseReportKind, phase: number, payload: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Read all reports of one kind, ascending by phase. Returns the raw payload
|
|
32
|
+
* strings; the caller validates (the curator drift reader keeps its
|
|
33
|
+
* skip-corrupt schema check).
|
|
34
|
+
*/
|
|
35
|
+
export declare function readPhaseReportsDb(directory: string, kind: PhaseReportKind): Array<{
|
|
36
|
+
phase: number;
|
|
37
|
+
payload: string;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Stable, human-readable locator for a stored report (event payloads and
|
|
41
|
+
* advisory text reference the DB-backed store instead of a file path).
|
|
42
|
+
*/
|
|
43
|
+
export declare function phaseReportLocator(kind: PhaseReportKind, phase: number): string;
|
|
44
|
+
/** Test hook: reset the per-process import guards. */
|
|
45
|
+
export declare function _resetPhaseReportImportGuards(): void;
|
package/dist/db/project-db.d.ts
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-project SQLite database for opencode-swarm.
|
|
3
3
|
*
|
|
4
|
-
* Owns `.swarm/swarm.db` in each project directory
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Owns `.swarm/swarm.db` in each project directory: the single durable
|
|
5
|
+
* substrate of Workstream D (issue #2480). One cached instance per CANONICAL
|
|
6
|
+
* project identity (`canonical-project.ts`): case-varied Windows spellings,
|
|
7
|
+
* trailing separators, and symlinked roots of the same project share one
|
|
8
|
+
* connection. Open failures are typed (`db-errors.ts`), failed migrations are
|
|
9
|
+
* recorded for diagnosis and retried on the next open, and close runs a
|
|
10
|
+
* best-effort WAL checkpoint. The durability-class policy for every table
|
|
11
|
+
* lives in `durability.ts`.
|
|
7
12
|
*/
|
|
8
13
|
import type { Database } from 'bun:sqlite';
|
|
14
|
+
/** Number of currently cached project DB handles (tests / observability). */
|
|
15
|
+
export declare function getOpenProjectDbCount(): number;
|
|
16
|
+
/**
|
|
17
|
+
* Detect "another process applied this migration concurrently" failures:
|
|
18
|
+
* a UNIQUE constraint violation on schema_migrations.version, or an
|
|
19
|
+
* "already exists" DDL error (table/index/trigger created by the winner).
|
|
20
|
+
*/
|
|
21
|
+
export declare function isConcurrentMigrationApply(err: unknown): boolean;
|
|
9
22
|
/**
|
|
10
23
|
* Run all pending migrations on the provided database.
|
|
11
|
-
* Idempotent: existing migrations are not re-applied.
|
|
24
|
+
* Idempotent: existing migrations are not re-applied. Each migration applies
|
|
25
|
+
* in its own transaction; a failure rolls back, is recorded for diagnosis
|
|
26
|
+
* (table row, or the marker fallback), and leaves the version un-bumped so
|
|
27
|
+
* the next open retries it.
|
|
12
28
|
*/
|
|
13
|
-
export declare function runProjectMigrations(db: Database): void;
|
|
29
|
+
export declare function runProjectMigrations(db: Database, markerDir?: string): void;
|
|
14
30
|
/**
|
|
15
31
|
* Return the absolute path to `.swarm/swarm.db` for the given directory.
|
|
16
32
|
* Does not create the file or any parent directory.
|
|
@@ -26,13 +42,24 @@ export declare function projectDbExists(directory: string): boolean;
|
|
|
26
42
|
/**
|
|
27
43
|
* Return the cached project database for the given directory, opening it
|
|
28
44
|
* if needed. Creates `.swarm/` if absent and enables WAL + foreign keys.
|
|
45
|
+
* The cache is keyed by canonical project identity, so case-varied Windows
|
|
46
|
+
* spellings, trailing separators, and symlinked roots share ONE handle.
|
|
47
|
+
* Open failures throw a typed `ProjectDbError` and never leave a
|
|
48
|
+
* half-open handle cached.
|
|
29
49
|
*/
|
|
30
50
|
export declare function getProjectDb(directory: string): Database;
|
|
31
51
|
/**
|
|
32
52
|
* Close and remove the cached project database for the given directory.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
53
|
+
* Runs a best-effort WAL checkpoint (TRUNCATE, PASSIVE fallback) first so the
|
|
54
|
+
* close leaves a self-contained DB file where possible. Called by the
|
|
55
|
+
* `/swarm close` clean stage before unlinking `swarm.db` (so a long-lived
|
|
56
|
+
* WAL-mode connection releases its file lock and Windows `unlink` does not
|
|
57
|
+
* fail with EBUSY), by the plugin dispose/exit close paths, and from tests.
|
|
58
|
+
*
|
|
59
|
+
* Callers that passed a different spelling of the same root (case variant on
|
|
60
|
+
* Windows, symlink) share the canonical handle: closing it invalidates every
|
|
61
|
+
* alias — which is the point (those aliases were previously silent duplicate
|
|
62
|
+
* writers on one file). Reopening via `getProjectDb` always works.
|
|
36
63
|
*/
|
|
37
64
|
export declare function closeProjectDb(directory: string): void;
|
|
38
65
|
/**
|
|
@@ -31,6 +31,8 @@ export declare const _internals: {
|
|
|
31
31
|
profileId: number;
|
|
32
32
|
storagePlanId: string;
|
|
33
33
|
}) => void) | undefined;
|
|
34
|
+
/** #2480 test probe: synchronous level observed during the last write txn. */
|
|
35
|
+
lastTxnSynchronous: number;
|
|
34
36
|
};
|
|
35
37
|
/**
|
|
36
38
|
* QA gate flags. All eleven gates are tracked explicitly.
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type { CriticDriftResult, CuratorConfig, CuratorPhaseResult, DriftReport } from './curator-types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Read all prior drift reports from
|
|
3
|
+
* Read all prior drift reports (#2480: from the `phase_report` entity table
|
|
4
|
+
* in `.swarm/swarm.db`, kind `curator_drift`; the legacy
|
|
5
|
+
* `.swarm/drift-report-phase-*.json` files are imported once — idempotent,
|
|
6
|
+
* one-txn — and cold-archived `.json.imported`).
|
|
4
7
|
* Returns reports sorted ascending by phase number.
|
|
5
|
-
* Skips corrupt/unreadable
|
|
8
|
+
* Skips corrupt/unreadable payloads with a console.warn.
|
|
6
9
|
*/
|
|
7
10
|
export declare function readPriorDriftReports(directory: string): Promise<DriftReport[]>;
|
|
8
11
|
/**
|
|
9
|
-
* Write a drift report to
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
* Write a drift report to the `phase_report` entity table (#2480: upsert via
|
|
13
|
+
* the group-commit writer — one txn per flush, atomic, replacing the legacy
|
|
14
|
+
* non-batched file rewrite). A same-phase re-run overwrites the row.
|
|
15
|
+
* Returns the DB-backed report locator.
|
|
12
16
|
*/
|
|
13
17
|
export declare function writeDriftReport(directory: string, report: DriftReport): Promise<string>;
|
|
14
18
|
export declare const _internals: {
|
|
@@ -155,6 +155,7 @@ export interface SkillCandidate {
|
|
|
155
155
|
export interface CriticDriftResult {
|
|
156
156
|
phase: number;
|
|
157
157
|
report: DriftReport;
|
|
158
|
+
/** #2480: DB-backed locator, e.g. `swarm.db:phase_report(curator_drift,3)`. */
|
|
158
159
|
report_path: string;
|
|
159
160
|
injection_text: string;
|
|
160
161
|
}
|
|
@@ -69,9 +69,11 @@ export declare function enrichLessonToV3(params: {
|
|
|
69
69
|
/** Max insight candidates folded into the store per phase boundary. */
|
|
70
70
|
export declare const MESO_INSIGHT_BATCH_LIMIT = 20;
|
|
71
71
|
/**
|
|
72
|
-
* Atomically consume up to `batchLimit` insight candidates from
|
|
73
|
-
* `.swarm/
|
|
74
|
-
*
|
|
72
|
+
* Atomically consume up to `batchLimit` insight candidates from the durable
|
|
73
|
+
* `insight_candidate` stream in `.swarm/swarm.db` (issue #2480). The SELECT
|
|
74
|
+
* and the consumed_at UPDATE happen in ONE immediate transaction, so
|
|
75
|
+
* concurrent appends are never lost and a batch is never double-taken.
|
|
76
|
+
* Fail-open: returns [] on any DB error.
|
|
75
77
|
*/
|
|
76
78
|
export declare function consumeInsightCandidates(directory: string, batchLimit?: number): Promise<InsightCandidate[]>;
|
|
77
79
|
/** Build a SwarmKnowledgeEntry from an already-v3-actionable insight candidate. */
|
|
@@ -123,14 +123,19 @@ export declare function classifyOutcome(transcript: string, trajectory: Trajecto
|
|
|
123
123
|
/** Read a task's trajectory slice. Fail-open: [] when absent/corrupt. */
|
|
124
124
|
export declare function readTaskTrajectory(directory: string, taskId: string): Promise<TrajectoryEntry[]>;
|
|
125
125
|
export declare const INSIGHT_CANDIDATES_MAX_ENTRIES = 500;
|
|
126
|
-
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
126
|
+
/**
|
|
127
|
+
* Append validated candidates to the insight queue (best-effort, fail-open).
|
|
128
|
+
*
|
|
129
|
+
* #2480: the durable queue is the `insight_candidate` stream table in
|
|
130
|
+
* `.swarm/swarm.db` (group-commit writer, one txn per flush; FIFO cap 500 on
|
|
131
|
+
* the pending queue — same bound as before). The legacy
|
|
132
|
+
* `.swarm/insight-candidates.jsonl` is imported once (idempotent, one-txn)
|
|
133
|
+
* and cold-archived `.jsonl.imported`.
|
|
129
134
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
135
|
+
* EXPORTED (#1821) so the PRM pattern producer can write the SAME durable
|
|
136
|
+
* crash backstop the micro-reflector writes. Any producer that only enqueues
|
|
137
|
+
* in memory loses its candidate on process death, on queue overflow, and on a
|
|
138
|
+
* drain failure — with no phase-boundary fold-in to recover it. */
|
|
134
139
|
export declare function appendInsightCandidates(directory: string, candidates: InsightCandidate[]): Promise<void>;
|
|
135
140
|
/** Build the bounded micro-reflection prompt (≤ MICRO_PROMPT_INPUT_CAP chars). */
|
|
136
141
|
export declare function buildMicroPrompt(params: {
|