@cleocode/core 2026.3.76 → 2026.4.2

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 (473) hide show
  1. package/dist/agents/agent-schema.d.ts.map +1 -1
  2. package/dist/audit.d.ts +1 -1
  3. package/dist/audit.d.ts.map +1 -1
  4. package/dist/bootstrap.d.ts +2 -2
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/caamp/adapter.d.ts +6 -49
  7. package/dist/caamp/adapter.d.ts.map +1 -1
  8. package/dist/caamp/index.d.ts +2 -2
  9. package/dist/caamp/index.d.ts.map +1 -1
  10. package/dist/code/index.d.ts +10 -0
  11. package/dist/code/index.d.ts.map +1 -0
  12. package/dist/code/outline.d.ts +51 -0
  13. package/dist/code/outline.d.ts.map +1 -0
  14. package/dist/code/parser.d.ts +32 -0
  15. package/dist/code/parser.d.ts.map +1 -0
  16. package/dist/code/search.d.ts +42 -0
  17. package/dist/code/search.d.ts.map +1 -0
  18. package/dist/code/unfold.d.ts +44 -0
  19. package/dist/code/unfold.d.ts.map +1 -0
  20. package/dist/compliance/protocol-enforcement.d.ts +1 -1
  21. package/dist/compliance/protocol-rules.d.ts +1 -1
  22. package/dist/compliance/protocol-types.d.ts +2 -3
  23. package/dist/compliance/protocol-types.d.ts.map +1 -1
  24. package/dist/conduit/conduit-client.d.ts +14 -0
  25. package/dist/conduit/conduit-client.d.ts.map +1 -1
  26. package/dist/conduit/factory.d.ts +11 -1
  27. package/dist/conduit/factory.d.ts.map +1 -1
  28. package/dist/conduit/http-transport.d.ts +17 -5
  29. package/dist/conduit/http-transport.d.ts.map +1 -1
  30. package/dist/conduit/index.d.ts +5 -2
  31. package/dist/conduit/index.d.ts.map +1 -1
  32. package/dist/conduit/local-transport.d.ts +91 -0
  33. package/dist/conduit/local-transport.d.ts.map +1 -0
  34. package/dist/conduit/sse-transport.d.ts +68 -0
  35. package/dist/conduit/sse-transport.d.ts.map +1 -0
  36. package/dist/crypto/credentials.d.ts.map +1 -1
  37. package/dist/error-catalog.d.ts +3 -3
  38. package/dist/error-catalog.d.ts.map +1 -1
  39. package/dist/errors.d.ts +1 -1
  40. package/dist/hooks/handlers/index.d.ts +2 -2
  41. package/dist/hooks/handlers/index.d.ts.map +1 -1
  42. package/dist/hooks/handlers/notification-hooks.d.ts +31 -0
  43. package/dist/hooks/handlers/notification-hooks.d.ts.map +1 -0
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +4646 -3476
  47. package/dist/index.js.map +4 -4
  48. package/dist/init.d.ts +6 -6
  49. package/dist/init.d.ts.map +1 -1
  50. package/dist/injection.d.ts.map +1 -1
  51. package/dist/internal.d.ts +7 -5
  52. package/dist/internal.d.ts.map +1 -1
  53. package/dist/lib/index.d.ts +1 -0
  54. package/dist/lib/index.d.ts.map +1 -1
  55. package/dist/lib/tree-sitter-languages.d.ts +29 -0
  56. package/dist/lib/tree-sitter-languages.d.ts.map +1 -0
  57. package/dist/logger.d.ts +3 -3
  58. package/dist/memory/brain-links.d.ts.map +1 -1
  59. package/dist/memory/brain-maintenance.d.ts +13 -0
  60. package/dist/memory/brain-maintenance.d.ts.map +1 -1
  61. package/dist/memory/brain-retrieval.d.ts +1 -1
  62. package/dist/memory/brain-retrieval.d.ts.map +1 -1
  63. package/dist/memory/decisions.d.ts.map +1 -1
  64. package/dist/memory/engine-compat.d.ts +392 -25
  65. package/dist/memory/engine-compat.d.ts.map +1 -1
  66. package/dist/memory/index.d.ts +416 -3
  67. package/dist/memory/index.d.ts.map +1 -1
  68. package/dist/metrics/token-service.d.ts +3 -3
  69. package/dist/metrics/token-service.d.ts.map +1 -1
  70. package/dist/orchestration/hierarchy.d.ts +32 -0
  71. package/dist/orchestration/hierarchy.d.ts.map +1 -0
  72. package/dist/orchestration/index.d.ts +1 -0
  73. package/dist/orchestration/index.d.ts.map +1 -1
  74. package/dist/paths.d.ts +335 -2
  75. package/dist/paths.d.ts.map +1 -1
  76. package/dist/routing/capability-matrix.d.ts +3 -3
  77. package/dist/routing/capability-matrix.d.ts.map +1 -1
  78. package/dist/scaffold.d.ts +422 -11
  79. package/dist/scaffold.d.ts.map +1 -1
  80. package/dist/security/input-sanitization.d.ts +2 -2
  81. package/dist/skills/dynamic-skill-generator.d.ts +3 -2
  82. package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
  83. package/dist/skills/routing-table.d.ts +4 -4
  84. package/dist/skills/routing-table.d.ts.map +1 -1
  85. package/dist/store/agent-registry-accessor.d.ts +10 -433
  86. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  87. package/dist/store/cross-db-cleanup.d.ts +34 -0
  88. package/dist/store/cross-db-cleanup.d.ts.map +1 -1
  89. package/dist/store/provider.d.ts +1 -1
  90. package/dist/store/signaldock-sqlite.d.ts.map +1 -1
  91. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  92. package/dist/store/sqlite.d.ts +1 -1
  93. package/dist/store/task-store.d.ts.map +1 -1
  94. package/dist/store/tasks-schema.d.ts +4 -228
  95. package/dist/store/tasks-schema.d.ts.map +1 -1
  96. package/dist/store/validation-schemas.d.ts +4 -5
  97. package/dist/store/validation-schemas.d.ts.map +1 -1
  98. package/dist/system/archive-analytics.d.ts +1 -1
  99. package/dist/system/health.d.ts +2 -2
  100. package/dist/system/health.d.ts.map +1 -1
  101. package/dist/system/runtime.d.ts +2 -1
  102. package/dist/system/runtime.d.ts.map +1 -1
  103. package/dist/tasks/list.d.ts +1 -1
  104. package/dist/tasks/list.d.ts.map +1 -1
  105. package/dist/tasks/task-ops.d.ts +415 -3
  106. package/dist/tasks/task-ops.d.ts.map +1 -1
  107. package/dist/templates/parser.d.ts +1 -1
  108. package/dist/ui/index.d.ts +1 -1
  109. package/dist/upgrade.d.ts +1 -1
  110. package/dist/upgrade.d.ts.map +1 -1
  111. package/dist/validation/operation-gate-validators.d.ts +1 -1
  112. package/dist/validation/operation-verification-gates.d.ts +3 -3
  113. package/dist/validation/param-utils.d.ts +6 -5
  114. package/dist/validation/param-utils.d.ts.map +1 -1
  115. package/dist/validation/validate-ops.d.ts +1 -1
  116. package/dist/validation/validate-ops.d.ts.map +1 -1
  117. package/package.json +19 -7
  118. package/src/__tests__/caamp-skill-install.test.js +0 -15
  119. package/src/__tests__/caamp-skill-install.test.js.map +1 -1
  120. package/src/__tests__/caamp-skill-install.test.ts +0 -16
  121. package/src/__tests__/injection-mvi-tiers.test.js +7 -7
  122. package/src/__tests__/injection-mvi-tiers.test.js.map +1 -1
  123. package/src/__tests__/injection-mvi-tiers.test.ts +55 -103
  124. package/src/agents/agent-schema.ts +2 -5
  125. package/src/audit.ts +2 -2
  126. package/src/bootstrap.ts +5 -39
  127. package/src/caamp/adapter.ts +3 -219
  128. package/src/caamp/index.ts +1 -13
  129. package/src/cant/__tests__/cant-agent-parse.test.d.ts.map +1 -0
  130. package/src/cant/__tests__/cant-agent-parse.test.js +77 -0
  131. package/src/cant/__tests__/cant-agent-parse.test.js.map +1 -0
  132. package/src/code/index.ts +10 -0
  133. package/src/code/outline.ts +214 -0
  134. package/src/code/parser.ts +331 -0
  135. package/src/code/search.ts +173 -0
  136. package/src/code/unfold.ts +204 -0
  137. package/src/codebase-map/analyzers/architecture.ts +2 -2
  138. package/src/compliance/protocol-enforcement.ts +1 -1
  139. package/src/compliance/protocol-rules.ts +1 -1
  140. package/src/compliance/protocol-types.ts +2 -3
  141. package/src/conduit/__tests__/dual-api-e2e.test.d.ts.map +1 -0
  142. package/src/conduit/__tests__/dual-api-e2e.test.js +178 -0
  143. package/src/conduit/__tests__/dual-api-e2e.test.js.map +1 -0
  144. package/src/conduit/__tests__/dual-api-e2e.test.ts +212 -0
  145. package/src/conduit/__tests__/local-credential-flow.test.d.ts.map +1 -0
  146. package/src/conduit/__tests__/local-credential-flow.test.js +185 -0
  147. package/src/conduit/__tests__/local-credential-flow.test.js.map +1 -0
  148. package/src/conduit/__tests__/local-credential-flow.test.ts +230 -0
  149. package/src/conduit/__tests__/local-transport.test.d.ts.map +1 -0
  150. package/src/conduit/__tests__/local-transport.test.js +404 -0
  151. package/src/conduit/__tests__/local-transport.test.js.map +1 -0
  152. package/src/conduit/__tests__/local-transport.test.ts +509 -0
  153. package/src/conduit/__tests__/sse-transport.test.d.ts.map +1 -0
  154. package/src/conduit/__tests__/sse-transport.test.js +291 -0
  155. package/src/conduit/__tests__/sse-transport.test.js.map +1 -0
  156. package/src/conduit/__tests__/sse-transport.test.ts +344 -0
  157. package/src/conduit/conduit-client.ts +14 -0
  158. package/src/conduit/factory.ts +29 -8
  159. package/src/conduit/http-transport.ts +78 -16
  160. package/src/conduit/index.ts +5 -2
  161. package/src/conduit/local-transport.ts +309 -0
  162. package/src/conduit/sse-transport.ts +382 -0
  163. package/src/crypto/credentials.ts +59 -13
  164. package/src/error-catalog.ts +3 -3
  165. package/src/errors.ts +1 -1
  166. package/src/hooks/__tests__/provider-hooks.test.js +4 -4
  167. package/src/hooks/__tests__/provider-hooks.test.js.map +1 -1
  168. package/src/hooks/__tests__/provider-hooks.test.ts +4 -4
  169. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js +2 -2
  170. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js.map +1 -1
  171. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +6 -4
  172. package/src/hooks/handlers/index.ts +2 -6
  173. package/src/hooks/handlers/notification-hooks.ts +65 -0
  174. package/src/index.ts +2 -1
  175. package/src/init.ts +14 -54
  176. package/src/injection.ts +4 -3
  177. package/src/internal.ts +7 -5
  178. package/src/lib/index.ts +8 -0
  179. package/src/lib/tree-sitter-languages.ts +88 -0
  180. package/src/logger.ts +5 -5
  181. package/src/memory/__tests__/brain-links.test.js +13 -0
  182. package/src/memory/__tests__/brain-links.test.js.map +1 -1
  183. package/src/memory/__tests__/brain-links.test.ts +14 -0
  184. package/src/memory/__tests__/brain-retrieval.test.js +9 -0
  185. package/src/memory/__tests__/brain-retrieval.test.js.map +1 -1
  186. package/src/memory/__tests__/brain-retrieval.test.ts +10 -0
  187. package/src/memory/__tests__/session-memory.test.js +16 -0
  188. package/src/memory/__tests__/session-memory.test.js.map +1 -1
  189. package/src/memory/__tests__/session-memory.test.ts +17 -0
  190. package/src/memory/brain-links.ts +17 -0
  191. package/src/memory/brain-maintenance.ts +33 -1
  192. package/src/memory/brain-retrieval.ts +19 -3
  193. package/src/memory/decisions.ts +18 -2
  194. package/src/memory/engine-compat.ts +392 -25
  195. package/src/memory/index.ts +417 -4
  196. package/src/metrics/token-service.ts +4 -4
  197. package/src/migration/index.ts +1 -1
  198. package/src/orchestration/hierarchy.ts +202 -0
  199. package/src/orchestration/index.ts +1 -0
  200. package/src/paths.ts +340 -5
  201. package/src/routing/capability-matrix.ts +49 -49
  202. package/src/scaffold.ts +428 -70
  203. package/src/security/input-sanitization.ts +4 -4
  204. package/src/sessions/__tests__/session-grade.integration.test.js +9 -9
  205. package/src/sessions/__tests__/session-grade.integration.test.ts +9 -9
  206. package/src/sessions/__tests__/session-grade.test.js +10 -10
  207. package/src/sessions/__tests__/session-grade.test.js.map +1 -1
  208. package/src/sessions/__tests__/session-grade.test.ts +10 -10
  209. package/src/sessions/session-grade.ts +4 -4
  210. package/src/skills/__tests__/dynamic-skill-generator.test.js +24 -26
  211. package/src/skills/__tests__/dynamic-skill-generator.test.js.map +1 -1
  212. package/src/skills/__tests__/dynamic-skill-generator.test.ts +24 -26
  213. package/src/skills/__tests__/routing-table.test.js +22 -22
  214. package/src/skills/__tests__/routing-table.test.js.map +1 -1
  215. package/src/skills/__tests__/routing-table.test.ts +23 -23
  216. package/src/skills/dynamic-skill-generator.ts +13 -24
  217. package/src/skills/routing-table.ts +4 -4
  218. package/src/store/__tests__/data-safety-central.test.js +8 -0
  219. package/src/store/__tests__/data-safety-central.test.js.map +1 -1
  220. package/src/store/__tests__/data-safety-central.test.ts +8 -0
  221. package/src/store/__tests__/safety-accessor.test.js +8 -0
  222. package/src/store/__tests__/safety-accessor.test.js.map +1 -1
  223. package/src/store/__tests__/safety-accessor.test.ts +8 -0
  224. package/src/store/agent-registry-accessor.ts +284 -108
  225. package/src/store/cross-db-cleanup.ts +175 -1
  226. package/src/store/provider.ts +2 -2
  227. package/src/store/signaldock-sqlite.ts +262 -60
  228. package/src/store/sqlite-data-accessor.ts +3 -0
  229. package/src/store/sqlite.ts +2 -2
  230. package/src/store/task-store.ts +8 -1
  231. package/src/store/tasks-schema.ts +5 -40
  232. package/src/system/__tests__/health.test.js +2 -2
  233. package/src/system/__tests__/health.test.js.map +1 -1
  234. package/src/system/__tests__/health.test.ts +2 -2
  235. package/src/system/archive-analytics.ts +1 -1
  236. package/src/system/health.ts +43 -19
  237. package/src/system/inject-generate.ts +20 -20
  238. package/src/system/runtime.ts +5 -4
  239. package/src/tasks/atomicity.ts +1 -1
  240. package/src/tasks/list.ts +1 -1
  241. package/src/tasks/task-ops.ts +415 -3
  242. package/src/templates/parser.ts +1 -1
  243. package/src/ui/index.ts +4 -4
  244. package/src/upgrade.ts +3 -14
  245. package/src/validation/operation-gate-validators.ts +1 -1
  246. package/src/validation/operation-verification-gates.ts +3 -3
  247. package/src/validation/param-utils.ts +11 -10
  248. package/src/validation/validate-ops.ts +6 -6
  249. package/templates/CLEO-INJECTION.md +38 -110
  250. package/dist/hooks/handlers/mcp-hooks.d.ts +0 -48
  251. package/dist/hooks/handlers/mcp-hooks.d.ts.map +0 -1
  252. package/dist/mcp/index.d.ts +0 -42
  253. package/dist/mcp/index.d.ts.map +0 -1
  254. package/src/__tests__/audit-prune.test.d.ts +0 -2
  255. package/src/__tests__/caamp-skill-install.test.d.ts +0 -14
  256. package/src/__tests__/cli-mcp-parity.integration.test.d.ts +0 -34
  257. package/src/__tests__/cli-mcp-parity.integration.test.d.ts.map +0 -1
  258. package/src/__tests__/cli-mcp-parity.integration.test.js +0 -898
  259. package/src/__tests__/cli-mcp-parity.integration.test.js.map +0 -1
  260. package/src/__tests__/cli-parity.test.d.ts +0 -9
  261. package/src/__tests__/config.test.d.ts +0 -7
  262. package/src/__tests__/core-parity.test.d.ts +0 -17
  263. package/src/__tests__/error-catalog.test.d.ts +0 -2
  264. package/src/__tests__/golden-parity.test.d.ts +0 -12
  265. package/src/__tests__/hooks.test.d.ts +0 -5
  266. package/src/__tests__/human-output.test.d.ts +0 -12
  267. package/src/__tests__/index-api-compat.test.d.ts +0 -2
  268. package/src/__tests__/init-e2e.test.d.ts +0 -12
  269. package/src/__tests__/injection-chain.test.d.ts +0 -18
  270. package/src/__tests__/injection-mvi-tiers.test.d.ts +0 -14
  271. package/src/__tests__/injection-shared.test.d.ts +0 -10
  272. package/src/__tests__/lafs-conformance.test.d.ts +0 -18
  273. package/src/__tests__/logger.test.d.ts +0 -2
  274. package/src/__tests__/mcp-install-verify.test.d.ts +0 -13
  275. package/src/__tests__/mcp-install-verify.test.d.ts.map +0 -1
  276. package/src/__tests__/mcp-install-verify.test.js +0 -177
  277. package/src/__tests__/mcp-install-verify.test.js.map +0 -1
  278. package/src/__tests__/mcp-install-verify.test.ts +0 -217
  279. package/src/__tests__/paths.test.d.ts +0 -7
  280. package/src/__tests__/project-info.test.d.ts +0 -2
  281. package/src/__tests__/rcsd-pipeline-e2e.test.d.ts +0 -14
  282. package/src/__tests__/remote.test.d.ts +0 -6
  283. package/src/__tests__/scaffold.test.d.ts +0 -6
  284. package/src/__tests__/schema-management.test.d.ts +0 -5
  285. package/src/__tests__/schema.test.d.ts +0 -2
  286. package/src/__tests__/sharing.test.d.ts +0 -6
  287. package/src/__tests__/snapshot.test.d.ts +0 -6
  288. package/src/__tests__/upgrade.test.d.ts +0 -7
  289. package/src/adapters/__tests__/discovery.test.d.ts +0 -6
  290. package/src/adapters/__tests__/manager.test.d.ts +0 -6
  291. package/src/agents/__tests__/agent-registry.test.d.ts +0 -12
  292. package/src/agents/__tests__/capacity.test.d.ts +0 -7
  293. package/src/agents/__tests__/execution-learning.test.d.ts +0 -14
  294. package/src/agents/__tests__/health-monitor.test.d.ts +0 -10
  295. package/src/agents/__tests__/registry.test.d.ts +0 -8
  296. package/src/agents/__tests__/retry.test.d.ts +0 -7
  297. package/src/compliance/__tests__/sync.test.d.ts +0 -5
  298. package/src/hooks/__tests__/provider-hooks.test.d.ts +0 -2
  299. package/src/hooks/__tests__/registry.test.d.ts +0 -2
  300. package/src/hooks/handlers/__tests__/error-hooks.test.d.ts +0 -2
  301. package/src/hooks/handlers/__tests__/file-hooks.test.d.ts +0 -2
  302. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.d.ts +0 -13
  303. package/src/hooks/handlers/__tests__/mcp-hooks.test.d.ts +0 -2
  304. package/src/hooks/handlers/__tests__/mcp-hooks.test.d.ts.map +0 -1
  305. package/src/hooks/handlers/__tests__/mcp-hooks.test.js +0 -119
  306. package/src/hooks/handlers/__tests__/mcp-hooks.test.js.map +0 -1
  307. package/src/hooks/handlers/__tests__/mcp-hooks.test.ts +0 -150
  308. package/src/hooks/handlers/__tests__/session-hooks.test.d.ts +0 -2
  309. package/src/hooks/handlers/__tests__/task-hooks.test.d.ts +0 -2
  310. package/src/hooks/handlers/mcp-hooks.ts +0 -162
  311. package/src/intelligence/__tests__/adaptive-validation.test.d.ts +0 -11
  312. package/src/intelligence/__tests__/impact.test.d.ts +0 -16
  313. package/src/intelligence/__tests__/patterns.test.d.ts +0 -8
  314. package/src/intelligence/__tests__/prediction.test.d.ts +0 -8
  315. package/src/lib/__tests__/retry.test.d.ts +0 -7
  316. package/src/lifecycle/__tests__/chain-store.test.d.ts +0 -10
  317. package/src/lifecycle/__tests__/consolidate-rcasd.test.d.ts +0 -7
  318. package/src/lifecycle/__tests__/default-chain.test.d.ts +0 -7
  319. package/src/lifecycle/__tests__/frontmatter.test.d.ts +0 -7
  320. package/src/lifecycle/__tests__/lifecycle.test.d.ts +0 -7
  321. package/src/lifecycle/__tests__/pipeline.integration.test.d.ts +0 -19
  322. package/src/lifecycle/__tests__/rcasd-paths.test.d.ts +0 -7
  323. package/src/lifecycle/__tests__/resume-schema-contract.test.d.ts +0 -16
  324. package/src/lifecycle/__tests__/stage-record-provenance.integration.test.d.ts +0 -7
  325. package/src/lifecycle/__tests__/tessera-engine.test.d.ts +0 -10
  326. package/src/mcp/index.ts +0 -163
  327. package/src/memory/__tests__/auto-extract.test.d.ts +0 -7
  328. package/src/memory/__tests__/brain-automation.test.d.ts +0 -11
  329. package/src/memory/__tests__/brain-embedding.test.d.ts +0 -2
  330. package/src/memory/__tests__/brain-links.test.d.ts +0 -8
  331. package/src/memory/__tests__/brain-migration.test.d.ts +0 -8
  332. package/src/memory/__tests__/brain-retrieval.test.d.ts +0 -10
  333. package/src/memory/__tests__/brain-search.test.d.ts +0 -8
  334. package/src/memory/__tests__/claude-mem-migration.test.d.ts +0 -12
  335. package/src/memory/__tests__/decisions.test.d.ts +0 -8
  336. package/src/memory/__tests__/engine-compat.test.d.ts +0 -12
  337. package/src/memory/__tests__/memory-bridge.test.d.ts +0 -10
  338. package/src/memory/__tests__/pipeline-manifest-sqlite.test.d.ts +0 -13
  339. package/src/memory/__tests__/session-memory.test.d.ts +0 -9
  340. package/src/metrics/__tests__/model-provider-registry.test.d.ts +0 -2
  341. package/src/metrics/__tests__/provider-detection.test.d.ts +0 -2
  342. package/src/migration/__tests__/checksum.test.d.ts +0 -8
  343. package/src/migration/__tests__/logger.test.d.ts +0 -5
  344. package/src/migration/__tests__/migration-failure.integration.test.d.ts +0 -15
  345. package/src/migration/__tests__/migration.test.d.ts +0 -13
  346. package/src/migration/__tests__/state.test.d.ts +0 -8
  347. package/src/migration/__tests__/validate.test.d.ts +0 -8
  348. package/src/nexus/__tests__/deps.test.d.ts +0 -7
  349. package/src/nexus/__tests__/nexus-e2e.test.d.ts +0 -12
  350. package/src/nexus/__tests__/permissions.test.d.ts +0 -7
  351. package/src/nexus/__tests__/query.test.d.ts +0 -7
  352. package/src/nexus/__tests__/reconcile.test.d.ts +0 -7
  353. package/src/nexus/__tests__/registry.test.d.ts +0 -7
  354. package/src/nexus/__tests__/transfer.test.d.ts +0 -8
  355. package/src/observability/__tests__/index.test.d.ts +0 -7
  356. package/src/observability/__tests__/log-filter.test.d.ts +0 -7
  357. package/src/observability/__tests__/log-parser.test.d.ts +0 -7
  358. package/src/observability/__tests__/log-reader.test.d.ts +0 -7
  359. package/src/orchestration/__tests__/autonomous-spec.test.d.ts +0 -9
  360. package/src/orchestration/__tests__/orchestration.test.d.ts +0 -7
  361. package/src/orchestration/__tests__/protocol-validators.test.d.ts +0 -9
  362. package/src/phases/__tests__/deps.test.d.ts +0 -7
  363. package/src/phases/__tests__/phases.test.d.ts +0 -7
  364. package/src/release/__tests__/artifacts.test.d.ts +0 -7
  365. package/src/release/__tests__/cancel-release.test.d.ts +0 -10
  366. package/src/release/__tests__/changelog-writer.test.d.ts +0 -6
  367. package/src/release/__tests__/push-policy.test.d.ts +0 -14
  368. package/src/release/__tests__/release.test.d.ts +0 -11
  369. package/src/sequence/__tests__/allocate.test.d.ts +0 -6
  370. package/src/sessions/__tests__/briefing-blocked.test.d.ts +0 -6
  371. package/src/sessions/__tests__/briefing.test.d.ts +0 -11
  372. package/src/sessions/__tests__/handoff-integration.test.d.ts +0 -8
  373. package/src/sessions/__tests__/handoff.test.d.ts +0 -11
  374. package/src/sessions/__tests__/index.test.d.ts +0 -2
  375. package/src/sessions/__tests__/session-cleanup.test.d.ts +0 -7
  376. package/src/sessions/__tests__/session-edge-cases.test.d.ts +0 -9
  377. package/src/sessions/__tests__/session-find.test.d.ts +0 -9
  378. package/src/sessions/__tests__/session-grade.integration.test.d.ts +0 -11
  379. package/src/sessions/__tests__/session-grade.test.d.ts +0 -6
  380. package/src/sessions/__tests__/session-memory-bridge.test.d.ts +0 -2
  381. package/src/sessions/__tests__/sessions.test.d.ts +0 -7
  382. package/src/skills/__tests__/discovery.test.d.ts +0 -6
  383. package/src/skills/__tests__/dispatch.test.d.ts +0 -6
  384. package/src/skills/__tests__/dynamic-skill-generator.test.d.ts +0 -2
  385. package/src/skills/__tests__/manifests.test.d.ts +0 -6
  386. package/src/skills/__tests__/precedence.test.d.ts +0 -6
  387. package/src/skills/__tests__/routing-table.test.d.ts +0 -2
  388. package/src/skills/__tests__/skill-paths.test.d.ts +0 -7
  389. package/src/skills/__tests__/test-utility.test.d.ts +0 -7
  390. package/src/skills/__tests__/token.test.d.ts +0 -6
  391. package/src/skills/__tests__/validation.test.d.ts +0 -6
  392. package/src/skills/__tests__/version.test.d.ts +0 -5
  393. package/src/skills/injection/__tests__/subagent.test.d.ts +0 -2
  394. package/src/skills/orchestrator/__tests__/spawn-tier.test.d.ts +0 -2
  395. package/src/spawn/__tests__/adapter-registry.test.d.ts +0 -2
  396. package/src/stats/__tests__/stats.test.d.ts +0 -7
  397. package/src/sticky/__tests__/purge.test.d.ts +0 -9
  398. package/src/store/__tests__/atomic.test.d.ts +0 -7
  399. package/src/store/__tests__/backup.test.d.ts +0 -7
  400. package/src/store/__tests__/brain-accessor-pageindex.test.d.ts +0 -12
  401. package/src/store/__tests__/brain-accessor.test.d.ts +0 -10
  402. package/src/store/__tests__/brain-pageindex.test.d.ts +0 -11
  403. package/src/store/__tests__/brain-schema.test.d.ts +0 -11
  404. package/src/store/__tests__/brain-vec.test.d.ts +0 -11
  405. package/src/store/__tests__/collision-detection.test.d.ts +0 -11
  406. package/src/store/__tests__/data-safety-central.test.d.ts +0 -20
  407. package/src/store/__tests__/db-helpers.test.d.ts +0 -7
  408. package/src/store/__tests__/e2e-safety-integration.test.d.ts +0 -13
  409. package/src/store/__tests__/git-checkpoint.test.d.ts +0 -7
  410. package/src/store/__tests__/idempotent-migration.test.d.ts +0 -5
  411. package/src/store/__tests__/import-logging.test.d.ts +0 -7
  412. package/src/store/__tests__/import-sort.test.d.ts +0 -7
  413. package/src/store/__tests__/json.test.d.ts +0 -7
  414. package/src/store/__tests__/lifecycle-schema-parity.test.d.ts +0 -2
  415. package/src/store/__tests__/migration-integration.test.d.ts +0 -15
  416. package/src/store/__tests__/migration-retry.test.d.ts +0 -10
  417. package/src/store/__tests__/migration-safety.test.d.ts +0 -21
  418. package/src/store/__tests__/migration-sqlite.test.d.ts +0 -11
  419. package/src/store/__tests__/performance-safety.test.d.ts +0 -17
  420. package/src/store/__tests__/project-detect.test.d.ts +0 -6
  421. package/src/store/__tests__/project-registry.test.d.ts +0 -7
  422. package/src/store/__tests__/provider.test.d.ts +0 -9
  423. package/src/store/__tests__/relations.test.d.ts +0 -9
  424. package/src/store/__tests__/safety-accessor.test.d.ts +0 -18
  425. package/src/store/__tests__/sequence-validation.test.d.ts +0 -11
  426. package/src/store/__tests__/session-store.test.d.ts +0 -11
  427. package/src/store/__tests__/sqlite-backup.test.d.ts +0 -14
  428. package/src/store/__tests__/sqlite.test.d.ts +0 -11
  429. package/src/store/__tests__/task-store.test.d.ts +0 -11
  430. package/src/store/__tests__/test-db-helper.d.ts +0 -61
  431. package/src/store/__tests__/write-verification.test.d.ts +0 -11
  432. package/src/system/__tests__/cleanup.test.d.ts +0 -2
  433. package/src/system/__tests__/health.test.d.ts +0 -2
  434. package/src/task-work/__tests__/start-deps.test.d.ts +0 -6
  435. package/src/tasks/__tests__/add.test.d.ts +0 -7
  436. package/src/tasks/__tests__/archive.test.d.ts +0 -7
  437. package/src/tasks/__tests__/assignee.test.d.ts +0 -14
  438. package/src/tasks/__tests__/atomicity.test.d.ts +0 -6
  439. package/src/tasks/__tests__/cancel-ops.test.d.ts +0 -7
  440. package/src/tasks/__tests__/complete-unblocks.test.d.ts +0 -6
  441. package/src/tasks/__tests__/complete.test.d.ts +0 -7
  442. package/src/tasks/__tests__/delete.test.d.ts +0 -7
  443. package/src/tasks/__tests__/dependency-check.test.d.ts +0 -7
  444. package/src/tasks/__tests__/deps-ready.test.d.ts +0 -6
  445. package/src/tasks/__tests__/epic-enforcement.test.d.ts +0 -15
  446. package/src/tasks/__tests__/find.test.d.ts +0 -7
  447. package/src/tasks/__tests__/graph-ops.test.d.ts +0 -7
  448. package/src/tasks/__tests__/hierarchy-policy.test.d.ts +0 -6
  449. package/src/tasks/__tests__/hierarchy.test.d.ts +0 -7
  450. package/src/tasks/__tests__/id-generator.test.d.ts +0 -2
  451. package/src/tasks/__tests__/labels.test.d.ts +0 -7
  452. package/src/tasks/__tests__/list.test.d.ts +0 -7
  453. package/src/tasks/__tests__/minimal-test.test.d.ts +0 -2
  454. package/src/tasks/__tests__/phase-tracking.test.d.ts +0 -7
  455. package/src/tasks/__tests__/pipeline-stage.test.d.ts +0 -14
  456. package/src/tasks/__tests__/plan-priority.test.d.ts +0 -10
  457. package/src/tasks/__tests__/priority-normalization.test.d.ts +0 -7
  458. package/src/tasks/__tests__/relates.test.d.ts +0 -9
  459. package/src/tasks/__tests__/show-deps.test.d.ts +0 -6
  460. package/src/tasks/__tests__/show.test.d.ts +0 -7
  461. package/src/tasks/__tests__/staleness.test.d.ts +0 -7
  462. package/src/tasks/__tests__/task-ops-depends.test.d.ts +0 -6
  463. package/src/tasks/__tests__/update.test.d.ts +0 -7
  464. package/src/validation/__tests__/chain-validation.test.d.ts +0 -7
  465. package/src/validation/__tests__/compliance.test.d.ts +0 -7
  466. package/src/validation/__tests__/docs-sync.test.d.ts +0 -7
  467. package/src/validation/__tests__/doctor-gitignore.test.d.ts +0 -7
  468. package/src/validation/__tests__/doctor-injection.test.d.ts +0 -11
  469. package/src/validation/__tests__/doctor.test.d.ts +0 -7
  470. package/src/validation/__tests__/engine.test.d.ts +0 -7
  471. package/src/validation/__tests__/manifest.test.d.ts +0 -7
  472. package/src/validation/__tests__/protocol-common.test.d.ts +0 -7
  473. package/src/validation/__tests__/verification.test.d.ts +0 -7
