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.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/{coder-settlement-f1gtvcy8.js → coder-settlement-w4qk90kh.js} +12 -13
  3. package/dist/cli/{config-doctor-0fnqzqz1.js → config-doctor-r81bp1nd.js} +3 -3
  4. package/dist/cli/{core-w81fk5sc.js → core-xfw4s9b9.js} +2 -2
  5. package/dist/cli/{curation-policy-j12j2gvc.js → curation-policy-2h37sd6p.js} +6 -7
  6. package/dist/cli/{curator-as495r18.js → curator-7zy6bdmw.js} +36 -39
  7. package/dist/cli/{curator-drift-g6w4ga1q.js → curator-drift-ykrdf08r.js} +105 -38
  8. package/dist/cli/curator-llm-factory-7gjvm4ds.js +66 -0
  9. package/dist/cli/{evidence-summary-service-51dxfcn5.js → evidence-summary-service-519ny6b1.js} +17 -18
  10. package/dist/cli/{gate-evidence-nb1e8hz0.js → gate-evidence-a7st3vbc.js} +8 -9
  11. package/dist/cli/guardrail-explain-ewcm37em.js +67 -0
  12. package/dist/cli/{guardrail-log-2kwntcqw.js → guardrail-log-kp51by1v.js} +8 -9
  13. package/dist/cli/{guardrail-reset-mrxrc56j.js → guardrail-reset-reyfwtwn.js} +36 -39
  14. package/dist/cli/hive-promoter-zf2vf5sw.js +81 -0
  15. package/dist/cli/{index-4p0wyz5p.js → index-1af3rb5n.js} +9 -9
  16. package/dist/cli/{index-2zgjcmmc.js → index-1b1h770t.js} +3 -3
  17. package/dist/cli/{index-0tervb1m.js → index-2ee2g27m.js} +7795 -2724
  18. package/dist/cli/{index-x2f1f011.js → index-2s40e3b0.js} +4 -3
  19. package/dist/cli/{index-9xd073d4.js → index-2yd732fd.js} +7 -1
  20. package/dist/cli/{index-9crtmnqg.js → index-36nt17m8.js} +1 -1
  21. package/dist/cli/{index-d3azve4r.js → index-5084szce.js} +122 -300
  22. package/dist/cli/{index-d9gdwh34.js → index-5bza8nxz.js} +2 -2
  23. package/dist/cli/{index-xyhmt813.js → index-6097tx05.js} +1 -1
  24. package/dist/cli/{index-5056zmpt.js → index-644t46hr.js} +1 -1
  25. package/dist/cli/{index-2v06a1yh.js → index-6ay5zp1v.js} +5 -5
  26. package/dist/cli/{index-n2mhyect.js → index-6kd3jnaf.js} +1 -1
  27. package/dist/cli/{index-n67vx5zw.js → index-6t35714n.js} +2 -2
  28. package/dist/cli/{index-tnpf9wwv.js → index-862c0xhc.js} +1 -1
  29. package/dist/cli/{index-2n1ym7jb.js → index-b98r3pyv.js} +5 -5
  30. package/dist/cli/{index-8ada7ag7.js → index-dhzsvmx6.js} +2 -2
  31. package/dist/cli/{index-n985274d.js → index-e630pvvw.js} +4 -4
  32. package/dist/cli/{index-3b762978.js → index-f9nfknjg.js} +182 -37
  33. package/dist/cli/{index-m1fvbah1.js → index-fwfhbs27.js} +2 -2
  34. package/dist/cli/{index-t34daffb.js → index-h2f21caa.js} +2 -2
  35. package/dist/cli/{index-9ss2m4rs.js → index-hcn69kp0.js} +410 -1
  36. package/dist/cli/{index-g3znh2yd.js → index-hzaw10zh.js} +7 -7
  37. package/dist/cli/{index-cqgpvx2d.js → index-j0ajeary.js} +2 -2
  38. package/dist/cli/{index-f923njwh.js → index-jczbtx2x.js} +7 -7
  39. package/dist/cli/{index-hm239n1p.js → index-k8j7m0e2.js} +1 -1
  40. package/dist/cli/{index-zjme8atd.js → index-n1wcq816.js} +5 -5
  41. package/dist/cli/{index-66073kej.js → index-pmmfhzsp.js} +3 -3
  42. package/dist/cli/{index-fckfgptr.js → index-qbr05tbw.js} +2 -2
  43. package/dist/cli/{index-r56f3f81.js → index-r5jn0ah5.js} +2 -2
  44. package/dist/cli/{index-dtn0pne5.js → index-v56mhyhs.js} +1 -1
  45. package/dist/cli/{index-etvq73mp.js → index-vc3zmtxb.js} +38 -41
  46. package/dist/cli/{index-kvra3nv1.js → index-vdgw2k4c.js} +3 -3
  47. package/dist/cli/{index-0103w5pf.js → index-vkckf2ch.js} +2 -2
  48. package/dist/cli/{index-swgy9xvk.js → index-vrxx0ea4.js} +4 -4
  49. package/dist/cli/{index-08y8pccg.js → index-wnf1ej2q.js} +4 -4
  50. package/dist/cli/{index-qynqyfgj.js → index-wv4b01ex.js} +32 -34
  51. package/dist/cli/{index-7n9jznv0.js → index-x2qmpkth.js} +5 -5
  52. package/dist/cli/index-y2f5s2cf.js +403 -0
  53. package/dist/cli/{index-ma52g2pq.js → index-yc415pzf.js} +655 -16
  54. package/dist/cli/{index-n249fbw7.js → index-zaab1wz9.js} +5 -0
  55. package/dist/cli/index.js +36 -39
  56. package/dist/cli/{knowledge-escalator-fq7dm2g4.js → knowledge-escalator-wwkbsgvw.js} +14 -15
  57. package/dist/cli/{knowledge-events-3zanyfkr.js → knowledge-events-vmmgwfmc.js} +12 -13
  58. package/dist/cli/{knowledge-link-vmdj5e5d.js → knowledge-link-bvra01zv.js} +5 -6
  59. package/dist/cli/{knowledge-store-vhehnw52.js → knowledge-store-6wbagbqm.js} +6 -7
  60. package/dist/cli/{knowledge-validator-0tt0pe6b.js → knowledge-validator-q1z4fmeg.js} +8 -9
  61. package/dist/cli/{model-preflight-c3mc8njg.js → model-preflight-1ecjbg73.js} +1 -1
  62. package/dist/cli/{pending-delegations-b92pecbj.js → pending-delegations-cq5g4rr4.js} +6 -8
  63. package/dist/cli/{pr-subscriptions-2mkdt0ak.js → pr-subscriptions-m0z5wxkb.js} +6 -7
  64. package/dist/cli/pr-workflow-gate-0zvp0qs9.js +221 -0
  65. package/dist/cli/{runner-3gw2njnx.js → runner-s55g5233.js} +6 -7
  66. package/dist/cli/{scan-cursor-1c8a3b0m.js → scan-cursor-z6zepy3r.js} +7 -8
  67. package/dist/cli/{schema-c554j5c8.js → schema-skf0ckh4.js} +2 -2
  68. package/dist/cli/{scope-persistence-vtbcszvv.js → scope-persistence-f6davq7x.js} +10 -11
  69. package/dist/cli/{skill-generator-0es21fck.js → skill-generator-wqbazppk.js} +16 -17
  70. package/dist/cli/{sqlite-loader-c92413n7.js → sqlite-loader-8zefc142.js} +1 -1
  71. package/dist/cli/{telemetry-x4zggfd7.js → telemetry-q51s6tyt.js} +1 -1
  72. package/dist/cli/{worktree-collision-ownership-043dg8gg.js → worktree-collision-ownership-c0030qbm.js} +7 -9
  73. package/dist/cli/{worktree-isolation-hk42yxw7.js → worktree-isolation-09qq8066.js} +36 -39
  74. package/dist/db/canonical-project.d.ts +31 -0
  75. package/dist/db/db-errors.d.ts +24 -0
  76. package/dist/db/driver-parity.d.ts +31 -0
  77. package/dist/db/durability.d.ts +40 -0
  78. package/dist/db/group-commit-writer.d.ts +117 -0
  79. package/dist/db/health.d.ts +35 -0
  80. package/dist/db/insight-candidate-store.d.ts +61 -0
  81. package/dist/db/legacy-import.d.ts +77 -0
  82. package/dist/db/phase-report-store.d.ts +45 -0
  83. package/dist/db/project-db.d.ts +35 -8
  84. package/dist/db/qa-gate-profile.d.ts +2 -0
  85. package/dist/hooks/curator-drift.d.ts +9 -5
  86. package/dist/hooks/curator-types.d.ts +1 -0
  87. package/dist/hooks/delegation-gate.d.ts +1 -0
  88. package/dist/hooks/knowledge-curator.d.ts +5 -3
  89. package/dist/hooks/micro-reflector.d.ts +12 -7
  90. package/dist/hooks/pr-workflow-gate.d.ts +14 -8
  91. package/dist/hooks/pr-workflow-response-gate.d.ts +9 -12
  92. package/dist/index.js +627 -574
  93. package/dist/memory/schema.d.ts +4 -4
  94. package/dist/pr-review/authorization.d.ts +18 -12
  95. package/dist/prm/index.d.ts +3 -1
  96. package/dist/tools/authorize-pr-review-reentry.d.ts +12 -8
  97. package/package.json +3 -2
  98. package/dist/cli/authorization-vstrh7ra.js +0 -23
  99. package/dist/cli/curator-llm-factory-v8vwz20c.js +0 -69
  100. package/dist/cli/guardrail-explain-z2qb6v67.js +0 -70
  101. package/dist/cli/hive-promoter-c62x2ncb.js +0 -84
  102. package/dist/cli/index-c8s9a3zh.js +0 -73
  103. package/dist/cli/index-ed5ykebp.js +0 -151
  104. package/dist/cli/index-mmngnxev.js +0 -883
  105. 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-n985274d.js";
