@cleocode/core 2026.4.9 → 2026.4.12

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 (1011) hide show
  1. package/dist/adapters/adapter-registry.js +64 -0
  2. package/dist/adapters/adapter-registry.js.map +1 -0
  3. package/dist/adapters/discovery.js +83 -0
  4. package/dist/adapters/discovery.js.map +1 -0
  5. package/dist/adapters/index.js +9 -0
  6. package/dist/adapters/index.js.map +1 -0
  7. package/dist/adapters/manager.js +260 -0
  8. package/dist/adapters/manager.js.map +1 -0
  9. package/dist/admin/export-tasks.js +171 -0
  10. package/dist/admin/export-tasks.js.map +1 -0
  11. package/dist/admin/export.js +103 -0
  12. package/dist/admin/export.js.map +1 -0
  13. package/dist/admin/help.js +106 -0
  14. package/dist/admin/help.js.map +1 -0
  15. package/dist/admin/import-tasks.js +182 -0
  16. package/dist/admin/import-tasks.js.map +1 -0
  17. package/dist/admin/import.js +129 -0
  18. package/dist/admin/import.js.map +1 -0
  19. package/dist/admin/index.js +13 -0
  20. package/dist/admin/index.js.map +1 -0
  21. package/dist/adrs/find.js +134 -0
  22. package/dist/adrs/find.js.map +1 -0
  23. package/dist/adrs/index.js +15 -0
  24. package/dist/adrs/index.js.map +1 -0
  25. package/dist/adrs/link-pipeline.js +160 -0
  26. package/dist/adrs/link-pipeline.js.map +1 -0
  27. package/dist/adrs/list.js +43 -0
  28. package/dist/adrs/list.js.map +1 -0
  29. package/dist/adrs/parse.js +51 -0
  30. package/dist/adrs/parse.js.map +1 -0
  31. package/dist/adrs/show.js +22 -0
  32. package/dist/adrs/show.js.map +1 -0
  33. package/dist/adrs/sync.js +188 -0
  34. package/dist/adrs/sync.js.map +1 -0
  35. package/dist/adrs/types.js +9 -0
  36. package/dist/adrs/types.js.map +1 -0
  37. package/dist/adrs/validate.js +57 -0
  38. package/dist/adrs/validate.js.map +1 -0
  39. package/dist/agents/agent-registry.js +288 -0
  40. package/dist/agents/agent-registry.js.map +1 -0
  41. package/dist/agents/agent-schema.d.ts +2 -2
  42. package/dist/agents/agent-schema.js +82 -0
  43. package/dist/agents/agent-schema.js.map +1 -0
  44. package/dist/agents/capacity.js +116 -0
  45. package/dist/agents/capacity.js.map +1 -0
  46. package/dist/agents/execution-learning.js +474 -0
  47. package/dist/agents/execution-learning.js.map +1 -0
  48. package/dist/agents/health-monitor.js +217 -0
  49. package/dist/agents/health-monitor.js.map +1 -0
  50. package/dist/agents/index.js +29 -0
  51. package/dist/agents/index.js.map +1 -0
  52. package/dist/agents/registry.js +314 -0
  53. package/dist/agents/registry.js.map +1 -0
  54. package/dist/agents/retry.js +215 -0
  55. package/dist/agents/retry.js.map +1 -0
  56. package/dist/audit-prune.js +94 -0
  57. package/dist/audit-prune.js.map +1 -0
  58. package/dist/audit.js +68 -0
  59. package/dist/audit.js.map +1 -0
  60. package/dist/backfill/index.js +229 -0
  61. package/dist/backfill/index.js.map +1 -0
  62. package/dist/bootstrap.js +344 -0
  63. package/dist/bootstrap.js.map +1 -0
  64. package/dist/caamp/adapter.js +259 -0
  65. package/dist/caamp/adapter.js.map +1 -0
  66. package/dist/caamp/capability-check.js +38 -0
  67. package/dist/caamp/capability-check.js.map +1 -0
  68. package/dist/caamp/index.js +21 -0
  69. package/dist/caamp/index.js.map +1 -0
  70. package/dist/caamp-init.js +16 -0
  71. package/dist/caamp-init.js.map +1 -0
  72. package/dist/cleo.js +322 -0
  73. package/dist/cleo.js.map +1 -0
  74. package/dist/code/index.js +10 -0
  75. package/dist/code/index.js.map +1 -0
  76. package/dist/code/outline.js +165 -0
  77. package/dist/code/outline.js.map +1 -0
  78. package/dist/code/parser.js +295 -0
  79. package/dist/code/parser.js.map +1 -0
  80. package/dist/code/search.js +135 -0
  81. package/dist/code/search.js.map +1 -0
  82. package/dist/code/unfold.js +155 -0
  83. package/dist/code/unfold.js.map +1 -0
  84. package/dist/codebase-map/analyzers/architecture.d.ts.map +1 -1
  85. package/dist/codebase-map/analyzers/architecture.js +129 -0
  86. package/dist/codebase-map/analyzers/architecture.js.map +1 -0
  87. package/dist/codebase-map/analyzers/concerns.js +122 -0
  88. package/dist/codebase-map/analyzers/concerns.js.map +1 -0
  89. package/dist/codebase-map/analyzers/conventions.js +149 -0
  90. package/dist/codebase-map/analyzers/conventions.js.map +1 -0
  91. package/dist/codebase-map/analyzers/integrations.js +108 -0
  92. package/dist/codebase-map/analyzers/integrations.js.map +1 -0
  93. package/dist/codebase-map/analyzers/stack.js +117 -0
  94. package/dist/codebase-map/analyzers/stack.js.map +1 -0
  95. package/dist/codebase-map/analyzers/structure.js +137 -0
  96. package/dist/codebase-map/analyzers/structure.js.map +1 -0
  97. package/dist/codebase-map/analyzers/testing.js +118 -0
  98. package/dist/codebase-map/analyzers/testing.js.map +1 -0
  99. package/dist/codebase-map/index.js +57 -0
  100. package/dist/codebase-map/index.js.map +1 -0
  101. package/dist/codebase-map/store.js +122 -0
  102. package/dist/codebase-map/store.js.map +1 -0
  103. package/dist/codebase-map/summary.js +152 -0
  104. package/dist/codebase-map/summary.js.map +1 -0
  105. package/dist/compliance/index.js +288 -0
  106. package/dist/compliance/index.js.map +1 -0
  107. package/dist/compliance/protocol-enforcement.js +332 -0
  108. package/dist/compliance/protocol-enforcement.js.map +1 -0
  109. package/dist/compliance/protocol-rules.js +786 -0
  110. package/dist/compliance/protocol-rules.js.map +1 -0
  111. package/dist/compliance/protocol-types.js +79 -0
  112. package/dist/compliance/protocol-types.js.map +1 -0
  113. package/dist/compliance/store.js +53 -0
  114. package/dist/compliance/store.js.map +1 -0
  115. package/dist/conduit/conduit-client.js +107 -0
  116. package/dist/conduit/conduit-client.js.map +1 -0
  117. package/dist/conduit/factory.js +52 -0
  118. package/dist/conduit/factory.js.map +1 -0
  119. package/dist/conduit/http-transport.js +155 -0
  120. package/dist/conduit/http-transport.js.map +1 -0
  121. package/dist/conduit/index.js +15 -0
  122. package/dist/conduit/index.js.map +1 -0
  123. package/dist/conduit/local-transport.d.ts +18 -8
  124. package/dist/conduit/local-transport.d.ts.map +1 -1
  125. package/dist/conduit/local-transport.js +255 -0
  126. package/dist/conduit/local-transport.js.map +1 -0
  127. package/dist/conduit/sse-transport.js +299 -0
  128. package/dist/conduit/sse-transport.js.map +1 -0
  129. package/dist/config/build-config.js +29 -0
  130. package/dist/config/build-config.js.map +1 -0
  131. package/dist/config.d.ts.map +1 -1
  132. package/dist/config.js +400 -0
  133. package/dist/config.js.map +1 -0
  134. package/dist/constants.js +18 -0
  135. package/dist/constants.js.map +1 -0
  136. package/dist/context/index.js +137 -0
  137. package/dist/context/index.js.map +1 -0
  138. package/dist/crypto/credentials.js +191 -0
  139. package/dist/crypto/credentials.js.map +1 -0
  140. package/dist/discovery.js +182 -0
  141. package/dist/discovery.js.map +1 -0
  142. package/dist/engine-result.js +12 -0
  143. package/dist/engine-result.js.map +1 -0
  144. package/dist/error-catalog.js +404 -0
  145. package/dist/error-catalog.js.map +1 -0
  146. package/dist/error-registry.js +393 -0
  147. package/dist/error-registry.js.map +1 -0
  148. package/dist/errors.d.ts +19 -0
  149. package/dist/errors.d.ts.map +1 -1
  150. package/dist/errors.js +173 -0
  151. package/dist/errors.js.map +1 -0
  152. package/dist/hooks/handlers/agent-hooks.js +106 -0
  153. package/dist/hooks/handlers/agent-hooks.js.map +1 -0
  154. package/dist/hooks/handlers/context-hooks.js +111 -0
  155. package/dist/hooks/handlers/context-hooks.js.map +1 -0
  156. package/dist/hooks/handlers/error-hooks.js +52 -0
  157. package/dist/hooks/handlers/error-hooks.js.map +1 -0
  158. package/dist/hooks/handlers/file-hooks.js +104 -0
  159. package/dist/hooks/handlers/file-hooks.js.map +1 -0
  160. package/dist/hooks/handlers/handler-helpers.js +61 -0
  161. package/dist/hooks/handlers/handler-helpers.js.map +1 -0
  162. package/dist/hooks/handlers/index.js +28 -0
  163. package/dist/hooks/handlers/index.js.map +1 -0
  164. package/dist/hooks/handlers/memory-bridge-refresh.js +42 -0
  165. package/dist/hooks/handlers/memory-bridge-refresh.js.map +1 -0
  166. package/dist/hooks/handlers/notification-hooks.js +62 -0
  167. package/dist/hooks/handlers/notification-hooks.js.map +1 -0
  168. package/dist/hooks/handlers/session-hooks.d.ts +21 -0
  169. package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
  170. package/dist/hooks/handlers/session-hooks.js +142 -0
  171. package/dist/hooks/handlers/session-hooks.js.map +1 -0
  172. package/dist/hooks/handlers/task-hooks.js +65 -0
  173. package/dist/hooks/handlers/task-hooks.js.map +1 -0
  174. package/dist/hooks/handlers/work-capture-hooks.js +165 -0
  175. package/dist/hooks/handlers/work-capture-hooks.js.map +1 -0
  176. package/dist/hooks/index.js +13 -0
  177. package/dist/hooks/index.js.map +1 -0
  178. package/dist/hooks/payload-schemas.d.ts +2 -2
  179. package/dist/hooks/payload-schemas.js +220 -0
  180. package/dist/hooks/payload-schemas.js.map +1 -0
  181. package/dist/hooks/provider-hooks.js +66 -0
  182. package/dist/hooks/provider-hooks.js.map +1 -0
  183. package/dist/hooks/registry.js +229 -0
  184. package/dist/hooks/registry.js.map +1 -0
  185. package/dist/hooks/types.js +66 -0
  186. package/dist/hooks/types.js.map +1 -0
  187. package/dist/hooks.js +136 -0
  188. package/dist/hooks.js.map +1 -0
  189. package/dist/index.js +175 -68684
  190. package/dist/index.js.map +1 -7
  191. package/dist/init.d.ts +1 -2
  192. package/dist/init.d.ts.map +1 -1
  193. package/dist/init.js +851 -0
  194. package/dist/init.js.map +1 -0
  195. package/dist/inject/index.js +82 -0
  196. package/dist/inject/index.js.map +1 -0
  197. package/dist/injection.js +343 -0
  198. package/dist/injection.js.map +1 -0
  199. package/dist/intelligence/adaptive-validation.js +497 -0
  200. package/dist/intelligence/adaptive-validation.js.map +1 -0
  201. package/dist/intelligence/impact.js +675 -0
  202. package/dist/intelligence/impact.js.map +1 -0
  203. package/dist/intelligence/index.js +22 -0
  204. package/dist/intelligence/index.js.map +1 -0
  205. package/dist/intelligence/patterns.js +492 -0
  206. package/dist/intelligence/patterns.js.map +1 -0
  207. package/dist/intelligence/prediction.js +499 -0
  208. package/dist/intelligence/prediction.js.map +1 -0
  209. package/dist/intelligence/types.js +13 -0
  210. package/dist/intelligence/types.js.map +1 -0
  211. package/dist/internal.d.ts +15 -5
  212. package/dist/internal.d.ts.map +1 -1
  213. package/dist/internal.js +306 -0
  214. package/dist/internal.js.map +1 -0
  215. package/dist/issue/create.js +121 -0
  216. package/dist/issue/create.js.map +1 -0
  217. package/dist/issue/diagnostics.js +59 -0
  218. package/dist/issue/diagnostics.js.map +1 -0
  219. package/dist/issue/index.js +10 -0
  220. package/dist/issue/index.js.map +1 -0
  221. package/dist/issue/template-parser.js +267 -0
  222. package/dist/issue/template-parser.js.map +1 -0
  223. package/dist/json-schema-validator.js +76 -0
  224. package/dist/json-schema-validator.js.map +1 -0
  225. package/dist/lib/index.js +11 -0
  226. package/dist/lib/index.js.map +1 -0
  227. package/dist/lib/retry.js +152 -0
  228. package/dist/lib/retry.js.map +1 -0
  229. package/dist/lib/tree-sitter-languages.js +71 -0
  230. package/dist/lib/tree-sitter-languages.js.map +1 -0
  231. package/dist/lifecycle/chain-composition.js +152 -0
  232. package/dist/lifecycle/chain-composition.js.map +1 -0
  233. package/dist/lifecycle/chain-store.js +246 -0
  234. package/dist/lifecycle/chain-store.js.map +1 -0
  235. package/dist/lifecycle/consolidate-rcasd.js +352 -0
  236. package/dist/lifecycle/consolidate-rcasd.js.map +1 -0
  237. package/dist/lifecycle/default-chain.js +176 -0
  238. package/dist/lifecycle/default-chain.js.map +1 -0
  239. package/dist/lifecycle/evidence.js +180 -0
  240. package/dist/lifecycle/evidence.js.map +1 -0
  241. package/dist/lifecycle/frontmatter.js +363 -0
  242. package/dist/lifecycle/frontmatter.js.map +1 -0
  243. package/dist/lifecycle/index.js +756 -0
  244. package/dist/lifecycle/index.js.map +1 -0
  245. package/dist/lifecycle/pipeline.js +656 -0
  246. package/dist/lifecycle/pipeline.js.map +1 -0
  247. package/dist/lifecycle/rcasd-index.js +326 -0
  248. package/dist/lifecycle/rcasd-index.js.map +1 -0
  249. package/dist/lifecycle/rcasd-paths.js +220 -0
  250. package/dist/lifecycle/rcasd-paths.js.map +1 -0
  251. package/dist/lifecycle/resume.js +864 -0
  252. package/dist/lifecycle/resume.js.map +1 -0
  253. package/dist/lifecycle/stage-artifacts.js +94 -0
  254. package/dist/lifecycle/stage-artifacts.js.map +1 -0
  255. package/dist/lifecycle/stage-guidance.js +234 -0
  256. package/dist/lifecycle/stage-guidance.js.map +1 -0
  257. package/dist/lifecycle/stages.js +534 -0
  258. package/dist/lifecycle/stages.js.map +1 -0
  259. package/dist/lifecycle/state-machine.js +516 -0
  260. package/dist/lifecycle/state-machine.js.map +1 -0
  261. package/dist/lifecycle/tessera-engine.js +249 -0
  262. package/dist/lifecycle/tessera-engine.js.map +1 -0
  263. package/dist/logger.js +140 -0
  264. package/dist/logger.js.map +1 -0
  265. package/dist/memory/auto-extract.js +177 -0
  266. package/dist/memory/auto-extract.js.map +1 -0
  267. package/dist/memory/brain-embedding.js +66 -0
  268. package/dist/memory/brain-embedding.js.map +1 -0
  269. package/dist/memory/brain-lifecycle.js +298 -0
  270. package/dist/memory/brain-lifecycle.js.map +1 -0
  271. package/dist/memory/brain-links.js +161 -0
  272. package/dist/memory/brain-links.js.map +1 -0
  273. package/dist/memory/brain-maintenance.js +114 -0
  274. package/dist/memory/brain-maintenance.js.map +1 -0
  275. package/dist/memory/brain-migration.js +149 -0
  276. package/dist/memory/brain-migration.js.map +1 -0
  277. package/dist/memory/brain-reasoning.js +215 -0
  278. package/dist/memory/brain-reasoning.js.map +1 -0
  279. package/dist/memory/brain-retrieval.js +542 -0
  280. package/dist/memory/brain-retrieval.js.map +1 -0
  281. package/dist/memory/brain-row-types.js +10 -0
  282. package/dist/memory/brain-row-types.js.map +1 -0
  283. package/dist/memory/brain-search.js +519 -0
  284. package/dist/memory/brain-search.js.map +1 -0
  285. package/dist/memory/brain-similarity.js +145 -0
  286. package/dist/memory/brain-similarity.js.map +1 -0
  287. package/dist/memory/claude-mem-migration.js +277 -0
  288. package/dist/memory/claude-mem-migration.js.map +1 -0
  289. package/dist/memory/decisions.js +162 -0
  290. package/dist/memory/decisions.js.map +1 -0
  291. package/dist/memory/embedding-local.js +97 -0
  292. package/dist/memory/embedding-local.js.map +1 -0
  293. package/dist/memory/embedding-queue.js +271 -0
  294. package/dist/memory/embedding-queue.js.map +1 -0
  295. package/dist/memory/embedding-worker.js +58 -0
  296. package/dist/memory/embedding-worker.js.map +1 -0
  297. package/dist/memory/engine-compat.js +1397 -0
  298. package/dist/memory/engine-compat.js.map +1 -0
  299. package/dist/memory/index.js +1140 -0
  300. package/dist/memory/index.js.map +1 -0
  301. package/dist/memory/learnings.d.ts +2 -2
  302. package/dist/memory/learnings.js +121 -0
  303. package/dist/memory/learnings.js.map +1 -0
  304. package/dist/memory/memory-bridge.js +370 -0
  305. package/dist/memory/memory-bridge.js.map +1 -0
  306. package/dist/memory/patterns.d.ts +4 -4
  307. package/dist/memory/patterns.js +122 -0
  308. package/dist/memory/patterns.js.map +1 -0
  309. package/dist/memory/pipeline-manifest-sqlite.js +975 -0
  310. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -0
  311. package/dist/memory/session-memory.js +331 -0
  312. package/dist/memory/session-memory.js.map +1 -0
  313. package/dist/metrics/ab-test.js +260 -0
  314. package/dist/metrics/ab-test.js.map +1 -0
  315. package/dist/metrics/aggregation.js +363 -0
  316. package/dist/metrics/aggregation.js.map +1 -0
  317. package/dist/metrics/common.js +64 -0
  318. package/dist/metrics/common.js.map +1 -0
  319. package/dist/metrics/enums.js +78 -0
  320. package/dist/metrics/enums.js.map +1 -0
  321. package/dist/metrics/index.js +19 -0
  322. package/dist/metrics/index.js.map +1 -0
  323. package/dist/metrics/model-provider-registry.js +88 -0
  324. package/dist/metrics/model-provider-registry.js.map +1 -0
  325. package/dist/metrics/otel-integration.js +263 -0
  326. package/dist/metrics/otel-integration.js.map +1 -0
  327. package/dist/metrics/provider-detection.js +103 -0
  328. package/dist/metrics/provider-detection.js.map +1 -0
  329. package/dist/metrics/token-estimation.js +253 -0
  330. package/dist/metrics/token-estimation.js.map +1 -0
  331. package/dist/metrics/token-service.js +450 -0
  332. package/dist/metrics/token-service.js.map +1 -0
  333. package/dist/migration/agent-outputs.js +316 -0
  334. package/dist/migration/agent-outputs.js.map +1 -0
  335. package/dist/migration/checksum.js +92 -0
  336. package/dist/migration/checksum.js.map +1 -0
  337. package/dist/migration/index.js +282 -0
  338. package/dist/migration/index.js.map +1 -0
  339. package/dist/migration/logger.js +360 -0
  340. package/dist/migration/logger.js.map +1 -0
  341. package/dist/migration/preflight.js +9 -0
  342. package/dist/migration/preflight.js.map +1 -0
  343. package/dist/migration/state.js +421 -0
  344. package/dist/migration/state.js.map +1 -0
  345. package/dist/migration/validate.js +241 -0
  346. package/dist/migration/validate.js.map +1 -0
  347. package/dist/mvi-helpers.js +74 -0
  348. package/dist/mvi-helpers.js.map +1 -0
  349. package/dist/nexus/deps.js +375 -0
  350. package/dist/nexus/deps.js.map +1 -0
  351. package/dist/nexus/discover.js +288 -0
  352. package/dist/nexus/discover.js.map +1 -0
  353. package/dist/nexus/hash.js +10 -0
  354. package/dist/nexus/hash.js.map +1 -0
  355. package/dist/nexus/index.js +40 -0
  356. package/dist/nexus/index.js.map +1 -0
  357. package/dist/nexus/migrate-json-to-sqlite.js +115 -0
  358. package/dist/nexus/migrate-json-to-sqlite.js.map +1 -0
  359. package/dist/nexus/permissions.js +105 -0
  360. package/dist/nexus/permissions.js.map +1 -0
  361. package/dist/nexus/query.js +175 -0
  362. package/dist/nexus/query.js.map +1 -0
  363. package/dist/nexus/registry.js +584 -0
  364. package/dist/nexus/registry.js.map +1 -0
  365. package/dist/nexus/sharing/index.js +288 -0
  366. package/dist/nexus/sharing/index.js.map +1 -0
  367. package/dist/nexus/transfer-types.js +8 -0
  368. package/dist/nexus/transfer-types.js.map +1 -0
  369. package/dist/nexus/transfer.js +263 -0
  370. package/dist/nexus/transfer.js.map +1 -0
  371. package/dist/nexus/workspace.js +355 -0
  372. package/dist/nexus/workspace.js.map +1 -0
  373. package/dist/observability/index.js +103 -0
  374. package/dist/observability/index.js.map +1 -0
  375. package/dist/observability/log-filter.js +63 -0
  376. package/dist/observability/log-filter.js.map +1 -0
  377. package/dist/observability/log-parser.js +99 -0
  378. package/dist/observability/log-parser.js.map +1 -0
  379. package/dist/observability/log-reader.js +139 -0
  380. package/dist/observability/log-reader.js.map +1 -0
  381. package/dist/observability/types.js +19 -0
  382. package/dist/observability/types.js.map +1 -0
  383. package/dist/orchestration/analyze.js +107 -0
  384. package/dist/orchestration/analyze.js.map +1 -0
  385. package/dist/orchestration/bootstrap.js +132 -0
  386. package/dist/orchestration/bootstrap.js.map +1 -0
  387. package/dist/orchestration/context.js +56 -0
  388. package/dist/orchestration/context.js.map +1 -0
  389. package/dist/orchestration/critical-path.js +100 -0
  390. package/dist/orchestration/critical-path.js.map +1 -0
  391. package/dist/orchestration/hierarchy.js +183 -0
  392. package/dist/orchestration/hierarchy.js.map +1 -0
  393. package/dist/orchestration/index.js +287 -0
  394. package/dist/orchestration/index.js.map +1 -0
  395. package/dist/orchestration/parallel.js +89 -0
  396. package/dist/orchestration/parallel.js.map +1 -0
  397. package/dist/orchestration/protocol-validators.js +815 -0
  398. package/dist/orchestration/protocol-validators.js.map +1 -0
  399. package/dist/orchestration/skill-ops.js +98 -0
  400. package/dist/orchestration/skill-ops.js.map +1 -0
  401. package/dist/orchestration/status.js +107 -0
  402. package/dist/orchestration/status.js.map +1 -0
  403. package/dist/orchestration/unblock.js +103 -0
  404. package/dist/orchestration/unblock.js.map +1 -0
  405. package/dist/orchestration/validate-spawn.js +67 -0
  406. package/dist/orchestration/validate-spawn.js.map +1 -0
  407. package/dist/orchestration/waves.js +86 -0
  408. package/dist/orchestration/waves.js.map +1 -0
  409. package/dist/otel/index.js +163 -0
  410. package/dist/otel/index.js.map +1 -0
  411. package/dist/output.d.ts +32 -11
  412. package/dist/output.d.ts.map +1 -1
  413. package/dist/output.js +164 -0
  414. package/dist/output.js.map +1 -0
  415. package/dist/pagination.js +64 -0
  416. package/dist/pagination.js.map +1 -0
  417. package/dist/paths.d.ts +39 -9
  418. package/dist/paths.d.ts.map +1 -1
  419. package/dist/paths.js +842 -0
  420. package/dist/paths.js.map +1 -0
  421. package/dist/phases/deps.js +372 -0
  422. package/dist/phases/deps.js.map +1 -0
  423. package/dist/phases/index.js +349 -0
  424. package/dist/phases/index.js.map +1 -0
  425. package/dist/pipeline/index.js +10 -0
  426. package/dist/pipeline/index.js.map +1 -0
  427. package/dist/pipeline/phase.js +45 -0
  428. package/dist/pipeline/phase.js.map +1 -0
  429. package/dist/platform.js +211 -0
  430. package/dist/platform.js.map +1 -0
  431. package/dist/project-info.js +84 -0
  432. package/dist/project-info.js.map +1 -0
  433. package/dist/reconciliation/index.js +10 -0
  434. package/dist/reconciliation/index.js.map +1 -0
  435. package/dist/reconciliation/link-store.js +129 -0
  436. package/dist/reconciliation/link-store.js.map +1 -0
  437. package/dist/reconciliation/reconciliation-engine.js +298 -0
  438. package/dist/reconciliation/reconciliation-engine.js.map +1 -0
  439. package/dist/release/artifacts.js +427 -0
  440. package/dist/release/artifacts.js.map +1 -0
  441. package/dist/release/changelog-writer.js +151 -0
  442. package/dist/release/changelog-writer.js.map +1 -0
  443. package/dist/release/channel.js +144 -0
  444. package/dist/release/channel.js.map +1 -0
  445. package/dist/release/ci.js +166 -0
  446. package/dist/release/ci.js.map +1 -0
  447. package/dist/release/github-pr.js +225 -0
  448. package/dist/release/github-pr.js.map +1 -0
  449. package/dist/release/guards.js +116 -0
  450. package/dist/release/guards.js.map +1 -0
  451. package/dist/release/index.js +22 -0
  452. package/dist/release/index.js.map +1 -0
  453. package/dist/release/release-config.js +158 -0
  454. package/dist/release/release-config.js.map +1 -0
  455. package/dist/release/release-manifest.js +1019 -0
  456. package/dist/release/release-manifest.js.map +1 -0
  457. package/dist/release/version-bump.js +255 -0
  458. package/dist/release/version-bump.js.map +1 -0
  459. package/dist/remote/index.js +257 -0
  460. package/dist/remote/index.js.map +1 -0
  461. package/dist/repair.js +130 -0
  462. package/dist/repair.js.map +1 -0
  463. package/dist/research/index.js +2 -0
  464. package/dist/research/index.js.map +1 -0
  465. package/dist/roadmap/index.js +59 -0
  466. package/dist/roadmap/index.js.map +1 -0
  467. package/dist/routing/capability-matrix.js +1556 -0
  468. package/dist/routing/capability-matrix.js.map +1 -0
  469. package/dist/routing/index.js +9 -0
  470. package/dist/routing/index.js.map +1 -0
  471. package/dist/scaffold.d.ts +15 -2
  472. package/dist/scaffold.d.ts.map +1 -1
  473. package/dist/scaffold.js +1759 -0
  474. package/dist/scaffold.js.map +1 -0
  475. package/dist/schema-management.js +295 -0
  476. package/dist/schema-management.js.map +1 -0
  477. package/dist/security/index.js +9 -0
  478. package/dist/security/index.js.map +1 -0
  479. package/dist/security/input-sanitization.js +321 -0
  480. package/dist/security/input-sanitization.js.map +1 -0
  481. package/dist/sequence/index.js +295 -0
  482. package/dist/sequence/index.js.map +1 -0
  483. package/dist/sessions/assumptions.js +54 -0
  484. package/dist/sessions/assumptions.js.map +1 -0
  485. package/dist/sessions/briefing.js +377 -0
  486. package/dist/sessions/briefing.js.map +1 -0
  487. package/dist/sessions/context-alert.js +222 -0
  488. package/dist/sessions/context-alert.js.map +1 -0
  489. package/dist/sessions/context-inject.js +61 -0
  490. package/dist/sessions/context-inject.js.map +1 -0
  491. package/dist/sessions/context-monitor.js +98 -0
  492. package/dist/sessions/context-monitor.js.map +1 -0
  493. package/dist/sessions/decisions.js +65 -0
  494. package/dist/sessions/decisions.js.map +1 -0
  495. package/dist/sessions/find.js +65 -0
  496. package/dist/sessions/find.js.map +1 -0
  497. package/dist/sessions/handoff.js +328 -0
  498. package/dist/sessions/handoff.js.map +1 -0
  499. package/dist/sessions/hitl-warnings.js +254 -0
  500. package/dist/sessions/hitl-warnings.js.map +1 -0
  501. package/dist/sessions/index.js +327 -0
  502. package/dist/sessions/index.js.map +1 -0
  503. package/dist/sessions/session-archive.js +40 -0
  504. package/dist/sessions/session-archive.js.map +1 -0
  505. package/dist/sessions/session-cleanup.js +59 -0
  506. package/dist/sessions/session-cleanup.js.map +1 -0
  507. package/dist/sessions/session-drift.js +134 -0
  508. package/dist/sessions/session-drift.js.map +1 -0
  509. package/dist/sessions/session-enforcement.js +144 -0
  510. package/dist/sessions/session-enforcement.js.map +1 -0
  511. package/dist/sessions/session-grade.js +253 -0
  512. package/dist/sessions/session-grade.js.map +1 -0
  513. package/dist/sessions/session-history.js +42 -0
  514. package/dist/sessions/session-history.js.map +1 -0
  515. package/dist/sessions/session-id.js +81 -0
  516. package/dist/sessions/session-id.js.map +1 -0
  517. package/dist/sessions/session-memory-bridge.js +52 -0
  518. package/dist/sessions/session-memory-bridge.js.map +1 -0
  519. package/dist/sessions/session-show.js +24 -0
  520. package/dist/sessions/session-show.js.map +1 -0
  521. package/dist/sessions/session-stats.js +69 -0
  522. package/dist/sessions/session-stats.js.map +1 -0
  523. package/dist/sessions/session-suspend.js +39 -0
  524. package/dist/sessions/session-suspend.js.map +1 -0
  525. package/dist/sessions/session-switch.js +51 -0
  526. package/dist/sessions/session-switch.js.map +1 -0
  527. package/dist/sessions/session-view.js +76 -0
  528. package/dist/sessions/session-view.js.map +1 -0
  529. package/dist/sessions/snapshot.js +213 -0
  530. package/dist/sessions/snapshot.js.map +1 -0
  531. package/dist/sessions/statusline-setup.js +85 -0
  532. package/dist/sessions/statusline-setup.js.map +1 -0
  533. package/dist/sessions/types.js +8 -0
  534. package/dist/sessions/types.js.map +1 -0
  535. package/dist/skills/agents/config.js +94 -0
  536. package/dist/skills/agents/config.js.map +1 -0
  537. package/dist/skills/agents/install.js +116 -0
  538. package/dist/skills/agents/install.js.map +1 -0
  539. package/dist/skills/agents/registry.js +161 -0
  540. package/dist/skills/agents/registry.js.map +1 -0
  541. package/dist/skills/discovery.js +333 -0
  542. package/dist/skills/discovery.js.map +1 -0
  543. package/dist/skills/dispatch.js +347 -0
  544. package/dist/skills/dispatch.js.map +1 -0
  545. package/dist/skills/dynamic-skill-generator.d.ts +0 -2
  546. package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
  547. package/dist/skills/dynamic-skill-generator.js +87 -0
  548. package/dist/skills/dynamic-skill-generator.js.map +1 -0
  549. package/dist/skills/index.js +44 -0
  550. package/dist/skills/index.js.map +1 -0
  551. package/dist/skills/injection/subagent.js +195 -0
  552. package/dist/skills/injection/subagent.js.map +1 -0
  553. package/dist/skills/injection/token.js +260 -0
  554. package/dist/skills/injection/token.js.map +1 -0
  555. package/dist/skills/install.js +40 -0
  556. package/dist/skills/install.js.map +1 -0
  557. package/dist/skills/manifests/contribution.js +175 -0
  558. package/dist/skills/manifests/contribution.js.map +1 -0
  559. package/dist/skills/manifests/research.js +281 -0
  560. package/dist/skills/manifests/research.js.map +1 -0
  561. package/dist/skills/manifests/resolver.js +146 -0
  562. package/dist/skills/manifests/resolver.js.map +1 -0
  563. package/dist/skills/marketplace.js +90 -0
  564. package/dist/skills/marketplace.js.map +1 -0
  565. package/dist/skills/orchestrator/spawn.js +178 -0
  566. package/dist/skills/orchestrator/spawn.js.map +1 -0
  567. package/dist/skills/orchestrator/startup.js +451 -0
  568. package/dist/skills/orchestrator/startup.js.map +1 -0
  569. package/dist/skills/orchestrator/validator.js +301 -0
  570. package/dist/skills/orchestrator/validator.js.map +1 -0
  571. package/dist/skills/precedence-integration.js +73 -0
  572. package/dist/skills/precedence-integration.js.map +1 -0
  573. package/dist/skills/precedence-types.js +16 -0
  574. package/dist/skills/precedence-types.js.map +1 -0
  575. package/dist/skills/routing-table.js +63 -0
  576. package/dist/skills/routing-table.js.map +1 -0
  577. package/dist/skills/skill-paths.js +217 -0
  578. package/dist/skills/skill-paths.js.map +1 -0
  579. package/dist/skills/test-utility.js +55 -0
  580. package/dist/skills/test-utility.js.map +1 -0
  581. package/dist/skills/types.js +118 -0
  582. package/dist/skills/types.js.map +1 -0
  583. package/dist/skills/validation.js +183 -0
  584. package/dist/skills/validation.js.map +1 -0
  585. package/dist/skills/version.js +57 -0
  586. package/dist/skills/version.js.map +1 -0
  587. package/dist/snapshot/index.js +188 -0
  588. package/dist/snapshot/index.js.map +1 -0
  589. package/dist/spawn/adapter-registry.js +246 -0
  590. package/dist/spawn/adapter-registry.js.map +1 -0
  591. package/dist/spawn/index.js +10 -0
  592. package/dist/spawn/index.js.map +1 -0
  593. package/dist/stats/index.js +343 -0
  594. package/dist/stats/index.js.map +1 -0
  595. package/dist/stats/workflow-telemetry.js +400 -0
  596. package/dist/stats/workflow-telemetry.js.map +1 -0
  597. package/dist/sticky/archive.js +47 -0
  598. package/dist/sticky/archive.js.map +1 -0
  599. package/dist/sticky/convert.js +235 -0
  600. package/dist/sticky/convert.js.map +1 -0
  601. package/dist/sticky/create.js +48 -0
  602. package/dist/sticky/create.js.map +1 -0
  603. package/dist/sticky/id.js +35 -0
  604. package/dist/sticky/id.js.map +1 -0
  605. package/dist/sticky/index.js +16 -0
  606. package/dist/sticky/index.js.map +1 -0
  607. package/dist/sticky/list.js +44 -0
  608. package/dist/sticky/list.js.map +1 -0
  609. package/dist/sticky/purge.js +45 -0
  610. package/dist/sticky/purge.js.map +1 -0
  611. package/dist/sticky/show.js +42 -0
  612. package/dist/sticky/show.js.map +1 -0
  613. package/dist/sticky/types.js +10 -0
  614. package/dist/sticky/types.js.map +1 -0
  615. package/dist/store/agent-registry-accessor.d.ts +203 -12
  616. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  617. package/dist/store/agent-registry-accessor.js +783 -0
  618. package/dist/store/agent-registry-accessor.js.map +1 -0
  619. package/dist/store/api-key-kdf.d.ts +73 -0
  620. package/dist/store/api-key-kdf.d.ts.map +1 -0
  621. package/dist/store/api-key-kdf.js +84 -0
  622. package/dist/store/api-key-kdf.js.map +1 -0
  623. package/dist/store/atomic.js +167 -0
  624. package/dist/store/atomic.js.map +1 -0
  625. package/dist/store/backup.js +94 -0
  626. package/dist/store/backup.js.map +1 -0
  627. package/dist/store/brain-accessor.js +397 -0
  628. package/dist/store/brain-accessor.js.map +1 -0
  629. package/dist/store/brain-schema.d.ts +8 -8
  630. package/dist/store/brain-schema.js +215 -0
  631. package/dist/store/brain-schema.js.map +1 -0
  632. package/dist/store/brain-sqlite.js +222 -0
  633. package/dist/store/brain-sqlite.js.map +1 -0
  634. package/dist/store/cache.js +168 -0
  635. package/dist/store/cache.js.map +1 -0
  636. package/dist/store/chain-schema.js +51 -0
  637. package/dist/store/chain-schema.js.map +1 -0
  638. package/dist/store/cleanup-legacy.d.ts +128 -0
  639. package/dist/store/cleanup-legacy.d.ts.map +1 -0
  640. package/dist/store/cleanup-legacy.js +171 -0
  641. package/dist/store/cleanup-legacy.js.map +1 -0
  642. package/dist/store/conduit-sqlite.d.ts +184 -0
  643. package/dist/store/conduit-sqlite.d.ts.map +1 -0
  644. package/dist/store/conduit-sqlite.js +570 -0
  645. package/dist/store/conduit-sqlite.js.map +1 -0
  646. package/dist/store/converters.js +124 -0
  647. package/dist/store/converters.js.map +1 -0
  648. package/dist/store/cross-db-cleanup.js +319 -0
  649. package/dist/store/cross-db-cleanup.js.map +1 -0
  650. package/dist/store/data-accessor.js +26 -0
  651. package/dist/store/data-accessor.js.map +1 -0
  652. package/dist/store/data-safety-central.js +269 -0
  653. package/dist/store/data-safety-central.js.map +1 -0
  654. package/dist/store/data-safety.js +274 -0
  655. package/dist/store/data-safety.js.map +1 -0
  656. package/dist/store/db-helpers.js +224 -0
  657. package/dist/store/db-helpers.js.map +1 -0
  658. package/dist/store/export.js +155 -0
  659. package/dist/store/export.js.map +1 -0
  660. package/dist/store/file-utils.js +270 -0
  661. package/dist/store/file-utils.js.map +1 -0
  662. package/dist/store/git-checkpoint.js +365 -0
  663. package/dist/store/git-checkpoint.js.map +1 -0
  664. package/dist/store/global-salt.d.ts +78 -0
  665. package/dist/store/global-salt.d.ts.map +1 -0
  666. package/dist/store/global-salt.js +147 -0
  667. package/dist/store/global-salt.js.map +1 -0
  668. package/dist/store/import-logging.js +139 -0
  669. package/dist/store/import-logging.js.map +1 -0
  670. package/dist/store/import-remap.js +145 -0
  671. package/dist/store/import-remap.js.map +1 -0
  672. package/dist/store/import-sort.js +121 -0
  673. package/dist/store/import-sort.js.map +1 -0
  674. package/dist/store/index.d.ts +1 -0
  675. package/dist/store/index.d.ts.map +1 -1
  676. package/dist/store/index.js +29 -0
  677. package/dist/store/index.js.map +1 -0
  678. package/dist/store/json.js +208 -0
  679. package/dist/store/json.js.map +1 -0
  680. package/dist/store/lifecycle-store.js +249 -0
  681. package/dist/store/lifecycle-store.js.map +1 -0
  682. package/dist/store/lock.js +70 -0
  683. package/dist/store/lock.js.map +1 -0
  684. package/dist/store/migrate-signaldock-to-conduit.d.ts +81 -0
  685. package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -0
  686. package/dist/store/migrate-signaldock-to-conduit.js +555 -0
  687. package/dist/store/migrate-signaldock-to-conduit.js.map +1 -0
  688. package/dist/store/migration-manager.js +151 -0
  689. package/dist/store/migration-manager.js.map +1 -0
  690. package/dist/store/migration-sqlite.js +676 -0
  691. package/dist/store/migration-sqlite.js.map +1 -0
  692. package/dist/store/nexus-schema.js +62 -0
  693. package/dist/store/nexus-schema.js.map +1 -0
  694. package/dist/store/nexus-sqlite.d.ts +14 -2
  695. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  696. package/dist/store/nexus-sqlite.js +242 -0
  697. package/dist/store/nexus-sqlite.js.map +1 -0
  698. package/dist/store/nexus-validation-schemas.js +40 -0
  699. package/dist/store/nexus-validation-schemas.js.map +1 -0
  700. package/dist/store/parsers.js +37 -0
  701. package/dist/store/parsers.js.map +1 -0
  702. package/dist/store/project-detect.js +457 -0
  703. package/dist/store/project-detect.js.map +1 -0
  704. package/dist/store/provider.js +101 -0
  705. package/dist/store/provider.js.map +1 -0
  706. package/dist/store/safety-data-accessor.js +257 -0
  707. package/dist/store/safety-data-accessor.js.map +1 -0
  708. package/dist/store/schema.js +7 -0
  709. package/dist/store/schema.js.map +1 -0
  710. package/dist/store/session-store.js +219 -0
  711. package/dist/store/session-store.js.map +1 -0
  712. package/dist/store/signaldock-sqlite.d.ts +122 -19
  713. package/dist/store/signaldock-sqlite.d.ts.map +1 -1
  714. package/dist/store/signaldock-sqlite.js +550 -0
  715. package/dist/store/signaldock-sqlite.js.map +1 -0
  716. package/dist/store/sqlite-backup.d.ts +121 -10
  717. package/dist/store/sqlite-backup.d.ts.map +1 -1
  718. package/dist/store/sqlite-backup.js +359 -0
  719. package/dist/store/sqlite-backup.js.map +1 -0
  720. package/dist/store/sqlite-data-accessor.js +787 -0
  721. package/dist/store/sqlite-data-accessor.js.map +1 -0
  722. package/dist/store/sqlite.d.ts.map +1 -1
  723. package/dist/store/sqlite.js +481 -0
  724. package/dist/store/sqlite.js.map +1 -0
  725. package/dist/store/status-registry.js +8 -0
  726. package/dist/store/status-registry.js.map +1 -0
  727. package/dist/store/task-store.js +358 -0
  728. package/dist/store/task-store.js.map +1 -0
  729. package/dist/store/tasks-schema.d.ts +8 -8
  730. package/dist/store/tasks-schema.js +610 -0
  731. package/dist/store/tasks-schema.js.map +1 -0
  732. package/dist/store/typed-query.js +15 -0
  733. package/dist/store/typed-query.js.map +1 -0
  734. package/dist/store/validation-schemas.d.ts +37 -37
  735. package/dist/store/validation-schemas.js +278 -0
  736. package/dist/store/validation-schemas.js.map +1 -0
  737. package/dist/system/archive-analytics.js +277 -0
  738. package/dist/system/archive-analytics.js.map +1 -0
  739. package/dist/system/archive-stats.js +64 -0
  740. package/dist/system/archive-stats.js.map +1 -0
  741. package/dist/system/audit.js +145 -0
  742. package/dist/system/audit.js.map +1 -0
  743. package/dist/system/backup.d.ts +65 -3
  744. package/dist/system/backup.d.ts.map +1 -1
  745. package/dist/system/backup.js +280 -0
  746. package/dist/system/backup.js.map +1 -0
  747. package/dist/system/cleanup.js +134 -0
  748. package/dist/system/cleanup.js.map +1 -0
  749. package/dist/system/health.js +1100 -0
  750. package/dist/system/health.js.map +1 -0
  751. package/dist/system/index.js +18 -0
  752. package/dist/system/index.js.map +1 -0
  753. package/dist/system/inject-generate.js +122 -0
  754. package/dist/system/inject-generate.js.map +1 -0
  755. package/dist/system/labels.js +38 -0
  756. package/dist/system/labels.js.map +1 -0
  757. package/dist/system/metrics.js +61 -0
  758. package/dist/system/metrics.js.map +1 -0
  759. package/dist/system/migrate.js +43 -0
  760. package/dist/system/migrate.js.map +1 -0
  761. package/dist/system/platform-paths.js +80 -0
  762. package/dist/system/platform-paths.js.map +1 -0
  763. package/dist/system/runtime.d.ts +0 -2
  764. package/dist/system/runtime.d.ts.map +1 -1
  765. package/dist/system/runtime.js +161 -0
  766. package/dist/system/runtime.js.map +1 -0
  767. package/dist/system/safestop.js +99 -0
  768. package/dist/system/safestop.js.map +1 -0
  769. package/dist/system/storage-preflight.js +123 -0
  770. package/dist/system/storage-preflight.js.map +1 -0
  771. package/dist/task-work/index.js +159 -0
  772. package/dist/task-work/index.js.map +1 -0
  773. package/dist/tasks/add.d.ts +1 -1
  774. package/dist/tasks/add.d.ts.map +1 -1
  775. package/dist/tasks/add.js +736 -0
  776. package/dist/tasks/add.js.map +1 -0
  777. package/dist/tasks/analyze.js +85 -0
  778. package/dist/tasks/analyze.js.map +1 -0
  779. package/dist/tasks/archive.js +90 -0
  780. package/dist/tasks/archive.js.map +1 -0
  781. package/dist/tasks/atomicity.js +83 -0
  782. package/dist/tasks/atomicity.js.map +1 -0
  783. package/dist/tasks/cancel-ops.js +83 -0
  784. package/dist/tasks/cancel-ops.js.map +1 -0
  785. package/dist/tasks/complete.d.ts.map +1 -1
  786. package/dist/tasks/complete.js +214 -0
  787. package/dist/tasks/complete.js.map +1 -0
  788. package/dist/tasks/crossref-extract.js +73 -0
  789. package/dist/tasks/crossref-extract.js.map +1 -0
  790. package/dist/tasks/delete-preview.js +192 -0
  791. package/dist/tasks/delete-preview.js.map +1 -0
  792. package/dist/tasks/delete.js +120 -0
  793. package/dist/tasks/delete.js.map +1 -0
  794. package/dist/tasks/deletion-strategy.js +200 -0
  795. package/dist/tasks/deletion-strategy.js.map +1 -0
  796. package/dist/tasks/dependency-check.js +278 -0
  797. package/dist/tasks/dependency-check.js.map +1 -0
  798. package/dist/tasks/deps-ready.js +32 -0
  799. package/dist/tasks/deps-ready.js.map +1 -0
  800. package/dist/tasks/enforcement.js +86 -0
  801. package/dist/tasks/enforcement.js.map +1 -0
  802. package/dist/tasks/epic-enforcement.js +294 -0
  803. package/dist/tasks/epic-enforcement.js.map +1 -0
  804. package/dist/tasks/find.d.ts.map +1 -1
  805. package/dist/tasks/find.js +157 -0
  806. package/dist/tasks/find.js.map +1 -0
  807. package/dist/tasks/graph-cache.js +127 -0
  808. package/dist/tasks/graph-cache.js.map +1 -0
  809. package/dist/tasks/graph-ops.js +171 -0
  810. package/dist/tasks/graph-ops.js.map +1 -0
  811. package/dist/tasks/graph-rag.js +328 -0
  812. package/dist/tasks/graph-rag.js.map +1 -0
  813. package/dist/tasks/hierarchy-policy.js +149 -0
  814. package/dist/tasks/hierarchy-policy.js.map +1 -0
  815. package/dist/tasks/hierarchy.js +185 -0
  816. package/dist/tasks/hierarchy.js.map +1 -0
  817. package/dist/tasks/id-generator.js +65 -0
  818. package/dist/tasks/id-generator.js.map +1 -0
  819. package/dist/tasks/index.js +14 -0
  820. package/dist/tasks/index.js.map +1 -0
  821. package/dist/tasks/labels.d.ts.map +1 -1
  822. package/dist/tasks/labels.js +55 -0
  823. package/dist/tasks/labels.js.map +1 -0
  824. package/dist/tasks/list.js +75 -0
  825. package/dist/tasks/list.js.map +1 -0
  826. package/dist/tasks/phase-tracking.js +133 -0
  827. package/dist/tasks/phase-tracking.js.map +1 -0
  828. package/dist/tasks/pipeline-stage.js +248 -0
  829. package/dist/tasks/pipeline-stage.js.map +1 -0
  830. package/dist/tasks/plan.js +268 -0
  831. package/dist/tasks/plan.js.map +1 -0
  832. package/dist/tasks/relates.d.ts.map +1 -1
  833. package/dist/tasks/relates.js +101 -0
  834. package/dist/tasks/relates.js.map +1 -0
  835. package/dist/tasks/show.d.ts.map +1 -1
  836. package/dist/tasks/show.js +83 -0
  837. package/dist/tasks/show.js.map +1 -0
  838. package/dist/tasks/size-weighting.js +86 -0
  839. package/dist/tasks/size-weighting.js.map +1 -0
  840. package/dist/tasks/staleness.js +86 -0
  841. package/dist/tasks/staleness.js.map +1 -0
  842. package/dist/tasks/task-ops.js +1741 -0
  843. package/dist/tasks/task-ops.js.map +1 -0
  844. package/dist/tasks/update.d.ts.map +1 -1
  845. package/dist/tasks/update.js +303 -0
  846. package/dist/tasks/update.js.map +1 -0
  847. package/dist/templates/index.js +10 -0
  848. package/dist/templates/index.js.map +1 -0
  849. package/dist/templates/parser.js +254 -0
  850. package/dist/templates/parser.js.map +1 -0
  851. package/dist/ui/aliases.js +153 -0
  852. package/dist/ui/aliases.js.map +1 -0
  853. package/dist/ui/changelog.js +184 -0
  854. package/dist/ui/changelog.js.map +1 -0
  855. package/dist/ui/command-registry.js +168 -0
  856. package/dist/ui/command-registry.js.map +1 -0
  857. package/dist/ui/flags.js +94 -0
  858. package/dist/ui/flags.js.map +1 -0
  859. package/dist/ui/index.js +24 -0
  860. package/dist/ui/index.js.map +1 -0
  861. package/dist/upgrade.js +1148 -0
  862. package/dist/upgrade.js.map +1 -0
  863. package/dist/validation/chain-validation.js +146 -0
  864. package/dist/validation/chain-validation.js.map +1 -0
  865. package/dist/validation/compliance.js +155 -0
  866. package/dist/validation/compliance.js.map +1 -0
  867. package/dist/validation/docs-sync.js +212 -0
  868. package/dist/validation/docs-sync.js.map +1 -0
  869. package/dist/validation/doctor/checks.js +1069 -0
  870. package/dist/validation/doctor/checks.js.map +1 -0
  871. package/dist/validation/doctor/index.js +9 -0
  872. package/dist/validation/doctor/index.js.map +1 -0
  873. package/dist/validation/doctor/project-cache.js +160 -0
  874. package/dist/validation/doctor/project-cache.js.map +1 -0
  875. package/dist/validation/doctor/utils.js +155 -0
  876. package/dist/validation/doctor/utils.js.map +1 -0
  877. package/dist/validation/engine.d.ts.map +1 -1
  878. package/dist/validation/engine.js +914 -0
  879. package/dist/validation/engine.js.map +1 -0
  880. package/dist/validation/gap-check.js +175 -0
  881. package/dist/validation/gap-check.js.map +1 -0
  882. package/dist/validation/index.js +40 -0
  883. package/dist/validation/index.js.map +1 -0
  884. package/dist/validation/manifest.js +237 -0
  885. package/dist/validation/manifest.js.map +1 -0
  886. package/dist/validation/operation-gate-validators.js +724 -0
  887. package/dist/validation/operation-gate-validators.js.map +1 -0
  888. package/dist/validation/operation-verification-gates.js +532 -0
  889. package/dist/validation/operation-verification-gates.js.map +1 -0
  890. package/dist/validation/param-utils.d.ts +5 -3
  891. package/dist/validation/param-utils.d.ts.map +1 -1
  892. package/dist/validation/param-utils.js +141 -0
  893. package/dist/validation/param-utils.js.map +1 -0
  894. package/dist/validation/protocol-common.js +300 -0
  895. package/dist/validation/protocol-common.js.map +1 -0
  896. package/dist/validation/protocols/_shared.d.ts.map +1 -1
  897. package/dist/validation/protocols/_shared.js +82 -0
  898. package/dist/validation/protocols/_shared.js.map +1 -0
  899. package/dist/validation/protocols/architecture-decision.js +31 -0
  900. package/dist/validation/protocols/architecture-decision.js.map +1 -0
  901. package/dist/validation/protocols/artifact-publish.js +28 -0
  902. package/dist/validation/protocols/artifact-publish.js.map +1 -0
  903. package/dist/validation/protocols/consensus.js +41 -0
  904. package/dist/validation/protocols/consensus.js.map +1 -0
  905. package/dist/validation/protocols/contribution.js +27 -0
  906. package/dist/validation/protocols/contribution.js.map +1 -0
  907. package/dist/validation/protocols/decomposition.js +28 -0
  908. package/dist/validation/protocols/decomposition.js.map +1 -0
  909. package/dist/validation/protocols/implementation.js +24 -0
  910. package/dist/validation/protocols/implementation.js.map +1 -0
  911. package/dist/validation/protocols/provenance.js +29 -0
  912. package/dist/validation/protocols/provenance.js.map +1 -0
  913. package/dist/validation/protocols/release.js +29 -0
  914. package/dist/validation/protocols/release.js.map +1 -0
  915. package/dist/validation/protocols/research.js +24 -0
  916. package/dist/validation/protocols/research.js.map +1 -0
  917. package/dist/validation/protocols/specification.js +27 -0
  918. package/dist/validation/protocols/specification.js.map +1 -0
  919. package/dist/validation/protocols/testing.js +30 -0
  920. package/dist/validation/protocols/testing.js.map +1 -0
  921. package/dist/validation/protocols/validation.js +30 -0
  922. package/dist/validation/protocols/validation.js.map +1 -0
  923. package/dist/validation/schema-integrity.js +170 -0
  924. package/dist/validation/schema-integrity.js.map +1 -0
  925. package/dist/validation/schema-validator.js +176 -0
  926. package/dist/validation/schema-validator.js.map +1 -0
  927. package/dist/validation/validate-ops.js +937 -0
  928. package/dist/validation/validate-ops.js.map +1 -0
  929. package/dist/validation/validation-rules.js +226 -0
  930. package/dist/validation/validation-rules.js.map +1 -0
  931. package/dist/validation/verification.js +321 -0
  932. package/dist/validation/verification.js.map +1 -0
  933. package/package.json +10 -8
  934. package/src/__tests__/paths-walkup.test.ts +305 -0
  935. package/src/__tests__/paths.test.ts +61 -17
  936. package/src/adapters/__tests__/manager.test.ts +0 -1
  937. package/src/codebase-map/analyzers/architecture.ts +0 -1
  938. package/src/conduit/__tests__/local-credential-flow.test.ts +20 -18
  939. package/src/conduit/__tests__/local-transport.test.ts +14 -12
  940. package/src/conduit/local-transport.ts +23 -13
  941. package/src/config.ts +0 -1
  942. package/src/errors.ts +24 -0
  943. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +2 -5
  944. package/src/hooks/handlers/session-hooks.ts +42 -0
  945. package/src/init.ts +1 -2
  946. package/src/internal.ts +67 -3
  947. package/src/lifecycle/cant/lifecycle-rcasd.cant +133 -0
  948. package/src/memory/__tests__/engine-compat.test.ts +2 -2
  949. package/src/memory/__tests__/pipeline-manifest-sqlite.test.ts +4 -4
  950. package/src/observability/__tests__/index.test.ts +4 -4
  951. package/src/observability/__tests__/log-filter.test.ts +4 -4
  952. package/src/output.ts +73 -75
  953. package/src/paths.ts +91 -14
  954. package/src/scaffold.ts +22 -3
  955. package/src/sessions/__tests__/session-grade.integration.test.ts +1 -1
  956. package/src/sessions/__tests__/session-grade.test.ts +2 -2
  957. package/src/skills/__tests__/dynamic-skill-generator.test.ts +0 -2
  958. package/src/skills/dynamic-skill-generator.ts +0 -2
  959. package/src/store/__tests__/agent-registry-accessor.test.ts +807 -0
  960. package/src/store/__tests__/api-key-kdf.test.ts +113 -0
  961. package/src/store/__tests__/cleanup-legacy.test.ts +268 -0
  962. package/src/store/__tests__/conduit-sqlite.test.ts +413 -0
  963. package/src/store/__tests__/database-topology-integration.test.ts +504 -0
  964. package/src/store/__tests__/global-salt.test.ts +195 -0
  965. package/src/store/__tests__/migrate-signaldock-to-conduit.test.ts +715 -0
  966. package/src/store/__tests__/signaldock-sqlite.test.ts +652 -0
  967. package/src/store/__tests__/sqlite-backup-global.test.ts +585 -0
  968. package/src/store/__tests__/sqlite-backup.test.ts +122 -10
  969. package/src/store/__tests__/t310-integration.test.ts +1150 -0
  970. package/src/store/agent-registry-accessor.ts +847 -140
  971. package/src/store/api-key-kdf.ts +104 -0
  972. package/src/store/cleanup-legacy.ts +208 -0
  973. package/src/store/conduit-sqlite.ts +655 -0
  974. package/src/store/global-salt.ts +175 -0
  975. package/src/store/index.ts +7 -0
  976. package/src/store/migrate-signaldock-to-conduit.ts +669 -0
  977. package/src/store/nexus-sqlite.ts +32 -3
  978. package/src/store/signaldock-sqlite.ts +431 -254
  979. package/src/store/sqlite-backup.ts +544 -38
  980. package/src/store/sqlite.ts +19 -3
  981. package/src/system/__tests__/backup.test.ts +237 -0
  982. package/src/system/backup.ts +186 -26
  983. package/src/system/runtime.ts +4 -6
  984. package/src/tasks/__tests__/error-hints.test.ts +256 -0
  985. package/src/tasks/add.ts +99 -9
  986. package/src/tasks/complete.ts +4 -1
  987. package/src/tasks/find.ts +4 -1
  988. package/src/tasks/labels.ts +4 -1
  989. package/src/tasks/relates.ts +16 -4
  990. package/src/tasks/show.ts +4 -1
  991. package/src/tasks/update.ts +32 -3
  992. package/src/validation/__tests__/error-hints.test.ts +97 -0
  993. package/src/validation/engine.ts +16 -1
  994. package/src/validation/param-utils.ts +10 -7
  995. package/src/validation/protocols/_shared.ts +14 -6
  996. package/src/validation/protocols/cant/architecture-decision.cant +80 -0
  997. package/src/validation/protocols/cant/artifact-publish.cant +95 -0
  998. package/src/validation/protocols/cant/consensus.cant +74 -0
  999. package/src/validation/protocols/cant/contribution.cant +82 -0
  1000. package/src/validation/protocols/cant/decomposition.cant +92 -0
  1001. package/src/validation/protocols/cant/implementation.cant +67 -0
  1002. package/src/validation/protocols/cant/provenance.cant +88 -0
  1003. package/src/validation/protocols/cant/release.cant +96 -0
  1004. package/src/validation/protocols/cant/research.cant +66 -0
  1005. package/src/validation/protocols/cant/specification.cant +67 -0
  1006. package/src/validation/protocols/cant/testing.cant +88 -0
  1007. package/src/validation/protocols/cant/validation.cant +65 -0
  1008. package/src/validation/protocols/protocols-markdown/decomposition.md +0 -4
  1009. package/templates/cleo-gitignore +19 -3
  1010. package/templates/config.template.json +0 -1
  1011. package/templates/global-config.template.json +0 -1
