@cleocode/core 2026.3.74 → 2026.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/agent-schema.d.ts.map +1 -1
  3. package/dist/agents/retry.js +26 -21
  4. package/dist/agents/retry.js.map +1 -1
  5. package/dist/cant/approval.d.ts +110 -0
  6. package/dist/cant/approval.d.ts.map +1 -0
  7. package/dist/cant/approval.js +185 -0
  8. package/dist/cant/approval.js.map +1 -0
  9. package/dist/cant/context-builder.d.ts +79 -0
  10. package/dist/cant/context-builder.d.ts.map +1 -0
  11. package/dist/cant/context-builder.js +117 -0
  12. package/dist/cant/context-builder.js.map +1 -0
  13. package/dist/cant/discretion.d.ts +95 -0
  14. package/dist/cant/discretion.d.ts.map +1 -0
  15. package/dist/cant/discretion.js +116 -0
  16. package/dist/cant/discretion.js.map +1 -0
  17. package/dist/cant/index.d.ts +25 -0
  18. package/dist/cant/index.d.ts.map +1 -0
  19. package/dist/cant/index.js +23 -0
  20. package/dist/cant/index.js.map +1 -0
  21. package/dist/cant/parallel-runner.d.ts +38 -0
  22. package/dist/cant/parallel-runner.d.ts.map +1 -0
  23. package/dist/cant/parallel-runner.js +173 -0
  24. package/dist/cant/parallel-runner.js.map +1 -0
  25. package/dist/cant/types.d.ts +127 -0
  26. package/dist/cant/types.d.ts.map +1 -0
  27. package/dist/cant/types.js +11 -0
  28. package/dist/cant/types.js.map +1 -0
  29. package/dist/cant/workflow-executor.d.ts +105 -0
  30. package/dist/cant/workflow-executor.d.ts.map +1 -0
  31. package/dist/cant/workflow-executor.js +440 -0
  32. package/dist/cant/workflow-executor.js.map +1 -0
  33. package/dist/cleo.js +21 -1
  34. package/dist/cleo.js.map +1 -1
  35. package/dist/code/index.d.ts +10 -0
  36. package/dist/code/index.d.ts.map +1 -0
  37. package/dist/code/outline.d.ts +51 -0
  38. package/dist/code/outline.d.ts.map +1 -0
  39. package/dist/code/parser.d.ts +30 -0
  40. package/dist/code/parser.d.ts.map +1 -0
  41. package/dist/code/search.d.ts +42 -0
  42. package/dist/code/search.d.ts.map +1 -0
  43. package/dist/code/unfold.d.ts +44 -0
  44. package/dist/code/unfold.d.ts.map +1 -0
  45. package/dist/conduit/conduit-client.d.ts +35 -0
  46. package/dist/conduit/conduit-client.d.ts.map +1 -0
  47. package/dist/conduit/conduit-client.js +94 -0
  48. package/dist/conduit/conduit-client.js.map +1 -0
  49. package/dist/conduit/factory.d.ts +15 -0
  50. package/dist/conduit/factory.d.ts.map +1 -0
  51. package/dist/conduit/factory.js +35 -0
  52. package/dist/conduit/factory.js.map +1 -0
  53. package/dist/conduit/http-transport.d.ts +44 -0
  54. package/dist/conduit/http-transport.d.ts.map +1 -0
  55. package/dist/conduit/http-transport.js +165 -0
  56. package/dist/conduit/http-transport.js.map +1 -0
  57. package/dist/conduit/index.d.ts +15 -0
  58. package/dist/conduit/index.d.ts.map +1 -0
  59. package/dist/conduit/index.js +12 -0
  60. package/dist/conduit/index.js.map +1 -0
  61. package/dist/conduit/local-transport.d.ts +91 -0
  62. package/dist/conduit/local-transport.d.ts.map +1 -0
  63. package/dist/conduit/sse-transport.d.ts +68 -0
  64. package/dist/conduit/sse-transport.d.ts.map +1 -0
  65. package/dist/config.js +4 -3
  66. package/dist/config.js.map +1 -1
  67. package/dist/crypto/credentials.d.ts +40 -0
  68. package/dist/crypto/credentials.d.ts.map +1 -0
  69. package/dist/crypto/credentials.js +144 -0
  70. package/dist/crypto/credentials.js.map +1 -0
  71. package/dist/engine-result.d.ts +1 -1
  72. package/dist/engine-result.d.ts.map +1 -1
  73. package/dist/error-catalog.d.ts +1 -1
  74. package/dist/error-catalog.d.ts.map +1 -1
  75. package/dist/error-registry.d.ts +1 -1
  76. package/dist/error-registry.d.ts.map +1 -1
  77. package/dist/errors.d.ts +1 -1
  78. package/dist/errors.d.ts.map +1 -1
  79. package/dist/hooks/handlers/agent-hooks.d.ts.map +1 -1
  80. package/dist/hooks/handlers/agent-hooks.js +106 -0
  81. package/dist/hooks/handlers/agent-hooks.js.map +1 -0
  82. package/dist/hooks/handlers/context-hooks.d.ts.map +1 -1
  83. package/dist/hooks/handlers/context-hooks.js +111 -0
  84. package/dist/hooks/handlers/context-hooks.js.map +1 -0
  85. package/dist/hooks/handlers/error-hooks.d.ts +14 -5
  86. package/dist/hooks/handlers/error-hooks.d.ts.map +1 -1
  87. package/dist/hooks/handlers/error-hooks.js +15 -6
  88. package/dist/hooks/handlers/error-hooks.js.map +1 -1
  89. package/dist/hooks/handlers/file-hooks.d.ts.map +1 -1
  90. package/dist/hooks/handlers/file-hooks.js +35 -11
  91. package/dist/hooks/handlers/file-hooks.js.map +1 -1
  92. package/dist/hooks/handlers/handler-helpers.d.ts +41 -0
  93. package/dist/hooks/handlers/handler-helpers.d.ts.map +1 -0
  94. package/dist/hooks/handlers/handler-helpers.js +61 -0
  95. package/dist/hooks/handlers/handler-helpers.js.map +1 -0
  96. package/dist/hooks/handlers/index.js +10 -1
  97. package/dist/hooks/handlers/index.js.map +1 -1
  98. package/dist/hooks/handlers/mcp-hooks.d.ts.map +1 -1
  99. package/dist/hooks/handlers/mcp-hooks.js +88 -21
  100. package/dist/hooks/handlers/mcp-hooks.js.map +1 -1
  101. package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
  102. package/dist/hooks/handlers/session-hooks.js +5 -10
  103. package/dist/hooks/handlers/session-hooks.js.map +1 -1
  104. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  105. package/dist/hooks/handlers/task-hooks.js +5 -10
  106. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  107. package/dist/hooks/handlers/work-capture-hooks.d.ts.map +1 -1
  108. package/dist/hooks/handlers/work-capture-hooks.js +165 -0
  109. package/dist/hooks/handlers/work-capture-hooks.js.map +1 -0
  110. package/dist/hooks/payload-schemas.js +83 -26
  111. package/dist/hooks/payload-schemas.js.map +1 -1
  112. package/dist/hooks/provider-hooks.js +37 -5
  113. package/dist/hooks/provider-hooks.js.map +1 -1
  114. package/dist/hooks/registry.js +76 -23
  115. package/dist/hooks/registry.js.map +1 -1
  116. package/dist/hooks/types.js +17 -13
  117. package/dist/hooks/types.js.map +1 -1
  118. package/dist/index.d.ts +4 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +6452 -3371
  121. package/dist/index.js.map +4 -4
  122. package/dist/init.d.ts.map +1 -1
  123. package/dist/init.js +12 -0
  124. package/dist/init.js.map +1 -1
  125. package/dist/internal.d.ts +11 -1
  126. package/dist/internal.d.ts.map +1 -1
  127. package/dist/internal.js +10 -0
  128. package/dist/internal.js.map +1 -1
  129. package/dist/lib/index.d.ts +1 -0
  130. package/dist/lib/index.d.ts.map +1 -1
  131. package/dist/lib/tree-sitter-languages.d.ts +29 -0
  132. package/dist/lib/tree-sitter-languages.d.ts.map +1 -0
  133. package/dist/memory/brain-links.d.ts.map +1 -1
  134. package/dist/memory/brain-maintenance.d.ts +13 -0
  135. package/dist/memory/brain-maintenance.d.ts.map +1 -1
  136. package/dist/memory/brain-retrieval.d.ts +3 -0
  137. package/dist/memory/brain-retrieval.d.ts.map +1 -1
  138. package/dist/memory/brain-retrieval.js +5 -0
  139. package/dist/memory/brain-retrieval.js.map +1 -1
  140. package/dist/memory/decisions.d.ts.map +1 -1
  141. package/dist/mvi-helpers.d.ts +52 -0
  142. package/dist/mvi-helpers.d.ts.map +1 -0
  143. package/dist/mvi-helpers.js +74 -0
  144. package/dist/mvi-helpers.js.map +1 -0
  145. package/dist/nexus/index.js +2 -0
  146. package/dist/nexus/index.js.map +1 -1
  147. package/dist/nexus/workspace.d.ts.map +1 -1
  148. package/dist/nexus/workspace.js +355 -0
  149. package/dist/nexus/workspace.js.map +1 -0
  150. package/dist/orchestration/hierarchy.d.ts +32 -0
  151. package/dist/orchestration/hierarchy.d.ts.map +1 -0
  152. package/dist/orchestration/index.d.ts +1 -0
  153. package/dist/orchestration/index.d.ts.map +1 -1
  154. package/dist/output.d.ts +2 -2
  155. package/dist/output.d.ts.map +1 -1
  156. package/dist/output.js +40 -8
  157. package/dist/output.js.map +1 -1
  158. package/dist/pagination.d.ts +1 -1
  159. package/dist/pagination.d.ts.map +1 -1
  160. package/dist/sessions/find.d.ts +3 -0
  161. package/dist/sessions/find.d.ts.map +1 -1
  162. package/dist/sessions/find.js +3 -1
  163. package/dist/sessions/find.js.map +1 -1
  164. package/dist/sessions/index.d.ts.map +1 -1
  165. package/dist/sessions/index.js +11 -4
  166. package/dist/sessions/index.js.map +1 -1
  167. package/dist/sessions/snapshot.js +213 -0
  168. package/dist/sessions/snapshot.js.map +1 -0
  169. package/dist/store/agent-registry-accessor.d.ts +31 -0
  170. package/dist/store/agent-registry-accessor.d.ts.map +1 -0
  171. package/dist/store/agent-registry-accessor.js +169 -0
  172. package/dist/store/agent-registry-accessor.js.map +1 -0
  173. package/dist/store/converters.d.ts.map +1 -1
  174. package/dist/store/converters.js +2 -0
  175. package/dist/store/converters.js.map +1 -1
  176. package/dist/store/cross-db-cleanup.d.ts +34 -0
  177. package/dist/store/cross-db-cleanup.d.ts.map +1 -1
  178. package/dist/store/db-helpers.d.ts.map +1 -1
  179. package/dist/store/db-helpers.js +1 -0
  180. package/dist/store/db-helpers.js.map +1 -1
  181. package/dist/store/json.js +2 -2
  182. package/dist/store/safety-data-accessor.d.ts +7 -0
  183. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  184. package/dist/store/safety-data-accessor.js +14 -0
  185. package/dist/store/safety-data-accessor.js.map +1 -1
  186. package/dist/store/signaldock-sqlite.d.ts +48 -0
  187. package/dist/store/signaldock-sqlite.d.ts.map +1 -0
  188. package/dist/store/signaldock-sqlite.js +178 -0
  189. package/dist/store/signaldock-sqlite.js.map +1 -0
  190. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  191. package/dist/store/sqlite-data-accessor.js +50 -0
  192. package/dist/store/sqlite-data-accessor.js.map +1 -1
  193. package/dist/store/sqlite.d.ts.map +1 -1
  194. package/dist/store/sqlite.js +30 -1
  195. package/dist/store/sqlite.js.map +1 -1
  196. package/dist/store/task-store.d.ts.map +1 -1
  197. package/dist/store/task-store.js +2 -0
  198. package/dist/store/task-store.js.map +1 -1
  199. package/dist/store/tasks-schema.d.ts +16 -0
  200. package/dist/store/tasks-schema.d.ts.map +1 -1
  201. package/dist/store/tasks-schema.js +33 -0
  202. package/dist/store/tasks-schema.js.map +1 -1
  203. package/dist/store/validation-schemas.d.ts +32 -0
  204. package/dist/store/validation-schemas.d.ts.map +1 -1
  205. package/dist/system/health.d.ts +1 -1
  206. package/dist/system/health.d.ts.map +1 -1
  207. package/dist/system/health.js +35 -0
  208. package/dist/system/health.js.map +1 -1
  209. package/dist/task-work/index.d.ts.map +1 -1
  210. package/dist/task-work/index.js +8 -4
  211. package/dist/task-work/index.js.map +1 -1
  212. package/dist/tasks/complete.js +5 -2
  213. package/dist/tasks/complete.js.map +1 -1
  214. package/dist/tasks/find.d.ts +3 -0
  215. package/dist/tasks/find.d.ts.map +1 -1
  216. package/dist/tasks/find.js +7 -1
  217. package/dist/tasks/find.js.map +1 -1
  218. package/dist/tasks/list.d.ts +5 -2
  219. package/dist/tasks/list.d.ts.map +1 -1
  220. package/dist/tasks/list.js +9 -2
  221. package/dist/tasks/list.js.map +1 -1
  222. package/dist/tasks/show.d.ts +3 -0
  223. package/dist/tasks/show.d.ts.map +1 -1
  224. package/dist/tasks/show.js +2 -0
  225. package/dist/tasks/show.js.map +1 -1
  226. package/dist/upgrade.d.ts.map +1 -1
  227. package/dist/upgrade.js +15 -0
  228. package/dist/upgrade.js.map +1 -1
  229. package/migrations/drizzle-tasks/20260324000000_assignee-column/migration.sql +6 -0
  230. package/migrations/drizzle-tasks/20260324000000_assignee-column/snapshot.json +9 -0
  231. package/migrations/drizzle-tasks/20260327000000_agent-credentials/migration.sql +23 -0
  232. package/package.json +17 -7
  233. package/src/__tests__/cli-parity.test.js +11 -1
  234. package/src/__tests__/cli-parity.test.js.map +1 -1
  235. package/src/__tests__/cli-parity.test.ts +17 -1
  236. package/src/__tests__/human-output.test.js +11 -1
  237. package/src/__tests__/human-output.test.js.map +1 -1
  238. package/src/__tests__/human-output.test.ts +18 -1
  239. package/src/__tests__/injection-chain.test.js +3 -2
  240. package/src/__tests__/injection-chain.test.js.map +1 -1
  241. package/src/__tests__/injection-mvi-tiers.test.d.ts +2 -2
  242. package/src/__tests__/injection-mvi-tiers.test.js +15 -15
  243. package/src/__tests__/injection-mvi-tiers.test.js.map +1 -1
  244. package/src/__tests__/lafs-conformance.test.d.ts +1 -1
  245. package/src/__tests__/lafs-conformance.test.js +2 -2
  246. package/src/__tests__/sharing.test.js +19 -0
  247. package/src/__tests__/sharing.test.js.map +1 -1
  248. package/src/agents/__tests__/agent-registry.test.d.ts +12 -0
  249. package/src/agents/__tests__/agent-registry.test.d.ts.map +1 -0
  250. package/src/agents/__tests__/agent-registry.test.js +262 -0
  251. package/src/agents/__tests__/agent-registry.test.js.map +1 -0
  252. package/src/agents/__tests__/execution-learning.test.d.ts +14 -0
  253. package/src/agents/__tests__/execution-learning.test.d.ts.map +1 -0
  254. package/src/agents/__tests__/execution-learning.test.js +533 -0
  255. package/src/agents/__tests__/execution-learning.test.js.map +1 -0
  256. package/src/agents/__tests__/health-monitor.test.d.ts +10 -0
  257. package/src/agents/__tests__/health-monitor.test.d.ts.map +1 -0
  258. package/src/agents/__tests__/health-monitor.test.js +259 -0
  259. package/src/agents/__tests__/health-monitor.test.js.map +1 -0
  260. package/src/agents/__tests__/registry.test.js +27 -2
  261. package/src/agents/__tests__/registry.test.js.map +1 -1
  262. package/src/agents/agent-schema.ts +2 -5
  263. package/src/cant/__tests__/cant-agent-parse.test.ts +94 -0
  264. package/src/cant/approval.ts +218 -0
  265. package/src/cant/context-builder.ts +135 -0
  266. package/src/cant/discretion.ts +149 -0
  267. package/src/cant/index.ts +58 -0
  268. package/src/cant/parallel-runner.ts +205 -0
  269. package/src/cant/types.ts +158 -0
  270. package/src/cant/workflow-executor.ts +618 -0
  271. package/src/code/index.ts +10 -0
  272. package/src/code/outline.ts +214 -0
  273. package/src/code/parser.ts +299 -0
  274. package/src/code/search.ts +173 -0
  275. package/src/code/unfold.ts +204 -0
  276. package/src/conduit/__tests__/dual-api-e2e.test.ts +212 -0
  277. package/src/conduit/__tests__/local-credential-flow.test.ts +230 -0
  278. package/src/conduit/__tests__/local-transport.test.ts +320 -0
  279. package/src/conduit/__tests__/sse-transport.test.ts +344 -0
  280. package/src/conduit/conduit-client.ts +123 -0
  281. package/src/conduit/factory.ts +49 -0
  282. package/src/conduit/http-transport.ts +201 -0
  283. package/src/conduit/index.ts +15 -0
  284. package/src/conduit/local-transport.ts +309 -0
  285. package/src/conduit/sse-transport.ts +382 -0
  286. package/src/crypto/credentials.ts +166 -0
  287. package/src/engine-result.ts +1 -1
  288. package/src/error-catalog.ts +1 -1
  289. package/src/error-registry.ts +1 -1
  290. package/src/errors.ts +1 -1
  291. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.d.ts +13 -0
  292. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.d.ts.map +1 -0
  293. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js +501 -0
  294. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js.map +1 -0
  295. package/src/hooks/handlers/agent-hooks.ts +1 -30
  296. package/src/hooks/handlers/context-hooks.ts +1 -30
  297. package/src/hooks/handlers/error-hooks.ts +14 -5
  298. package/src/hooks/handlers/file-hooks.ts +1 -6
  299. package/src/hooks/handlers/handler-helpers.ts +62 -0
  300. package/src/hooks/handlers/mcp-hooks.ts +2 -14
  301. package/src/hooks/handlers/session-hooks.ts +1 -6
  302. package/src/hooks/handlers/task-hooks.ts +1 -6
  303. package/src/hooks/handlers/work-capture-hooks.ts +1 -10
  304. package/src/index.ts +12 -1
  305. package/src/init.ts +12 -0
  306. package/src/intelligence/__tests__/adaptive-validation.test.d.ts +11 -0
  307. package/src/intelligence/__tests__/adaptive-validation.test.d.ts.map +1 -0
  308. package/src/intelligence/__tests__/adaptive-validation.test.js +517 -0
  309. package/src/intelligence/__tests__/adaptive-validation.test.js.map +1 -0
  310. package/src/intelligence/__tests__/impact.test.d.ts +1 -0
  311. package/src/intelligence/__tests__/impact.test.d.ts.map +1 -1
  312. package/src/intelligence/__tests__/impact.test.js +132 -1
  313. package/src/intelligence/__tests__/impact.test.js.map +1 -1
  314. package/src/internal.ts +22 -0
  315. package/src/lib/__tests__/retry.test.d.ts +7 -0
  316. package/src/lib/__tests__/retry.test.d.ts.map +1 -0
  317. package/src/lib/__tests__/retry.test.js +225 -0
  318. package/src/lib/__tests__/retry.test.js.map +1 -0
  319. package/src/lib/index.ts +8 -0
  320. package/src/lib/tree-sitter-languages.ts +88 -0
  321. package/src/lifecycle/__tests__/chain-store.test.js +6 -0
  322. package/src/lifecycle/__tests__/chain-store.test.js.map +1 -1
  323. package/src/lifecycle/__tests__/tessera-engine.test.js +52 -0
  324. package/src/lifecycle/__tests__/tessera-engine.test.js.map +1 -1
  325. package/src/memory/__tests__/brain-automation.test.d.ts +11 -0
  326. package/src/memory/__tests__/brain-automation.test.d.ts.map +1 -0
  327. package/src/memory/__tests__/brain-automation.test.js +730 -0
  328. package/src/memory/__tests__/brain-automation.test.js.map +1 -0
  329. package/src/memory/__tests__/brain-links.test.ts +14 -0
  330. package/src/memory/__tests__/brain-retrieval.test.ts +10 -0
  331. package/src/memory/__tests__/session-memory.test.ts +17 -0
  332. package/src/memory/brain-links.ts +17 -0
  333. package/src/memory/brain-maintenance.ts +33 -1
  334. package/src/memory/brain-retrieval.ts +27 -2
  335. package/src/memory/decisions.ts +18 -2
  336. package/src/mvi-helpers.ts +81 -0
  337. package/src/nexus/workspace.ts +19 -7
  338. package/src/orchestration/hierarchy.ts +202 -0
  339. package/src/orchestration/index.ts +1 -0
  340. package/src/output.ts +43 -10
  341. package/src/pagination.ts +1 -1
  342. package/src/sessions/__tests__/session-edge-cases.test.js +20 -1
  343. package/src/sessions/__tests__/session-edge-cases.test.js.map +1 -1
  344. package/src/sessions/__tests__/session-find.test.js +1 -1
  345. package/src/sessions/__tests__/session-find.test.js.map +1 -1
  346. package/src/sessions/__tests__/session-find.test.ts +1 -1
  347. package/src/sessions/find.ts +6 -1
  348. package/src/sessions/index.ts +9 -0
  349. package/src/store/__tests__/migration-safety.test.js +3 -0
  350. package/src/store/__tests__/migration-safety.test.js.map +1 -1
  351. package/src/store/__tests__/session-store.test.js +128 -1
  352. package/src/store/__tests__/session-store.test.js.map +1 -1
  353. package/src/store/__tests__/task-store.test.js +18 -1
  354. package/src/store/__tests__/task-store.test.js.map +1 -1
  355. package/src/store/__tests__/test-db-helper.d.ts.map +1 -1
  356. package/src/store/__tests__/test-db-helper.js +12 -0
  357. package/src/store/__tests__/test-db-helper.js.map +1 -1
  358. package/src/store/agent-registry-accessor.ts +375 -0
  359. package/src/store/converters.ts +2 -0
  360. package/src/store/cross-db-cleanup.ts +175 -1
  361. package/src/store/db-helpers.ts +1 -0
  362. package/src/store/safety-data-accessor.ts +23 -0
  363. package/src/store/signaldock-sqlite.ts +429 -0
  364. package/src/store/sqlite-data-accessor.ts +72 -0
  365. package/src/store/sqlite.ts +4 -1
  366. package/src/store/task-store.ts +9 -1
  367. package/src/store/tasks-schema.ts +7 -0
  368. package/src/system/__tests__/health.test.ts +2 -2
  369. package/src/system/health.ts +54 -2
  370. package/src/task-work/index.ts +5 -0
  371. package/src/tasks/__tests__/add.test.js +19 -1
  372. package/src/tasks/__tests__/add.test.js.map +1 -1
  373. package/src/tasks/__tests__/assignee.test.d.ts +14 -0
  374. package/src/tasks/__tests__/assignee.test.d.ts.map +1 -0
  375. package/src/tasks/__tests__/assignee.test.js +125 -0
  376. package/src/tasks/__tests__/assignee.test.js.map +1 -0
  377. package/src/tasks/__tests__/assignee.test.ts +162 -0
  378. package/src/tasks/__tests__/complete-unblocks.test.js +13 -1
  379. package/src/tasks/__tests__/complete-unblocks.test.js.map +1 -1
  380. package/src/tasks/__tests__/complete.test.js +28 -7
  381. package/src/tasks/__tests__/complete.test.js.map +1 -1
  382. package/src/tasks/__tests__/epic-enforcement.test.d.ts +15 -0
  383. package/src/tasks/__tests__/epic-enforcement.test.d.ts.map +1 -0
  384. package/src/tasks/__tests__/epic-enforcement.test.js +669 -0
  385. package/src/tasks/__tests__/epic-enforcement.test.js.map +1 -0
  386. package/src/tasks/__tests__/hierarchy-policy.test.js +5 -0
  387. package/src/tasks/__tests__/hierarchy-policy.test.js.map +1 -1
  388. package/src/tasks/__tests__/minimal-test.test.d.ts +2 -0
  389. package/src/tasks/__tests__/minimal-test.test.d.ts.map +1 -0
  390. package/src/tasks/__tests__/minimal-test.test.js +25 -0
  391. package/src/tasks/__tests__/minimal-test.test.js.map +1 -0
  392. package/src/tasks/__tests__/pipeline-stage.test.d.ts +14 -0
  393. package/src/tasks/__tests__/pipeline-stage.test.d.ts.map +1 -0
  394. package/src/tasks/__tests__/pipeline-stage.test.js +277 -0
  395. package/src/tasks/__tests__/pipeline-stage.test.js.map +1 -0
  396. package/src/tasks/__tests__/update.test.js +43 -6
  397. package/src/tasks/__tests__/update.test.js.map +1 -1
  398. package/src/tasks/find.ts +11 -1
  399. package/src/tasks/list.ts +14 -3
  400. package/src/tasks/show.ts +6 -0
  401. package/src/upgrade.ts +16 -0
  402. package/dist/tasks/reparent.d.ts +0 -38
  403. package/dist/tasks/reparent.d.ts.map +0 -1
  404. package/dist/ui/injection-legacy.d.ts +0 -26
  405. package/dist/ui/injection-legacy.d.ts.map +0 -1
  406. package/dist/ui/injection-legacy.js +0 -42
  407. package/dist/ui/injection-legacy.js.map +0 -1
  408. package/src/signaldock/__tests__/claude-code-transport.test.d.ts +0 -7
  409. package/src/signaldock/__tests__/claude-code-transport.test.d.ts.map +0 -1
  410. package/src/signaldock/__tests__/claude-code-transport.test.js +0 -147
  411. package/src/signaldock/__tests__/claude-code-transport.test.js.map +0 -1
  412. package/src/signaldock/__tests__/claude-code-transport.test.ts +0 -180
  413. package/src/signaldock/__tests__/factory.test.d.ts +0 -7
  414. package/src/signaldock/__tests__/factory.test.d.ts.map +0 -1
  415. package/src/signaldock/__tests__/factory.test.js +0 -55
  416. package/src/signaldock/__tests__/factory.test.js.map +0 -1
  417. package/src/signaldock/__tests__/factory.test.ts +0 -61
  418. package/src/signaldock/__tests__/signaldock-transport.test.d.ts +0 -9
  419. package/src/signaldock/__tests__/signaldock-transport.test.d.ts.map +0 -1
  420. package/src/signaldock/__tests__/signaldock-transport.test.js +0 -321
  421. package/src/signaldock/__tests__/signaldock-transport.test.js.map +0 -1
  422. package/src/signaldock/__tests__/signaldock-transport.test.ts +0 -421
  423. package/src/signaldock/claude-code-transport.ts +0 -137
  424. package/src/signaldock/factory.ts +0 -39
  425. package/src/signaldock/index.ts +0 -28
  426. package/src/signaldock/signaldock-transport.ts +0 -194
  427. package/src/signaldock/transport.ts +0 -78
  428. package/src/signaldock/types.ts +0 -100