37
- import"./index-08y8pccg.js";
38
- import"./index-hm239n1p.js";
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-f923njwh.js";
42
- import"./index-4p0wyz5p.js";
43
- import"./index-66073kej.js";
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-dtn0pne5.js";
46
+ import"./index-v56mhyhs.js";
47
47
  import"./index-z6xqpmqg.js";
48
48
  import"./index-r3mvsbtq.js";
49
- import"./index-tnpf9wwv.js";
50
- import"./index-x2f1f011.js";
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-cqgpvx2d.js";
54
- import"./index-9xd073d4.js";
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-n2mhyect.js";
58
- import"./index-n67vx5zw.js";
57
+ import"./index-6kd3jnaf.js";
58
+ import"./index-6t35714n.js";
59
59
  import"./index-bk5tah7q.js";
60
- import"./index-9crtmnqg.js";
61
- import"./index-3b762978.js";
62
- import"./index-2zgjcmmc.js";
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";
@@ -3,7 +3,7 @@ import {
3
3
  _internals,
4
4
  createNodeDatabaseCtor,
5
5
  loadDatabaseCtor
6
- } from "./index-n249fbw7.js";
6
+ } from "./index-zaab1wz9.js";
7
7
  import"./index-a76rekgs.js";
8
8
  export {
9
9
  loadDatabaseCtor,
@@ -14,7 +14,7 @@ import {
14
14
  startHeartbeatTracking,
15
15
  stopHeartbeatTracking,
16
16
  telemetry
17
- } from "./index-2zgjcmmc.js";
17
+ } from "./index-1b1h770t.js";
18
18
  import"./index-bpmtbmy9.js";