@@ -0,0 +1,1150 @@
1
+ /**
2
+ * T310 integration test suite: conduit + signaldock cross-project agent lifecycle.
3
+ *
4
+ * Covers 12 end-to-end scenarios across the full conduit + signaldock topology
5
+ * introduced by ADR-037 and spec §7.5 (cross-DB integration), §7.6 (migration),
6
+ * and §7.8 (KDF / reauth).
7
+ *
8
+ * All filesystem interactions occur inside fresh tmp directories per test.
9
+ * The real user's $XDG_DATA_HOME and project directories are never touched.
10
+ * `getCleoHome()` is redirected to a per-test tmp directory via `vi.doMock`.
11
+ *
12
+ * Test approach: `vi.resetModules()` before each test then `vi.doMock()` for
13
+ * paths.js → fresh module import chain → functions use isolated tmp dirs.
14
+ *
15
+ * @task T371
16
+ * @epic T310
17
+ * @why Verifies the full cross-DB lifecycle contract (ADR-037) including:
18
+ * conduit.db creation, global signaldock.db identity, project_agent_refs
19
+ * INNER/OUTER join semantics, cross-project isolation, migration, KDF, and
20
+ * backup registry.
21
+ */
22
+
23
+ import {
24
+ existsSync,
25
+ mkdirSync,
26
+ mkdtempSync,
27
+ readFileSync,
28
+ rmSync,
29
+ statSync,
30
+ writeFileSync,
31
+ } from 'node:fs';
32
+ import { tmpdir } from 'node:os';
33
+ import { join } from 'node:path';
34
+ import { DatabaseSync } from 'node:sqlite';
35
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Logger mock — prevents pino from attempting to open real log files.
39
+ // ---------------------------------------------------------------------------
40
+
41
+ vi.mock('../../logger.js', () => ({
42
+ getLogger: () => ({
43
+ info: vi.fn(),
44
+ warn: vi.fn(),
45
+ error: vi.fn(),
46
+ debug: vi.fn(),
47
+ }),
48
+ }));
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Helpers
52
+ // ---------------------------------------------------------------------------
53
+
54
+ /**
55
+ * Create isolated tmp directory pair for one test.
56
+ *
57
+ * @param prefix - Short identifier for debug visibility.
58
+ * @returns cleoHome and one projectRoot, plus cleanup.
59
+ */
60
+ function makeTmpPair(prefix: string): {
61
+ cleoHome: string;
62
+ projectRoot: string;
63
+ cleanup: () => void;
64
+ } {
65
+ const base = mkdtempSync(join(tmpdir(), `cleo-t371-${prefix}-`));
66
+ const cleoHome = join(base, 'cleo-home');
67
+ const projectRoot = join(base, 'project');
68
+ mkdirSync(cleoHome, { recursive: true });
69
+ mkdirSync(join(projectRoot, '.cleo'), { recursive: true });
70
+ return {
71
+ cleoHome,
72
+ projectRoot,
73
+ cleanup: () => rmSync(base, { recursive: true, force: true }),
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Create a second isolated project root under the same base directory.
79
+ * Used for cross-project scenarios.
80
+ *
81
+ * @param base - Base tmp directory.
82
+ * @returns Absolute path to the second project root.
83
+ */
84
+ function makeSecondProject(base: string): string {
85
+ const projectB = join(base, 'project-b');
86
+ mkdirSync(join(projectB, '.cleo'), { recursive: true });
87
+ return projectB;
88
+ }
89
+
90
+ /**
91
+ * Seed a deterministic machine-key and global-salt so KDF is testable without
92
+ * random entropy. Returns the fixed buffers used.
93
+ *
94
+ * @param cleoHome - Global tier home directory.
95
+ * @param saltByte - Byte value to fill the 32-byte global-salt. Defaults to 0xcd.
96
+ * @param keyByte - Byte value to fill the 32-byte machine-key. Defaults to 0xab.
97
+ */
98
+ function seedKeys(
99
+ cleoHome: string,
100
+ saltByte = 0xcd,
101
+ keyByte = 0xab,
102
+ ): { machineKey: Buffer; globalSalt: Buffer } {
103
+ const machineKey = Buffer.alloc(32, keyByte);
104
+ const globalSalt = Buffer.alloc(32, saltByte);
105
+ writeFileSync(join(cleoHome, 'machine-key'), machineKey, { mode: 0o600 });
106
+ writeFileSync(join(cleoHome, 'global-salt'), globalSalt, { mode: 0o600 });
107
+ return { machineKey, globalSalt };
108
+ }
109
+
110
+ /**
111
+ * Insert a minimal agent row directly into a global signaldock.db.
112
+ * Used in seeding tests without going through the full accessor layer.
113
+ */
114
+ function insertGlobalAgent(
115
+ globalDb: DatabaseSync,
116
+ agentId: string,
117
+ name: string,
118
+ requiresReauth = 0,
119
+ ): void {
120
+ const now = Math.floor(Date.now() / 1000);
121
+ globalDb
122
+ .prepare(
123
+ `INSERT OR IGNORE INTO agents
124
+ (id, agent_id, name, class, privacy_tier, capabilities, skills,
125
+ transport_type, api_base_url, classification, transport_config,
126
+ is_active, status, created_at, updated_at, requires_reauth)
127
+ VALUES (?, ?, ?, 'custom', 'public', '[]', '[]', 'http',
128
+ 'https://api.signaldock.io', NULL, '{}', 1, 'online', ?, ?, ?)`,
129
+ )
130
+ .run(crypto.randomUUID(), agentId, name, now, now, requiresReauth);
131
+ }
132
+
133
+ /**
134
+ * Insert a project_agent_refs row directly into a conduit.db.
135
+ * Used in seeding scenarios that bypass the accessor layer.
136
+ */
137
+ function insertConduitRef(conduitDb: DatabaseSync, agentId: string, enabled = 1): void {
138
+ const now = new Date().toISOString();
139
+ conduitDb
140
+ .prepare(
141
+ `INSERT OR IGNORE INTO project_agent_refs
142
+ (agent_id, attached_at, role, capabilities_override, last_used_at, enabled)
143
+ VALUES (?, ?, NULL, NULL, NULL, ?)`,
144
+ )
145
+ .run(agentId, now, enabled);
146
+ }
147
+
148
+ /**
149
+ * Create a legacy project-tier signaldock.db at `<projectRoot>/.cleo/signaldock.db`
150
+ * with the pre-T310 schema and optionally seed agents / messages / conversations.
151
+ */
152
+ function createLegacySignaldockDb(
153
+ projectRoot: string,
154
+ agents: Array<{
155
+ id: string;
156
+ agentId: string;
157
+ name: string;
158
+ classification?: string;
159
+ createdAt?: number;
160
+ lastUsedAt?: number;
161
+ }> = [],
162
+ messages: Array<{
163
+ id: string;
164
+ conversationId: string;
165
+ fromAgentId: string;
166
+ toAgentId: string;
167
+ content: string;
168
+ createdAt: number;
169
+ }> = [],
170
+ conversations: Array<{
171
+ id: string;
172
+ participants: string;
173
+ createdAt: number;
174
+ updatedAt: number;
175
+ }> = [],
176
+ ): string {
177
+ const dbPath = join(projectRoot, '.cleo', 'signaldock.db');
178
+ const db = new DatabaseSync(dbPath);
179
+ const now = Math.floor(Date.now() / 1000);
180
+
181
+ db.exec(`
182
+ CREATE TABLE IF NOT EXISTS agents (
183
+ id TEXT PRIMARY KEY,
184
+ agent_id TEXT NOT NULL UNIQUE,
185
+ name TEXT NOT NULL,
186
+ class TEXT NOT NULL DEFAULT 'custom',
187
+ classification TEXT,
188
+ created_at INTEGER NOT NULL,
189
+ updated_at INTEGER NOT NULL,
190
+ api_key_encrypted TEXT,
191
+ last_used_at INTEGER,
192
+ requires_reauth INTEGER NOT NULL DEFAULT 0
193
+ );
194
+ CREATE TABLE IF NOT EXISTS conversations (
195
+ id TEXT PRIMARY KEY,
196
+ participants TEXT NOT NULL,
197
+ visibility TEXT NOT NULL DEFAULT 'private',
198
+ message_count INTEGER NOT NULL DEFAULT 0,
199
+ last_message_at INTEGER,
200
+ created_at INTEGER NOT NULL,
201
+ updated_at INTEGER NOT NULL
202
+ );
203
+ CREATE TABLE IF NOT EXISTS messages (
204
+ id TEXT PRIMARY KEY,
205
+ conversation_id TEXT NOT NULL,
206
+ from_agent_id TEXT NOT NULL,
207
+ to_agent_id TEXT NOT NULL,
208
+ content TEXT NOT NULL,
209
+ content_type TEXT NOT NULL DEFAULT 'text',
210
+ status TEXT NOT NULL DEFAULT 'pending',
211
+ attachments TEXT NOT NULL DEFAULT '[]',
212
+ group_id TEXT,
213
+ metadata TEXT DEFAULT '{}',
214
+ reply_to TEXT,
215
+ created_at INTEGER NOT NULL,
216
+ delivered_at INTEGER,
217
+ read_at INTEGER
218
+ );
219
+ `);
220
+
221
+ for (const agent of agents) {
222
+ db.prepare(
223
+ `INSERT INTO agents
224
+ (id, agent_id, name, classification, created_at, updated_at, api_key_encrypted, last_used_at)
225
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?)`,
226
+ ).run(
227
+ agent.id,
228
+ agent.agentId,
229
+ agent.name,
230
+ agent.classification ?? null,
231
+ agent.createdAt ?? now,
232
+ now,
233
+ agent.lastUsedAt ?? null,
234
+ );
235
+ }
236
+
237
+ for (const conv of conversations) {
238
+ db.prepare(
239
+ `INSERT INTO conversations (id, participants, created_at, updated_at) VALUES (?, ?, ?, ?)`,
240
+ ).run(conv.id, conv.participants, conv.createdAt, conv.updatedAt);
241
+ }
242
+
243
+ for (const msg of messages) {
244
+ db.prepare(
245
+ `INSERT INTO messages
246
+ (id, conversation_id, from_agent_id, to_agent_id, content, created_at)
247
+ VALUES (?, ?, ?, ?, ?, ?)`,
248
+ ).run(msg.id, msg.conversationId, msg.fromAgentId, msg.toAgentId, msg.content, msg.createdAt);
249
+ }
250
+
251
+ db.close();
252
+ return dbPath;
253
+ }
254
+
255
+ /**
256
+ * Create a pre-seeded global signaldock.db (schema applied, agents optionally inserted).
257
+ * Returns the path to the created file.
258
+ */
259
+ function createGlobalSignaldockDbFile(
260
+ cleoHome: string,
261
+ agents: Array<{ id: string; agentId: string; name: string; requiresReauth?: number }> = [],
262
+ ): string {
263
+ const dbPath = join(cleoHome, 'signaldock.db');
264
+ const db = new DatabaseSync(dbPath);
265
+ const now = Math.floor(Date.now() / 1000);
266
+
267
+ db.exec(`
268
+ CREATE TABLE IF NOT EXISTS agents (
269
+ id TEXT PRIMARY KEY,
270
+ agent_id TEXT NOT NULL UNIQUE,
271
+ name TEXT NOT NULL,
272
+ class TEXT NOT NULL DEFAULT 'custom',
273
+ privacy_tier TEXT NOT NULL DEFAULT 'public',
274
+ capabilities TEXT NOT NULL DEFAULT '[]',
275
+ skills TEXT NOT NULL DEFAULT '[]',
276
+ messages_sent INTEGER NOT NULL DEFAULT 0,
277
+ messages_received INTEGER NOT NULL DEFAULT 0,
278
+ conversation_count INTEGER NOT NULL DEFAULT 0,
279
+ friend_count INTEGER NOT NULL DEFAULT 0,
280
+ status TEXT NOT NULL DEFAULT 'online',
281
+ payment_config TEXT,
282
+ api_key_hash TEXT,
283
+ created_at INTEGER NOT NULL,
284
+ updated_at INTEGER NOT NULL,
285
+ transport_type TEXT NOT NULL DEFAULT 'http',
286
+ api_key_encrypted TEXT,
287
+ api_base_url TEXT NOT NULL DEFAULT 'https://api.signaldock.io',
288
+ classification TEXT,
289
+ transport_config TEXT NOT NULL DEFAULT '{}',
290
+ is_active INTEGER NOT NULL DEFAULT 1,
291
+ last_used_at INTEGER,
292
+ requires_reauth INTEGER NOT NULL DEFAULT 0
293
+ );
294
+ CREATE UNIQUE INDEX IF NOT EXISTS agents_agent_id_idx ON agents(agent_id);
295
+ CREATE TABLE IF NOT EXISTS capabilities (
296
+ id TEXT PRIMARY KEY, slug TEXT NOT NULL UNIQUE, name TEXT NOT NULL,
297
+ description TEXT NOT NULL, category TEXT NOT NULL, created_at INTEGER NOT NULL
298
+ );
299
+ CREATE TABLE IF NOT EXISTS skills (
300
+ id TEXT PRIMARY KEY, slug TEXT NOT NULL UNIQUE, name TEXT NOT NULL,
301
+ description TEXT NOT NULL, category TEXT NOT NULL, created_at INTEGER NOT NULL
302
+ );
303
+ CREATE TABLE IF NOT EXISTS agent_capabilities (
304
+ agent_id TEXT NOT NULL, capability_id TEXT NOT NULL, PRIMARY KEY (agent_id, capability_id)
305
+ );
306
+ CREATE TABLE IF NOT EXISTS agent_skills (
307
+ agent_id TEXT NOT NULL, skill_id TEXT NOT NULL, PRIMARY KEY (agent_id, skill_id)
308
+ );
309
+ CREATE TABLE IF NOT EXISTS agent_connections (
310
+ id TEXT PRIMARY KEY NOT NULL, agent_id TEXT NOT NULL,
311
+ transport_type TEXT NOT NULL DEFAULT 'http', connection_id TEXT,
312
+ connected_at BIGINT NOT NULL, last_heartbeat BIGINT NOT NULL,
313
+ connection_metadata TEXT, created_at BIGINT NOT NULL,
314
+ UNIQUE(agent_id, connection_id)
315
+ );
316
+ CREATE TABLE IF NOT EXISTS users (
317
+ id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE,
318
+ password_hash TEXT NOT NULL, name TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
319
+ );
320
+ CREATE TABLE IF NOT EXISTS accounts (
321
+ id TEXT PRIMARY KEY NOT NULL, user_id TEXT NOT NULL, account_id TEXT NOT NULL,
322
+ provider_id TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
323
+ );
324
+ CREATE TABLE IF NOT EXISTS sessions (
325
+ id TEXT PRIMARY KEY NOT NULL, user_id TEXT NOT NULL, token TEXT NOT NULL UNIQUE,
326
+ expires_at TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
327
+ );
328
+ CREATE TABLE IF NOT EXISTS verifications (
329
+ id TEXT PRIMARY KEY NOT NULL, identifier TEXT NOT NULL, value TEXT NOT NULL,
330
+ expires_at TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
331
+ );
332
+ CREATE TABLE IF NOT EXISTS organization (
333
+ id TEXT PRIMARY KEY NOT NULL, name TEXT NOT NULL,
334
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
335
+ updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
336
+ );
337
+ CREATE TABLE IF NOT EXISTS claim_codes (
338
+ id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, code TEXT NOT NULL UNIQUE,
339
+ expires_at INTEGER NOT NULL, created_at INTEGER NOT NULL
340
+ );
341
+ CREATE TABLE IF NOT EXISTS org_agent_keys (
342
+ id TEXT PRIMARY KEY NOT NULL, organization_id TEXT NOT NULL,
343
+ agent_id TEXT NOT NULL, created_by TEXT NOT NULL, created_at INTEGER NOT NULL
344
+ );
345
+ CREATE TABLE IF NOT EXISTS _signaldock_meta (
346
+ key TEXT PRIMARY KEY, value TEXT NOT NULL,
347
+ updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
348
+ );
349
+ CREATE TABLE IF NOT EXISTS _signaldock_migrations (
350
+ name TEXT PRIMARY KEY,
351
+ applied_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
352
+ );
353
+ `);
354
+
355
+ for (const agent of agents) {
356
+ db.prepare(
357
+ `INSERT OR IGNORE INTO agents
358
+ (id, agent_id, name, created_at, updated_at, requires_reauth)
359
+ VALUES (?, ?, ?, ?, ?, ?)`,
360
+ ).run(agent.id, agent.agentId, agent.name, now, now, agent.requiresReauth ?? 0);
361
+ }
362
+
363
+ db.close();
364
+ return dbPath;
365
+ }
366
+
367
+ /**
368
+ * Run the signaldock→conduit migration with an isolated cleoHome mock.
369
+ * Always resets modules first so the import chain gets the fresh mock.
370
+ */
371
+ async function runMigration(
372
+ projectRoot: string,
373
+ cleoHome: string,
374
+ ): Promise<import('../migrate-signaldock-to-conduit.js').MigrationResult> {
375
+ vi.resetModules();
376
+ vi.doMock('../../paths.js', () => ({
377
+ getCleoHome: () => cleoHome,
378
+ getProjectRoot: () => projectRoot,
379
+ }));
380
+ vi.doMock('../global-salt.js', () => ({
381
+ getGlobalSalt: () => Buffer.alloc(32, 0xab),
382
+ __clearGlobalSaltCache: vi.fn(),
383
+ }));
384
+ vi.doMock('../signaldock-sqlite.js', () => ({
385
+ ensureGlobalSignaldockDb: vi.fn(async () => ({
386
+ action: 'exists',
387
+ path: join(cleoHome, 'signaldock.db'),
388
+ })),
389
+ getGlobalSignaldockDbPath: () => join(cleoHome, 'signaldock.db'),
390
+ }));
391
+ const { migrateSignaldockToConduit } = await import('../migrate-signaldock-to-conduit.js');
392
+ return migrateSignaldockToConduit(projectRoot);
393
+ }
394
+
395
+ // ---------------------------------------------------------------------------
396
+ // Suite
397
+ // ---------------------------------------------------------------------------
398
+
399
+ describe('T310: conduit + signaldock integration', () => {
400
+ let base: ReturnType<typeof makeTmpPair>;
401
+
402
+ beforeEach(() => {
403
+ vi.resetModules();
404
+ base = makeTmpPair('s');
405
+ });
406
+
407
+ afterEach(() => {
408
+ vi.restoreAllMocks();
409
+ base.cleanup();
410
+ });
411
+
412
+ // -------------------------------------------------------------------------
413
+ // Scenario 1: Fresh install creates conduit.db + global signaldock.db + global-salt
414
+ // -------------------------------------------------------------------------
415
+
416
+ it('Scenario 1: fresh install creates conduit.db, global signaldock.db, and global-salt', async () => {
417
+ const { cleoHome, projectRoot } = base;
418
+ seedKeys(cleoHome);
419
+
420
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
421
+ vi.doMock('../global-salt.js', () => ({
422
+ getGlobalSalt: () => Buffer.alloc(32, 0xcd),
423
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
424
+ __clearGlobalSaltCache: vi.fn(),
425
+ }));
426
+
427
+ const { ensureConduitDb } = await import('../conduit-sqlite.js');
428
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
429
+
430
+ const conduitResult = ensureConduitDb(projectRoot);
431
+ expect(conduitResult.action).toBe('created');
432
+ expect(existsSync(conduitResult.path)).toBe(true);
433
+
434
+ const sdResult = await ensureGlobalSignaldockDb();
435
+ expect(sdResult.action).toBe('created');
436
+ expect(existsSync(sdResult.path)).toBe(true);
437
+
438
+ // Global-salt already written by seedKeys; verify it exists
439
+ expect(existsSync(join(cleoHome, 'global-salt'))).toBe(true);
440
+
441
+ // project_agent_refs table must exist and be empty
442
+ const conduitDb = new DatabaseSync(conduitResult.path, { readonly: true });
443
+ const refs = conduitDb.prepare('SELECT COUNT(*) as n FROM project_agent_refs').get() as {
444
+ n: number;
445
+ };
446
+ expect(refs.n).toBe(0);
447
+ conduitDb.close();
448
+
449
+ // global agents table must exist and be empty
450
+ const globalDb = new DatabaseSync(sdResult.path, { readonly: true });
451
+ const agents = globalDb.prepare('SELECT COUNT(*) as n FROM agents').get() as { n: number };
452
+ expect(agents.n).toBe(0);
453
+ globalDb.close();
454
+ });
455
+
456
+ // -------------------------------------------------------------------------
457
+ // Scenario 2: createProjectAgent writes identity globally + attachment locally
458
+ // -------------------------------------------------------------------------
459
+
460
+ it('Scenario 2: createProjectAgent writes global identity and local project_agent_refs row', async () => {
461
+ const { cleoHome, projectRoot } = base;
462
+ const { machineKey, globalSalt } = seedKeys(cleoHome);
463
+
464
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
465
+ vi.doMock('../global-salt.js', () => ({
466
+ getGlobalSalt: () => globalSalt,
467
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
468
+ __clearGlobalSaltCache: vi.fn(),
469
+ }));
470
+
471
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
472
+ const { ensureConduitDb, closeConduitDb } = await import('../conduit-sqlite.js');
473
+ const { createProjectAgent } = await import('../agent-registry-accessor.js');
474
+ const { deriveApiKey } = await import('../api-key-kdf.js');
475
+
476
+ await ensureGlobalSignaldockDb();
477
+ ensureConduitDb(projectRoot);
478
+ closeConduitDb();
479
+
480
+ const spec = {
481
+ agentId: 'integ-agent-sc2',
482
+ displayName: 'Scenario Two Agent',
483
+ apiKey: 'sk_test_sc2',
484
+ apiBaseUrl: 'https://api.signaldock.io',
485
+ privacyTier: 'public' as const,
486
+ capabilities: [],
487
+ skills: [],
488
+ transportType: 'http' as const,
489
+ transportConfig: {},
490
+ isActive: true,
491
+ };
492
+
493
+ const result = createProjectAgent(projectRoot, spec);
494
+ expect(result.agentId).toBe(spec.agentId);
495
+ expect(result.projectRef).not.toBeNull();
496
+ expect(result.projectRef?.enabled).toBe(1);
497
+
498
+ // Verify global signaldock.db has the agent row
499
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'), { readonly: true });
500
+ const agentRow = globalDb
501
+ .prepare('SELECT agent_id FROM agents WHERE agent_id = ?')
502
+ .get(spec.agentId) as { agent_id: string } | undefined;
503
+ expect(agentRow).toBeDefined();
504
+ expect(agentRow?.agent_id).toBe(spec.agentId);
505
+ globalDb.close();
506
+
507
+ // Verify conduit.db has a project_agent_refs row
508
+ const conduitDb = new DatabaseSync(join(projectRoot, '.cleo', 'conduit.db'), {
509
+ readonly: true,
510
+ });
511
+ const refRow = conduitDb
512
+ .prepare('SELECT agent_id, enabled FROM project_agent_refs WHERE agent_id = ?')
513
+ .get(spec.agentId) as { agent_id: string; enabled: number } | undefined;
514
+ expect(refRow).toBeDefined();
515
+ expect(refRow?.enabled).toBe(1);
516
+ conduitDb.close();
517
+
518
+ // Verify KDF: key should be HMAC-SHA256(machineKey || globalSalt, agentId)
519
+ const expectedKey = deriveApiKey({ machineKey, globalSalt, agentId: spec.agentId });
520
+ expect(expectedKey).toHaveLength(32);
521
+ // KDF must be different from legacy scheme (which uses projectPath instead of globalSalt)
522
+ const { deriveLegacyProjectKey } = await import('../api-key-kdf.js');
523
+ const legacyKey = deriveLegacyProjectKey(machineKey, projectRoot);
524
+ expect(Buffer.compare(expectedKey, legacyKey)).not.toBe(0);
525
+ });
526
+
527
+ // -------------------------------------------------------------------------
528
+ // Scenario 3: lookupAgent cross-DB join — default project-scoped
529
+ // -------------------------------------------------------------------------
530
+
531
+ it('Scenario 3: lookupAgent returns null without project ref; returns agent with includeGlobal=true', async () => {
532
+ const { cleoHome, projectRoot } = base;
533
+ const { globalSalt } = seedKeys(cleoHome);
534
+
535
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
536
+ vi.doMock('../global-salt.js', () => ({
537
+ getGlobalSalt: () => globalSalt,
538
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
539
+ __clearGlobalSaltCache: vi.fn(),
540
+ }));
541
+
542
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
543
+ const { ensureConduitDb, closeConduitDb } = await import('../conduit-sqlite.js');
544
+ const { lookupAgent } = await import('../agent-registry-accessor.js');
545
+
546
+ await ensureGlobalSignaldockDb();
547
+ ensureConduitDb(projectRoot);
548
+ closeConduitDb();
549
+
550
+ // Seed agent X into global only (no project ref)
551
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'));
552
+ insertGlobalAgent(globalDb, 'global-agent-x', 'Agent X');
553
+ globalDb.close();
554
+
555
+ // Default (INNER JOIN): must return null because no project_agent_refs row
556
+ const defaultResult = lookupAgent(projectRoot, 'global-agent-x');
557
+ expect(defaultResult).toBeNull();
558
+
559
+ // includeGlobal=true: must return the agent with projectRef: null
560
+ const globalResult = lookupAgent(projectRoot, 'global-agent-x', { includeGlobal: true });
561
+ expect(globalResult).not.toBeNull();
562
+ expect(globalResult?.agentId).toBe('global-agent-x');
563
+ expect(globalResult?.projectRef).toBeNull();
564
+ });
565
+
566
+ // -------------------------------------------------------------------------
567
+ // Scenario 4: listAgentsForProject — INNER vs OUTER join semantics
568
+ // -------------------------------------------------------------------------
569
+
570
+ it('Scenario 4: listAgentsForProject INNER returns only attached; OUTER returns all with correct projectRef', async () => {
571
+ const { cleoHome, projectRoot } = base;
572
+ const { globalSalt } = seedKeys(cleoHome);
573
+
574
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
575
+ vi.doMock('../global-salt.js', () => ({
576
+ getGlobalSalt: () => globalSalt,
577
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
578
+ __clearGlobalSaltCache: vi.fn(),
579
+ }));
580
+
581
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
582
+ const { ensureConduitDb, closeConduitDb } = await import('../conduit-sqlite.js');
583
+ const { listAgentsForProject } = await import('../agent-registry-accessor.js');
584
+
585
+ await ensureGlobalSignaldockDb();
586
+ ensureConduitDb(projectRoot);
587
+ closeConduitDb();
588
+
589
+ // Seed 3 global agents
590
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'));
591
+ insertGlobalAgent(globalDb, 'agent-x', 'Agent X');
592
+ insertGlobalAgent(globalDb, 'agent-y', 'Agent Y');
593
+ insertGlobalAgent(globalDb, 'agent-z', 'Agent Z');
594
+ globalDb.close();
595
+
596
+ // Attach only Y and Z to the project
597
+ const conduitDb = new DatabaseSync(join(projectRoot, '.cleo', 'conduit.db'));
598
+ insertConduitRef(conduitDb, 'agent-y');
599
+ insertConduitRef(conduitDb, 'agent-z');
600
+ conduitDb.close();
601
+
602
+ // Default INNER join: should return only Y and Z
603
+ const innerResult = listAgentsForProject(projectRoot);
604
+ expect(innerResult).toHaveLength(2);
605
+ const innerIds = innerResult.map((a) => a.agentId).sort();
606
+ expect(innerIds).toEqual(['agent-y', 'agent-z']);
607
+ // Both must have populated projectRef
608
+ for (const agent of innerResult) {
609
+ expect(agent.projectRef).not.toBeNull();
610
+ }
611
+
612
+ // includeGlobal=true: should return all 3 agents
613
+ const globalResult = listAgentsForProject(projectRoot, { includeGlobal: true });
614
+ expect(globalResult).toHaveLength(3);
615
+ const globalIds = globalResult.map((a) => a.agentId).sort();
616
+ expect(globalIds).toEqual(['agent-x', 'agent-y', 'agent-z']);
617
+
618
+ // X must have projectRef: null (not attached)
619
+ const agentX = globalResult.find((a) => a.agentId === 'agent-x');
620
+ expect(agentX?.projectRef).toBeNull();
621
+
622
+ // Y and Z must have populated projectRef
623
+ const agentY = globalResult.find((a) => a.agentId === 'agent-y');
624
+ expect(agentY?.projectRef).not.toBeNull();
625
+ const agentZ = globalResult.find((a) => a.agentId === 'agent-z');
626
+ expect(agentZ?.projectRef).not.toBeNull();
627
+ });
628
+
629
+ // -------------------------------------------------------------------------
630
+ // Scenario 5: Cross-project visibility isolation
631
+ // -------------------------------------------------------------------------
632
+
633
+ it('Scenario 5: agent created in project A is invisible to project B by default', async () => {
634
+ const { cleoHome, projectRoot: projectA } = base;
635
+ const projectB = makeSecondProject(join(cleoHome, '..'));
636
+ const { globalSalt } = seedKeys(cleoHome);
637
+
638
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
639
+ vi.doMock('../global-salt.js', () => ({
640
+ getGlobalSalt: () => globalSalt,
641
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
642
+ __clearGlobalSaltCache: vi.fn(),
643
+ }));
644
+
645
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
646
+ const { ensureConduitDb, closeConduitDb } = await import('../conduit-sqlite.js');
647
+ const { createProjectAgent, listAgentsForProject } = await import(
648
+ '../agent-registry-accessor.js'
649
+ );
650
+
651
+ await ensureGlobalSignaldockDb();
652
+ ensureConduitDb(projectA);
653
+ closeConduitDb();
654
+ ensureConduitDb(projectB);
655
+ closeConduitDb();
656
+
657
+ // Create agent in A
658
+ createProjectAgent(projectA, {
659
+ agentId: 'cross-project-agent',
660
+ displayName: 'Cross Project Agent',
661
+ apiKey: 'sk_test_cross',
662
+ apiBaseUrl: 'https://api.signaldock.io',
663
+ privacyTier: 'public',
664
+ capabilities: [],
665
+ skills: [],
666
+ transportType: 'http',
667
+ transportConfig: {},
668
+ isActive: true,
669
+ });
670
+
671
+ // A must see the agent
672
+ const inA = listAgentsForProject(projectA);
673
+ const agentInA = inA.find((a) => a.agentId === 'cross-project-agent');
674
+ expect(agentInA).toBeDefined();
675
+
676
+ // B must NOT see the agent by default (INNER JOIN — no project_agent_refs row in B)
677
+ const inB = listAgentsForProject(projectB);
678
+ const agentInB = inB.find((a) => a.agentId === 'cross-project-agent');
679
+ expect(agentInB).toBeUndefined();
680
+
681
+ // B with includeGlobal=true should see the agent but with projectRef: null
682
+ const inBGlobal = listAgentsForProject(projectB, { includeGlobal: true });
683
+ const agentInBGlobal = inBGlobal.find((a) => a.agentId === 'cross-project-agent');
684
+ expect(agentInBGlobal).toBeDefined();
685
+ expect(agentInBGlobal?.projectRef).toBeNull();
686
+ });
687
+
688
+ // -------------------------------------------------------------------------
689
+ // Scenario 6: Attach + detach across projects
690
+ // -------------------------------------------------------------------------
691
+
692
+ it('Scenario 6: attach to B makes agent visible in B; detach from A leaves B intact; global untouched', async () => {
693
+ const { cleoHome, projectRoot: projectA } = base;
694
+ const projectB = makeSecondProject(join(cleoHome, '..'));
695
+ const { globalSalt } = seedKeys(cleoHome);
696
+
697
+ vi.doMock('../../paths.js', () => ({ getCleoHome: () => cleoHome }));
698
+ vi.doMock('../global-salt.js', () => ({
699
+ getGlobalSalt: () => globalSalt,
700
+ getGlobalSaltPath: () => join(cleoHome, 'global-salt'),
701
+ __clearGlobalSaltCache: vi.fn(),
702
+ }));
703
+
704
+ const { ensureGlobalSignaldockDb } = await import('../signaldock-sqlite.js');
705
+ const { ensureConduitDb, closeConduitDb } = await import('../conduit-sqlite.js');
706
+ const {
707
+ createProjectAgent,
708
+ attachAgentToProject,
709
+ detachAgentFromProject,
710
+ listAgentsForProject,
711
+ } = await import('../agent-registry-accessor.js');
712
+
713
+ await ensureGlobalSignaldockDb();
714
+ ensureConduitDb(projectA);
715
+ closeConduitDb();
716
+ ensureConduitDb(projectB);
717
+ closeConduitDb();
718
+
719
+ // Create agent in A
720
+ createProjectAgent(projectA, {
721
+ agentId: 'attach-detach-agent',
722
+ displayName: 'Attach Detach Agent',
723
+ apiKey: 'sk_test_ad',
724
+ apiBaseUrl: 'https://api.signaldock.io',
725
+ privacyTier: 'public',
726
+ capabilities: [],
727
+ skills: [],
728
+ transportType: 'http',
729
+ transportConfig: {},
730
+ isActive: true,
731
+ });
732
+
733
+ // Attach to B
734
+ attachAgentToProject(projectB, 'attach-detach-agent');
735
+
736
+ // Now both A and B should see the agent
737
+ const inA = listAgentsForProject(projectA);
738
+ expect(inA.find((a) => a.agentId === 'attach-detach-agent')).toBeDefined();
739
+ const inB = listAgentsForProject(projectB);
740
+ expect(inB.find((a) => a.agentId === 'attach-detach-agent')).toBeDefined();
741
+
742
+ // Detach from A
743
+ detachAgentFromProject(projectA, 'attach-detach-agent');
744
+
745
+ // A must no longer see it
746
+ const inAAfter = listAgentsForProject(projectA);
747
+ expect(inAAfter.find((a) => a.agentId === 'attach-detach-agent')).toBeUndefined();
748
+
749
+ // B must still see it
750
+ const inBAfter = listAgentsForProject(projectB);
751
+ expect(inBAfter.find((a) => a.agentId === 'attach-detach-agent')).toBeDefined();
752
+
753
+ // Global identity must still exist
754
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'), { readonly: true });
755
+ const globalRow = globalDb
756
+ .prepare("SELECT agent_id FROM agents WHERE agent_id = 'attach-detach-agent'")
757
+ .get() as { agent_id: string } | undefined;
758
+ globalDb.close();
759
+ expect(globalRow).toBeDefined();
760
+ });
761
+
762
+ // -------------------------------------------------------------------------
763
+ // Scenario 7: Migration from legacy signaldock.db
764
+ // -------------------------------------------------------------------------
765
+
766
+ it('Scenario 7: migration preserves messages, creates conduit.db, global signaldock.db, .pre-t310.bak', async () => {
767
+ const { cleoHome, projectRoot } = base;
768
+ const now = Math.floor(Date.now() / 1000);
769
+
770
+ // Seed global signaldock.db (the migration will populate it)
771
+ createGlobalSignaldockDbFile(cleoHome, []);
772
+
773
+ // Create legacy project signaldock.db with 3 agents + 5 messages
774
+ createLegacySignaldockDb(
775
+ projectRoot,
776
+ [
777
+ { id: 'a1', agentId: 'mig-agent-1', name: 'Mig Agent 1', createdAt: now },
778
+ { id: 'a2', agentId: 'mig-agent-2', name: 'Mig Agent 2', createdAt: now },
779
+ { id: 'a3', agentId: 'mig-agent-3', name: 'Mig Agent 3', createdAt: now },
780
+ ],
781
+ [
782
+ {
783
+ id: 'msg-1',
784
+ conversationId: 'conv-1',
785
+ fromAgentId: 'mig-agent-1',
786
+ toAgentId: 'mig-agent-2',
787
+ content: 'hello',
788
+ createdAt: now,
789
+ },
790
+ {
791
+ id: 'msg-2',
792
+ conversationId: 'conv-1',
793
+ fromAgentId: 'mig-agent-2',
794
+ toAgentId: 'mig-agent-1',
795
+ content: 'world',
796
+ createdAt: now + 1,
797
+ },
798
+ {
799
+ id: 'msg-3',
800
+ conversationId: 'conv-1',
801
+ fromAgentId: 'mig-agent-1',
802
+ toAgentId: 'mig-agent-2',
803
+ content: 'foo',
804
+ createdAt: now + 2,
805
+ },
806
+ {
807
+ id: 'msg-4',
808
+ conversationId: 'conv-1',
809
+ fromAgentId: 'mig-agent-2',
810
+ toAgentId: 'mig-agent-1',
811
+ content: 'bar',
812
+ createdAt: now + 3,
813
+ },
814
+ {
815
+ id: 'msg-5',
816
+ conversationId: 'conv-1',
817
+ fromAgentId: 'mig-agent-1',
818
+ toAgentId: 'mig-agent-2',
819
+ content: 'baz',
820
+ createdAt: now + 4,
821
+ },
822
+ ],
823
+ [
824
+ {
825
+ id: 'conv-1',
826
+ participants: '["mig-agent-1","mig-agent-2"]',
827
+ createdAt: now,
828
+ updatedAt: now,
829
+ },
830
+ ],
831
+ );
832
+
833
+ const result = await runMigration(projectRoot, cleoHome);
834
+
835
+ expect(result.status).toBe('migrated');
836
+ expect(result.agentsCopied).toBe(3);
837
+ expect(result.errors).toHaveLength(0);
838
+
839
+ // conduit.db created
840
+ const conduitPath = join(projectRoot, '.cleo', 'conduit.db');
841
+ expect(existsSync(conduitPath)).toBe(true);
842
+
843
+ // .pre-t310.bak created; legacy signaldock.db renamed
844
+ const bakPath = join(projectRoot, '.cleo', 'signaldock.db.pre-t310.bak');
845
+ expect(existsSync(bakPath)).toBe(true);
846
+ expect(existsSync(join(projectRoot, '.cleo', 'signaldock.db'))).toBe(false);
847
+
848
+ // conduit.db has 5 messages + 3 project_agent_refs
849
+ const conduitDb = new DatabaseSync(conduitPath, { readonly: true });
850
+ const msgCount = conduitDb.prepare('SELECT COUNT(*) as n FROM messages').get() as { n: number };
851
+ expect(msgCount.n).toBe(5);
852
+ const refCount = conduitDb.prepare('SELECT COUNT(*) as n FROM project_agent_refs').get() as {
853
+ n: number;
854
+ };
855
+ expect(refCount.n).toBe(3);
856
+ conduitDb.close();
857
+
858
+ // global signaldock.db has 3 agents with requires_reauth=1
859
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'), { readonly: true });
860
+ const globalAgents = globalDb
861
+ .prepare('SELECT agent_id, requires_reauth FROM agents ORDER BY agent_id')
862
+ .all() as Array<{ agent_id: string; requires_reauth: number }>;
863
+ expect(globalAgents).toHaveLength(3);
864
+ for (const agent of globalAgents) {
865
+ expect(agent.requires_reauth).toBe(1);
866
+ }
867
+ globalDb.close();
868
+ });
869
+
870
+ // -------------------------------------------------------------------------
871
+ // Scenario 8: Migration multi-project deduplication
872
+ // -------------------------------------------------------------------------
873
+
874
+ it('Scenario 8: migration on two projects deduplicates shared agent in global signaldock.db', async () => {
875
+ const { cleoHome } = base;
876
+
877
+ // Two isolated project roots sharing the same cleoHome
878
+ const projectA = join(cleoHome, '..', 'project-a');
879
+ const projectB = join(cleoHome, '..', 'project-b');
880
+ mkdirSync(join(projectA, '.cleo'), { recursive: true });
881
+ mkdirSync(join(projectB, '.cleo'), { recursive: true });
882
+
883
+ const now = Math.floor(Date.now() / 1000);
884
+
885
+ // Project A has agent X
886
+ createGlobalSignaldockDbFile(cleoHome, []);
887
+ createLegacySignaldockDb(projectA, [
888
+ { id: 'ax-id', agentId: 'shared-agent-x', name: 'Agent X from A', createdAt: now },
889
+ ]);
890
+
891
+ // Migrate A first
892
+ const resultA = await runMigration(projectA, cleoHome);
893
+ expect(resultA.status).toBe('migrated');
894
+ expect(resultA.agentsCopied).toBe(1);
895
+
896
+ // Project B has agent X + agent Y
897
+ createLegacySignaldockDb(projectB, [
898
+ { id: 'bx-id', agentId: 'shared-agent-x', name: 'Agent X from B', createdAt: now },
899
+ { id: 'by-id', agentId: 'agent-y-unique', name: 'Agent Y', createdAt: now },
900
+ ]);
901
+
902
+ // Migrate B second
903
+ const resultB = await runMigration(projectB, cleoHome);
904
+ expect(resultB.status).toBe('migrated');
905
+
906
+ // Global must have exactly 2 agents (X + Y), not 3 (INSERT OR IGNORE deduplicates X)
907
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'), { readonly: true });
908
+ const allAgents = globalDb
909
+ .prepare('SELECT agent_id FROM agents ORDER BY agent_id')
910
+ .all() as Array<{ agent_id: string }>;
911
+ const agentIds = allAgents.map((a) => a.agent_id);
912
+ expect(agentIds).toContain('shared-agent-x');
913
+ expect(agentIds).toContain('agent-y-unique');
914
+ // X must appear exactly once
915
+ expect(agentIds.filter((id) => id === 'shared-agent-x')).toHaveLength(1);
916
+ globalDb.close();
917
+
918
+ // Both projects must have their own project_agent_refs
919
+ const conduitA = new DatabaseSync(join(projectA, '.cleo', 'conduit.db'), { readonly: true });
920
+ const refsA = conduitA.prepare('SELECT agent_id FROM project_agent_refs').all() as Array<{
921
+ agent_id: string;
922
+ }>;
923
+ conduitA.close();
924
+ expect(refsA.map((r) => r.agent_id)).toContain('shared-agent-x');
925
+
926
+ const conduitB = new DatabaseSync(join(projectB, '.cleo', 'conduit.db'), { readonly: true });
927
+ const refsB = conduitB
928
+ .prepare('SELECT agent_id FROM project_agent_refs ORDER BY agent_id')
929
+ .all() as Array<{ agent_id: string }>;
930
+ conduitB.close();
931
+ expect(refsB.map((r) => r.agent_id)).toContain('shared-agent-x');
932
+ expect(refsB.map((r) => r.agent_id)).toContain('agent-y-unique');
933
+ });
934
+
935
+ // -------------------------------------------------------------------------
936
+ // Scenario 9: Migration is idempotent
937
+ // -------------------------------------------------------------------------
938
+
939
+ it('Scenario 9: second migration call returns no-op; no duplicate rows', async () => {
940
+ const { cleoHome, projectRoot } = base;
941
+ const now = Math.floor(Date.now() / 1000);
942
+
943
+ createGlobalSignaldockDbFile(cleoHome, []);
944
+ createLegacySignaldockDb(projectRoot, [
945
+ { id: 'idem-id', agentId: 'idempotent-agent', name: 'Idempotent Agent', createdAt: now },
946
+ ]);
947
+
948
+ // First migration
949
+ const first = await runMigration(projectRoot, cleoHome);
950
+ expect(first.status).toBe('migrated');
951
+ expect(first.agentsCopied).toBe(1);
952
+
953
+ // Second migration — conduit.db already exists
954
+ const second = await runMigration(projectRoot, cleoHome);
955
+ expect(second.status).toBe('no-op');
956
+ expect(second.errors).toHaveLength(0);
957
+
958
+ // Verify no duplicate rows in conduit.db
959
+ const conduitDb = new DatabaseSync(join(projectRoot, '.cleo', 'conduit.db'), {
960
+ readonly: true,
961
+ });
962
+ const refRows = conduitDb
963
+ .prepare("SELECT COUNT(*) as n FROM project_agent_refs WHERE agent_id = 'idempotent-agent'")
964
+ .get() as { n: number };
965
+ expect(refRows.n).toBe(1);
966
+ conduitDb.close();
967
+
968
+ // Verify no duplicate rows in global signaldock.db
969
+ const globalDb = new DatabaseSync(join(cleoHome, 'signaldock.db'), { readonly: true });
970
+ const globalRows = globalDb
971
+ .prepare("SELECT COUNT(*) as n FROM agents WHERE agent_id = 'idempotent-agent'")
972
+ .get() as { n: number };
973
+ globalDb.close();
974
+ expect(globalRows.n).toBe(1);
975
+ });
976
+
977
+ // -------------------------------------------------------------------------
978
+ // Scenario 10: KDF binds to machine + salt + agentId
979
+ // -------------------------------------------------------------------------
980
+
981
+ it('Scenario 10: KDF output changes with salt, agentId, and machineKey independently', async () => {
982
+ vi.resetModules();
983
+ const { deriveApiKey } = await import('../api-key-kdf.js');
984
+
985
+ const machineKey = Buffer.alloc(32, 0x01);
986
+ const s1 = Buffer.alloc(32, 0x10);
987
+ const s2 = Buffer.alloc(32, 0x20);
988
+
989
+ // K1 = derive(agentId=X, salt=S1)
990
+ const k1 = deriveApiKey({ machineKey, globalSalt: s1, agentId: 'agent-x' });
991
+ // K2 = derive(agentId=X, salt=S2) — must differ (salt change)
992
+ const k2 = deriveApiKey({ machineKey, globalSalt: s2, agentId: 'agent-x' });
993
+ expect(Buffer.compare(k1, k2)).not.toBe(0);
994
+
995
+ // K3 = derive(agentId=Y, salt=S1) — must differ from K1 (agentId change)
996
+ const k3 = deriveApiKey({ machineKey, globalSalt: s1, agentId: 'agent-y' });
997
+ expect(Buffer.compare(k1, k3)).not.toBe(0);
998
+
999
+ // K4 = derive with different machineKey — must differ from K1 (machine change)
1000
+ const differentMachineKey = Buffer.alloc(32, 0x99);
1001
+ const k4 = deriveApiKey({
1002
+ machineKey: differentMachineKey,
1003
+ globalSalt: s1,
1004
+ agentId: 'agent-x',
1005
+ });
1006
+ expect(Buffer.compare(k1, k4)).not.toBe(0);
1007
+
1008
+ // All derived keys must be exactly 32 bytes
1009
+ for (const k of [k1, k2, k3, k4]) {
1010
+ expect(k).toHaveLength(32);
1011
+ }
1012
+ });
1013
+
1014
+ // -------------------------------------------------------------------------
1015
+ // Scenario 11: Backup registry includes conduit + global signaldock + global-salt
1016
+ // -------------------------------------------------------------------------
1017
+
1018
+ it('Scenario 11: vacuumIntoBackupAll snapshots conduit.db; vacuumIntoGlobalBackup snapshots signaldock; backupGlobalSalt copies salt', async () => {
1019
+ vi.resetModules();
1020
+
1021
+ const { cleoHome, projectRoot } = base;
1022
+ const cleoDir = join(projectRoot, '.cleo');
1023
+
1024
+ // Seed project DBs
1025
+ const conduitPath = join(cleoDir, 'conduit.db');
1026
+ const tasksPath = join(cleoDir, 'tasks.db');
1027
+ const brainPath = join(cleoDir, 'brain.db');
1028
+ const sdPath = join(cleoHome, 'signaldock.db');
1029
+ const saltPath = join(cleoHome, 'global-salt');
1030
+
1031
+ for (const dbPath of [conduitPath, tasksPath, brainPath, sdPath]) {
1032
+ const db = new DatabaseSync(dbPath);
1033
+ db.exec(
1034
+ `CREATE TABLE IF NOT EXISTS stub (id INTEGER PRIMARY KEY); INSERT INTO stub VALUES (1);`,
1035
+ );
1036
+ db.close();
1037
+ }
1038
+ // Write a 32-byte global-salt file
1039
+ writeFileSync(saltPath, Buffer.alloc(32, 0xef), { mode: 0o600 });
1040
+
1041
+ // Open live handles that the backup module will call
1042
+ const conduitDb = new DatabaseSync(conduitPath);
1043
+ const tasksDb = new DatabaseSync(tasksPath);
1044
+ const brainDb = new DatabaseSync(brainPath);
1045
+ const sdDb = new DatabaseSync(sdPath);
1046
+
1047
+ // Mock the native DB getters and path helpers
1048
+ vi.doMock('../sqlite.js', () => ({ getNativeDb: () => tasksDb, getDb: () => tasksDb }));
1049
+ vi.doMock('../brain-sqlite.js', () => ({ getBrainNativeDb: () => brainDb }));
1050
+ vi.doMock('../conduit-sqlite.js', () => ({ getConduitNativeDb: () => conduitDb }));
1051
+ vi.doMock('../signaldock-sqlite.js', () => ({
1052
+ getGlobalSignaldockNativeDb: () => sdDb,
1053
+ getGlobalSignaldockDbPath: () => sdPath,
1054
+ }));
1055
+ vi.doMock('../nexus-sqlite.js', () => ({ getNexusNativeDb: () => null }));
1056
+ vi.doMock('../global-salt.js', () => ({ getGlobalSaltPath: () => saltPath }));
1057
+ vi.doMock('../../paths.js', () => ({
1058
+ getCleoHome: () => cleoHome,
1059
+ getCleoDir: () => cleoDir,
1060
+ }));
1061
+
1062
+ const { vacuumIntoBackupAll, vacuumIntoGlobalBackup, backupGlobalSalt, listSqliteBackupsAll } =
1063
+ await import('../sqlite-backup.js');
1064
+
1065
+ // Project-tier backup (tasks, brain, conduit)
1066
+ await vacuumIntoBackupAll({ cwd: projectRoot, force: true });
1067
+
1068
+ tasksDb.close();
1069
+ brainDb.close();
1070
+ conduitDb.close();
1071
+
1072
+ const projectBackupDir = join(cleoDir, 'backups', 'sqlite');
1073
+ expect(existsSync(projectBackupDir)).toBe(true);
1074
+
1075
+ const allBackups = listSqliteBackupsAll(projectRoot);
1076
+ expect(allBackups).toHaveProperty('conduit');
1077
+ expect(allBackups['conduit']?.length).toBeGreaterThanOrEqual(1);
1078
+
1079
+ // Conduit snapshot must pass integrity_check
1080
+ const conduitSnapPath = allBackups['conduit']?.[0]?.path;
1081
+ expect(conduitSnapPath).toBeDefined();
1082
+ if (conduitSnapPath) {
1083
+ const snapDb = new DatabaseSync(conduitSnapPath, { readonly: true });
1084
+ const ic = snapDb.prepare('PRAGMA integrity_check').get() as Record<string, unknown>;
1085
+ snapDb.close();
1086
+ expect(ic['integrity_check']).toBe('ok');
1087
+ }
1088
+
1089
+ // Global-tier backup: signaldock
1090
+ const sdResult = await vacuumIntoGlobalBackup('signaldock', { cleoHomeOverride: cleoHome });
1091
+ sdDb.close();
1092
+
1093
+ expect(sdResult.snapshotPath).toBeTruthy();
1094
+ expect(existsSync(sdResult.snapshotPath)).toBe(true);
1095
+ expect(sdResult.snapshotPath).toContain('signaldock-');
1096
+
1097
+ // Global-tier backup: global-salt
1098
+ const saltResult = await backupGlobalSalt({ cleoHomeOverride: cleoHome });
1099
+ expect(saltResult.snapshotPath).toBeTruthy();
1100
+ expect(existsSync(saltResult.snapshotPath)).toBe(true);
1101
+
1102
+ // Verify salt backup is exactly 32 bytes and has 0o600 permissions
1103
+ const saltBackupStat = statSync(saltResult.snapshotPath);
1104
+ expect(saltBackupStat.size).toBe(32);
1105
+ if (process.platform !== 'win32') {
1106
+ expect(saltBackupStat.mode & 0o777).toBe(0o600);
1107
+ }
1108
+
1109
+ // Verify content matches the original salt
1110
+ const saltBackupContent = readFileSync(saltResult.snapshotPath);
1111
+ expect(Buffer.compare(saltBackupContent, Buffer.alloc(32, 0xef))).toBe(0);
1112
+ });
1113
+
1114
+ // -------------------------------------------------------------------------
1115
+ // Scenario 12: CLI startup wires migration (smoke — needsMigration detection)
1116
+ // -------------------------------------------------------------------------
1117
+
1118
+ it('Scenario 12: needsSignaldockToConduitMigration detects legacy correctly in all three states', async () => {
1119
+ const { projectRoot } = base;
1120
+ const cleoHome = base.cleoHome;
1121
+
1122
+ vi.doMock('../../paths.js', () => ({
1123
+ getCleoHome: () => cleoHome,
1124
+ getProjectRoot: () => projectRoot,
1125
+ }));
1126
+
1127
+ const { needsSignaldockToConduitMigration } = await import(
1128
+ '../migrate-signaldock-to-conduit.js'
1129
+ );
1130
+
1131
+ // State 1: neither signaldock.db nor conduit.db — fresh install, no migration needed
1132
+ const freshResult = needsSignaldockToConduitMigration(projectRoot);
1133
+ expect(freshResult).toBe(false);
1134
+
1135
+ // State 2: signaldock.db present, conduit.db absent — migration needed
1136
+ writeFileSync(join(projectRoot, '.cleo', 'signaldock.db'), '');
1137
+ // Put a real valid SQLite DB there so the detection test doesn't fail on file format
1138
+ const tmpDb = new DatabaseSync(join(projectRoot, '.cleo', 'signaldock.db'));
1139
+ tmpDb.exec('CREATE TABLE t (id INTEGER PRIMARY KEY)');
1140
+ tmpDb.close();
1141
+
1142
+ const needsMig = needsSignaldockToConduitMigration(projectRoot);
1143
+ expect(needsMig).toBe(true);
1144
+
1145
+ // State 3: conduit.db present — migration already done, no-op
1146
+ writeFileSync(join(projectRoot, '.cleo', 'conduit.db'), '');
1147
+ const afterMig = needsSignaldockToConduitMigration(projectRoot);
1148
+ expect(afterMig).toBe(false);
1149
+ });
1150
+ });