@citadel-labs/citadel 0.1.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 (307) hide show
  1. package/README.md +145 -0
  2. package/dist/__tests__/append-bead.test.d.ts +2 -0
  3. package/dist/__tests__/append-bead.test.d.ts.map +1 -0
  4. package/dist/__tests__/append-bead.test.js +88 -0
  5. package/dist/__tests__/append-bead.test.js.map +1 -0
  6. package/dist/__tests__/blocked-outposts.test.d.ts +2 -0
  7. package/dist/__tests__/blocked-outposts.test.d.ts.map +1 -0
  8. package/dist/__tests__/blocked-outposts.test.js +142 -0
  9. package/dist/__tests__/blocked-outposts.test.js.map +1 -0
  10. package/dist/__tests__/bugfixes.test.d.ts +2 -0
  11. package/dist/__tests__/bugfixes.test.d.ts.map +1 -0
  12. package/dist/__tests__/bugfixes.test.js +503 -0
  13. package/dist/__tests__/bugfixes.test.js.map +1 -0
  14. package/dist/__tests__/citizen-tribute.test.d.ts +2 -0
  15. package/dist/__tests__/citizen-tribute.test.d.ts.map +1 -0
  16. package/dist/__tests__/citizen-tribute.test.js +106 -0
  17. package/dist/__tests__/citizen-tribute.test.js.map +1 -0
  18. package/dist/__tests__/cli-e2e/dispatch-note-resolve.test.d.ts +2 -0
  19. package/dist/__tests__/cli-e2e/dispatch-note-resolve.test.d.ts.map +1 -0
  20. package/dist/__tests__/cli-e2e/dispatch-note-resolve.test.js +65 -0
  21. package/dist/__tests__/cli-e2e/dispatch-note-resolve.test.js.map +1 -0
  22. package/dist/__tests__/cli-e2e/full-lifecycle.test.d.ts +2 -0
  23. package/dist/__tests__/cli-e2e/full-lifecycle.test.d.ts.map +1 -0
  24. package/dist/__tests__/cli-e2e/full-lifecycle.test.js +157 -0
  25. package/dist/__tests__/cli-e2e/full-lifecycle.test.js.map +1 -0
  26. package/dist/__tests__/cli-e2e/helpers.d.ts +28 -0
  27. package/dist/__tests__/cli-e2e/helpers.d.ts.map +1 -0
  28. package/dist/__tests__/cli-e2e/helpers.js +76 -0
  29. package/dist/__tests__/cli-e2e/helpers.js.map +1 -0
  30. package/dist/__tests__/cli-e2e/init-outpost-status.test.d.ts +2 -0
  31. package/dist/__tests__/cli-e2e/init-outpost-status.test.d.ts.map +1 -0
  32. package/dist/__tests__/cli-e2e/init-outpost-status.test.js +79 -0
  33. package/dist/__tests__/cli-e2e/init-outpost-status.test.js.map +1 -0
  34. package/dist/__tests__/cli-e2e/reset-stop-tribute-trace.test.d.ts +2 -0
  35. package/dist/__tests__/cli-e2e/reset-stop-tribute-trace.test.d.ts.map +1 -0
  36. package/dist/__tests__/cli-e2e/reset-stop-tribute-trace.test.js +158 -0
  37. package/dist/__tests__/cli-e2e/reset-stop-tribute-trace.test.js.map +1 -0
  38. package/dist/__tests__/courier.test.d.ts +2 -0
  39. package/dist/__tests__/courier.test.d.ts.map +1 -0
  40. package/dist/__tests__/courier.test.js +97 -0
  41. package/dist/__tests__/courier.test.js.map +1 -0
  42. package/dist/__tests__/e2e-smoke.test.d.ts +2 -0
  43. package/dist/__tests__/e2e-smoke.test.d.ts.map +1 -0
  44. package/dist/__tests__/e2e-smoke.test.js +137 -0
  45. package/dist/__tests__/e2e-smoke.test.js.map +1 -0
  46. package/dist/__tests__/fo-broadcast.test.d.ts +2 -0
  47. package/dist/__tests__/fo-broadcast.test.d.ts.map +1 -0
  48. package/dist/__tests__/fo-broadcast.test.js +134 -0
  49. package/dist/__tests__/fo-broadcast.test.js.map +1 -0
  50. package/dist/__tests__/fo-command-processor.test.d.ts +2 -0
  51. package/dist/__tests__/fo-command-processor.test.d.ts.map +1 -0
  52. package/dist/__tests__/fo-command-processor.test.js +86 -0
  53. package/dist/__tests__/fo-command-processor.test.js.map +1 -0
  54. package/dist/__tests__/fo-escalation.test.d.ts +2 -0
  55. package/dist/__tests__/fo-escalation.test.d.ts.map +1 -0
  56. package/dist/__tests__/fo-escalation.test.js +126 -0
  57. package/dist/__tests__/fo-escalation.test.js.map +1 -0
  58. package/dist/__tests__/fo-nudge-watcher.test.d.ts +2 -0
  59. package/dist/__tests__/fo-nudge-watcher.test.d.ts.map +1 -0
  60. package/dist/__tests__/fo-nudge-watcher.test.js +154 -0
  61. package/dist/__tests__/fo-nudge-watcher.test.js.map +1 -0
  62. package/dist/__tests__/fo-nudge-wiring.test.d.ts +2 -0
  63. package/dist/__tests__/fo-nudge-wiring.test.d.ts.map +1 -0
  64. package/dist/__tests__/fo-nudge-wiring.test.js +31 -0
  65. package/dist/__tests__/fo-nudge-wiring.test.js.map +1 -0
  66. package/dist/__tests__/fo-relay.test.d.ts +2 -0
  67. package/dist/__tests__/fo-relay.test.d.ts.map +1 -0
  68. package/dist/__tests__/fo-relay.test.js +90 -0
  69. package/dist/__tests__/fo-relay.test.js.map +1 -0
  70. package/dist/__tests__/fo-task-report.test.d.ts +2 -0
  71. package/dist/__tests__/fo-task-report.test.d.ts.map +1 -0
  72. package/dist/__tests__/fo-task-report.test.js +81 -0
  73. package/dist/__tests__/fo-task-report.test.js.map +1 -0
  74. package/dist/__tests__/fo-webhook.test.d.ts +2 -0
  75. package/dist/__tests__/fo-webhook.test.d.ts.map +1 -0
  76. package/dist/__tests__/fo-webhook.test.js +70 -0
  77. package/dist/__tests__/fo-webhook.test.js.map +1 -0
  78. package/dist/__tests__/integration.test.d.ts +2 -0
  79. package/dist/__tests__/integration.test.d.ts.map +1 -0
  80. package/dist/__tests__/integration.test.js +763 -0
  81. package/dist/__tests__/integration.test.js.map +1 -0
  82. package/dist/__tests__/multi-outpost-dep.test.d.ts +2 -0
  83. package/dist/__tests__/multi-outpost-dep.test.d.ts.map +1 -0
  84. package/dist/__tests__/multi-outpost-dep.test.js +173 -0
  85. package/dist/__tests__/multi-outpost-dep.test.js.map +1 -0
  86. package/dist/__tests__/nudge.test.d.ts +2 -0
  87. package/dist/__tests__/nudge.test.d.ts.map +1 -0
  88. package/dist/__tests__/nudge.test.js +103 -0
  89. package/dist/__tests__/nudge.test.js.map +1 -0
  90. package/dist/__tests__/outpost-registry.test.d.ts +2 -0
  91. package/dist/__tests__/outpost-registry.test.d.ts.map +1 -0
  92. package/dist/__tests__/outpost-registry.test.js +72 -0
  93. package/dist/__tests__/outpost-registry.test.js.map +1 -0
  94. package/dist/__tests__/process-registry.test.d.ts +2 -0
  95. package/dist/__tests__/process-registry.test.d.ts.map +1 -0
  96. package/dist/__tests__/process-registry.test.js +108 -0
  97. package/dist/__tests__/process-registry.test.js.map +1 -0
  98. package/dist/__tests__/session-log.test.d.ts +2 -0
  99. package/dist/__tests__/session-log.test.d.ts.map +1 -0
  100. package/dist/__tests__/session-log.test.js +60 -0
  101. package/dist/__tests__/session-log.test.js.map +1 -0
  102. package/dist/__tests__/spawn-citizen.test.d.ts +2 -0
  103. package/dist/__tests__/spawn-citizen.test.d.ts.map +1 -0
  104. package/dist/__tests__/spawn-citizen.test.js +48 -0
  105. package/dist/__tests__/spawn-citizen.test.js.map +1 -0
  106. package/dist/__tests__/timeout-watchdog.test.d.ts +2 -0
  107. package/dist/__tests__/timeout-watchdog.test.d.ts.map +1 -0
  108. package/dist/__tests__/timeout-watchdog.test.js +81 -0
  109. package/dist/__tests__/timeout-watchdog.test.js.map +1 -0
  110. package/dist/__tests__/worktree-manager.test.d.ts +2 -0
  111. package/dist/__tests__/worktree-manager.test.d.ts.map +1 -0
  112. package/dist/__tests__/worktree-manager.test.js +98 -0
  113. package/dist/__tests__/worktree-manager.test.js.map +1 -0
  114. package/dist/cli/aliases.d.ts +10 -0
  115. package/dist/cli/aliases.d.ts.map +1 -0
  116. package/dist/cli/aliases.js +56 -0
  117. package/dist/cli/aliases.js.map +1 -0
  118. package/dist/cli/command.d.ts +3 -0
  119. package/dist/cli/command.d.ts.map +1 -0
  120. package/dist/cli/command.js +63 -0
  121. package/dist/cli/command.js.map +1 -0
  122. package/dist/cli/index.d.ts +3 -0
  123. package/dist/cli/index.d.ts.map +1 -0
  124. package/dist/cli/index.js +29 -0
  125. package/dist/cli/index.js.map +1 -0
  126. package/dist/cli/init.d.ts +3 -0
  127. package/dist/cli/init.d.ts.map +1 -0
  128. package/dist/cli/init.js +57 -0
  129. package/dist/cli/init.js.map +1 -0
  130. package/dist/cli/outpost.d.ts +3 -0
  131. package/dist/cli/outpost.d.ts.map +1 -0
  132. package/dist/cli/outpost.js +65 -0
  133. package/dist/cli/outpost.js.map +1 -0
  134. package/dist/cli/reset.d.ts +3 -0
  135. package/dist/cli/reset.d.ts.map +1 -0
  136. package/dist/cli/reset.js +67 -0
  137. package/dist/cli/reset.js.map +1 -0
  138. package/dist/cli/session.d.ts +3 -0
  139. package/dist/cli/session.d.ts.map +1 -0
  140. package/dist/cli/session.js +112 -0
  141. package/dist/cli/session.js.map +1 -0
  142. package/dist/cli/start.d.ts +3 -0
  143. package/dist/cli/start.d.ts.map +1 -0
  144. package/dist/cli/start.js +105 -0
  145. package/dist/cli/start.js.map +1 -0
  146. package/dist/cli/status.d.ts +3 -0
  147. package/dist/cli/status.d.ts.map +1 -0
  148. package/dist/cli/status.js +128 -0
  149. package/dist/cli/status.js.map +1 -0
  150. package/dist/cli/tribute.d.ts +3 -0
  151. package/dist/cli/tribute.d.ts.map +1 -0
  152. package/dist/cli/tribute.js +160 -0
  153. package/dist/cli/tribute.js.map +1 -0
  154. package/dist/cli/worktree.d.ts +3 -0
  155. package/dist/cli/worktree.d.ts.map +1 -0
  156. package/dist/cli/worktree.js +64 -0
  157. package/dist/cli/worktree.js.map +1 -0
  158. package/dist/core/append-bead.d.ts +13 -0
  159. package/dist/core/append-bead.d.ts.map +1 -0
  160. package/dist/core/append-bead.js +68 -0
  161. package/dist/core/append-bead.js.map +1 -0
  162. package/dist/core/blocked-outposts.d.ts +15 -0
  163. package/dist/core/blocked-outposts.d.ts.map +1 -0
  164. package/dist/core/blocked-outposts.js +77 -0
  165. package/dist/core/blocked-outposts.js.map +1 -0
  166. package/dist/core/citizen-bootstrap.d.ts +17 -0
  167. package/dist/core/citizen-bootstrap.d.ts.map +1 -0
  168. package/dist/core/citizen-bootstrap.js +118 -0
  169. package/dist/core/citizen-bootstrap.js.map +1 -0
  170. package/dist/core/citizen-tribute.d.ts +17 -0
  171. package/dist/core/citizen-tribute.d.ts.map +1 -0
  172. package/dist/core/citizen-tribute.js +55 -0
  173. package/dist/core/citizen-tribute.js.map +1 -0
  174. package/dist/core/command-bead.d.ts +6 -0
  175. package/dist/core/command-bead.d.ts.map +1 -0
  176. package/dist/core/command-bead.js +20 -0
  177. package/dist/core/command-bead.js.map +1 -0
  178. package/dist/core/courier.d.ts +52 -0
  179. package/dist/core/courier.d.ts.map +1 -0
  180. package/dist/core/courier.js +167 -0
  181. package/dist/core/courier.js.map +1 -0
  182. package/dist/core/fo-broadcast.d.ts +15 -0
  183. package/dist/core/fo-broadcast.d.ts.map +1 -0
  184. package/dist/core/fo-broadcast.js +57 -0
  185. package/dist/core/fo-broadcast.js.map +1 -0
  186. package/dist/core/fo-command-processor.d.ts +7 -0
  187. package/dist/core/fo-command-processor.d.ts.map +1 -0
  188. package/dist/core/fo-command-processor.js +123 -0
  189. package/dist/core/fo-command-processor.js.map +1 -0
  190. package/dist/core/fo-dispatch.d.ts +24 -0
  191. package/dist/core/fo-dispatch.d.ts.map +1 -0
  192. package/dist/core/fo-dispatch.js +76 -0
  193. package/dist/core/fo-dispatch.js.map +1 -0
  194. package/dist/core/fo-escalation.d.ts +20 -0
  195. package/dist/core/fo-escalation.d.ts.map +1 -0
  196. package/dist/core/fo-escalation.js +83 -0
  197. package/dist/core/fo-escalation.js.map +1 -0
  198. package/dist/core/fo-handlers/ceiling-hit.d.ts +8 -0
  199. package/dist/core/fo-handlers/ceiling-hit.d.ts.map +1 -0
  200. package/dist/core/fo-handlers/ceiling-hit.js +10 -0
  201. package/dist/core/fo-handlers/ceiling-hit.js.map +1 -0
  202. package/dist/core/fo-handlers/slot-open.d.ts +13 -0
  203. package/dist/core/fo-handlers/slot-open.d.ts.map +1 -0
  204. package/dist/core/fo-handlers/slot-open.js +63 -0
  205. package/dist/core/fo-handlers/slot-open.js.map +1 -0
  206. package/dist/core/fo-nudge-watcher.d.ts +19 -0
  207. package/dist/core/fo-nudge-watcher.d.ts.map +1 -0
  208. package/dist/core/fo-nudge-watcher.js +71 -0
  209. package/dist/core/fo-nudge-watcher.js.map +1 -0
  210. package/dist/core/fo-nudge-wiring.d.ts +13 -0
  211. package/dist/core/fo-nudge-wiring.d.ts.map +1 -0
  212. package/dist/core/fo-nudge-wiring.js +120 -0
  213. package/dist/core/fo-nudge-wiring.js.map +1 -0
  214. package/dist/core/fo-relay.d.ts +7 -0
  215. package/dist/core/fo-relay.d.ts.map +1 -0
  216. package/dist/core/fo-relay.js +47 -0
  217. package/dist/core/fo-relay.js.map +1 -0
  218. package/dist/core/fo-retry-policy.d.ts +17 -0
  219. package/dist/core/fo-retry-policy.d.ts.map +1 -0
  220. package/dist/core/fo-retry-policy.js +89 -0
  221. package/dist/core/fo-retry-policy.js.map +1 -0
  222. package/dist/core/fo-state.d.ts +25 -0
  223. package/dist/core/fo-state.d.ts.map +1 -0
  224. package/dist/core/fo-state.js +99 -0
  225. package/dist/core/fo-state.js.map +1 -0
  226. package/dist/core/fo-task-report.d.ts +16 -0
  227. package/dist/core/fo-task-report.d.ts.map +1 -0
  228. package/dist/core/fo-task-report.js +63 -0
  229. package/dist/core/fo-task-report.js.map +1 -0
  230. package/dist/core/fo-webhook.d.ts +22 -0
  231. package/dist/core/fo-webhook.d.ts.map +1 -0
  232. package/dist/core/fo-webhook.js +43 -0
  233. package/dist/core/fo-webhook.js.map +1 -0
  234. package/dist/core/grand-archives.d.ts +14 -0
  235. package/dist/core/grand-archives.d.ts.map +1 -0
  236. package/dist/core/grand-archives.js +79 -0
  237. package/dist/core/grand-archives.js.map +1 -0
  238. package/dist/core/nudge.d.ts +6 -0
  239. package/dist/core/nudge.d.ts.map +1 -0
  240. package/dist/core/nudge.js +19 -0
  241. package/dist/core/nudge.js.map +1 -0
  242. package/dist/core/outpost-registry.d.ts +16 -0
  243. package/dist/core/outpost-registry.d.ts.map +1 -0
  244. package/dist/core/outpost-registry.js +27 -0
  245. package/dist/core/outpost-registry.js.map +1 -0
  246. package/dist/core/pre-spawn-check.d.ts +16 -0
  247. package/dist/core/pre-spawn-check.d.ts.map +1 -0
  248. package/dist/core/pre-spawn-check.js +50 -0
  249. package/dist/core/pre-spawn-check.js.map +1 -0
  250. package/dist/core/process-registry.d.ts +17 -0
  251. package/dist/core/process-registry.d.ts.map +1 -0
  252. package/dist/core/process-registry.js +71 -0
  253. package/dist/core/process-registry.js.map +1 -0
  254. package/dist/core/spawn-citizen.d.ts +23 -0
  255. package/dist/core/spawn-citizen.d.ts.map +1 -0
  256. package/dist/core/spawn-citizen.js +99 -0
  257. package/dist/core/spawn-citizen.js.map +1 -0
  258. package/dist/core/timeout-watchdog.d.ts +14 -0
  259. package/dist/core/timeout-watchdog.d.ts.map +1 -0
  260. package/dist/core/timeout-watchdog.js +68 -0
  261. package/dist/core/timeout-watchdog.js.map +1 -0
  262. package/dist/core/validate-tribute.d.ts +11 -0
  263. package/dist/core/validate-tribute.d.ts.map +1 -0
  264. package/dist/core/validate-tribute.js +44 -0
  265. package/dist/core/validate-tribute.js.map +1 -0
  266. package/dist/core/worktree-manager.d.ts +20 -0
  267. package/dist/core/worktree-manager.d.ts.map +1 -0
  268. package/dist/core/worktree-manager.js +123 -0
  269. package/dist/core/worktree-manager.js.map +1 -0
  270. package/dist/index.d.ts +30 -0
  271. package/dist/index.d.ts.map +1 -0
  272. package/dist/index.js +30 -0
  273. package/dist/index.js.map +1 -0
  274. package/dist/types/agent.d.ts +47 -0
  275. package/dist/types/agent.d.ts.map +1 -0
  276. package/dist/types/agent.js +4 -0
  277. package/dist/types/agent.js.map +1 -0
  278. package/dist/types/beads.d.ts +175 -0
  279. package/dist/types/beads.d.ts.map +1 -0
  280. package/dist/types/beads.js +4 -0
  281. package/dist/types/beads.js.map +1 -0
  282. package/dist/types/index.d.ts +4 -0
  283. package/dist/types/index.d.ts.map +1 -0
  284. package/dist/types/index.js +4 -0
  285. package/dist/types/index.js.map +1 -0
  286. package/dist/types/registry.d.ts +110 -0
  287. package/dist/types/registry.d.ts.map +1 -0
  288. package/dist/types/registry.js +3 -0
  289. package/dist/types/registry.js.map +1 -0
  290. package/docs/README.md +7 -0
  291. package/docs/architecture.md +106 -0
  292. package/docs/cli-reference.md +81 -0
  293. package/docs/configuration.md +143 -0
  294. package/docs/contributing.md +65 -0
  295. package/docs/getting-started.md +88 -0
  296. package/grand-archives/archetypes/architect/archetype.json +18 -0
  297. package/grand-archives/archetypes/qa-engineer/archetype.json +18 -0
  298. package/grand-archives/archetypes/software-engineer/archetype.json +18 -0
  299. package/grand-archives/archetypes/software-engineer/system-prompt.md +39 -0
  300. package/grand-archives/archetypes/software-engineer/toolset.json +15 -0
  301. package/grand-archives/first-officer/config.json +21 -0
  302. package/grand-archives/first-officer/system-prompt.md +47 -0
  303. package/grand-archives/first-officer/toolset.json +19 -0
  304. package/grand-archives/registry.json +8 -0
  305. package/grand-archives/shared/base-prompt-preamble.md +25 -0
  306. package/grand-archives/shared/base-tools.json +10 -0
  307. package/package.json +73 -0