19
19
  import"./index-a76rekgs.js";
20
20
  export {
@@ -6,14 +6,13 @@ import {
6
6
  WORKTREE_PROVISIONING_OWNER_LEASE_MS,
7
7
  removeWorktreeProvisioningOwner,
8
8
  scanWorktreeProvisioningOwnersForRecovery
9
- } from "./index-fckfgptr.js";
9
+ } from "./index-qbr05tbw.js";
10
10
  import {
11
11
  scanDelegationFallbacksForRecovery,
12
12
  scanDelegationsForRecovery
13
- } from "./index-ma52g2pq.js";
13
+ } from "./index-yc415pzf.js";
14
14
  import"./index-ddszzne4.js";
15
- import"./index-w7ekntej.js";
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-cqgpvx2d.js";
25
+ import"./index-j0ajeary.js";
27
26
  import"./index-zjygnfay.js";
28
- import"./index-9crtmnqg.js";
29
- import"./index-3b762978.js";
30
- import"./index-2zgjcmmc.js";
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-0tervb1m.js";
25
- import"./index-xyhmt813.js";
26
- import"./index-qynqyfgj.js";
27
- import"./index-r56f3f81.js";
28
- import"./index-d3azve4r.js";
29
- import"./index-0103w5pf.js";
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-n985274d.js";
34
- import"./index-2v06a1yh.js";
35
- import"./index-t34daffb.js";
32
+ import"./index-e630pvvw.js";
33
+ import"./index-6ay5zp1v.js";
34
+ import"./index-h2f21caa.js";
36
35
  import"./index-70ha9e09.js";
