@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,76 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { nanoid } from 'nanoid';
4
+ import { appendBead, mintBeadId } from './append-bead.js';
5
+ import { GrandArchives } from './grand-archives.js';
6
+ import { SCHEMA_VERSION } from '../types/index.js';
7
+ /**
8
+ * First Officer dispatch: select archetype, mint citizen_id, compose TASK_ASSIGNMENT mail,
9
+ * write to outpost inbox. Respects max_citizens ceiling.
10
+ */
11
+ export async function dispatch(opts) {
12
+ const { citadelRoot, outpostSlug, task, processRegistry } = opts;
13
+ // Resolve outpost from registry
14
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
15
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
16
+ const registry = JSON.parse(raw);
17
+ const outpost = registry.outposts.find((o) => o.slug === outpostSlug);
18
+ if (!outpost)
19
+ throw new Error(`Outpost "${outpostSlug}" not found`);
20
+ // Check ceiling
21
+ const maxCitizens = outpost.max_citizens ?? 3;
22
+ const activeCount = processRegistry.countActive(outpostSlug);
23
+ if (activeCount >= maxCitizens) {
24
+ console.log(`[FO dispatch] Ceiling reached for "${outpostSlug}": ${activeCount}/${maxCitizens}. Mail queued in inbox.`);
25
+ }
26
+ // Select archetype
27
+ let archetypeKey = opts.archetype ?? outpost.default_archetype;
28
+ if (!archetypeKey) {
29
+ // Auto-select: use first active archetype from registry
30
+ const archives = new GrandArchives(citadelRoot);
31
+ const archetypeRegistry = await archives.listArchetypes();
32
+ const active = archetypeRegistry.archetypes.find(a => a.status === 'active');
33
+ if (!active)
34
+ throw new Error('No active archetypes in registry');
35
+ archetypeKey = active.key;
36
+ }
37
+ // Mint citizen_id
38
+ const citizenId = `citizen-${nanoid()}`;
39
+ const taskId = `task-${nanoid()}`;
40
+ // Compose TASK_ASSIGNMENT mail
41
+ const payload = {
42
+ archetype: archetypeKey,
43
+ citizen_id: citizenId,
44
+ priority: task.priority ?? 'MEDIUM',
45
+ title: task.title,
46
+ description: task.description,
47
+ acceptance_criteria: task.acceptanceCriteria,
48
+ context_refs: task.contextRefs ?? [],
49
+ dependencies: task.dependencies ?? [],
50
+ timeout_seconds: task.timeoutSeconds ?? 1800,
51
+ };
52
+ const mail = {
53
+ bead_id: mintBeadId('MAIL'),
54
+ bead_type: 'MAIL',
55
+ schema_version: SCHEMA_VERSION,
56
+ created_at: new Date().toISOString(),
57
+ task_id: taskId,
58
+ mail_type: 'TASK_ASSIGNMENT',
59
+ from: 'citadel',
60
+ to: outpostSlug,
61
+ subject: task.title,
62
+ read: false,
63
+ retry_of: null,
64
+ spawn_hint: {
65
+ archetype: archetypeKey,
66
+ citizen_id: citizenId,
67
+ },
68
+ payload,
69
+ };
70
+ // Write to outpost inbox
71
+ const mailPath = path.join(outpost.path, '.beads', 'mail', `${taskId}.jsonl`);
72
+ await appendBead(mailPath, mail);
73
+ console.log(`[FO dispatch] Task "${task.title}" -> outpost "${outpostSlug}" (citizen: ${citizenId}, archetype: ${archetypeKey})`);
74
+ return mail;
75
+ }
76
+ //# sourceMappingURL=fo-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-dispatch.js","sourceRoot":"","sources":["../../src/core/fo-dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { TributeBead, ResolveAction } from '../types/index.js';
2
+ export interface EscalationReport {
3
+ taskId: string;
4
+ outpost: string;
5
+ attempts: TributeBead[];
6
+ lastStatus: string;
7
+ recommendation: string;
8
+ }
9
+ /**
10
+ * Build an escalation report for a task that has hit the retry ceiling.
11
+ */
12
+ export declare function buildEscalationReport(citadelRoot: string, taskId: string): Promise<EscalationReport>;
13
+ /**
14
+ * Resolve a task per Commander decision:
15
+ * - retry: override ceiling for one more attempt
16
+ * - abandon: log closure, no further action
17
+ * - rewrite: new TASK_ASSIGNMENT with Commander note
18
+ */
19
+ export declare function resolveTask(citadelRoot: string, taskId: string, action: ResolveAction, note?: string): Promise<void>;
20
+ //# sourceMappingURL=fo-escalation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-escalation.d.ts","sourceRoot":"","sources":["../../src/core/fo-escalation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAY,WAAW,EAAmB,aAAa,EAAyB,MAAM,mBAAmB,CAAC;AAEtH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAiB3B;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmDf"}
@@ -0,0 +1,83 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { appendBead, mintBeadId } from './append-bead.js';
4
+ import { reconstructState } from './fo-state.js';
5
+ /**
6
+ * Build an escalation report for a task that has hit the retry ceiling.
7
+ */
8
+ export async function buildEscalationReport(citadelRoot, taskId) {
9
+ const state = await reconstructState(citadelRoot);
10
+ const task = state.tasks.find(t => t.taskId === taskId);
11
+ if (!task)
12
+ throw new Error(`Task "${taskId}" not found`);
13
+ const lastStatus = task.latestTribute?.status ?? 'unknown';
14
+ const recommendation = lastStatus === 'PARTIAL'
15
+ ? 'Consider retry with adjusted criteria or rewrite the task'
16
+ : 'Consider abandoning or rewriting with different approach';
17
+ return {
18
+ taskId,
19
+ outpost: task.outpost,
20
+ attempts: task.tributes,
21
+ lastStatus,
22
+ recommendation,
23
+ };
24
+ }
25
+ /**
26
+ * Resolve a task per Commander decision:
27
+ * - retry: override ceiling for one more attempt
28
+ * - abandon: log closure, no further action
29
+ * - rewrite: new TASK_ASSIGNMENT with Commander note
30
+ */
31
+ export async function resolveTask(citadelRoot, taskId, action, note) {
32
+ const state = await reconstructState(citadelRoot);
33
+ const task = state.tasks.find(t => t.taskId === taskId);
34
+ if (!task)
35
+ throw new Error(`Task "${taskId}" not found`);
36
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
37
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
38
+ const registry = JSON.parse(raw);
39
+ const outpost = registry.outposts.find(o => o.slug === task.outpost);
40
+ if (!outpost)
41
+ throw new Error(`Outpost "${task.outpost}" not found`);
42
+ switch (action) {
43
+ case 'retry': {
44
+ // Override ceiling: re-issue TASK_ASSIGNMENT with retry_of
45
+ const retryMail = {
46
+ ...task.assignmentMail,
47
+ bead_id: mintBeadId('MAIL'),
48
+ created_at: new Date().toISOString(),
49
+ read: false,
50
+ retry_of: task.assignmentMail.bead_id,
51
+ };
52
+ const mailPath = path.join(outpost.path, '.beads', 'mail', `resolve-retry-${retryMail.bead_id}.jsonl`);
53
+ await appendBead(mailPath, retryMail);
54
+ console.log(`[FO] Ceiling override retry for task "${taskId}"`);
55
+ break;
56
+ }
57
+ case 'abandon': {
58
+ console.log(`[FO] Task "${taskId}" abandoned by Commander${note ? `: ${note}` : ''}`);
59
+ break;
60
+ }
61
+ case 'rewrite': {
62
+ // New TASK_ASSIGNMENT with note appended to description
63
+ const origPayload = task.assignmentMail.payload;
64
+ const newMail = {
65
+ ...task.assignmentMail,
66
+ bead_id: mintBeadId('MAIL'),
67
+ created_at: new Date().toISOString(),
68
+ read: false,
69
+ retry_of: null,
70
+ subject: `[REWRITE] ${task.assignmentMail.subject}`,
71
+ payload: {
72
+ ...origPayload,
73
+ description: `${origPayload.description}\n\n[Commander rewrite note]: ${note ?? 'No additional notes.'}`,
74
+ },
75
+ };
76
+ const mailPath = path.join(outpost.path, '.beads', 'mail', `rewrite-${newMail.bead_id}.jsonl`);
77
+ await appendBead(mailPath, newMail);
78
+ console.log(`[FO] Task "${taskId}" rewritten by Commander${note ? `: ${note}` : ''}`);
79
+ break;
80
+ }
81
+ }
82
+ }
83
+ //# sourceMappingURL=fo-escalation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-escalation.js","sourceRoot":"","sources":["../../src/core/fo-escalation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { NudgeBead } from '../../types/index.js';
2
+ /**
3
+ * Handle PARALLELISM_CEILING_HIT nudge.
4
+ * Log contention and do nothing — pending work stays in inbox.
5
+ * Dispatch resumes automatically when a slot opens via TRIBUTE_WRITTEN SUCCESS.
6
+ */
7
+ export declare function handleCeilingHit(nudge: NudgeBead): Promise<void>;
8
+ //# sourceMappingURL=ceiling-hit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceiling-hit.d.ts","sourceRoot":"","sources":["../../../src/core/fo-handlers/ceiling-hit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAgC,MAAM,sBAAsB,CAAC;AAEpF;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtE"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Handle PARALLELISM_CEILING_HIT nudge.
3
+ * Log contention and do nothing — pending work stays in inbox.
4
+ * Dispatch resumes automatically when a slot opens via TRIBUTE_WRITTEN SUCCESS.
5
+ */
6
+ export async function handleCeilingHit(nudge) {
7
+ const payload = nudge.payload;
8
+ console.log(`[FO] Ceiling hit on outpost "${payload.outpost}": ${payload.active_count}/${payload.ceiling} active citizens. Pending work queued.`);
9
+ }
10
+ //# sourceMappingURL=ceiling-hit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceiling-hit.js","sourceRoot":"","sources":["../../../src/core/fo-handlers/ceiling-hit.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAgB;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAuC,CAAC;IAC9D,OAAO,CAAC,GAAG,CACT,gCAAgC,OAAO,CAAC,OAAO,MAAM,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,wCAAwC,CACrI,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { ProcessRegistry } from '../process-registry.js';
2
+ import type { NudgeBead } from '../../types/index.js';
3
+ export interface SlotOpenResult {
4
+ dispatched: boolean;
5
+ taskId?: string;
6
+ }
7
+ /**
8
+ * Handle TRIBUTE_WRITTEN nudge — slot-open dispatch.
9
+ * On SUCCESS: check for pending TASK_ASSIGNMENT mail and dispatch if under ceiling.
10
+ * PRD §3.3.3/§3.3.4
11
+ */
12
+ export declare function handleSlotOpen(nudge: NudgeBead, citadelRoot: string, processRegistry?: ProcessRegistry): Promise<SlotOpenResult | undefined>;
13
+ //# sourceMappingURL=slot-open.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-open.d.ts","sourceRoot":"","sources":["../../../src/core/fo-handlers/slot-open.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAuF,MAAM,sBAAsB,CAAC;AAE3I,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAyDrC"}
@@ -0,0 +1,63 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads } from '../append-bead.js';
4
+ /**
5
+ * Handle TRIBUTE_WRITTEN nudge — slot-open dispatch.
6
+ * On SUCCESS: check for pending TASK_ASSIGNMENT mail and dispatch if under ceiling.
7
+ * PRD §3.3.3/§3.3.4
8
+ */
9
+ export async function handleSlotOpen(nudge, citadelRoot, processRegistry) {
10
+ const payload = nudge.payload;
11
+ // Read the tribute to check status
12
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
13
+ let outpostEntry;
14
+ let outpostPath = '';
15
+ try {
16
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
17
+ const registry = JSON.parse(raw);
18
+ outpostEntry = registry.outposts.find(o => o.slug === payload.outpost);
19
+ if (outpostEntry)
20
+ outpostPath = outpostEntry.path;
21
+ }
22
+ catch {
23
+ return;
24
+ }
25
+ if (!outpostPath || !outpostEntry)
26
+ return;
27
+ // Read tribute file
28
+ const tributePath = path.join(outpostPath, '.beads', 'tribute', `${payload.task_id}_tribute.jsonl`);
29
+ const tributes = await readBeads(tributePath);
30
+ const latest = tributes[tributes.length - 1];
31
+ if (!latest || latest.status !== 'SUCCESS') {
32
+ console.log(`[FO] Tribute for task "${payload.task_id}" is not SUCCESS (${latest?.status ?? 'none'}), no slot opened`);
33
+ return { dispatched: false };
34
+ }
35
+ // Check inbox for pending unread TASK_ASSIGNMENT
36
+ const mailDir = path.join(outpostPath, '.beads', 'mail');
37
+ const pendingMails = [];
38
+ try {
39
+ const files = await fs.readdir(mailDir);
40
+ for (const file of files) {
41
+ if (!file.endsWith('.jsonl'))
42
+ continue;
43
+ const mails = await readBeads(path.join(mailDir, file));
44
+ pendingMails.push(...mails.filter(m => m.mail_type === 'TASK_ASSIGNMENT' && !m.read));
45
+ }
46
+ }
47
+ catch { /* no mail dir */ }
48
+ // Sort by created_at to get oldest first
49
+ pendingMails.sort((a, b) => a.created_at.localeCompare(b.created_at));
50
+ console.log(`[FO] Slot opened on outpost "${payload.outpost}" (task "${payload.task_id}" completed). ${pendingMails.length} pending task(s) in inbox.`);
51
+ // If pending work exists and we have a process registry, check ceiling and dispatch
52
+ if (pendingMails.length > 0 && processRegistry) {
53
+ const maxCitizens = outpostEntry.max_citizens ?? 3;
54
+ const activeCount = processRegistry.countActive(payload.outpost);
55
+ if (activeCount < maxCitizens) {
56
+ const oldest = pendingMails[0];
57
+ console.log(`[FO] Dispatching pending task "${oldest.task_id}" on slot open`);
58
+ return { dispatched: true, taskId: oldest.task_id };
59
+ }
60
+ }
61
+ return { dispatched: pendingMails.length > 0 };
62
+ }
63
+ //# sourceMappingURL=slot-open.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-open.js","sourceRoot":"","sources":["../../../src/core/fo-handlers/slot-open.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { NudgeBead, NudgeSignalType } from '../types/index.js';
2
+ export type NudgeHandler = (nudge: NudgeBead) => Promise<void>;
3
+ export declare class NudgeWatcher {
4
+ private citadelRoot;
5
+ private handlers;
6
+ private running;
7
+ private pollIntervalMs;
8
+ private intervalHandle;
9
+ constructor(citadelRoot: string, pollIntervalMs?: number);
10
+ /** Register a handler for a specific signal type */
11
+ on(signalType: NudgeSignalType, handler: NudgeHandler): void;
12
+ /** Start the watcher loop */
13
+ start(): void;
14
+ /** Stop the watcher loop */
15
+ stop(): void;
16
+ /** Process unprocessed nudges in arrival order */
17
+ private processNudges;
18
+ }
19
+ //# sourceMappingURL=fo-nudge-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-nudge-watcher.d.ts","sourceRoot":"","sources":["../../src/core/fo-nudge-watcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpE,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/D,qBAAa,YAAY;IAOrB,OAAO,CAAC,WAAW;IANrB,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,cAAc,CAA+C;gBAG3D,WAAW,EAAE,MAAM,EAC3B,cAAc,GAAE,MAAY;IAK9B,oDAAoD;IACpD,EAAE,CAAC,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAI5D,6BAA6B;IAC7B,KAAK,IAAI,IAAI;IAUb,4BAA4B;IAC5B,IAAI,IAAI,IAAI;IAQZ,kDAAkD;YACpC,aAAa;CAoC5B"}
@@ -0,0 +1,71 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads } from './append-bead.js';
4
+ export class NudgeWatcher {
5
+ citadelRoot;
6
+ handlers = new Map();
7
+ running = false;
8
+ pollIntervalMs;
9
+ intervalHandle = null;
10
+ constructor(citadelRoot, pollIntervalMs = 500) {
11
+ this.citadelRoot = citadelRoot;
12
+ this.pollIntervalMs = pollIntervalMs;
13
+ }
14
+ /** Register a handler for a specific signal type */
15
+ on(signalType, handler) {
16
+ this.handlers.set(signalType, handler);
17
+ }
18
+ /** Start the watcher loop */
19
+ start() {
20
+ if (this.running)
21
+ return;
22
+ this.running = true;
23
+ this.intervalHandle = setInterval(() => {
24
+ this.processNudges().catch(err => {
25
+ console.warn(`[NudgeWatcher] error: ${err.message}`);
26
+ });
27
+ }, this.pollIntervalMs);
28
+ }
29
+ /** Stop the watcher loop */
30
+ stop() {
31
+ this.running = false;
32
+ if (this.intervalHandle) {
33
+ clearInterval(this.intervalHandle);
34
+ this.intervalHandle = null;
35
+ }
36
+ }
37
+ /** Process unprocessed nudges in arrival order */
38
+ async processNudges() {
39
+ const nudgesPath = path.join(this.citadelRoot, '.citadel', 'nudges.jsonl');
40
+ const nudges = await readBeads(nudgesPath);
41
+ const unprocessed = nudges.filter(n => !n.processed);
42
+ if (unprocessed.length === 0)
43
+ return;
44
+ // Sort by created_at (arrival order)
45
+ unprocessed.sort((a, b) => a.created_at.localeCompare(b.created_at));
46
+ let modified = false;
47
+ for (const nudge of unprocessed) {
48
+ const handler = this.handlers.get(nudge.signal_type);
49
+ if (handler) {
50
+ try {
51
+ await handler(nudge);
52
+ }
53
+ catch (err) {
54
+ console.warn(`[NudgeWatcher] handler error for ${nudge.signal_type}: ${err.message}`);
55
+ }
56
+ }
57
+ else {
58
+ console.warn(`[NudgeWatcher] unrecognized signal: ${nudge.signal_type}, skipping`);
59
+ }
60
+ // Mark as processed
61
+ nudge.processed = true;
62
+ modified = true;
63
+ }
64
+ // Write back if any were processed
65
+ if (modified) {
66
+ const allLines = nudges.map(n => JSON.stringify(n)).join('\n') + '\n';
67
+ await fs.writeFile(nudgesPath, allLines, 'utf-8');
68
+ }
69
+ }
70
+ }
71
+ //# sourceMappingURL=fo-nudge-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-nudge-watcher.js","sourceRoot":"","sources":["../../src/core/fo-nudge-watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { NudgeWatcher } from './fo-nudge-watcher.js';
2
+ import { ProcessRegistry } from './process-registry.js';
3
+ export interface NudgeWiringOptions {
4
+ citadelRoot: string;
5
+ processRegistry: ProcessRegistry;
6
+ webhookUrl?: string;
7
+ }
8
+ /**
9
+ * Wire all 7 NudgeSignalType handlers to a NudgeWatcher instance.
10
+ * PRD §3.3.4: FO decision flow routes each signal to its handler.
11
+ */
12
+ export declare function wireNudgeHandlers(watcher: NudgeWatcher, opts: NudgeWiringOptions): void;
13
+ //# sourceMappingURL=fo-nudge-wiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-nudge-wiring.d.ts","sourceRoot":"","sources":["../../src/core/fo-nudge-wiring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAUrD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAMxD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,eAAe,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,kBAAkB,GACvB,IAAI,CAoGN"}
@@ -0,0 +1,120 @@
1
+ import { processCommandBead } from './fo-command-processor.js';
2
+ import { applyRetryPolicy } from './fo-retry-policy.js';
3
+ import { handleSlotOpen } from './fo-handlers/slot-open.js';
4
+ import { handleCeilingHit } from './fo-handlers/ceiling-hit.js';
5
+ import { handleRelayRequest } from './fo-relay.js';
6
+ import { handleTaskReport } from './fo-task-report.js';
7
+ import { broadcastDependencyResolved } from './fo-broadcast.js';
8
+ import { broadcastWebhook } from './fo-webhook.js';
9
+ import { buildEscalationReport } from './fo-escalation.js';
10
+ import { readBeads } from './append-bead.js';
11
+ import path from 'node:path';
12
+ import fs from 'node:fs/promises';
13
+ /**
14
+ * Wire all 7 NudgeSignalType handlers to a NudgeWatcher instance.
15
+ * PRD §3.3.4: FO decision flow routes each signal to its handler.
16
+ */
17
+ export function wireNudgeHandlers(watcher, opts) {
18
+ const { citadelRoot, processRegistry } = opts;
19
+ // 1. TRIBUTE_WRITTEN -> retry policy -> broadcast/escalate -> slot-open
20
+ watcher.on('TRIBUTE_WRITTEN', async (nudge) => {
21
+ const result = await applyRetryPolicy(citadelRoot, nudge);
22
+ if (result.decision === 'success') {
23
+ await broadcastDependencyResolved(citadelRoot, result.tribute);
24
+ await broadcastWebhook(result.tribute, opts.webhookUrl ? { url: opts.webhookUrl } : undefined);
25
+ }
26
+ else if (result.decision === 'escalate') {
27
+ await buildEscalationReport(citadelRoot, result.tribute.task_id);
28
+ }
29
+ await handleSlotOpen(nudge, citadelRoot, processRegistry);
30
+ });
31
+ // 2. MAIL_RECEIVED -> route upward mail (RELAY_REQUEST, TASK_REPORT)
32
+ watcher.on('MAIL_RECEIVED', async (nudge) => {
33
+ const payload = nudge.payload;
34
+ if (payload.mail_type === 'RELAY_REQUEST') {
35
+ // Find the mail bead from the outpost
36
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
37
+ try {
38
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
39
+ const registry = JSON.parse(raw);
40
+ for (const outpost of registry.outposts) {
41
+ const mDir = path.join(outpost.path, '.beads', 'mail');
42
+ try {
43
+ const files = await fs.readdir(mDir);
44
+ for (const file of files) {
45
+ if (!file.endsWith('.jsonl'))
46
+ continue;
47
+ const mails = await readBeads(path.join(mDir, file));
48
+ const match = mails.find(m => m.bead_id === payload.mail_bead_id);
49
+ if (match) {
50
+ await handleRelayRequest(citadelRoot, match);
51
+ return;
52
+ }
53
+ }
54
+ }
55
+ catch { /* no mail dir */ }
56
+ }
57
+ }
58
+ catch { /* no outposts */ }
59
+ }
60
+ else if (payload.mail_type === 'TASK_REPORT') {
61
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
62
+ try {
63
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
64
+ const registry = JSON.parse(raw);
65
+ for (const outpost of registry.outposts) {
66
+ const mDir = path.join(outpost.path, '.beads', 'mail');
67
+ try {
68
+ const files = await fs.readdir(mDir);
69
+ for (const file of files) {
70
+ if (!file.endsWith('.jsonl'))
71
+ continue;
72
+ const mails = await readBeads(path.join(mDir, file));
73
+ const match = mails.find(m => m.bead_id === payload.mail_bead_id);
74
+ if (match) {
75
+ await handleTaskReport(citadelRoot, match);
76
+ return;
77
+ }
78
+ }
79
+ }
80
+ catch { /* no mail dir */ }
81
+ }
82
+ }
83
+ catch { /* no outposts */ }
84
+ }
85
+ console.log(`[FO] MAIL_RECEIVED: ${payload.mail_type} from ${payload.from}`);
86
+ });
87
+ // 3. COMMAND_RECEIVED -> process command bead
88
+ watcher.on('COMMAND_RECEIVED', async (nudge) => {
89
+ const payload = nudge.payload;
90
+ const commandPath = path.join(citadelRoot, '.citadel', 'commands', `${payload.command_bead_id}.jsonl`);
91
+ try {
92
+ const beads = await readBeads(commandPath);
93
+ const bead = beads.find(b => b.bead_id === payload.command_bead_id);
94
+ if (bead && !bead.processed) {
95
+ await processCommandBead(citadelRoot, bead, processRegistry);
96
+ }
97
+ }
98
+ catch {
99
+ console.warn(`[FO] Could not read command bead: ${payload.command_bead_id}`);
100
+ }
101
+ });
102
+ // 4. CITIZEN_EXIT_ERROR -> log error, trigger retry policy check
103
+ watcher.on('CITIZEN_EXIT_ERROR', async (nudge) => {
104
+ const payload = nudge.payload;
105
+ console.log(`[FO] CITIZEN_EXIT_ERROR: citizen "${payload.citizen_id}" on outpost "${payload.outpost}" exited with code ${payload.exit_code}`);
106
+ });
107
+ // 5. CITIZEN_TIMEOUT -> log timeout
108
+ watcher.on('CITIZEN_TIMEOUT', async (nudge) => {
109
+ const payload = nudge.payload;
110
+ console.log(`[FO] CITIZEN_TIMEOUT: citizen "${payload.citizen_id}" on outpost "${payload.outpost}" timed out`);
111
+ });
112
+ // 6. PARALLELISM_CEILING_HIT -> delegate to ceiling-hit handler
113
+ watcher.on('PARALLELISM_CEILING_HIT', handleCeilingHit);
114
+ // 7. NO_TASK_ASSIGNMENT -> log (no action needed)
115
+ watcher.on('NO_TASK_ASSIGNMENT', async (nudge) => {
116
+ const payload = nudge.payload;
117
+ console.log(`[FO] NO_TASK_ASSIGNMENT on outpost "${payload.outpost}"`);
118
+ });
119
+ }
120
+ //# sourceMappingURL=fo-nudge-wiring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-nudge-wiring.js","sourceRoot":"","sources":["../../src/core/fo-nudge-wiring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { MailBead } from '../types/index.js';
2
+ /**
3
+ * Handle a RELAY_REQUEST mail from a Citizen: compose and write a PEER_RELAY
4
+ * mail to the intended outpost with spawn_hint.
5
+ */
6
+ export declare function handleRelayRequest(citadelRoot: string, relayMail: MailBead): Promise<MailBead>;
7
+ //# sourceMappingURL=fo-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-relay.d.ts","sourceRoot":"","sources":["../../src/core/fo-relay.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAyC,MAAM,mBAAmB,CAAC;AAEzF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,QAAQ,GAClB,OAAO,CAAC,QAAQ,CAAC,CA2CnB"}
@@ -0,0 +1,47 @@
1
+ import path from 'node:path';
2
+ import { appendBead, mintBeadId } from './append-bead.js';
3
+ import { getActiveOutposts } from './outpost-registry.js';
4
+ import { SCHEMA_VERSION } from '../types/index.js';
5
+ /**
6
+ * Handle a RELAY_REQUEST mail from a Citizen: compose and write a PEER_RELAY
7
+ * mail to the intended outpost with spawn_hint.
8
+ */
9
+ export async function handleRelayRequest(citadelRoot, relayMail) {
10
+ const payload = relayMail.payload;
11
+ // Resolve target outpost path
12
+ const activeOutposts = await getActiveOutposts(citadelRoot);
13
+ const target = activeOutposts.find(o => o.slug === payload.intended_for);
14
+ if (!target) {
15
+ throw new Error(`Relay target outpost "${payload.intended_for}" not found or not ACTIVE`);
16
+ }
17
+ const peerPayload = {
18
+ origin_outpost: relayMail.from,
19
+ origin_mail_ref: relayMail.bead_id,
20
+ subject: payload.subject,
21
+ body: payload.body,
22
+ context_refs: payload.context_refs,
23
+ };
24
+ const peerMail = {
25
+ bead_id: mintBeadId('MAIL'),
26
+ bead_type: 'MAIL',
27
+ schema_version: SCHEMA_VERSION,
28
+ created_at: new Date().toISOString(),
29
+ task_id: relayMail.task_id,
30
+ mail_type: 'PEER_RELAY',
31
+ from: relayMail.from,
32
+ to: payload.intended_for,
33
+ subject: payload.subject,
34
+ read: false,
35
+ retry_of: null,
36
+ spawn_hint: {
37
+ archetype: target.default_archetype ?? 'software-engineer',
38
+ citizen_id: `citizen-relay-${mintBeadId()}`,
39
+ },
40
+ payload: peerPayload,
41
+ };
42
+ const mailPath = path.join(target.path, '.beads', 'mail', `relay-${peerMail.bead_id}.jsonl`);
43
+ await appendBead(mailPath, peerMail);
44
+ console.log(`[FO] PEER_RELAY: "${relayMail.from}" -> "${payload.intended_for}" (subject: "${payload.subject}")`);
45
+ return peerMail;
46
+ }
47
+ //# sourceMappingURL=fo-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-relay.js","sourceRoot":"","sources":["../../src/core/fo-relay.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,SAAmB;IAEnB,MAAM,OAAO,GAAG,SAAS,CAAC,OAA8B,CAAC;IAEzD,8BAA8B;IAC9B,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACzE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,CAAC,YAAY,2BAA2B,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,WAAW,GAAqB;QACpC,cAAc,EAAE,SAAS,CAAC,IAAI;QAC9B,eAAe,EAAE,SAAS,CAAC,OAAO;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC;IAEF,MAAM,QAAQ,GAAa;QACzB,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC;QAC3B,SAAS,EAAE,MAAM;QACjB,cAAc,EAAE,cAAc;QAC9B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,SAAS,EAAE,YAAY;QACvB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,EAAE,EAAE,OAAO,CAAC,YAAY;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE;YACV,SAAS,EAAE,MAAM,CAAC,iBAAiB,IAAI,mBAAmB;YAC1D,UAAU,EAAE,iBAAiB,UAAU,EAAE,EAAE;SAC5C;QACD,OAAO,EAAE,WAAW;KACrB,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAC;IAC7F,MAAM,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAErC,OAAO,CAAC,GAAG,CAAC,qBAAqB,SAAS,CAAC,IAAI,SAAS,OAAO,CAAC,YAAY,gBAAgB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IAEjH,OAAO,QAAQ,CAAC;AAClB,CAAC"}