opencode-swarm 7.163.1 → 7.164.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.
- package/README.md +1 -1
- package/dist/cli/{coder-settlement-f1gtvcy8.js → coder-settlement-w4qk90kh.js} +12 -13
- package/dist/cli/{config-doctor-0fnqzqz1.js → config-doctor-r81bp1nd.js} +3 -3
- package/dist/cli/{core-w81fk5sc.js → core-xfw4s9b9.js} +2 -2
- package/dist/cli/{curation-policy-j12j2gvc.js → curation-policy-2h37sd6p.js} +6 -7
- package/dist/cli/{curator-as495r18.js → curator-7zy6bdmw.js} +36 -39
- package/dist/cli/{curator-drift-g6w4ga1q.js → curator-drift-ykrdf08r.js} +105 -38
- package/dist/cli/curator-llm-factory-7gjvm4ds.js +66 -0
- package/dist/cli/{evidence-summary-service-51dxfcn5.js → evidence-summary-service-519ny6b1.js} +17 -18
- package/dist/cli/{gate-evidence-nb1e8hz0.js → gate-evidence-a7st3vbc.js} +8 -9
- package/dist/cli/guardrail-explain-ewcm37em.js +67 -0
- package/dist/cli/{guardrail-log-2kwntcqw.js → guardrail-log-kp51by1v.js} +8 -9
- package/dist/cli/{guardrail-reset-mrxrc56j.js → guardrail-reset-reyfwtwn.js} +36 -39
- package/dist/cli/hive-promoter-zf2vf5sw.js +81 -0
- package/dist/cli/{index-4p0wyz5p.js → index-1af3rb5n.js} +9 -9
- package/dist/cli/{index-2zgjcmmc.js → index-1b1h770t.js} +3 -3
- package/dist/cli/{index-0tervb1m.js → index-2ee2g27m.js} +7795 -2724
- package/dist/cli/{index-x2f1f011.js → index-2s40e3b0.js} +4 -3
- package/dist/cli/{index-9xd073d4.js → index-2yd732fd.js} +7 -1
- package/dist/cli/{index-9crtmnqg.js → index-36nt17m8.js} +1 -1
- package/dist/cli/{index-d3azve4r.js → index-5084szce.js} +122 -300
- package/dist/cli/{index-d9gdwh34.js → index-5bza8nxz.js} +2 -2
- package/dist/cli/{index-xyhmt813.js → index-6097tx05.js} +1 -1
- package/dist/cli/{index-5056zmpt.js → index-644t46hr.js} +1 -1
- package/dist/cli/{index-2v06a1yh.js → index-6ay5zp1v.js} +5 -5
- package/dist/cli/{index-n2mhyect.js → index-6kd3jnaf.js} +1 -1
- package/dist/cli/{index-n67vx5zw.js → index-6t35714n.js} +2 -2
- package/dist/cli/{index-tnpf9wwv.js → index-862c0xhc.js} +1 -1
- package/dist/cli/{index-2n1ym7jb.js → index-b98r3pyv.js} +5 -5
- package/dist/cli/{index-8ada7ag7.js → index-dhzsvmx6.js} +2 -2
- package/dist/cli/{index-n985274d.js → index-e630pvvw.js} +4 -4
- package/dist/cli/{index-3b762978.js → index-f9nfknjg.js} +182 -37
- package/dist/cli/{index-m1fvbah1.js → index-fwfhbs27.js} +2 -2
- package/dist/cli/{index-t34daffb.js → index-h2f21caa.js} +2 -2
- package/dist/cli/{index-9ss2m4rs.js → index-hcn69kp0.js} +410 -1
- package/dist/cli/{index-g3znh2yd.js → index-hzaw10zh.js} +7 -7
- package/dist/cli/{index-cqgpvx2d.js → index-j0ajeary.js} +2 -2
- package/dist/cli/{index-f923njwh.js → index-jczbtx2x.js} +7 -7
- package/dist/cli/{index-hm239n1p.js → index-k8j7m0e2.js} +1 -1
- package/dist/cli/{index-zjme8atd.js → index-n1wcq816.js} +5 -5
- package/dist/cli/{index-66073kej.js → index-pmmfhzsp.js} +3 -3
- package/dist/cli/{index-fckfgptr.js → index-qbr05tbw.js} +2 -2
- package/dist/cli/{index-r56f3f81.js → index-r5jn0ah5.js} +2 -2
- package/dist/cli/{index-dtn0pne5.js → index-v56mhyhs.js} +1 -1
- package/dist/cli/{index-etvq73mp.js → index-vc3zmtxb.js} +38 -41
- package/dist/cli/{index-kvra3nv1.js → index-vdgw2k4c.js} +3 -3
- package/dist/cli/{index-0103w5pf.js → index-vkckf2ch.js} +2 -2
- package/dist/cli/{index-swgy9xvk.js → index-vrxx0ea4.js} +4 -4
- package/dist/cli/{index-08y8pccg.js → index-wnf1ej2q.js} +4 -4
- package/dist/cli/{index-qynqyfgj.js → index-wv4b01ex.js} +32 -34
- package/dist/cli/{index-7n9jznv0.js → index-x2qmpkth.js} +5 -5
- package/dist/cli/index-y2f5s2cf.js +403 -0
- package/dist/cli/{index-ma52g2pq.js → index-yc415pzf.js} +655 -16
- package/dist/cli/{index-n249fbw7.js → index-zaab1wz9.js} +5 -0
- package/dist/cli/index.js +36 -39
- package/dist/cli/{knowledge-escalator-fq7dm2g4.js → knowledge-escalator-wwkbsgvw.js} +14 -15
- package/dist/cli/{knowledge-events-3zanyfkr.js → knowledge-events-vmmgwfmc.js} +12 -13
- package/dist/cli/{knowledge-link-vmdj5e5d.js → knowledge-link-bvra01zv.js} +5 -6
- package/dist/cli/{knowledge-store-vhehnw52.js → knowledge-store-6wbagbqm.js} +6 -7
- package/dist/cli/{knowledge-validator-0tt0pe6b.js → knowledge-validator-q1z4fmeg.js} +8 -9
- package/dist/cli/{model-preflight-c3mc8njg.js → model-preflight-1ecjbg73.js} +1 -1
- package/dist/cli/{pending-delegations-b92pecbj.js → pending-delegations-cq5g4rr4.js} +6 -8
- package/dist/cli/{pr-subscriptions-2mkdt0ak.js → pr-subscriptions-m0z5wxkb.js} +6 -7
- package/dist/cli/pr-workflow-gate-0zvp0qs9.js +221 -0
- package/dist/cli/{runner-3gw2njnx.js → runner-s55g5233.js} +6 -7
- package/dist/cli/{scan-cursor-1c8a3b0m.js → scan-cursor-z6zepy3r.js} +7 -8
- package/dist/cli/{schema-c554j5c8.js → schema-skf0ckh4.js} +2 -2
- package/dist/cli/{scope-persistence-vtbcszvv.js → scope-persistence-f6davq7x.js} +10 -11
- package/dist/cli/{skill-generator-0es21fck.js → skill-generator-wqbazppk.js} +16 -17
- 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-c0030qbm.js} +7 -9
- package/dist/cli/{worktree-isolation-hk42yxw7.js → worktree-isolation-09qq8066.js} +36 -39
- 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/delegation-gate.d.ts +1 -0
- package/dist/hooks/knowledge-curator.d.ts +5 -3
- package/dist/hooks/micro-reflector.d.ts +12 -7
- package/dist/hooks/pr-workflow-gate.d.ts +14 -8
- package/dist/hooks/pr-workflow-response-gate.d.ts +9 -12
- package/dist/index.js +627 -574
- package/dist/memory/schema.d.ts +4 -4
- package/dist/pr-review/authorization.d.ts +18 -12
- package/dist/prm/index.d.ts +3 -1
- package/dist/tools/authorize-pr-review-reentry.d.ts +12 -8
- package/package.json +3 -2
- package/dist/cli/authorization-vstrh7ra.js +0 -23
- package/dist/cli/curator-llm-factory-v8vwz20c.js +0 -69
- package/dist/cli/guardrail-explain-z2qb6v67.js +0 -70
- package/dist/cli/hive-promoter-c62x2ncb.js +0 -84
- package/dist/cli/index-c8s9a3zh.js +0 -73
- package/dist/cli/index-ed5ykebp.js +0 -151
- package/dist/cli/index-mmngnxev.js +0 -883
- package/dist/cli/index-w7ekntej.js +0 -643
|
@@ -33,34 +33,33 @@ import {
|
|
|
33
33
|
sanitizeSlug,
|
|
34
34
|
selectCandidateEntries,
|
|
35
35
|
writeEvalStub
|
|
36
|
-
} from "./index-
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
36
|
+
} from "./index-e630pvvw.js";
|
|
37
|
+
import"./index-wnf1ej2q.js";
|
|
38
|
+
import"./index-k8j7m0e2.js";
|
|
39
39
|
import"./index-rtry5xyf.js";
|
|
40
40
|
import"./index-q7sjgr1y.js";
|
|
41
|
-
import"./index-
|
|
42
|
-
import"./index-
|
|
43
|
-
import"./index-
|
|
41
|
+
import"./index-jczbtx2x.js";
|
|
42
|
+
import"./index-1af3rb5n.js";
|
|
43
|
+
import"./index-pmmfhzsp.js";
|
|
44
44
|
import"./index-zg9d392c.js";
|
|
45
45
|
import"./index-n832052r.js";
|
|
46
|
-
import"./index-
|
|
46
|
+
import"./index-v56mhyhs.js";
|
|
47
47
|
import"./index-z6xqpmqg.js";
|
|
48
48
|
import"./index-r3mvsbtq.js";
|
|
49
|
-
import"./index-
|
|
50
|
-
import"./index-
|
|
49
|
+
import"./index-862c0xhc.js";
|
|
50
|
+
import"./index-2s40e3b0.js";
|
|
51
51
|
import"./index-9e6fdz2h.js";
|
|
52
52
|
import"./index-4rhhvd1a.js";
|
|
53
|
-
import"./index-
|
|
54
|
-
import"./index-
|
|
53
|
+
import"./index-j0ajeary.js";
|
|
54
|
+
import"./index-2yd732fd.js";
|
|
55
55
|
import"./index-zjygnfay.js";
|
|
56
56
|
import"./index-ae75rja9.js";
|
|
57
|
-
import"./index-
|
|
58
|
-
import"./index-
|
|
57
|
+
import"./index-6kd3jnaf.js";
|
|
58
|
+
import"./index-6t35714n.js";
|
|
59
59
|
import"./index-bk5tah7q.js";
|
|
60
|
-
import"./index-
|
|
61
|
-
import"./index-
|
|
62
|
-
import"./index-
|
|
63
|
-
import"./index-ed5ykebp.js";
|
|
60
|
+
import"./index-36nt17m8.js";
|
|
61
|
+
import"./index-f9nfknjg.js";
|
|
62
|
+
import"./index-1b1h770t.js";
|
|
64
63
|
import"./index-7g4c7s5r.js";
|
|
65
64
|
import"./index-bpmtbmy9.js";
|
|
66
65
|
import"./index-zgwm4ryv.js";
|
|
@@ -6,14 +6,13 @@ import {
|
|
|
6
6
|
WORKTREE_PROVISIONING_OWNER_LEASE_MS,
|
|
7
7
|
removeWorktreeProvisioningOwner,
|
|
8
8
|
scanWorktreeProvisioningOwnersForRecovery
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-qbr05tbw.js";
|
|
10
10
|
import {
|
|
11
11
|
scanDelegationFallbacksForRecovery,
|
|
12
12
|
scanDelegationsForRecovery
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-yc415pzf.js";
|
|
14
14
|
import"./index-ddszzne4.js";
|
|
15
|
-
import"./index-
|
|
16
|
-
import"./index-dtn0pne5.js";
|
|
15
|
+
import"./index-v56mhyhs.js";
|
|
17
16
|
import"./index-z6xqpmqg.js";
|
|
18
17
|
import {
|
|
19
18
|
bunSpawn
|
|
@@ -23,12 +22,11 @@ import {
|
|
|
23
22
|
resolveGitExecutable
|
|
24
23
|
} from "./index-9e6fdz2h.js";
|
|
25
24
|
import"./index-4rhhvd1a.js";
|
|
26
|
-
import"./index-
|
|
25
|
+
import"./index-j0ajeary.js";
|
|
27
26
|
import"./index-zjygnfay.js";
|
|
28
|
-
import"./index-
|
|
29
|
-
import"./index-
|
|
30
|
-
import"./index-
|
|
31
|
-
import"./index-ed5ykebp.js";
|
|
27
|
+
import"./index-36nt17m8.js";
|
|
28
|
+
import"./index-f9nfknjg.js";
|
|
29
|
+
import"./index-1b1h770t.js";
|
|
32
30
|
import"./index-7g4c7s5r.js";
|
|
33
31
|
import"./index-bpmtbmy9.js";
|
|
34
32
|
import"./index-zgwm4ryv.js";
|
|
@@ -21,67 +21,64 @@ import {
|
|
|
21
21
|
sanitizeWorktreeTaskId,
|
|
22
22
|
standardWorktreeByCallID,
|
|
23
23
|
standardWorktreeSerializationSessions
|
|
24
|
-
} from "./index-
|
|
25
|
-
import"./index-
|
|
26
|
-
import"./index-
|
|
27
|
-
import"./index-
|
|
28
|
-
import"./index-
|
|
29
|
-
import"./index-
|
|
24
|
+
} from "./index-2ee2g27m.js";
|
|
25
|
+
import"./index-6097tx05.js";
|
|
26
|
+
import"./index-wv4b01ex.js";
|
|
27
|
+
import"./index-r5jn0ah5.js";
|
|
28
|
+
import"./index-5084szce.js";
|
|
29
|
+
import"./index-vkckf2ch.js";
|
|
30
30
|
import"./index-txdagbh7.js";
|
|
31
|
-
import"./index-n249fbw7.js";
|
|
32
31
|
import"./index-3146wmgv.js";
|
|
33
|
-
import"./index-
|
|
34
|
-
import"./index-
|
|
35
|
-
import"./index-
|
|
32
|
+
import"./index-e630pvvw.js";
|
|
33
|
+
import"./index-6ay5zp1v.js";
|
|
34
|
+
import"./index-h2f21caa.js";
|
|
36
35
|
import"./index-70ha9e09.js";
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
39
|
-
import"./index-
|
|
36
|
+
import"./index-y2f5s2cf.js";
|
|
37
|
+
import"./index-hcn69kp0.js";
|
|
38
|
+
import"./index-zaab1wz9.js";
|
|
39
|
+
import"./index-x2qmpkth.js";
|
|
40
40
|
import"./index-zsrtt42s.js";
|
|
41
|
-
import"./index-
|
|
41
|
+
import"./index-hzaw10zh.js";
|
|
42
42
|
import"./index-3f7hqtgg.js";
|
|
43
|
-
import"./index-
|
|
44
|
-
import"./index-
|
|
45
|
-
import"./index-
|
|
43
|
+
import"./index-qbr05tbw.js";
|
|
44
|
+
import"./index-wnf1ej2q.js";
|
|
45
|
+
import"./index-k8j7m0e2.js";
|
|
46
46
|
import"./index-rtry5xyf.js";
|
|
47
|
-
import"./index-
|
|
48
|
-
import"./index-
|
|
49
|
-
import"./index-
|
|
47
|
+
import"./index-n1wcq816.js";
|
|
48
|
+
import"./index-5bza8nxz.js";
|
|
49
|
+
import"./index-yc415pzf.js";
|
|
50
50
|
import"./index-ddszzne4.js";
|
|
51
|
-
import"./index-
|
|
52
|
-
import"./index-
|
|
53
|
-
import"./index-
|
|
54
|
-
import"./index-kvra3nv1.js";
|
|
55
|
-
import"./index-8ada7ag7.js";
|
|
51
|
+
import"./index-b98r3pyv.js";
|
|
52
|
+
import"./index-vdgw2k4c.js";
|
|
53
|
+
import"./index-dhzsvmx6.js";
|
|
56
54
|
import"./index-556ja8an.js";
|
|
57
55
|
import"./index-4fwbbad3.js";
|
|
58
56
|
import"./index-b43rt5ph.js";
|
|
59
57
|
import"./index-q7sjgr1y.js";
|
|
60
|
-
import"./index-
|
|
61
|
-
import"./index-
|
|
58
|
+
import"./index-jczbtx2x.js";
|
|
59
|
+
import"./index-1af3rb5n.js";
|
|
62
60
|
import {
|
|
63
61
|
resolveWorktreeIsolationConfig
|
|
64
|
-
} from "./index-
|
|
62
|
+
} from "./index-pmmfhzsp.js";
|
|
65
63
|
import"./index-zg9d392c.js";
|
|
66
64
|
import"./index-n832052r.js";
|
|
67
|
-
import"./index-
|
|
65
|
+
import"./index-v56mhyhs.js";
|
|
68
66
|
import"./index-z6xqpmqg.js";
|
|
69
67
|
import"./index-r3mvsbtq.js";
|
|
70
|
-
import"./index-
|
|
71
|
-
import"./index-
|
|
68
|
+
import"./index-862c0xhc.js";
|
|
69
|
+
import"./index-2s40e3b0.js";
|
|
72
70
|
import"./index-9e6fdz2h.js";
|
|
73
71
|
import"./index-4rhhvd1a.js";
|
|
74
|
-
import"./index-
|
|
75
|
-
import"./index-
|
|
72
|
+
import"./index-j0ajeary.js";
|
|
73
|
+
import"./index-2yd732fd.js";
|
|
76
74
|
import"./index-zjygnfay.js";
|
|
77
75
|
import"./index-ae75rja9.js";
|
|
78
|
-
import"./index-
|
|
79
|
-
import"./index-
|
|
76
|
+
import"./index-6kd3jnaf.js";
|
|
77
|
+
import"./index-6t35714n.js";
|
|
80
78
|
import"./index-bk5tah7q.js";
|
|
81
|
-
import"./index-
|
|
82
|
-
import"./index-
|
|
83
|
-
import"./index-
|
|
84
|
-
import"./index-ed5ykebp.js";
|
|
79
|
+
import"./index-36nt17m8.js";
|
|
80
|
+
import"./index-f9nfknjg.js";
|
|
81
|
+
import"./index-1b1h770t.js";
|
|
85
82
|
import"./index-7g4c7s5r.js";
|
|
86
83
|
import"./index-bpmtbmy9.js";
|
|
87
84
|
import"./index-zgwm4ryv.js";
|
|
@@ -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 {};
|