@@ -25,19 +25,23 @@ export class ConduitClient implements Conduit {
25
25
  private credential: AgentCredential;
26
26
  private state: ConduitState = 'disconnected';
27
27
 
28
+ /** Create a ConduitClient backed by the given transport and credential. */
28
29
  constructor(transport: Transport, credential: AgentCredential) {
29
30
  this.transport = transport;
30
31
  this.credential = credential;
31
32
  }
32
33
 
34
+ /** The agent ID from the bound credential. */
33
35
  get agentId(): string {
34
36
  return this.credential.agentId;
35
37
  }
36
38
 
39
+ /** Current connection state (disconnected → connecting → connected | error). */
37
40
  getState(): ConduitState {
38
41
  return this.state;
39
42
  }
40
43
 
44
+ /** Connect the underlying transport using the bound credential. */
41
45
  async connect(): Promise<void> {
42
46
  this.state = 'connecting';
43
47
  try {
@@ -55,6 +59,7 @@ export class ConduitClient implements Conduit {
55
59
  }
56
60
  }
57
61
 
62
+ /** Send a message to another agent, optionally within a thread. */
58
63
  async send(
59
64
  to: string,
60
65
  content: string,
@@ -69,6 +74,12 @@ export class ConduitClient implements Conduit {
69
74
  };
70
75
  }
71
76
 
77
+ /** One-shot poll for new messages. Delegates to the transport's poll method. */
78
+ async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
79
+ return this.transport.poll(options);
80
+ }
81
+
82
+ /** Subscribe to incoming messages. Uses real-time transport when available, else polls. */
72
83
  onMessage(handler: (message: ConduitMessage) => void): ConduitUnsubscribe {
73
84
  // Prefer real-time subscription if transport supports it
74
85
  if (this.transport.subscribe) {
@@ -85,11 +96,13 @@ export class ConduitClient implements Conduit {
85
96
  return () => clearInterval(interval);
86
97
  }
87
98
 
99
+ /** Send an empty heartbeat to maintain presence on the relay. */
88
100
  async heartbeat(): Promise<void> {
89
101
  // Send empty heartbeat via transport
90
102
  await this.transport.push(this.credential.agentId, '', {});
91
103
  }
92
104
 
105
+ /** Check whether a remote agent is currently online via the cloud API. */
93
106
  async isOnline(agentId: string): Promise<boolean> {
94
107
  // Delegate to cloud API check — stub for now
95
108
  try {
@@ -107,6 +120,7 @@ export class ConduitClient implements Conduit {
107
120
  }
108
121
  }
109
122
 
123
+ /** Disconnect the transport and reset state to disconnected. */
110
124
  async disconnect(): Promise<void> {
111
125
  await this.transport.disconnect();
112
126
  this.state = 'disconnected';
@@ -11,17 +11,38 @@
11
11
  import type { AgentCredential, AgentRegistryAPI, Conduit, Transport } from '@cleocode/contracts';
12
12
  import { ConduitClient } from './conduit-client.js';
13
13
  import { HttpTransport } from './http-transport.js';
14
+ import { LocalTransport } from './local-transport.js';
15
+ import { SseTransport } from './sse-transport.js';
14
16
 
15
- /** Resolve the best available transport for a credential. */
16
- function resolveTransport(credential: AgentCredential): Transport {
17
- // Priority: Local (napi-rs) > WebSocket > SSE > HTTP polling
18
- // LocalTransport and SseTransport are future stubs not yet implemented
19
- if (credential.transportConfig.wsUrl) {
20
- // WsTransport stub fall through to HTTP for now
17
+ /**
18
+ * Resolve the best available transport for a credential.
19
+ *
20
+ * Cloud-backed agents (apiBaseUrl is a remote URL) use HttpTransport
21
+ * so they can receive messages from the SignalDock cloud relay.
22
+ * LocalTransport is only used when the agent is explicitly local-only
23
+ * (apiBaseUrl is 'local' or absent), since local signaldock.db doesn't
24
+ * sync with the cloud.
25
+ */
26
+ export function resolveTransport(credential: AgentCredential): Transport {
27
+ const isCloudBacked =
28
+ credential.apiBaseUrl &&
29
+ credential.apiBaseUrl !== 'local' &&
30
+ credential.apiBaseUrl.startsWith('http');
31
+
32
+ // Cloud-backed agents must use network transports to receive cloud messages
33
+ if (isCloudBacked) {
34
+ if (credential.transportConfig.sseEndpoint) {
35
+ return new SseTransport();
36
+ }
37
+ return new HttpTransport();
21
38
  }
22
- if (credential.transportConfig.sseEndpoint) {
23
- // SseTransport stub fall through to HTTP for now
39
+
40
+ // Local-only agents use LocalTransport when signaldock.db is available
41
+ if (LocalTransport.isAvailable()) {
42
+ return new LocalTransport();
24
43
  }
44
+
45
+ // Fallback to HTTP
25
46
  return new HttpTransport();
26
47
  }
27
48
 
@@ -1,9 +1,10 @@
1
1
  /**
2
- * HttpTransport — HTTP polling transport to cloud SignalDock API.
2
+ * HttpTransport — HTTP polling transport with automatic failover.
3
3
  *
4
- * Implements the Transport interface using HTTP requests to the SignalDock
5
- * (api.signaldock.io) REST API. This is the default transport for
6
- * cloud-connected agents.
4
+ * Tries the primary API URL (api.signaldock.io) first. If unreachable,
5
+ * falls back to the legacy URL (api.clawmsgr.com). Failover is transparent
6
+ * to callers — they see a single transport that always works if either
7
+ * endpoint is up.
7
8
  *
8
9
  * @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 4.4
9
10
  * @task T177
@@ -15,28 +16,52 @@ import type { ConduitMessage, Transport, TransportConnectConfig } from '@cleocod
15
16
  interface HttpTransportState {
16
17
  agentId: string;
17
18
  apiKey: string;
18
- apiBaseUrl: string;
19
+ primaryUrl: string;
20
+ fallbackUrl: string | null;
21
+ activeUrl: string;
19
22
  connected: boolean;
20
23
  }
21
24
 
22
- /** HTTP polling transport to cloud SignalDock API. */
25
+ /** HTTP transport with automatic primary/fallback failover. */
23
26
  export class HttpTransport implements Transport {
24
27
  readonly name = 'http';
25
28
  private state: HttpTransportState | null = null;
26
29
 
30
+ /** Connect to the SignalDock API, probing primary/fallback health when both are configured. */
27
31
  async connect(config: TransportConnectConfig): Promise<void> {
32
+ const primaryUrl = config.apiBaseUrl;
33
+ const fallbackUrl = config.apiBaseUrlFallback ?? null;
34
+
35
+ // Only probe health when there's a fallback to choose between
36
+ let activeUrl = primaryUrl;
37
+ if (fallbackUrl) {
38
+ const [primaryResult, fallbackResult] = await Promise.allSettled([
39
+ fetch(`${primaryUrl}/health`, { method: 'GET', signal: AbortSignal.timeout(5000) }),
40
+ fetch(`${fallbackUrl}/health`, { method: 'GET', signal: AbortSignal.timeout(5000) }),
41
+ ]);
42
+ const primaryOk = primaryResult.status === 'fulfilled' && primaryResult.value.ok;
43
+ const fallbackOk = fallbackResult.status === 'fulfilled' && fallbackResult.value.ok;
44
+ if (!primaryOk && fallbackOk) {
45
+ activeUrl = fallbackUrl;
46
+ }
47
+ }
48
+
28
49
  this.state = {
29
50
  agentId: config.agentId,
30
51
  apiKey: config.apiKey,
31
- apiBaseUrl: config.apiBaseUrl,
52
+ primaryUrl,
53
+ fallbackUrl,
54
+ activeUrl,
32
55
  connected: true,
33
56
  };
34
57
  }
35
58
 
59
+ /** Disconnect and clear connection state. */
36
60
  async disconnect(): Promise<void> {
37
61
  this.state = null;
38
62
  }
39
63
 
64
+ /** Send a message to an agent (direct or within a conversation thread). */
40
65
  async push(
41
66
  to: string,
42
67
  content: string,
@@ -46,18 +71,18 @@ export class HttpTransport implements Transport {
46
71
 
47
72
  const body: Record<string, string> = { content };
48
73
 
49
- let url: string;
74
+ let path: string;
50
75
  if (options?.conversationId) {
51
- url = `${this.state!.apiBaseUrl}/conversations/${options.conversationId}/messages`;
76
+ path = `/conversations/${options.conversationId}/messages`;
52
77
  if (options.replyTo) {
53
78
  body['replyTo'] = options.replyTo;
54
79
  }
55
80
  } else {
56
- url = `${this.state!.apiBaseUrl}/messages`;
81
+ path = '/messages';
57
82
  body['toAgentId'] = to;
58
83
  }
59
84
 
60
- const response = await fetch(url, {
85
+ const response = await this.fetchWithFallback(path, {
61
86
  method: 'POST',
62
87
  headers: this.headers(),
63
88
  body: JSON.stringify(body),
@@ -76,17 +101,17 @@ export class HttpTransport implements Transport {
76
101
  return { messageId };
77
102
  }
78
103
 
104
+ /** Poll for new messages for this agent. Returns empty array on HTTP error. */
79
105
  async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
80
106
  this.ensureConnected();
81
107
 
82
108
  const params = new URLSearchParams();
83
- params.set('mentioned', this.state!.agentId);
109
+ // Don't filter by mentioned — the API already scopes by X-Agent-Id header.
110
+ // Using mentioned= misses messages sent TO this agent without @-mentions.
84
111
  if (options?.limit) params.set('limit', String(options.limit));
85
- // H5 fix: pass since param to avoid reprocessing old messages
86
112
  if (options?.since) params.set('since', options.since);
87
113
 
88
- const url = `${this.state!.apiBaseUrl}/messages/peek?${params}`;
89
- const response = await fetch(url, {
114
+ const response = await this.fetchWithFallback(`/messages/peek?${params}`, {
90
115
  method: 'GET',
91
116
  headers: this.headers(),
92
117
  });
@@ -114,16 +139,53 @@ export class HttpTransport implements Transport {
114
139
  }));
115
140
  }
116
141
 
142
+ /** Acknowledge messages by ID so they are not returned by future polls. */
117
143
  async ack(messageIds: string[]): Promise<void> {
118
144
  this.ensureConnected();
119
145
 
120
- await fetch(`${this.state!.apiBaseUrl}/messages/ack`, {
146
+ await this.fetchWithFallback('/messages/ack', {
121
147
  method: 'POST',
122
148
  headers: this.headers(),
123
149
  body: JSON.stringify({ messageIds }),
124
150
  });
125
151
  }
126
152
 
153
+ /**
154
+ * Fetch with automatic failover. Tries activeUrl first.
155
+ * If it fails and a fallback exists, retries on the other URL
156
+ * and swaps activeUrl for subsequent calls.
157
+ */
158
+ private async fetchWithFallback(path: string, init: RequestInit): Promise<Response> {
159
+ const timeout = AbortSignal.timeout(10000);
160
+ const signal = init.signal ? AbortSignal.any([init.signal, timeout]) : timeout;
161
+ const url = `${this.state!.activeUrl}${path}`;
162
+
163
+ try {
164
+ return await fetch(url, { ...init, signal });
165
+ } catch (primaryErr) {
166
+ const otherUrl =
167
+ this.state!.activeUrl === this.state!.primaryUrl
168
+ ? this.state!.fallbackUrl
169
+ : this.state!.primaryUrl;
170
+
171
+ if (!otherUrl) throw primaryErr;
172
+
173
+ try {
174
+ const fallbackSignal = init.signal
175
+ ? AbortSignal.any([init.signal, AbortSignal.timeout(10000)])
176
+ : AbortSignal.timeout(10000);
177
+ const fallbackResponse = await fetch(`${otherUrl}${path}`, {
178
+ ...init,
179
+ signal: fallbackSignal,
180
+ });
181
+ this.state!.activeUrl = otherUrl;
182
+ return fallbackResponse;
183
+ } catch {
184
+ throw primaryErr;
185
+ }
186
+ }
187
+ }
188
+
127
189
  private headers(): Record<string, string> {
128
190
  return {
129
191
  'Content-Type': 'application/json',
@@ -2,11 +2,14 @@
2
2
  * Conduit — High-level agent messaging for the CLEO ecosystem.
3
3
  *
4
4
  * Exports the ConduitClient (high-level messaging), HttpTransport
5
- * (HTTP polling to cloud), and createConduit factory.
5
+ * (HTTP polling to cloud), LocalTransport (offline SQLite), and
6
+ * createConduit factory.
6
7
  *
7
8
  * @module conduit
8
9
  */
9
10
 
10
11
  export { ConduitClient } from './conduit-client.js';
11
- export { createConduit } from './factory.js';
12
+ export { createConduit, resolveTransport } from './factory.js';
12
13
  export { HttpTransport } from './http-transport.js';
14
+ export { LocalTransport } from './local-transport.js';
15
+ export { SseTransport } from './sse-transport.js';
@@ -0,0 +1,309 @@
1
+ /**
2
+ * LocalTransport — In-process SQLite transport for fully offline agent messaging.
3
+ *
4
+ * Reads and writes messages directly to signaldock.db via node:sqlite.
5
+ * No network calls. Works fully offline. Messages are stored in the
6
+ * same schema that the Rust signaldock-storage crate manages, so both
7
+ * the local CLI and the cloud backend see the same data.
8
+ *
9
+ * Priority: LocalTransport is preferred over HttpTransport when
10
+ * signaldock.db is available (see factory.ts).
11
+ *
12
+ * @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 4.4
13
+ * @task T213
14
+ */
15
+
16
+ import { randomUUID } from 'node:crypto';
17
+ import { existsSync } from 'node:fs';
18
+ import { createRequire } from 'node:module';
19
+ import type { DatabaseSync } from 'node:sqlite';
20
+ import type { ConduitMessage, Transport, TransportConnectConfig } from '@cleocode/contracts';
21
+ import { getSignaldockDbPath } from '../store/signaldock-sqlite.js';
22
+
23
+ const _require = createRequire(import.meta.url);
24
+ const { DatabaseSync: DatabaseSyncClass } = _require('node:sqlite') as {
25
+ DatabaseSync: new (...args: ConstructorParameters<typeof DatabaseSync>) => DatabaseSync;
26
+ };
27
+
28
+ /** Internal state for an active local transport connection. */
29
+ interface LocalTransportState {
30
+ agentId: string;
31
+ db: DatabaseSync;
32
+ dbPath: string;
33
+ subscribers: Set<(message: ConduitMessage) => void>;
34
+ pollTimer: ReturnType<typeof setInterval> | null;
35
+ }
36
+
37
+ /** In-process SQLite transport for fully offline agent messaging. */
38
+ export class LocalTransport implements Transport {
39
+ readonly name = 'local';
40
+ private state: LocalTransportState | null = null;
41
+
42
+ /**
43
+ * Connect to signaldock.db for in-process messaging.
44
+ *
45
+ * Opens the database, sets WAL mode pragmas, and verifies
46
+ * the messages table exists. Throws if signaldock.db is missing
47
+ * or uninitialized (run `cleo init` first).
48
+ */
49
+ async connect(config: TransportConnectConfig): Promise<void> {
50
+ const dbPath = getSignaldockDbPath();
51
+
52
+ if (!existsSync(dbPath)) {
53
+ throw new Error(`LocalTransport: signaldock.db not found at ${dbPath}. Run: cleo init`);
54
+ }
55
+
56
+ const db = new DatabaseSyncClass(dbPath);
57
+ db.exec('PRAGMA journal_mode = WAL');
58
+ db.exec('PRAGMA busy_timeout = 5000');
59
+ db.exec('PRAGMA foreign_keys = ON');
60
+
61
+ // Verify the messages table exists
62
+ const hasMessages = db
63
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'")
64
+ .get() as { name: string } | undefined;
65
+
66
+ if (!hasMessages) {
67
+ db.close();
68
+ throw new Error(
69
+ 'LocalTransport: signaldock.db exists but messages table missing. Run: cleo upgrade',
70
+ );
71
+ }
72
+
73
+ this.state = {
74
+ agentId: config.agentId,
75
+ db,
76
+ dbPath,
77
+ subscribers: new Set(),
78
+ pollTimer: null,
79
+ };
80
+ }
81
+
82
+ /** Close the database connection and stop any subscriber polling. */
83
+ async disconnect(): Promise<void> {
84
+ if (!this.state) return;
85
+
86
+ if (this.state.pollTimer) {
87
+ clearInterval(this.state.pollTimer);
88
+ }
89
+ this.state.subscribers.clear();
90
+ this.state.db.close();
91
+ this.state = null;
92
+ }
93
+
94
+ /**
95
+ * Store a message in signaldock.db.
96
+ *
97
+ * Inserts into the messages table with status 'pending'.
98
+ * For conversation messages, also links via conversation_participants
99
+ * if not already present.
100
+ */
101
+ async push(
102
+ to: string,
103
+ content: string,
104
+ options?: { conversationId?: string; replyTo?: string },
105
+ ): Promise<{ messageId: string }> {
106
+ this.ensureConnected();
107
+ const { db, agentId } = this.state!;
108
+ const messageId = randomUUID();
109
+ const nowUnix = Math.floor(Date.now() / 1000);
110
+
111
+ if (options?.conversationId) {
112
+ db.prepare(
113
+ `INSERT INTO messages (id, conversation_id, from_agent_id, to_agent_id, content, content_type, status, created_at)
114
+ VALUES (?, ?, ?, ?, ?, 'text', 'pending', ?)`,
115
+ ).run(messageId, options.conversationId, agentId, to, content, nowUnix);
116
+ } else {
117
+ // Direct message — create or reuse a DM conversation
118
+ const convId = this.ensureDmConversation(agentId, to);
119
+ db.prepare(
120
+ `INSERT INTO messages (id, conversation_id, from_agent_id, to_agent_id, content, content_type, status, created_at)
121
+ VALUES (?, ?, ?, ?, ?, 'text', 'pending', ?)`,
122
+ ).run(messageId, convId, agentId, to, content, nowUnix);
123
+ }
124
+
125
+ // Notify local subscribers
126
+ this.notifySubscribers({
127
+ id: messageId,
128
+ from: agentId,
129
+ content,
130
+ threadId: options?.conversationId,
131
+ timestamp: new Date(nowUnix * 1000).toISOString(),
132
+ });
133
+
134
+ return { messageId };
135
+ }
136
+
137
+ /**
138
+ * Poll for messages addressed to this agent.
139
+ *
140
+ * Returns messages with status 'pending' where to_agent_id matches
141
+ * the connected agent. Messages are returned oldest-first.
142
+ */
143
+ async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
144
+ this.ensureConnected();
145
+ const { db, agentId } = this.state!;
146
+ const limit = options?.limit ?? 50;
147
+
148
+ let query: string;
149
+ let params: (string | number)[];
150
+
151
+ if (options?.since) {
152
+ query = `SELECT id, from_agent_id, content, conversation_id, created_at
153
+ FROM messages
154
+ WHERE to_agent_id = ? AND status = 'pending' AND created_at > ?
155
+ ORDER BY created_at ASC
156
+ LIMIT ?`;
157
+ params = [agentId, options.since, limit];
158
+ } else {
159
+ query = `SELECT id, from_agent_id, content, conversation_id, created_at
160
+ FROM messages
161
+ WHERE to_agent_id = ? AND status = 'pending'
162
+ ORDER BY created_at ASC
163
+ LIMIT ?`;
164
+ params = [agentId, limit];
165
+ }
166
+
167
+ const rows = db.prepare(query).all(...params) as Array<{
168
+ id: string;
169
+ from_agent_id: string;
170
+ content: string;
171
+ conversation_id: string | null;
172
+ created_at: number;
173
+ }>;
174
+
175
+ return rows.map((r) => ({
176
+ id: r.id,
177
+ from: r.from_agent_id,
178
+ content: r.content,
179
+ threadId: r.conversation_id ?? undefined,
180
+ timestamp: new Date(r.created_at * 1000).toISOString(),
181
+ }));
182
+ }
183
+
184
+ /**
185
+ * Acknowledge messages by marking them as 'delivered'.
186
+ *
187
+ * Updates the status and delivered_at timestamp for each message ID.
188
+ */
189
+ async ack(messageIds: string[]): Promise<void> {
190
+ this.ensureConnected();
191
+ if (messageIds.length === 0) return;
192
+
193
+ const { db } = this.state!;
194
+ const nowUnix = Math.floor(Date.now() / 1000);
195
+
196
+ const placeholders = messageIds.map(() => '?').join(', ');
197
+ db.prepare(
198
+ `UPDATE messages SET status = 'delivered', delivered_at = ? WHERE id IN (${placeholders})`,
199
+ ).run(nowUnix, ...messageIds);
200
+ }
201
+
202
+ /**
203
+ * Subscribe to real-time local messages.
204
+ *
205
+ * Since this is in-process, subscribers are notified synchronously
206
+ * when push() is called. Additionally, a polling interval checks
207
+ * for messages inserted by other processes (e.g., Rust CLI).
208
+ *
209
+ * @returns Unsubscribe function.
210
+ */
211
+ subscribe(handler: (message: ConduitMessage) => void): () => void {
212
+ this.ensureConnected();
213
+ this.state!.subscribers.add(handler);
214
+
215
+ // Start cross-process polling if not already running
216
+ if (!this.state!.pollTimer && this.state!.subscribers.size === 1) {
217
+ this.state!.pollTimer = setInterval(() => {
218
+ void this.pollAndNotify();
219
+ }, 1000);
220
+ }
221
+
222
+ return () => {
223
+ this.state?.subscribers.delete(handler);
224
+ if (this.state?.subscribers.size === 0 && this.state.pollTimer) {
225
+ clearInterval(this.state.pollTimer);
226
+ this.state.pollTimer = null;
227
+ }
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Check whether signaldock.db is available for local transport.
233
+ *
234
+ * Used by factory.ts to decide whether to use LocalTransport.
235
+ */
236
+ static isAvailable(cwd?: string): boolean {
237
+ const dbPath = getSignaldockDbPath(cwd);
238
+ return existsSync(dbPath);
239
+ }
240
+
241
+ /** Poll for new messages and notify subscribers (cross-process sync). */
242
+ private async pollAndNotify(): Promise<void> {
243
+ if (!this.state || this.state.subscribers.size === 0) return;
244
+
245
+ const messages = await this.poll({ limit: 20 });
246
+ for (const msg of messages) {
247
+ this.notifySubscribers(msg);
248
+ }
249
+ if (messages.length > 0) {
250
+ await this.ack(messages.map((m) => m.id));
251
+ }
252
+ }
253
+
254
+ /** Notify all active subscribers of a new message. */
255
+ private notifySubscribers(message: ConduitMessage): void {
256
+ if (!this.state) return;
257
+ for (const handler of this.state.subscribers) {
258
+ try {
259
+ handler(message);
260
+ } catch {
261
+ // Subscriber errors must not break the transport
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Ensure a DM conversation exists between two agents.
268
+ *
269
+ * Conversations store participants as a comma-separated TEXT field.
270
+ * We search for existing private conversations containing both agents.
271
+ *
272
+ * @returns The conversation ID.
273
+ */
274
+ private ensureDmConversation(fromAgentId: string, toAgentId: string): string {
275
+ const { db } = this.state!;
276
+
277
+ // Participants are stored as comma-separated text, sorted alphabetically
278
+ const sortedParticipants = [fromAgentId, toAgentId].sort().join(',');
279
+
280
+ // Check for existing DM conversation with these exact participants
281
+ const existing = db
282
+ .prepare(
283
+ `SELECT id FROM conversations
284
+ WHERE visibility = 'private' AND participants = ?
285
+ LIMIT 1`,
286
+ )
287
+ .get(sortedParticipants) as { id: string } | undefined;
288
+
289
+ if (existing) return existing.id;
290
+
291
+ // Create new DM conversation
292
+ const convId = randomUUID();
293
+ const nowUnix = Math.floor(Date.now() / 1000);
294
+
295
+ db.prepare(
296
+ `INSERT INTO conversations (id, participants, visibility, message_count, created_at, updated_at)
297
+ VALUES (?, ?, 'private', 0, ?, ?)`,
298
+ ).run(convId, sortedParticipants, nowUnix, nowUnix);
299
+
300
+ return convId;
301
+ }
302
+
303
+ /** Throw if not connected. */
304
+ private ensureConnected(): void {
305
+ if (!this.state) {
306
+ throw new Error('LocalTransport not connected. Call connect() first.');
307
+ }
308
+ }
309
+ }