@@ -0,0 +1,158 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { runCli, seedWorkspace, cleanupWorkspace } from './helpers.js';
5
+ import { appendBead, mintBeadId } from '../../core/append-bead.js';
6
+ import { SCHEMA_VERSION } from '../../types/index.js';
7
+ describe('CLI e2e: reset, stop, tribute, trace', () => {
8
+ const dirs = [];
9
+ afterEach(async () => {
10
+ for (const d of dirs) {
11
+ await cleanupWorkspace(d);
12
+ }
13
+ dirs.length = 0;
14
+ });
15
+ it('citadel start writes identity bead and session.log', async () => {
16
+ const { workspace, outpostPath } = await seedWorkspace();
17
+ dirs.push(workspace, outpostPath);
18
+ const result = await runCli(['start'], workspace);
19
+ expect(result.exitCode).toBe(0);
20
+ expect(result.stdout).toContain('Citadel started');
21
+ // Verify identity.jsonl has content
22
+ const identity = await fs.readFile(path.join(workspace, '.citadel', 'identity.jsonl'), 'utf-8');
23
+ expect(identity.trim().length).toBeGreaterThan(0);
24
+ // Verify session.log
25
+ const log = await fs.readFile(path.join(workspace, '.citadel', 'logs', 'session.log'), 'utf-8');
26
+ expect(log).toContain('Session started');
27
+ });
28
+ it('citadel stop writes session.log and clears nudges', async () => {
29
+ const { workspace, outpostPath } = await seedWorkspace();
30
+ dirs.push(workspace, outpostPath);
31
+ // Start first to create identity
32
+ await runCli(['start'], workspace);
33
+ // Write an unprocessed nudge
34
+ const nudge = {
35
+ bead_id: mintBeadId('NUDGE'),
36
+ bead_type: 'NUDGE',
37
+ schema_version: SCHEMA_VERSION,
38
+ created_at: new Date().toISOString(),
39
+ signal_type: 'COMMAND_RECEIVED',
40
+ payload: { command_bead_id: 'cmd_test', command: 'dispatch' },
41
+ processed: false,
42
+ };
43
+ const nudgesPath = path.join(workspace, '.citadel', 'nudges.jsonl');
44
+ await fs.appendFile(nudgesPath, JSON.stringify(nudge) + '\n', 'utf-8');
45
+ const result = await runCli(['stop'], workspace);
46
+ expect(result.exitCode).toBe(0);
47
+ expect(result.stdout).toContain('Citadel stopped');
48
+ // Verify session.log has stop entry
49
+ const log = await fs.readFile(path.join(workspace, '.citadel', 'logs', 'session.log'), 'utf-8');
50
+ expect(log).toContain('Session stopped');
51
+ });
52
+ it('citadel reset clears unprocessed nudges and commands', async () => {
53
+ const { workspace, outpostPath } = await seedWorkspace();
54
+ dirs.push(workspace, outpostPath);
55
+ // Write some unprocessed nudges
56
+ const nudgesPath = path.join(workspace, '.citadel', 'nudges.jsonl');
57
+ for (let i = 0; i < 3; i++) {
58
+ await fs.appendFile(nudgesPath, JSON.stringify({
59
+ bead_id: mintBeadId('NUDGE'),
60
+ bead_type: 'NUDGE',
61
+ schema_version: SCHEMA_VERSION,
62
+ created_at: new Date().toISOString(),
63
+ signal_type: 'COMMAND_RECEIVED',
64
+ payload: { command_bead_id: `cmd_${i}`, command: 'dispatch' },
65
+ processed: false,
66
+ }) + '\n', 'utf-8');
67
+ }
68
+ const result = await runCli(['reset'], workspace);
69
+ expect(result.exitCode).toBe(0);
70
+ expect(result.stdout).toContain('reset');
71
+ });
72
+ it('citadel reset --hard removes .citadel/', async () => {
73
+ const { workspace, outpostPath } = await seedWorkspace();
74
+ dirs.push(workspace, outpostPath);
75
+ const result = await runCli(['reset', '--hard'], workspace);
76
+ expect(result.exitCode).toBe(0);
77
+ expect(result.stdout).toContain('hard reset');
78
+ // .citadel/ should be gone
79
+ try {
80
+ await fs.access(path.join(workspace, '.citadel'));
81
+ expect.fail('.citadel/ should not exist after hard reset');
82
+ }
83
+ catch {
84
+ // expected
85
+ }
86
+ });
87
+ it('citadel tribute shows tributes for a task', async () => {
88
+ const { workspace, outpostPath } = await seedWorkspace();
89
+ dirs.push(workspace, outpostPath);
90
+ // Write a tribute
91
+ const tribute = {
92
+ bead_id: mintBeadId('TRIBUTE'),
93
+ bead_type: 'TRIBUTE',
94
+ schema_version: SCHEMA_VERSION,
95
+ created_at: new Date().toISOString(),
96
+ citizen_id: 'citizen-test',
97
+ task_id: 'task-e2e',
98
+ originating_mail_ref: 'mail_ref',
99
+ archetype: 'software-engineer',
100
+ outpost: 'test-outpost',
101
+ worktree: '/tmp/wt',
102
+ attempt: 1,
103
+ status: 'SUCCESS',
104
+ summary: 'Feature implemented',
105
+ artifacts: ['src/feature.ts'],
106
+ acceptance_met: [true],
107
+ elapsed_seconds: 120,
108
+ };
109
+ await appendBead(path.join(outpostPath, '.beads', 'tribute', 'task-e2e_tribute.jsonl'), tribute);
110
+ const result = await runCli(['tribute', '--task', 'task-e2e'], workspace);
111
+ expect(result.exitCode).toBe(0);
112
+ expect(result.stdout).toContain('SUCCESS');
113
+ expect(result.stdout).toContain('Feature implemented');
114
+ expect(result.stdout).toContain('Attempt 1');
115
+ });
116
+ it('citadel tribute shows no results for unknown task', async () => {
117
+ const { workspace, outpostPath } = await seedWorkspace();
118
+ dirs.push(workspace, outpostPath);
119
+ const result = await runCli(['tribute', '--task', 'nonexistent'], workspace);
120
+ expect(result.exitCode).toBe(0);
121
+ expect(result.stdout).toContain('No tributes found');
122
+ });
123
+ it('citadel trace shows event timeline', async () => {
124
+ const { workspace, outpostPath } = await seedWorkspace();
125
+ dirs.push(workspace, outpostPath);
126
+ // Write a TASK_ASSIGNMENT mail
127
+ const mail = {
128
+ bead_id: mintBeadId('MAIL'),
129
+ bead_type: 'MAIL',
130
+ schema_version: SCHEMA_VERSION,
131
+ created_at: new Date().toISOString(),
132
+ task_id: 'task-trace',
133
+ mail_type: 'TASK_ASSIGNMENT',
134
+ from: 'citadel',
135
+ to: 'test-outpost',
136
+ subject: 'Test trace',
137
+ read: false,
138
+ retry_of: null,
139
+ payload: {
140
+ archetype: 'software-engineer',
141
+ citizen_id: 'citizen-1',
142
+ priority: 'MEDIUM',
143
+ title: 'Test',
144
+ description: 'Test',
145
+ acceptance_criteria: [],
146
+ context_refs: [],
147
+ dependencies: [],
148
+ timeout_seconds: 1800,
149
+ },
150
+ };
151
+ await appendBead(path.join(outpostPath, '.beads', 'mail', 'task-trace.jsonl'), mail);
152
+ const result = await runCli(['trace', '--task', 'task-trace'], workspace);
153
+ expect(result.exitCode).toBe(0);
154
+ expect(result.stdout).toContain('MAIL');
155
+ expect(result.stdout).toContain('TASK_ASSIGNMENT');
156
+ });
157
+ });
158
+ //# sourceMappingURL=reset-stop-tribute-trace.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-stop-tribute-trace.test.js","sourceRoot":"","sources":["../../../src/__tests__/cli-e2e/reset-stop-tribute-trace.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=courier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"courier.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/courier.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { Courier } from '../core/courier.js';
6
+ describe('Courier', () => {
7
+ let tmpDir;
8
+ beforeEach(async () => {
9
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'courier-'));
10
+ await fs.mkdir(path.join(tmpDir, '.citadel', 'commands'), { recursive: true });
11
+ await fs.writeFile(path.join(tmpDir, '.citadel', 'nudges.jsonl'), '', 'utf-8');
12
+ await fs.writeFile(path.join(tmpDir, '.citadel', 'outposts.json'), JSON.stringify({ schema_version: '1.0', outposts: [] }), 'utf-8');
13
+ });
14
+ afterEach(async () => {
15
+ await fs.rm(tmpDir, { recursive: true, force: true });
16
+ });
17
+ it('resolveConfig returns defaults when no config file exists', async () => {
18
+ const courier = new Courier({ citadelRoot: tmpDir });
19
+ const config = await courier.resolveConfig();
20
+ expect(config.poll_interval_ms).toBe(500);
21
+ expect(config.debounce_ms).toBe(200);
22
+ expect(config.default_max_citizens).toBe(3);
23
+ expect(config.citizen_timeout_seconds).toBe(1800);
24
+ expect(config.log_level).toBe('INFO');
25
+ });
26
+ it('resolveConfig reads courier.config.yaml when present', async () => {
27
+ const { stringify } = await import('yaml');
28
+ await fs.writeFile(path.join(tmpDir, 'courier.config.yaml'), stringify({
29
+ citadel_root: '.',
30
+ poll_interval_ms: 1000,
31
+ debounce_ms: 300,
32
+ default_max_citizens: 5,
33
+ citizen_timeout_seconds: 900,
34
+ log_level: 'DEBUG',
35
+ log_path: '.citadel/logs/courier.log',
36
+ }), 'utf-8');
37
+ const courier = new Courier({ citadelRoot: tmpDir });
38
+ const config = await courier.resolveConfig();
39
+ expect(config.poll_interval_ms).toBe(1000);
40
+ expect(config.default_max_citizens).toBe(5);
41
+ expect(config.citizen_timeout_seconds).toBe(900);
42
+ });
43
+ it('resolveConfig reads explicit config path', async () => {
44
+ const { stringify } = await import('yaml');
45
+ const customPath = path.join(tmpDir, 'custom.yaml');
46
+ await fs.writeFile(customPath, stringify({
47
+ citadel_root: '.',
48
+ poll_interval_ms: 2000,
49
+ debounce_ms: 100,
50
+ default_max_citizens: 1,
51
+ citizen_timeout_seconds: 600,
52
+ log_level: 'WARN',
53
+ log_path: '.citadel/logs/courier.log',
54
+ }), 'utf-8');
55
+ const courier = new Courier({ citadelRoot: tmpDir, configPath: customPath });
56
+ const config = await courier.resolveConfig();
57
+ expect(config.poll_interval_ms).toBe(2000);
58
+ expect(config.default_max_citizens).toBe(1);
59
+ });
60
+ it('getConfig returns the resolved config', async () => {
61
+ const courier = new Courier({ citadelRoot: tmpDir });
62
+ await courier.resolveConfig();
63
+ const config = courier.getConfig();
64
+ expect(config).toBeDefined();
65
+ expect(config.poll_interval_ms).toBe(500);
66
+ });
67
+ it('start and stop lifecycle works', async () => {
68
+ const courier = new Courier({ citadelRoot: tmpDir });
69
+ await courier.start();
70
+ await courier.stop();
71
+ });
72
+ it('classifyEvent correctly identifies command files', async () => {
73
+ const courier = new Courier({ citadelRoot: tmpDir });
74
+ await courier.resolveConfig();
75
+ // Access private method via casting
76
+ const classify = courier.classifyEvent.bind(courier);
77
+ const commandPath = path.resolve(tmpDir, '.citadel', 'commands', 'cmd_test.jsonl');
78
+ const result = classify(commandPath);
79
+ expect(result).toEqual({ type: 'command', filePath: commandPath });
80
+ });
81
+ it('classifyEvent correctly identifies nudges file', async () => {
82
+ const courier = new Courier({ citadelRoot: tmpDir });
83
+ await courier.resolveConfig();
84
+ const classify = courier.classifyEvent.bind(courier);
85
+ const nudgePath = path.resolve(tmpDir, '.citadel', 'nudges.jsonl');
86
+ const result = classify(nudgePath);
87
+ expect(result).toEqual({ type: 'nudge', filePath: nudgePath });
88
+ });
89
+ it('classifyEvent returns null for unrelated files', async () => {
90
+ const courier = new Courier({ citadelRoot: tmpDir });
91
+ await courier.resolveConfig();
92
+ const classify = courier.classifyEvent.bind(courier);
93
+ const result = classify(path.resolve(tmpDir, 'random.txt'));
94
+ expect(result).toBeNull();
95
+ });
96
+ });
97
+ //# sourceMappingURL=courier.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"courier.test.js","sourceRoot":"","sources":["../../src/__tests__/courier.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=e2e-smoke.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-smoke.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/e2e-smoke.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,137 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { execFile as execFileCb } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ const execFile = promisify(execFileCb);
8
+ /**
9
+ * E2E smoke test: simulates the critical user path
10
+ * npm install -> citadel init -> citadel start
11
+ *
12
+ * Since we can't actually run the CLI binary in tests easily,
13
+ * we test the same code paths programmatically.
14
+ */
15
+ describe('E2E smoke test (citadel-d60)', () => {
16
+ let tmpDir;
17
+ afterEach(async () => {
18
+ if (tmpDir)
19
+ await fs.rm(tmpDir, { recursive: true, force: true });
20
+ });
21
+ it('init -> register outpost -> start -> status flow works end-to-end', async () => {
22
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'citadel-e2e-'));
23
+ // Initialize git in tmpDir so appendBead git commits work
24
+ await execFile('git', ['init'], { cwd: tmpDir });
25
+ await execFile('git', ['config', 'user.email', 'test@citadel.dev'], { cwd: tmpDir });
26
+ await execFile('git', ['config', 'user.name', 'Citadel E2E'], { cwd: tmpDir });
27
+ await fs.writeFile(path.join(tmpDir, '.gitkeep'), '');
28
+ await execFile('git', ['add', '.'], { cwd: tmpDir });
29
+ await execFile('git', ['commit', '-m', 'init'], { cwd: tmpDir });
30
+ // 1. Init: create .citadel/ structure
31
+ const citadelDir = path.join(tmpDir, '.citadel');
32
+ await fs.mkdir(path.join(citadelDir, 'commands'), { recursive: true });
33
+ await fs.mkdir(path.join(citadelDir, 'logs'), { recursive: true });
34
+ await fs.writeFile(path.join(citadelDir, 'identity.jsonl'), '');
35
+ await fs.writeFile(path.join(citadelDir, 'nudges.jsonl'), '');
36
+ await fs.writeFile(path.join(citadelDir, 'outposts.json'), JSON.stringify({ schema_version: '1.0', outposts: [] }));
37
+ // Create grand-archives
38
+ const gaDir = path.join(tmpDir, 'grand-archives');
39
+ await fs.mkdir(path.join(gaDir, 'archetypes', 'software-engineer'), { recursive: true });
40
+ await fs.mkdir(path.join(gaDir, 'first-officer'), { recursive: true });
41
+ await fs.mkdir(path.join(gaDir, 'shared'), { recursive: true });
42
+ await fs.writeFile(path.join(gaDir, 'registry.json'), JSON.stringify({ schema_version: '1.0', archetypes: [{ key: 'software-engineer', description: 'SE', status: 'active' }] }));
43
+ await fs.writeFile(path.join(gaDir, 'first-officer', 'config.json'), JSON.stringify({
44
+ schema_version: '1.0', display_name: 'FO', singleton: true, assignable: false,
45
+ agent: 'claude-code', system_prompt_ref: 'first-officer/system-prompt.md',
46
+ toolset_ref: 'first-officer/toolset.json', model: 'claude-opus-4',
47
+ constraints: { temperature: 0.2, max_tokens_per_turn: 8192 },
48
+ retry_policy: { max_retries: 3, retry_on: ['PARTIAL'], partial_strategy: 'remaining_criteria_only', on_ceiling_reached: 'ESCALATE_TO_COMMANDER' },
49
+ nudge_retention: 500,
50
+ }));
51
+ await fs.writeFile(path.join(gaDir, 'shared', 'base-prompt-preamble.md'), '# Preamble\n');
52
+ await fs.writeFile(path.join(gaDir, 'archetypes', 'software-engineer', 'system-prompt.md'), '# SE Prompt\n');
53
+ await fs.writeFile(path.join(gaDir, 'archetypes', 'software-engineer', 'archetype.json'), JSON.stringify({
54
+ key: 'software-engineer', schema_version: '1.0', display_name: 'SE',
55
+ system_prompt: { preamble_ref: 'shared/base-prompt-preamble.md', body_ref: 'archetypes/software-engineer/system-prompt.md' },
56
+ toolset: { base_ref: 'shared/base-tools.json', override_ref: 'archetypes/software-engineer/toolset.json' },
57
+ constraints: { max_tokens_per_turn: 8192, temperature: 0.2, model: 'claude-opus-4' },
58
+ }));
59
+ await fs.writeFile(path.join(gaDir, 'archetypes', 'software-engineer', 'toolset.json'), JSON.stringify({ schema_version: '1.0', description: 'SE tools', tools: [] }));
60
+ // Commit the init
61
+ await execFile('git', ['add', '.'], { cwd: tmpDir });
62
+ await execFile('git', ['commit', '-m', 'citadel init'], { cwd: tmpDir });
63
+ // Verify .citadel/ exists
64
+ const stat = await fs.stat(citadelDir);
65
+ expect(stat.isDirectory()).toBe(true);
66
+ // 2. Register an outpost
67
+ const outpostPath = path.join(tmpDir, 'my-outpost');
68
+ await fs.mkdir(outpostPath, { recursive: true });
69
+ await execFile('git', ['init'], { cwd: outpostPath });
70
+ await execFile('git', ['config', 'user.email', 'test@citadel.dev'], { cwd: outpostPath });
71
+ await execFile('git', ['config', 'user.name', 'E2E'], { cwd: outpostPath });
72
+ await fs.writeFile(path.join(outpostPath, '.gitkeep'), '');
73
+ await execFile('git', ['add', '.'], { cwd: outpostPath });
74
+ await execFile('git', ['commit', '-m', 'init'], { cwd: outpostPath });
75
+ // Simulate outpost register
76
+ await fs.mkdir(path.join(outpostPath, '.beads', 'mail'), { recursive: true });
77
+ await fs.mkdir(path.join(outpostPath, '.beads', 'tribute'), { recursive: true });
78
+ await fs.mkdir(path.join(outpostPath, 'worktrees', 'citizen'), { recursive: true });
79
+ await fs.writeFile(path.join(outpostPath, '.beads', 'mail', '.gitignore'), '*.jsonl.lock\n');
80
+ await fs.writeFile(path.join(outpostPath, '.beads', 'tribute', '.gitignore'), '*.jsonl.lock\n');
81
+ const registry = {
82
+ schema_version: '1.0',
83
+ outposts: [{
84
+ slug: 'my-outpost', path: outpostPath, status: 'ACTIVE',
85
+ registered_at: new Date().toISOString(), default_archetype: 'software-engineer', max_citizens: 3,
86
+ }],
87
+ };
88
+ await fs.writeFile(path.join(citadelDir, 'outposts.json'), JSON.stringify(registry));
89
+ await execFile('git', ['add', '.'], { cwd: outpostPath });
90
+ await execFile('git', ['commit', '-m', 'register outpost'], { cwd: outpostPath });
91
+ // 3. Start: write identity bead, rotate nudges
92
+ const { appendBead, mintBeadId, readBeads } = await import('../core/append-bead.js');
93
+ const { SCHEMA_VERSION } = await import('../types/index.js');
94
+ await execFile('git', ['add', '.'], { cwd: tmpDir });
95
+ await execFile('git', ['commit', '-m', 'pre-start'], { cwd: tmpDir });
96
+ const identityBead = {
97
+ bead_id: mintBeadId('IDENTITY'),
98
+ bead_type: 'IDENTITY',
99
+ schema_version: SCHEMA_VERSION,
100
+ created_at: new Date().toISOString(),
101
+ role: 'first-officer',
102
+ display_name: 'First Officer',
103
+ agent: 'claude-code',
104
+ citadel_root: tmpDir,
105
+ last_session_at: new Date().toISOString(),
106
+ };
107
+ await appendBead(path.join(citadelDir, 'identity.jsonl'), identityBead);
108
+ // Verify identity bead
109
+ const identityBeads = await readBeads(path.join(citadelDir, 'identity.jsonl'));
110
+ expect(identityBeads.length).toBeGreaterThanOrEqual(1);
111
+ expect(identityBeads[0].bead_id).toMatch(/^identity_/);
112
+ // 4. Dispatch a task
113
+ const { dispatch } = await import('../core/fo-dispatch.js');
114
+ const { ProcessRegistry } = await import('../core/process-registry.js');
115
+ const processRegistry = new ProcessRegistry();
116
+ const mail = await dispatch({
117
+ citadelRoot: tmpDir,
118
+ outpostSlug: 'my-outpost',
119
+ task: { title: 'E2E Test Feature', description: 'Build it', acceptanceCriteria: ['It works'] },
120
+ processRegistry,
121
+ });
122
+ expect(mail.bead_id).toMatch(/^mail_/);
123
+ expect(mail.mail_type).toBe('TASK_ASSIGNMENT');
124
+ expect(mail.spawn_hint).toBeDefined();
125
+ expect(mail.spawn_hint.citizen_id).toMatch(/^citizen-/);
126
+ // 5. Verify .gitignore exists
127
+ const gitignoreContent = await fs.readFile(path.join(outpostPath, '.beads', 'mail', '.gitignore'), 'utf-8');
128
+ expect(gitignoreContent).toContain('*.jsonl.lock');
129
+ // 6. Verify the full composed prompt
130
+ const { GrandArchives } = await import('../core/grand-archives.js');
131
+ const archives = new GrandArchives(tmpDir);
132
+ const composed = await archives.resolveComposedPrompt('software-engineer');
133
+ expect(composed).toContain('Preamble');
134
+ expect(composed).toContain('SE Prompt');
135
+ });
136
+ });
137
+ //# sourceMappingURL=e2e-smoke.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/e2e-smoke.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;AAEvC;;;;;;GAMG;AACH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAI,MAAc,CAAC;IAEnB,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,MAAM;YAAE,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;QAElE,0DAA0D;QAC1D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,kBAAkB,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrF,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/E,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAEjE,sCAAsC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACjD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAC;QAChE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EACtC,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CACxD,CAAC;QAEF,wBAAwB;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAClD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEhE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,EAClD,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9H,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,aAAa,CAAC,EACjE,IAAI,CAAC,SAAS,CAAC;YACb,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK;YAC7E,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,gCAAgC;YACzE,WAAW,EAAE,4BAA4B,EAAE,KAAK,EAAE,eAAe;YACjE,WAAW,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE;YAC5D,YAAY,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE;YACjJ,eAAe,EAAE,GAAG;SACrB,CAAC,CAAC,CAAC;QACN,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,yBAAyB,CAAC,EAAE,cAAc,CAAC,CAAC;QAC1F,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,CAAC,EAAE,eAAe,CAAC,CAAC;QAC7G,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,EACtF,IAAI,CAAC,SAAS,CAAC;YACb,GAAG,EAAE,mBAAmB,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI;YACnE,aAAa,EAAE,EAAE,YAAY,EAAE,gCAAgC,EAAE,QAAQ,EAAE,+CAA+C,EAAE;YAC5H,OAAO,EAAE,EAAE,QAAQ,EAAE,wBAAwB,EAAE,YAAY,EAAE,2CAA2C,EAAE;YAC1G,WAAW,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE;SACrF,CAAC,CAAC,CAAC;QACN,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,CAAC,EACpF,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAEjF,kBAAkB;QAClB,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAEzE,0BAA0B;QAC1B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtC,yBAAyB;QACzB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QACtD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,kBAAkB,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1F,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5E,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAEtE,4BAA4B;QAC5B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC7F,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAEhG,MAAM,QAAQ,GAAG;YACf,cAAc,EAAE,KAAK;YACrB,QAAQ,EAAE,CAAC;oBACT,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ;oBACvD,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;iBACjG,CAAC;SACH,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrF,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,kBAAkB,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAElF,+CAA+C;QAC/C,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACrF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAE7D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtE,MAAM,YAAY,GAAG;YACnB,OAAO,EAAE,UAAU,CAAC,UAAU,CAAC;YAC/B,SAAS,EAAE,UAAmB;YAC9B,cAAc,EAAE,cAAc;YAC9B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,IAAI,EAAE,eAAwB;YAC9B,YAAY,EAAE,eAAe;YAC7B,KAAK,EAAE,aAAa;YACpB,YAAY,EAAE,MAAM;YACpB,eAAe,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC1C,CAAC;QACF,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,YAAY,CAAC,CAAC;QAExE,uBAAuB;QACvB,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAC/E,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,aAAa,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAExD,qBAAqB;QACrB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;QAC5D,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;QAExE,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC;YAC1B,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,YAAY;YACzB,IAAI,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,UAAU,CAAC,EAAE;YAC9F,eAAe;SAChB,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,UAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEzD,8BAA8B;QAC9B,MAAM,gBAAgB,GAAG,MAAM,EAAE,CAAC,QAAQ,CACxC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QACnE,MAAM,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAEnD,qCAAqC;QACrC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fo-broadcast.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-broadcast.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fo-broadcast.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import { broadcastDependencyResolved } from '../core/fo-broadcast.js';
6
+ import { readBeads } from '../core/append-bead.js';
7
+ describe('broadcastDependencyResolved', () => {
8
+ let tmpDir;
9
+ let alphaPath;
10
+ let betaPath;
11
+ beforeEach(async () => {
12
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'citadel-broadcast-'));
13
+ alphaPath = path.join(tmpDir, 'outposts', 'alpha');
14
+ betaPath = path.join(tmpDir, 'outposts', 'beta');
15
+ await fs.mkdir(path.join(tmpDir, '.citadel'), { recursive: true });
16
+ await fs.mkdir(path.join(alphaPath, '.beads', 'mail'), { recursive: true });
17
+ await fs.mkdir(path.join(alphaPath, '.beads', 'tribute'), { recursive: true });
18
+ await fs.mkdir(path.join(betaPath, '.beads', 'mail'), { recursive: true });
19
+ await fs.mkdir(path.join(betaPath, '.beads', 'tribute'), { recursive: true });
20
+ const registry = {
21
+ schema_version: '1.0',
22
+ outposts: [
23
+ { slug: 'alpha', path: alphaPath, status: 'ACTIVE', registered_at: '2026-01-01T00:00:00Z' },
24
+ { slug: 'beta', path: betaPath, status: 'ACTIVE', registered_at: '2026-01-02T00:00:00Z' },
25
+ ],
26
+ };
27
+ await fs.writeFile(path.join(tmpDir, '.citadel', 'outposts.json'), JSON.stringify(registry));
28
+ });
29
+ afterEach(async () => {
30
+ await fs.rm(tmpDir, { recursive: true, force: true });
31
+ });
32
+ const makeAssignmentMail = (taskId, to, deps) => ({
33
+ bead_id: `bead-${taskId}`,
34
+ bead_type: 'MAIL',
35
+ schema_version: '9.0',
36
+ created_at: '2026-01-01T00:00:00Z',
37
+ task_id: taskId,
38
+ mail_type: 'TASK_ASSIGNMENT',
39
+ from: 'citadel',
40
+ to,
41
+ subject: `Task ${taskId}`,
42
+ read: false,
43
+ retry_of: null,
44
+ payload: {
45
+ archetype: 'software-engineer',
46
+ citizen_id: `citizen-${taskId}`,
47
+ priority: 'MEDIUM',
48
+ title: `Task ${taskId}`,
49
+ description: 'test',
50
+ acceptance_criteria: [],
51
+ context_refs: [],
52
+ dependencies: deps,
53
+ timeout_seconds: 1800,
54
+ },
55
+ });
56
+ const successTribute = {
57
+ bead_id: 'tribute-task-X',
58
+ bead_type: 'TRIBUTE',
59
+ schema_version: '9.0',
60
+ created_at: '2026-01-01T01:00:00Z',
61
+ citizen_id: 'citizen-X',
62
+ task_id: 'task-X',
63
+ originating_mail_ref: 'bead-task-X',
64
+ archetype: 'software-engineer',
65
+ outpost: 'alpha',
66
+ worktree: 'worktrees/citizen/task-X',
67
+ attempt: 1,
68
+ status: 'SUCCESS',
69
+ pr_url: 'https://github.com/org/repo/pull/42',
70
+ summary: 'Implemented feature X',
71
+ artifacts: ['src/feature-x.ts'],
72
+ acceptance_met: [true],
73
+ elapsed_seconds: 300,
74
+ };
75
+ it('sends DEPENDENCY_RESOLVED to all blocked tasks', async () => {
76
+ // alpha task-A depends on task-X
77
+ const mailA = makeAssignmentMail('task-A', 'alpha', ['task-X']);
78
+ await fs.writeFile(path.join(alphaPath, '.beads', 'mail', 'task-A.jsonl'), JSON.stringify(mailA) + '\n');
79
+ // beta task-B depends on task-X
80
+ const mailB = makeAssignmentMail('task-B', 'beta', ['task-X']);
81
+ await fs.writeFile(path.join(betaPath, '.beads', 'mail', 'task-B.jsonl'), JSON.stringify(mailB) + '\n');
82
+ const result = await broadcastDependencyResolved(tmpDir, successTribute);
83
+ expect(result.sent).toBe(2);
84
+ expect(result.recipients.map(r => r.outpost).sort()).toEqual(['alpha', 'beta']);
85
+ // Verify DEPENDENCY_RESOLVED mail was written to alpha
86
+ const alphaFiles = await fs.readdir(path.join(alphaPath, '.beads', 'mail'));
87
+ const depResFiles = alphaFiles.filter(f => f.startsWith('depres-'));
88
+ expect(depResFiles).toHaveLength(1);
89
+ const mails = await readBeads(path.join(alphaPath, '.beads', 'mail', depResFiles[0]));
90
+ expect(mails).toHaveLength(1);
91
+ expect(mails[0].mail_type).toBe('DEPENDENCY_RESOLVED');
92
+ expect(mails[0].task_id).toBe('task-A');
93
+ expect(mails[0].to).toBe('alpha');
94
+ const payload = mails[0].payload;
95
+ expect(payload.resolved_task_id).toBe('task-X');
96
+ expect(payload.resolved_by_outpost).toBe('alpha');
97
+ expect(payload.tribute_ref).toBe('tribute-task-X');
98
+ expect(payload.pr_url).toBe('https://github.com/org/repo/pull/42');
99
+ expect(payload.summary).toBe('Implemented feature X');
100
+ });
101
+ it('returns empty result when no tasks are blocked', async () => {
102
+ // No tasks depend on task-X
103
+ const result = await broadcastDependencyResolved(tmpDir, successTribute);
104
+ expect(result.sent).toBe(0);
105
+ expect(result.recipients).toEqual([]);
106
+ });
107
+ it('skips tasks that already succeeded', async () => {
108
+ // alpha task-A depends on task-X but already succeeded
109
+ const mailA = makeAssignmentMail('task-A', 'alpha', ['task-X']);
110
+ await fs.writeFile(path.join(alphaPath, '.beads', 'mail', 'task-A.jsonl'), JSON.stringify(mailA) + '\n');
111
+ const tribute = {
112
+ bead_id: 'tribute-task-A',
113
+ bead_type: 'TRIBUTE',
114
+ schema_version: '9.0',
115
+ created_at: '2026-01-01T00:30:00Z',
116
+ citizen_id: 'citizen-A',
117
+ task_id: 'task-A',
118
+ originating_mail_ref: 'bead-task-A',
119
+ archetype: 'software-engineer',
120
+ outpost: 'alpha',
121
+ worktree: 'worktrees/citizen/task-A',
122
+ attempt: 1,
123
+ status: 'SUCCESS',
124
+ summary: 'done',
125
+ artifacts: [],
126
+ acceptance_met: [],
127
+ elapsed_seconds: 60,
128
+ };
129
+ await fs.writeFile(path.join(alphaPath, '.beads', 'tribute', 'task-A.jsonl'), JSON.stringify(tribute) + '\n');
130
+ const result = await broadcastDependencyResolved(tmpDir, successTribute);
131
+ expect(result.sent).toBe(0);
132
+ });
133
+ });
134
+ //# sourceMappingURL=fo-broadcast.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-broadcast.test.js","sourceRoot":"","sources":["../../src/__tests__/fo-broadcast.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fo-command-processor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-command-processor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fo-command-processor.test.ts"],"names":[],"mappings":""}