@@ -0,0 +1,204 @@
1
+ /**
2
+ * smart_unfold — single symbol extraction from source files.
3
+ *
4
+ * Takes a file path + symbol name, parses the file via tree-sitter,
5
+ * finds the matching symbol node, and extracts complete source including
6
+ * JSDoc/docstring, decorators, and full body. AST node boundaries
7
+ * guarantee no truncation.
8
+ *
9
+ * @task T153
10
+ */
11
+
12
+ import { readFileSync } from 'node:fs';
13
+ import { relative } from 'node:path';
14
+ import type { CodeSymbol } from '@cleocode/contracts';
15
+ import { detectLanguage } from '../lib/tree-sitter-languages.js';
16
+ import { parseFile } from './parser.js';
17
+
18
+ /** Result of unfolding a single symbol. */
19
+ export interface SmartUnfoldResult {
20
+ /** Whether the symbol was found. */
21
+ found: boolean;
22
+ /** The matched symbol metadata. */
23
+ symbol?: CodeSymbol;
24
+ /** Complete source text including JSDoc, decorators, and body. */
25
+ source: string;
26
+ /** Start line (1-based, inclusive of leading doc comment). */
27
+ startLine: number;
28
+ /** End line (1-based). */
29
+ endLine: number;
30
+ /** Estimated token count for this extraction. */
31
+ estimatedTokens: number;
32
+ /** File path (relative). */
33
+ filePath: string;
34
+ /** Errors encountered. */
35
+ errors: string[];
36
+ }
37
+
38
+ /**
39
+ * Find leading documentation comment (JSDoc, docstring, Rust doc) above a symbol.
40
+ *
41
+ * Scans backwards from the symbol's start line to find attached doc comments.
42
+ */
43
+ function findLeadingDocStart(lines: string[], symbolStartLine: number, language: string): number {
44
+ const idx = symbolStartLine - 1; // 1-based to 0-based
45
+ if (idx <= 0) return symbolStartLine;
46
+
47
+ let docStart = idx;
48
+
49
+ if (language === 'python') {
50
+ // Python: look for decorator lines above
51
+ let i = idx - 1;
52
+ while (i >= 0 && lines[i]!.trimStart().startsWith('@')) {
53
+ docStart = i + 1; // back to 1-based
54
+ i--;
55
+ }
56
+ return docStart;
57
+ }
58
+
59
+ // C-family / Rust / JS/TS: look for block comments (/** ... */) or /// lines
60
+ let i = idx - 1;
61
+
62
+ // Skip blank lines immediately above
63
+ while (i >= 0 && lines[i]!.trim() === '') i--;
64
+
65
+ if (i < 0) return symbolStartLine;
66
+
67
+ const line = lines[i]!.trimStart();
68
+
69
+ // Block comment ending: */
70
+ if (line.endsWith('*/')) {
71
+ // Walk backwards to find opening /**
72
+ while (i >= 0) {
73
+ if (lines[i]!.trimStart().startsWith('/**') || lines[i]!.trimStart().startsWith('/*')) {
74
+ docStart = i + 1; // 1-based
75
+ break;
76
+ }
77
+ i--;
78
+ }
79
+ }
80
+ // Line comments: /// (Rust) or // (TS/JS decorators less common)
81
+ else if (line.startsWith('///') || line.startsWith('//!')) {
82
+ while (
83
+ i >= 0 &&
84
+ (lines[i]!.trimStart().startsWith('///') || lines[i]!.trimStart().startsWith('//!'))
85
+ ) {
86
+ docStart = i + 1;
87
+ i--;
88
+ }
89
+ }
90
+
91
+ // Also capture decorators (TS/Java) above the doc comment
92
+ i = docStart - 2; // 0-based, line above current docStart
93
+ while (i >= 0 && lines[i]!.trimStart().startsWith('@')) {
94
+ docStart = i + 1;
95
+ i--;
96
+ }
97
+
98
+ return docStart;
99
+ }
100
+
101
+ /**
102
+ * Extract a symbol's complete source from a file.
103
+ *
104
+ * Finds the symbol by name (supports "Class.method" dot notation),
105
+ * determines its full range including leading documentation, and
106
+ * returns the exact source text.
107
+ *
108
+ * @param filePath - Absolute path to source file
109
+ * @param symbolName - Symbol to extract (e.g. "parseFile" or "HttpTransport.connect")
110
+ * @param projectRoot - Project root for relative path computation
111
+ * @returns Unfold result with complete source text
112
+ */
113
+ export function smartUnfold(
114
+ filePath: string,
115
+ symbolName: string,
116
+ projectRoot?: string,
117
+ ): SmartUnfoldResult {
118
+ const root = projectRoot ?? process.cwd();
119
+ const relPath = relative(root, filePath);
120
+ const language = detectLanguage(filePath);
121
+
122
+ const empty: SmartUnfoldResult = {
123
+ found: false,
124
+ source: '',
125
+ startLine: 0,
126
+ endLine: 0,
127
+ estimatedTokens: 0,
128
+ filePath: relPath,
129
+ errors: [],
130
+ };
131
+
132
+ if (!language) {
133
+ return { ...empty, errors: ['Unsupported language'] };
134
+ }
135
+
136
+ // Parse the file
137
+ const parseResult = parseFile(filePath, root);
138
+ if (parseResult.symbols.length === 0) {
139
+ return {
140
+ ...empty,
141
+ errors: parseResult.errors.length > 0 ? parseResult.errors : ['No symbols found'],
142
+ };
143
+ }
144
+
145
+ // Find the matching symbol
146
+ const parts = symbolName.split('.');
147
+ let match: CodeSymbol | undefined;
148
+
149
+ if (parts.length === 2) {
150
+ // Nested: "Class.method" — find method with matching parent range
151
+ const [parentName, childName] = parts;
152
+ const parent = parseResult.symbols.find(
153
+ (s) =>
154
+ s.name === parentName && (s.kind === 'class' || s.kind === 'struct' || s.kind === 'impl'),
155
+ );
156
+ if (parent) {
157
+ match = parseResult.symbols.find(
158
+ (s) =>
159
+ s.name === childName && s.startLine >= parent.startLine && s.endLine <= parent.endLine,
160
+ );
161
+ }
162
+ } else {
163
+ // Top-level: exact name match, prefer non-method over method
164
+ match = parseResult.symbols.find((s) => s.name === symbolName && s.kind !== 'method');
165
+ if (!match) {
166
+ match = parseResult.symbols.find((s) => s.name === symbolName);
167
+ }
168
+ }
169
+
170
+ if (!match) {
171
+ return { ...empty, errors: [`Symbol "${symbolName}" not found in ${relPath}`] };
172
+ }
173
+
174
+ // Read source lines
175
+ let lines: string[];
176
+ try {
177
+ lines = readFileSync(filePath, 'utf-8').split('\n');
178
+ } catch (err) {
179
+ return {
180
+ ...empty,
181
+ errors: [`Failed to read file: ${err instanceof Error ? err.message : String(err)}`],
182
+ };
183
+ }
184
+
185
+ // Determine full range including doc comment
186
+ const docStart = findLeadingDocStart(lines, match.startLine, language);
187
+ const startLine = Math.min(docStart, match.startLine);
188
+ const endLine = match.endLine;
189
+
190
+ // Extract source text
191
+ const source = lines.slice(startLine - 1, endLine).join('\n');
192
+ const estimatedTokens = Math.ceil(source.length / 4);
193
+
194
+ return {
195
+ found: true,
196
+ symbol: match,
197
+ source,
198
+ startLine,
199
+ endLine,
200
+ estimatedTokens,
201
+ filePath: relPath,
202
+ errors: [],
203
+ };
204
+ }
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Dual-API E2E test — verify messaging across both SignalDock endpoints.
3
+ *
4
+ * Tests that agents can exchange messages on:
5
+ * 1. api.signaldock.io (canonical)
6
+ * 2. api.clawmsgr.com (legacy)
7
+ * 3. Local signaldock.db (offline)
8
+ *
9
+ * These tests hit real APIs and require valid credentials.
10
+ * Set SKIP_E2E=1 to skip when running in CI without network.
11
+ *
12
+ * @task T226
13
+ */
14
+
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { describe, expect, it } from 'vitest';
18
+ import { HttpTransport } from '../http-transport.js';
19
+
20
+ // ============================================================================
21
+ // Config helpers
22
+ // ============================================================================
23
+
24
+ const CLEO_DIR = join(process.cwd(), '.cleo');
25
+ const SKIP_E2E = process.env['SKIP_E2E'] === '1';
26
+
27
+ /** Load a ClawMsgr/SignalDock config file. */
28
+ function loadConfig(
29
+ filename: string,
30
+ ): { agentId: string; apiKey: string; apiBaseUrl: string } | null {
31
+ const path = join(CLEO_DIR, filename);
32
+ if (!existsSync(path)) return null;
33
+ try {
34
+ return JSON.parse(readFileSync(path, 'utf-8')) as {
35
+ agentId: string;
36
+ apiKey: string;
37
+ apiBaseUrl: string;
38
+ };
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /** Send a test message and verify it arrives. */
45
+ async function testMessageExchange(
46
+ apiBaseUrl: string,
47
+ senderConfig: { agentId: string; apiKey: string },
48
+ receiverAgentId: string,
49
+ ): Promise<{ sent: boolean; messageId: string | null; error: string | null }> {
50
+ const transport = new HttpTransport();
51
+ try {
52
+ await transport.connect({
53
+ agentId: senderConfig.agentId,
54
+ apiKey: senderConfig.apiKey,
55
+ apiBaseUrl,
56
+ });
57
+
58
+ const testContent = `/info @${receiverAgentId} #e2e-test T226 verification at ${new Date().toISOString()}`;
59
+ const result = await transport.push(receiverAgentId, testContent);
60
+
61
+ await transport.disconnect();
62
+ return { sent: true, messageId: result.messageId, error: null };
63
+ } catch (err) {
64
+ await transport.disconnect();
65
+ return { sent: false, messageId: null, error: String(err) };
66
+ }
67
+ }
68
+
69
+ // ============================================================================
70
+ // Test suite
71
+ // ============================================================================
72
+
73
+ describe('Dual-API E2E', () => {
74
+ // --------------------------------------------------------------------------
75
+ // Config verification
76
+ // --------------------------------------------------------------------------
77
+
78
+ describe('config files exist', () => {
79
+ it('has clawmsgr configs (legacy)', () => {
80
+ const config = loadConfig('clawmsgr-cleo-rust-lead.json');
81
+ if (!config) {
82
+ console.log('SKIP: clawmsgr config not found');
83
+ return;
84
+ }
85
+ expect(config.agentId).toBe('cleo-rust-lead');
86
+ expect(config.apiBaseUrl).toContain('clawmsgr.com');
87
+ });
88
+
89
+ it('has signaldock configs (canonical)', () => {
90
+ const config = loadConfig('signaldock-cleo-rust-lead.json');
91
+ if (!config) {
92
+ console.log('SKIP: signaldock config not found');
93
+ return;
94
+ }
95
+ expect(config.agentId).toBe('cleo-rust-lead');
96
+ expect(config.apiBaseUrl).toContain('signaldock.io');
97
+ });
98
+ });
99
+
100
+ // --------------------------------------------------------------------------
101
+ // API health checks
102
+ // --------------------------------------------------------------------------
103
+
104
+ describe('API health', () => {
105
+ it('api.signaldock.io is healthy', async () => {
106
+ if (SKIP_E2E) return;
107
+ const response = await fetch('https://api.signaldock.io/health', {
108
+ signal: AbortSignal.timeout(10_000),
109
+ });
110
+ expect(response.ok).toBe(true);
111
+ const data = (await response.json()) as { data?: { status?: string } };
112
+ expect(data.data?.status).toBe('ok');
113
+ });
114
+
115
+ it('api.clawmsgr.com is healthy', async () => {
116
+ if (SKIP_E2E) return;
117
+ const response = await fetch('https://api.clawmsgr.com/health', {
118
+ signal: AbortSignal.timeout(10_000),
119
+ });
120
+ expect(response.ok).toBe(true);
121
+ const data = (await response.json()) as { data?: { status?: string } };
122
+ expect(data.data?.status).toBe('ok');
123
+ });
124
+ });
125
+
126
+ // --------------------------------------------------------------------------
127
+ // Message exchange on api.signaldock.io
128
+ // --------------------------------------------------------------------------
129
+
130
+ describe('api.signaldock.io messaging', () => {
131
+ it('can send a message via signaldock.io', async () => {
132
+ if (SKIP_E2E) return;
133
+ const config = loadConfig('signaldock-cleo-rust-lead.json');
134
+ if (!config) {
135
+ console.log('SKIP: no signaldock config');
136
+ return;
137
+ }
138
+ const result = await testMessageExchange(
139
+ 'https://api.signaldock.io',
140
+ { agentId: config.agentId, apiKey: config.apiKey },
141
+ 'cleo-dev',
142
+ );
143
+ expect(result.sent).toBe(true);
144
+ expect(result.messageId).toBeDefined();
145
+ });
146
+ });
147
+
148
+ // --------------------------------------------------------------------------
149
+ // Message exchange on api.clawmsgr.com
150
+ // --------------------------------------------------------------------------
151
+
152
+ describe('api.clawmsgr.com messaging', () => {
153
+ it('can send a message via clawmsgr.com', async () => {
154
+ if (SKIP_E2E) return;
155
+ const config = loadConfig('clawmsgr-cleo-rust-lead.json');
156
+ if (!config) {
157
+ console.log('SKIP: no clawmsgr config');
158
+ return;
159
+ }
160
+ const result = await testMessageExchange(
161
+ 'https://api.clawmsgr.com',
162
+ { agentId: config.agentId, apiKey: config.apiKey },
163
+ 'cleo-dev',
164
+ );
165
+ expect(result.sent).toBe(true);
166
+ expect(result.messageId).toBeDefined();
167
+ });
168
+ });
169
+
170
+ // --------------------------------------------------------------------------
171
+ // Cross-API metadata consistency
172
+ // --------------------------------------------------------------------------
173
+
174
+ describe('cross-API consistency', () => {
175
+ it('agent profile exists on both APIs', async () => {
176
+ if (SKIP_E2E) return;
177
+ const clawConfig = loadConfig('clawmsgr-cleo-rust-lead.json');
178
+ const sdConfig = loadConfig('signaldock-cleo-rust-lead.json');
179
+ if (!clawConfig || !sdConfig) {
180
+ console.log('SKIP: missing configs');
181
+ return;
182
+ }
183
+
184
+ // Check agent exists on clawmsgr
185
+ const clawResp = await fetch('https://api.clawmsgr.com/agents/cleo-rust-lead', {
186
+ headers: {
187
+ Authorization: `Bearer ${clawConfig.apiKey}`,
188
+ 'X-Agent-Id': 'cleo-rust-lead',
189
+ },
190
+ signal: AbortSignal.timeout(10_000),
191
+ });
192
+
193
+ // Check agent exists on signaldock
194
+ const sdResp = await fetch('https://api.signaldock.io/agents/cleo-rust-lead', {
195
+ headers: {
196
+ Authorization: `Bearer ${sdConfig.apiKey}`,
197
+ 'X-Agent-Id': 'cleo-rust-lead',
198
+ },
199
+ signal: AbortSignal.timeout(10_000),
200
+ });
201
+
202
+ expect(clawResp.ok).toBe(true);
203
+ expect(sdResp.ok).toBe(true);
204
+
205
+ const clawData = (await clawResp.json()) as { data?: { agent?: { agentId?: string } } };
206
+ const sdData = (await sdResp.json()) as { data?: { agent?: { agentId?: string } } };
207
+
208
+ expect(clawData.data?.agent?.agentId).toBe('cleo-rust-lead');
209
+ expect(sdData.data?.agent?.agentId).toBe('cleo-rust-lead');
210
+ });
211
+ });
212
+ });
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Local credential flow — end-to-end validation.
3
+ *
4
+ * Tests the full lifecycle: signaldock.db creation → agent register →
5
+ * credential encryption/decryption → LocalTransport connect →
6
+ * push/poll/ack messaging.
7
+ *
8
+ * @task T227
9
+ */
10
+
11
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
15
+ import { ensureSignaldockDb, getSignaldockDbPath } from '../../store/signaldock-sqlite.js';
16
+ import { LocalTransport } from '../local-transport.js';
17
+
18
+ // ============================================================================
19
+ // Test helpers
20
+ // ============================================================================
21
+
22
+ let testDir: string;
23
+ let originalCwd: string;
24
+
25
+ async function setupTestEnvironment(): Promise<string> {
26
+ const dir = join(
27
+ tmpdir(),
28
+ `credential-flow-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
29
+ );
30
+ mkdirSync(join(dir, '.cleo'), { recursive: true });
31
+ // Create a minimal .cleo/project-context.json so paths resolve
32
+ writeFileSync(
33
+ join(dir, '.cleo', 'project-context.json'),
34
+ JSON.stringify({ schemaVersion: '1.0.0', projectTypes: ['node'], primaryType: 'node' }),
35
+ );
36
+ return dir;
37
+ }
38
+
39
+ // ============================================================================
40
+ // Test suite
41
+ // ============================================================================
42
+
43
+ describe('Local Credential Flow E2E', () => {
44
+ beforeEach(async () => {
45
+ originalCwd = process.cwd();
46
+ testDir = await setupTestEnvironment();
47
+ process.chdir(testDir);
48
+ });
49
+
50
+ afterEach(() => {
51
+ process.chdir(originalCwd);
52
+ if (testDir && existsSync(testDir)) {
53
+ rmSync(testDir, { recursive: true, force: true });
54
+ }
55
+ });
56
+
57
+ // --------------------------------------------------------------------------
58
+ // Step 1: cleo init creates signaldock.db
59
+ // --------------------------------------------------------------------------
60
+
61
+ describe('Step 1: signaldock.db creation', () => {
62
+ it('ensureSignaldockDb creates the database file', async () => {
63
+ const result = await ensureSignaldockDb(testDir);
64
+ expect(result.action).toBe('created');
65
+ expect(existsSync(result.path)).toBe(true);
66
+ });
67
+
68
+ it('ensureSignaldockDb is idempotent', async () => {
69
+ const first = await ensureSignaldockDb(testDir);
70
+ const second = await ensureSignaldockDb(testDir);
71
+ expect(first.action).toBe('created');
72
+ expect(second.action).toBe('exists');
73
+ expect(first.path).toBe(second.path);
74
+ });
75
+
76
+ it('signaldock.db has the messages table', async () => {
77
+ await ensureSignaldockDb(testDir);
78
+ const dbPath = getSignaldockDbPath(testDir);
79
+ expect(existsSync(dbPath)).toBe(true);
80
+
81
+ // Verify by connecting LocalTransport (which checks for messages table)
82
+ const transport = new LocalTransport();
83
+ await transport.connect({
84
+ agentId: 'test',
85
+ apiKey: 'sk_test',
86
+ apiBaseUrl: 'http://localhost',
87
+ });
88
+ await transport.disconnect();
89
+ });
90
+ });
91
+
92
+ // --------------------------------------------------------------------------
93
+ // Step 2: LocalTransport availability
94
+ // --------------------------------------------------------------------------
95
+
96
+ describe('Step 2: LocalTransport availability', () => {
97
+ it('isAvailable returns false before init', () => {
98
+ const emptyDir = join(tmpdir(), `no-init-${Date.now()}`);
99
+ mkdirSync(join(emptyDir, '.cleo'), { recursive: true });
100
+ expect(LocalTransport.isAvailable(emptyDir)).toBe(false);
101
+ rmSync(emptyDir, { recursive: true, force: true });
102
+ });
103
+
104
+ it('isAvailable returns true after init', async () => {
105
+ await ensureSignaldockDb(testDir);
106
+ expect(LocalTransport.isAvailable(testDir)).toBe(true);
107
+ });
108
+ });
109
+
110
+ // --------------------------------------------------------------------------
111
+ // Step 3: Full messaging lifecycle
112
+ // --------------------------------------------------------------------------
113
+
114
+ describe('Step 3: messaging lifecycle', () => {
115
+ it('complete flow: init → connect → push → poll → ack', async () => {
116
+ // 1. Init signaldock.db
117
+ await ensureSignaldockDb(testDir);
118
+
119
+ // 2. Connect two agents
120
+ const agent1 = new LocalTransport();
121
+ const agent2 = new LocalTransport();
122
+
123
+ await agent1.connect({
124
+ agentId: 'cleo-rust-lead',
125
+ apiKey: 'sk_live_fake1',
126
+ apiBaseUrl: 'http://localhost',
127
+ });
128
+ await agent2.connect({
129
+ agentId: 'cleo-dev',
130
+ apiKey: 'sk_live_fake2',
131
+ apiBaseUrl: 'http://localhost',
132
+ });
133
+
134
+ // 3. Agent 1 sends a message to Agent 2
135
+ const sendResult = await agent1.push(
136
+ 'cleo-dev',
137
+ '/action @cleo-dev #test Hello from rust-lead',
138
+ );
139
+ expect(sendResult.messageId).toBeDefined();
140
+
141
+ // 4. Agent 2 polls and receives the message
142
+ const messages = await agent2.poll();
143
+ expect(messages).toHaveLength(1);
144
+ expect(messages[0].from).toBe('cleo-rust-lead');
145
+ expect(messages[0].content).toContain('Hello from rust-lead');
146
+
147
+ // 5. Agent 2 acknowledges the message
148
+ await agent2.ack([messages[0].id]);
149
+
150
+ // 6. Subsequent poll returns empty (message was acked)
151
+ const afterAck = await agent2.poll();
152
+ expect(afterAck).toHaveLength(0);
153
+
154
+ // 7. Agent 2 replies
155
+ const replyResult = await agent2.push('cleo-rust-lead', '/ack Received.');
156
+ expect(replyResult.messageId).toBeDefined();
157
+
158
+ // 8. Agent 1 receives the reply
159
+ const replies = await agent1.poll();
160
+ expect(replies).toHaveLength(1);
161
+ expect(replies[0].from).toBe('cleo-dev');
162
+ expect(replies[0].content).toBe('/ack Received.');
163
+
164
+ // Cleanup
165
+ await agent1.disconnect();
166
+ await agent2.disconnect();
167
+ });
168
+
169
+ it('messages persist across transport reconnections', async () => {
170
+ await ensureSignaldockDb(testDir);
171
+
172
+ // Send a message
173
+ const sender = new LocalTransport();
174
+ await sender.connect({
175
+ agentId: 'sender',
176
+ apiKey: 'sk_test',
177
+ apiBaseUrl: 'http://localhost',
178
+ });
179
+ await sender.push('receiver', 'persistent message');
180
+ await sender.disconnect();
181
+
182
+ // New transport instance reads the same DB
183
+ const receiver = new LocalTransport();
184
+ await receiver.connect({
185
+ agentId: 'receiver',
186
+ apiKey: 'sk_test',
187
+ apiBaseUrl: 'http://localhost',
188
+ });
189
+ const messages = await receiver.poll();
190
+ expect(messages).toHaveLength(1);
191
+ expect(messages[0].content).toBe('persistent message');
192
+
193
+ await receiver.disconnect();
194
+ });
195
+
196
+ it('multiple agents can communicate in the same conversation', async () => {
197
+ await ensureSignaldockDb(testDir);
198
+
199
+ const prime = new LocalTransport();
200
+ const rustLead = new LocalTransport();
201
+ const dbLead = new LocalTransport();
202
+
203
+ await prime.connect({ agentId: 'prime', apiKey: 'sk1', apiBaseUrl: 'http://localhost' });
204
+ await rustLead.connect({
205
+ agentId: 'rust-lead',
206
+ apiKey: 'sk2',
207
+ apiBaseUrl: 'http://localhost',
208
+ });
209
+ await dbLead.connect({ agentId: 'db-lead', apiKey: 'sk3', apiBaseUrl: 'http://localhost' });
210
+
211
+ // Prime sends to rust-lead
212
+ await prime.push('rust-lead', 'Fix cant-lsp');
213
+ // Prime sends to db-lead
214
+ await prime.push('db-lead', 'Review schemas');
215
+
216
+ // Each agent only sees their own messages
217
+ const rustMessages = await rustLead.poll();
218
+ const dbMessages = await dbLead.poll();
219
+
220
+ expect(rustMessages).toHaveLength(1);
221
+ expect(rustMessages[0].content).toBe('Fix cant-lsp');
222
+ expect(dbMessages).toHaveLength(1);
223
+ expect(dbMessages[0].content).toBe('Review schemas');
224
+
225
+ await prime.disconnect();
226
+ await rustLead.disconnect();
227
+ await dbLead.disconnect();
228
+ });
229
+ });
230
+ });