37
- import"./index-c8s9a3zh.js";
38
- import"./index-9ss2m4rs.js";
39
- import"./index-7n9jznv0.js";
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-g3znh2yd.js";
41
+ import"./index-hzaw10zh.js";
42
42
  import"./index-3f7hqtgg.js";
43
- import"./index-fckfgptr.js";
44
- import"./index-08y8pccg.js";
45
- import"./index-hm239n1p.js";
43
+ import"./index-qbr05tbw.js";
44
+ import"./index-wnf1ej2q.js";
45
+ import"./index-k8j7m0e2.js";
46
46
  import"./index-rtry5xyf.js";
47
- import"./index-zjme8atd.js";
48
- import"./index-d9gdwh34.js";
49
- import"./index-ma52g2pq.js";
47
+ import"./index-n1wcq816.js";
48
+ import"./index-5bza8nxz.js";
49
+ import"./index-yc415pzf.js";
50
50
  import"./index-ddszzne4.js";
51
- import"./index-mmngnxev.js";
52
- import"./index-w7ekntej.js";
53
- import"./index-2n1ym7jb.js";
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-f923njwh.js";
61
- import"./index-4p0wyz5p.js";
58
+ import"./index-jczbtx2x.js";
59
+ import"./index-1af3rb5n.js";
62
60
  import {
63
61
  resolveWorktreeIsolationConfig
64
- } from "./index-66073kej.js";
62
+ } from "./index-pmmfhzsp.js";
65
63
  import"./index-zg9d392c.js";
66
64
  import"./index-n832052r.js";
67
- import"./index-dtn0pne5.js";
65
+ import"./index-v56mhyhs.js";
68
66
  import"./index-z6xqpmqg.js";
69
67
  import"./index-r3mvsbtq.js";
70
- import"./index-tnpf9wwv.js";
71
- import"./index-x2f1f011.js";
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-cqgpvx2d.js";
75
- import"./index-9xd073d4.js";
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-n2mhyect.js";
79
- import"./index-n67vx5zw.js";
76
+ import"./index-6kd3jnaf.js";
77
+ import"./index-6t35714n.js";
80
78
  import"./index-bk5tah7q.js";
81
- import"./index-9crtmnqg.js";
82
- import"./index-3b762978.js";
83
- import"./index-2zgjcmmc.js";
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 {};