@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,17 @@
1
+ import type { NudgeBead, TributeBead } from '../types/index.js';
2
+ export type RetryDecision = 'success' | 'retry' | 'escalate';
3
+ export interface RetryPolicyResult {
4
+ decision: RetryDecision;
5
+ tribute: TributeBead;
6
+ errors: string[];
7
+ }
8
+ /**
9
+ * Process a TRIBUTE_WRITTEN nudge through the retry policy.
10
+ *
11
+ * SUCCESS -> return 'success' (caller handles broadcast + slot-open)
12
+ * PARTIAL (under ceiling) -> issue TRIBUTE_INVALID + retry mail, return 'retry'
13
+ * FAILED (under ceiling) -> issue TRIBUTE_INVALID + retry mail, return 'retry'
14
+ * At max retries -> return 'escalate'
15
+ */
16
+ export declare function applyRetryPolicy(citadelRoot: string, nudge: NudgeBead): Promise<RetryPolicyResult>;
17
+ //# sourceMappingURL=fo-retry-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-retry-policy.d.ts","sourceRoot":"","sources":["../../src/core/fo-retry-policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAyB,WAAW,EAA6B,MAAM,mBAAmB,CAAC;AAElH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,iBAAiB,CAAC,CAkF5B"}
@@ -0,0 +1,89 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads, appendBead, mintBeadId } from './append-bead.js';
4
+ import { validateTribute } from './validate-tribute.js';
5
+ import { GrandArchives } from './grand-archives.js';
6
+ import { reconstructState } from './fo-state.js';
7
+ import { SCHEMA_VERSION } from '../types/index.js';
8
+ /**
9
+ * Process a TRIBUTE_WRITTEN nudge through the retry policy.
10
+ *
11
+ * SUCCESS -> return 'success' (caller handles broadcast + slot-open)
12
+ * PARTIAL (under ceiling) -> issue TRIBUTE_INVALID + retry mail, return 'retry'
13
+ * FAILED (under ceiling) -> issue TRIBUTE_INVALID + retry mail, return 'retry'
14
+ * At max retries -> return 'escalate'
15
+ */
16
+ export async function applyRetryPolicy(citadelRoot, nudge) {
17
+ const payload = nudge.payload;
18
+ // Load config for retry policy
19
+ const archives = new GrandArchives(citadelRoot);
20
+ const foConfig = await archives.loadFirstOfficerConfig();
21
+ const maxRetries = foConfig.retry_policy.max_retries;
22
+ // Read the tribute
23
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
24
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
25
+ const registry = JSON.parse(raw);
26
+ const outpost = registry.outposts.find(o => o.slug === payload.outpost);
27
+ if (!outpost)
28
+ throw new Error(`Outpost "${payload.outpost}" not found`);
29
+ const tributePath = path.join(outpost.path, '.beads', 'tribute', `${payload.task_id}_tribute.jsonl`);
30
+ const tributes = await readBeads(tributePath);
31
+ const tribute = tributes.find(t => t.bead_id === payload.tribute_bead_id);
32
+ if (!tribute)
33
+ throw new Error(`Tribute "${payload.tribute_bead_id}" not found`);
34
+ // Find the originating TASK_ASSIGNMENT mail
35
+ const state = await reconstructState(citadelRoot);
36
+ const task = state.tasks.find(t => t.taskId === payload.task_id);
37
+ if (!task)
38
+ throw new Error(`Task "${payload.task_id}" not found`);
39
+ // Validate
40
+ const validation = validateTribute(tribute, task.assignmentMail);
41
+ // SUCCESS
42
+ if (tribute.status === 'SUCCESS' && validation.valid) {
43
+ return { decision: 'success', tribute, errors: [] };
44
+ }
45
+ // At ceiling?
46
+ if (tribute.attempt >= maxRetries) {
47
+ console.log(`[FO] Task "${payload.task_id}" at retry ceiling (${tribute.attempt}/${maxRetries}). Escalating to Commander.`);
48
+ return { decision: 'escalate', tribute, errors: validation.errors };
49
+ }
50
+ // PARTIAL or FAILED -> retry
51
+ const errors = validation.errors.length > 0
52
+ ? validation.errors
53
+ : [`Tribute status: ${tribute.status}`];
54
+ // Write TRIBUTE_INVALID mail
55
+ const invalidMail = {
56
+ bead_id: mintBeadId('MAIL'),
57
+ bead_type: 'MAIL',
58
+ schema_version: SCHEMA_VERSION,
59
+ created_at: new Date().toISOString(),
60
+ task_id: payload.task_id,
61
+ mail_type: 'TRIBUTE_INVALID',
62
+ from: 'citadel',
63
+ to: payload.outpost,
64
+ subject: `Tribute invalid for task ${payload.task_id}`,
65
+ read: false,
66
+ retry_of: null,
67
+ spawn_hint: task.assignmentMail.spawn_hint,
68
+ payload: {
69
+ tribute_ref: tribute.bead_id,
70
+ errors,
71
+ suggested_action: 'RETRY',
72
+ },
73
+ };
74
+ const mailPath = path.join(outpost.path, '.beads', 'mail', `invalid-${invalidMail.bead_id}.jsonl`);
75
+ await appendBead(mailPath, invalidMail);
76
+ // Write retry TASK_ASSIGNMENT
77
+ const retryMail = {
78
+ ...task.assignmentMail,
79
+ bead_id: mintBeadId('MAIL'),
80
+ created_at: new Date().toISOString(),
81
+ read: false,
82
+ retry_of: task.assignmentMail.bead_id,
83
+ };
84
+ const retryPath = path.join(outpost.path, '.beads', 'mail', `retry-${retryMail.bead_id}.jsonl`);
85
+ await appendBead(retryPath, retryMail);
86
+ console.log(`[FO] Retry issued for task "${payload.task_id}" (attempt ${tribute.attempt + 1}/${maxRetries})`);
87
+ return { decision: 'retry', tribute, errors };
88
+ }
89
+ //# sourceMappingURL=fo-retry-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-retry-policy.js","sourceRoot":"","sources":["../../src/core/fo-retry-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { MailBead, TributeBead } from '../types/index.js';
2
+ export type TaskState = 'in_flight' | 'pending' | 'succeeded' | 'failed' | 'partial';
3
+ export interface ReconstructedTask {
4
+ taskId: string;
5
+ outpost: string;
6
+ state: TaskState;
7
+ assignmentMail: MailBead;
8
+ tributes: TributeBead[];
9
+ latestTribute: TributeBead | null;
10
+ attempt: number;
11
+ }
12
+ export interface FirstOfficerState {
13
+ tasks: ReconstructedTask[];
14
+ inFlight: ReconstructedTask[];
15
+ pending: ReconstructedTask[];
16
+ succeeded: ReconstructedTask[];
17
+ failed: ReconstructedTask[];
18
+ partial: ReconstructedTask[];
19
+ }
20
+ /**
21
+ * Reconstruct First Officer state from Mail + Tribute only.
22
+ * Never reads Nudge history.
23
+ */
24
+ export declare function reconstructState(citadelRoot: string): Promise<FirstOfficerState>;
25
+ //# sourceMappingURL=fo-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-state.d.ts","sourceRoot":"","sources":["../../src/core/fo-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAC;AAEhF,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,EAAE,QAAQ,CAAC;IACzB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,aAAa,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0FtF"}
@@ -0,0 +1,99 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads } from './append-bead.js';
4
+ /**
5
+ * Reconstruct First Officer state from Mail + Tribute only.
6
+ * Never reads Nudge history.
7
+ */
8
+ export async function reconstructState(citadelRoot) {
9
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
10
+ let registry;
11
+ try {
12
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
13
+ registry = JSON.parse(raw);
14
+ }
15
+ catch {
16
+ return emptyState();
17
+ }
18
+ const allMail = [];
19
+ const allTributes = [];
20
+ // Scan all outpost bead dirs
21
+ for (const outpost of registry.outposts) {
22
+ // Mail
23
+ const mailDir = path.join(outpost.path, '.beads', 'mail');
24
+ try {
25
+ const files = await fs.readdir(mailDir);
26
+ for (const file of files) {
27
+ if (!file.endsWith('.jsonl'))
28
+ continue;
29
+ const beads = await readBeads(path.join(mailDir, file));
30
+ allMail.push(...beads);
31
+ }
32
+ }
33
+ catch { /* no mail dir */ }
34
+ // Tributes
35
+ const tributeDir = path.join(outpost.path, '.beads', 'tribute');
36
+ try {
37
+ const files = await fs.readdir(tributeDir);
38
+ for (const file of files) {
39
+ if (!file.endsWith('.jsonl'))
40
+ continue;
41
+ const beads = await readBeads(path.join(tributeDir, file));
42
+ allTributes.push(...beads);
43
+ }
44
+ }
45
+ catch { /* no tribute dir */ }
46
+ }
47
+ // Find all TASK_ASSIGNMENT mails (downward)
48
+ const assignments = allMail.filter(m => m.mail_type === 'TASK_ASSIGNMENT');
49
+ // Group tributes by task_id
50
+ const tributesByTask = new Map();
51
+ for (const t of allTributes) {
52
+ const existing = tributesByTask.get(t.task_id) ?? [];
53
+ existing.push(t);
54
+ tributesByTask.set(t.task_id, existing);
55
+ }
56
+ const tasks = [];
57
+ for (const mail of assignments) {
58
+ const taskId = mail.task_id ?? mail.bead_id;
59
+ const tributes = (tributesByTask.get(taskId) ?? [])
60
+ .sort((a, b) => a.created_at.localeCompare(b.created_at));
61
+ const latest = tributes.length > 0 ? tributes[tributes.length - 1] : null;
62
+ let state;
63
+ if (!latest) {
64
+ state = 'in_flight';
65
+ }
66
+ else if (latest.status === 'SUCCESS') {
67
+ state = 'succeeded';
68
+ }
69
+ else if (latest.status === 'FAILED') {
70
+ state = 'failed';
71
+ }
72
+ else {
73
+ state = 'partial';
74
+ }
75
+ // Find outpost for this task
76
+ const outpost = mail.to; // TASK_ASSIGNMENT goes to outpost
77
+ tasks.push({
78
+ taskId,
79
+ outpost,
80
+ state,
81
+ assignmentMail: mail,
82
+ tributes,
83
+ latestTribute: latest,
84
+ attempt: tributes.length,
85
+ });
86
+ }
87
+ return {
88
+ tasks,
89
+ inFlight: tasks.filter(t => t.state === 'in_flight'),
90
+ pending: tasks.filter(t => t.state === 'in_flight' && !t.latestTribute), // subset
91
+ succeeded: tasks.filter(t => t.state === 'succeeded'),
92
+ failed: tasks.filter(t => t.state === 'failed'),
93
+ partial: tasks.filter(t => t.state === 'partial'),
94
+ };
95
+ }
96
+ function emptyState() {
97
+ return { tasks: [], inFlight: [], pending: [], succeeded: [], failed: [], partial: [] };
98
+ }
99
+ //# sourceMappingURL=fo-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-state.js","sourceRoot":"","sources":["../../src/core/fo-state.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAwB7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACzE,IAAI,QAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACrD,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAkB,EAAE,CAAC;IAEtC,6BAA6B;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBACvC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAW,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;gBAClE,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAE7B,WAAW;QACX,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBACvC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAc,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;gBACxE,WAAW,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;IAClC,CAAC;IAED,4CAA4C;IAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,iBAAiB,CAAC,CAAC;IAE3E,4BAA4B;IAC5B,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACrD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,KAAK,GAAwB,EAAE,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;QAC5C,MAAM,QAAQ,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;aAChD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1E,IAAI,KAAgB,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,KAAK,GAAG,WAAW,CAAC;QACtB,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACvC,KAAK,GAAG,WAAW,CAAC;QACtB,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,KAAK,GAAG,QAAQ,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;QAED,6BAA6B;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,kCAAkC;QAE3D,KAAK,CAAC,IAAI,CAAC;YACT,MAAM;YACN,OAAO;YACP,KAAK;YACL,cAAc,EAAE,IAAI;YACpB,QAAQ;YACR,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,QAAQ,CAAC,MAAM;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,KAAK;QACL,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC;QACpD,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,SAAS;QAClF,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC;QACrD,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAC/C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { MailBead } from '../types/index.js';
2
+ export interface TaskReportResult {
3
+ status: string;
4
+ action: 'logged' | 'escalated';
5
+ commandBeadPath?: string;
6
+ }
7
+ /**
8
+ * Handle TASK_REPORT mail from a Citizen.
9
+ *
10
+ * - IN_PROGRESS: log status update
11
+ * - BLOCKED: escalate to Commander with blocker details
12
+ * - NEEDS_INPUT: escalate to Commander with questions
13
+ * - COMPLETE: log note (actual completion comes via Tribute)
14
+ */
15
+ export declare function handleTaskReport(citadelRoot: string, reportMail: MailBead): Promise<TaskReportResult>;
16
+ //# sourceMappingURL=fo-task-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-task-report.d.ts","sourceRoot":"","sources":["../../src/core/fo-task-report.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,mBAAmB,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,QAAQ,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAiC3B"}
@@ -0,0 +1,63 @@
1
+ import path from 'node:path';
2
+ import { appendBead, mintBeadId } from './append-bead.js';
3
+ import { SCHEMA_VERSION } from '../types/index.js';
4
+ /**
5
+ * Handle TASK_REPORT mail from a Citizen.
6
+ *
7
+ * - IN_PROGRESS: log status update
8
+ * - BLOCKED: escalate to Commander with blocker details
9
+ * - NEEDS_INPUT: escalate to Commander with questions
10
+ * - COMPLETE: log note (actual completion comes via Tribute)
11
+ */
12
+ export async function handleTaskReport(citadelRoot, reportMail) {
13
+ const payload = reportMail.payload;
14
+ const taskId = reportMail.task_id ?? 'unknown';
15
+ const from = reportMail.from;
16
+ switch (payload.status) {
17
+ case 'IN_PROGRESS': {
18
+ console.log(`[FO] TASK_REPORT from "${from}": task "${taskId}" in progress — ${payload.summary}`);
19
+ return { status: 'IN_PROGRESS', action: 'logged' };
20
+ }
21
+ case 'BLOCKED': {
22
+ console.log(`[FO] TASK_REPORT from "${from}": task "${taskId}" BLOCKED — ${payload.blockers.join(', ')}`);
23
+ const cmdPath = await writeEscalation(citadelRoot, taskId, from, payload);
24
+ return { status: 'BLOCKED', action: 'escalated', commandBeadPath: cmdPath };
25
+ }
26
+ case 'NEEDS_INPUT': {
27
+ console.log(`[FO] TASK_REPORT from "${from}": task "${taskId}" NEEDS_INPUT — ${payload.questions.join(', ')}`);
28
+ const cmdPath = await writeEscalation(citadelRoot, taskId, from, payload);
29
+ return { status: 'NEEDS_INPUT', action: 'escalated', commandBeadPath: cmdPath };
30
+ }
31
+ case 'COMPLETE': {
32
+ console.log(`[FO] TASK_REPORT from "${from}": task "${taskId}" reports COMPLETE — awaiting Tribute`);
33
+ return { status: 'COMPLETE', action: 'logged' };
34
+ }
35
+ default: {
36
+ console.warn(`[FO] Unknown TASK_REPORT status "${payload.status}" from "${from}" for task "${taskId}"`);
37
+ return { status: payload.status, action: 'logged' };
38
+ }
39
+ }
40
+ }
41
+ /**
42
+ * Write an escalation bead to .citadel/escalations/ for the Commander.
43
+ */
44
+ async function writeEscalation(citadelRoot, taskId, fromOutpost, payload) {
45
+ const escalation = {
46
+ bead_id: mintBeadId('MAIL'),
47
+ bead_type: 'MAIL',
48
+ schema_version: SCHEMA_VERSION,
49
+ created_at: new Date().toISOString(),
50
+ task_id: taskId,
51
+ mail_type: 'TASK_REPORT',
52
+ from: fromOutpost,
53
+ to: 'commander',
54
+ subject: `[${payload.status}] Task ${taskId}`,
55
+ read: false,
56
+ retry_of: null,
57
+ payload,
58
+ };
59
+ const escalationPath = path.join(citadelRoot, '.citadel', 'escalations', `${payload.status.toLowerCase()}-${escalation.bead_id}.jsonl`);
60
+ await appendBead(escalationPath, escalation);
61
+ return escalationPath;
62
+ }
63
+ //# sourceMappingURL=fo-task-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-task-report.js","sourceRoot":"","sources":["../../src/core/fo-task-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { TributeBead } from '../types/index.js';
2
+ export interface WebhookConfig {
3
+ url: string;
4
+ timeout_ms?: number;
5
+ }
6
+ export interface WebhookPayload {
7
+ event: 'task.success';
8
+ task_id: string;
9
+ outpost: string;
10
+ summary: string;
11
+ pr_url?: string;
12
+ attempt: number;
13
+ citizen_id: string;
14
+ elapsed_seconds: number;
15
+ timestamp: string;
16
+ }
17
+ /**
18
+ * POST a SUCCESS tribute summary to an optional webhook URL.
19
+ * Fails silently — webhook is best-effort notification.
20
+ */
21
+ export declare function broadcastWebhook(tribute: TributeBead, webhook: WebhookConfig | undefined): Promise<boolean>;
22
+ //# sourceMappingURL=fo-webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-webhook.d.ts","sourceRoot":"","sources":["../../src/core/fo-webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,aAAa,GAAG,SAAS,GACjC,OAAO,CAAC,OAAO,CAAC,CAuClB"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * POST a SUCCESS tribute summary to an optional webhook URL.
3
+ * Fails silently — webhook is best-effort notification.
4
+ */
5
+ export async function broadcastWebhook(tribute, webhook) {
6
+ if (!webhook?.url)
7
+ return false;
8
+ const payload = {
9
+ event: 'task.success',
10
+ task_id: tribute.task_id,
11
+ outpost: tribute.outpost,
12
+ summary: tribute.summary,
13
+ pr_url: tribute.pr_url,
14
+ attempt: tribute.attempt,
15
+ citizen_id: tribute.citizen_id,
16
+ elapsed_seconds: tribute.elapsed_seconds,
17
+ timestamp: new Date().toISOString(),
18
+ };
19
+ try {
20
+ const controller = new AbortController();
21
+ const timeoutId = setTimeout(() => controller.abort(), webhook.timeout_ms ?? 5000);
22
+ const response = await fetch(webhook.url, {
23
+ method: 'POST',
24
+ headers: { 'Content-Type': 'application/json' },
25
+ body: JSON.stringify(payload),
26
+ signal: controller.signal,
27
+ });
28
+ clearTimeout(timeoutId);
29
+ if (response.ok) {
30
+ console.log(`[FO] Webhook POST to ${webhook.url} — ${response.status}`);
31
+ return true;
32
+ }
33
+ else {
34
+ console.warn(`[FO] Webhook POST failed: ${response.status} ${response.statusText}`);
35
+ return false;
36
+ }
37
+ }
38
+ catch (err) {
39
+ console.warn(`[FO] Webhook POST error: ${err.message}`);
40
+ return false;
41
+ }
42
+ }
43
+ //# sourceMappingURL=fo-webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fo-webhook.js","sourceRoot":"","sources":["../../src/core/fo-webhook.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAoB,EACpB,OAAkC;IAElC,IAAI,CAAC,OAAO,EAAE,GAAG;QAAE,OAAO,KAAK,CAAC;IAEhC,MAAM,OAAO,GAAmB;QAC9B,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;QAEnF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACxC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,YAAY,CAAC,SAAS,CAAC,CAAC;QAExB,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,wBAAwB,OAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACxE,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACpF,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,4BAA6B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ArchetypeRegistry, FirstOfficerConfig, ResolvedArchetype } from '../types/index.js';
2
+ export declare class GrandArchives {
3
+ private archivesRoot;
4
+ constructor(citadelRoot: string);
5
+ resolve(archetypeKey: string): Promise<ResolvedArchetype>;
6
+ /**
7
+ * Resolve and compose the full system prompt: preamble + body.
8
+ * PRD §4.8: [base-prompt-preamble.md] + [archetype/system-prompt.md]
9
+ */
10
+ resolveComposedPrompt(archetypeKey: string): Promise<string>;
11
+ loadFirstOfficerConfig(): Promise<FirstOfficerConfig>;
12
+ listArchetypes(): Promise<ArchetypeRegistry>;
13
+ }
14
+ //# sourceMappingURL=grand-archives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grand-archives.d.ts","sourceRoot":"","sources":["../../src/core/grand-archives.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAS;gBAEjB,WAAW,EAAE,MAAM;IAIzB,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwD/D;;;OAGG;IACG,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS5D,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAerD,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC;CAcnD"}
@@ -0,0 +1,79 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ export class GrandArchives {
4
+ archivesRoot;
5
+ constructor(citadelRoot) {
6
+ this.archivesRoot = path.join(citadelRoot, 'grand-archives');
7
+ }
8
+ async resolve(archetypeKey) {
9
+ const configPath = path.join(this.archivesRoot, 'archetypes', archetypeKey, 'archetype.json');
10
+ let raw;
11
+ try {
12
+ raw = await fs.readFile(configPath, 'utf-8');
13
+ }
14
+ catch {
15
+ throw new Error(`Archetype config not found for "${archetypeKey}" at ${configPath}`);
16
+ }
17
+ const config = JSON.parse(raw);
18
+ const preamblePath = path.join(this.archivesRoot, config.system_prompt.preamble_ref);
19
+ const systemPromptPath = path.join(this.archivesRoot, config.system_prompt.body_ref);
20
+ const toolsetManifestPath = path.join(this.archivesRoot, config.toolset.override_ref);
21
+ // Resolve agent binary: archetype config > FO config > default 'claude'
22
+ let agentBinary = 'claude';
23
+ try {
24
+ const foConfig = await this.loadFirstOfficerConfig();
25
+ agentBinary = foConfig.agent ?? 'claude';
26
+ }
27
+ catch {
28
+ // FO config not found, use default
29
+ }
30
+ return {
31
+ key: config.key,
32
+ display_name: config.display_name,
33
+ preamble_path: preamblePath,
34
+ system_prompt_path: systemPromptPath,
35
+ toolset_manifest_path: toolsetManifestPath,
36
+ model: config.constraints.model,
37
+ agent_binary: agentBinary,
38
+ constraints: {
39
+ max_tokens_per_turn: config.constraints.max_tokens_per_turn,
40
+ temperature: config.constraints.temperature,
41
+ },
42
+ };
43
+ }
44
+ /**
45
+ * Resolve and compose the full system prompt: preamble + body.
46
+ * PRD §4.8: [base-prompt-preamble.md] + [archetype/system-prompt.md]
47
+ */
48
+ async resolveComposedPrompt(archetypeKey) {
49
+ const resolved = await this.resolve(archetypeKey);
50
+ const [preamble, body] = await Promise.all([
51
+ fs.readFile(resolved.preamble_path, 'utf-8'),
52
+ fs.readFile(resolved.system_prompt_path, 'utf-8'),
53
+ ]);
54
+ return `${preamble}\n${body}`;
55
+ }
56
+ async loadFirstOfficerConfig() {
57
+ const configPath = path.join(this.archivesRoot, 'first-officer', 'config.json');
58
+ let raw;
59
+ try {
60
+ raw = await fs.readFile(configPath, 'utf-8');
61
+ }
62
+ catch {
63
+ throw new Error(`First Officer config not found at ${configPath}`);
64
+ }
65
+ return JSON.parse(raw);
66
+ }
67
+ async listArchetypes() {
68
+ const registryPath = path.join(this.archivesRoot, 'registry.json');
69
+ let raw;
70
+ try {
71
+ raw = await fs.readFile(registryPath, 'utf-8');
72
+ }
73
+ catch {
74
+ throw new Error(`Archetype registry not found at ${registryPath}`);
75
+ }
76
+ return JSON.parse(raw);
77
+ }
78
+ }
79
+ //# sourceMappingURL=grand-archives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grand-archives.js","sourceRoot":"","sources":["../../src/core/grand-archives.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { NudgeBead, NudgeSignalType, NudgePayload } from '../types/index.js';
2
+ /**
3
+ * Append a NudgeBead to .citadel/nudges.jsonl
4
+ */
5
+ export declare function nudgeFirstOfficer(citadelRoot: string, signalType: NudgeSignalType, payload: NudgePayload): Promise<NudgeBead>;
6
+ //# sourceMappingURL=nudge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nudge.d.ts","sourceRoot":"","sources":["../../src/core/nudge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAElF;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,SAAS,CAAC,CAepB"}
@@ -0,0 +1,19 @@
1
+ import path from 'node:path';
2
+ import { appendBead, mintBeadId } from './append-bead.js';
3
+ import { SCHEMA_VERSION } from '../types/index.js';
4
+ /**
5
+ * Append a NudgeBead to .citadel/nudges.jsonl
6
+ */
7
+ export async function nudgeFirstOfficer(citadelRoot, signalType, payload) {
8
+ const bead = {
9
+ bead_id: mintBeadId('NUDGE'),
10
+ bead_type: 'NUDGE',
11
+ schema_version: SCHEMA_VERSION,
12
+ created_at: new Date().toISOString(),
13
+ signal_type: signalType,
14
+ payload,
15
+ processed: false,
16
+ };
17
+ return appendBead(path.join(citadelRoot, '.citadel', 'nudges.jsonl'), bead);
18
+ }
19
+ //# sourceMappingURL=nudge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nudge.js","sourceRoot":"","sources":["../../src/core/nudge.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,UAA2B,EAC3B,OAAqB;IAErB,MAAM,IAAI,GAAc;QACtB,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC;QAC5B,SAAS,EAAE,OAAO;QAClB,cAAc,EAAE,cAAc;QAC9B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,WAAW,EAAE,UAAU;QACvB,OAAO;QACP,SAAS,EAAE,KAAK;KACjB,CAAC;IAEF,OAAO,UAAU,CACf,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,CAAC,EAClD,IAAI,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { OutpostRegistry, OutpostRegistryEntry } from '../types/index.js';
2
+ /**
3
+ * Read .citadel/outposts.json and return the parsed registry.
4
+ * Throws if the file is missing or malformed.
5
+ */
6
+ export declare function loadOutpostRegistry(citadelRoot: string): Promise<OutpostRegistry>;
7
+ /**
8
+ * Return ACTIVE outpost entries from the registry.
9
+ */
10
+ export declare function getActiveOutposts(citadelRoot: string): Promise<OutpostRegistryEntry[]>;
11
+ /**
12
+ * Return mail directory paths for all ACTIVE outposts.
13
+ * Each path is `<outpost.path>/.beads/mail`.
14
+ */
15
+ export declare function getRegisteredOutpostMailDirs(citadelRoot: string): Promise<string[]>;
16
+ //# sourceMappingURL=outpost-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outpost-registry.d.ts","sourceRoot":"","sources":["../../src/core/outpost-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAIvF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAG5F;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGzF"}
@@ -0,0 +1,27 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ /**
4
+ * Read .citadel/outposts.json and return the parsed registry.
5
+ * Throws if the file is missing or malformed.
6
+ */
7
+ export async function loadOutpostRegistry(citadelRoot) {
8
+ const outpostsPath = path.join(citadelRoot, '.citadel', 'outposts.json');
9
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
10
+ return JSON.parse(raw);
11
+ }
12
+ /**
13
+ * Return ACTIVE outpost entries from the registry.
14
+ */
15
+ export async function getActiveOutposts(citadelRoot) {
16
+ const registry = await loadOutpostRegistry(citadelRoot);
17
+ return registry.outposts.filter(o => o.status === 'ACTIVE');
18
+ }
19
+ /**
20
+ * Return mail directory paths for all ACTIVE outposts.
21
+ * Each path is `<outpost.path>/.beads/mail`.
22
+ */
23
+ export async function getRegisteredOutpostMailDirs(citadelRoot) {
24
+ const active = await getActiveOutposts(citadelRoot);
25
+ return active.map(o => path.join(o.path, '.beads', 'mail'));
26
+ }
27
+ //# sourceMappingURL=outpost-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outpost-registry.js","sourceRoot":"","sources":["../../src/core/outpost-registry.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGlC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACzE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IACzD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxD,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,WAAmB;IACpE,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { ProcessRegistry } from './process-registry.js';
2
+ import type { MailBead, OutpostRegistryEntry } from '../types/index.js';
3
+ export interface PreSpawnResult {
4
+ canSpawn: boolean;
5
+ taskMail: MailBead | null;
6
+ reason?: string;
7
+ }
8
+ /**
9
+ * Pre-spawn check for an outpost:
10
+ * 1. Read unread TASK_ASSIGNMENT mail
11
+ * 2. If none, nudge NO_TASK_ASSIGNMENT
12
+ * 3. Check citizen ceiling
13
+ * 4. If at ceiling, nudge PARALLELISM_CEILING_HIT
14
+ */
15
+ export declare function preSpawnCheck(citadelRoot: string, outpost: OutpostRegistryEntry, processRegistry: ProcessRegistry, maxCitizens: number): Promise<PreSpawnResult>;
16
+ //# sourceMappingURL=pre-spawn-check.d.ts.map