@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,160 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { readBeads } from '../core/append-bead.js';
4
+ async function loadOutposts(citadelDir) {
5
+ try {
6
+ const raw = await fs.readFile(path.join(citadelDir, 'outposts.json'), 'utf-8');
7
+ const registry = JSON.parse(raw);
8
+ return registry.outposts;
9
+ }
10
+ catch {
11
+ return [];
12
+ }
13
+ }
14
+ async function listJsonlFiles(dirPath) {
15
+ try {
16
+ const entries = await fs.readdir(dirPath);
17
+ return entries
18
+ .filter((e) => e.endsWith('.jsonl'))
19
+ .map((e) => path.join(dirPath, e));
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ }
25
+ async function readAllBeadsFromDir(dirPath) {
26
+ const files = await listJsonlFiles(dirPath);
27
+ const results = [];
28
+ for (const file of files) {
29
+ const beads = await readBeads(file);
30
+ results.push(...beads);
31
+ }
32
+ return results;
33
+ }
34
+ function nudgePayloadHasTaskId(payload, taskId) {
35
+ if ('task_id' in payload && payload.task_id === taskId) {
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ function commandBeadReferencesTask(bead, taskId) {
41
+ const args = bead.args;
42
+ return args.task_id === taskId;
43
+ }
44
+ export function registerTributeCommand(program) {
45
+ program
46
+ .command('tribute')
47
+ .description('List tributes for a task')
48
+ .requiredOption('--task <id>', 'Task ID to look up')
49
+ .action(async (opts) => {
50
+ const citadelDir = path.resolve('.citadel');
51
+ try {
52
+ await fs.access(citadelDir);
53
+ }
54
+ catch {
55
+ console.error('Not a Citadel workspace');
56
+ process.exit(1);
57
+ }
58
+ const outposts = await loadOutposts(citadelDir);
59
+ const allTributes = [];
60
+ for (const op of outposts) {
61
+ const tributeDir = path.join(op.path, '.beads', 'tribute');
62
+ const tributes = await readAllBeadsFromDir(tributeDir);
63
+ allTributes.push(...tributes);
64
+ }
65
+ const matched = allTributes
66
+ .filter((t) => t.task_id === opts.task)
67
+ .sort((a, b) => a.created_at.localeCompare(b.created_at));
68
+ if (matched.length === 0) {
69
+ console.log(`No tributes found for task ${opts.task}`);
70
+ return;
71
+ }
72
+ for (const t of matched) {
73
+ const criteria = t.acceptance_met
74
+ .map((met) => (met ? '[x]' : '[ ]'))
75
+ .join(' ');
76
+ console.log(`--- Attempt ${t.attempt} ---`);
77
+ console.log(` status: ${t.status}`);
78
+ console.log(` citizen_id: ${t.citizen_id}`);
79
+ console.log(` elapsed: ${t.elapsed_seconds}s`);
80
+ console.log(` summary: ${t.summary}`);
81
+ console.log(` acceptance: ${criteria}`);
82
+ }
83
+ });
84
+ program
85
+ .command('trace')
86
+ .description('Show full event timeline for a task')
87
+ .requiredOption('--task <id>', 'Task ID to trace')
88
+ .action(async (opts) => {
89
+ const citadelDir = path.resolve('.citadel');
90
+ try {
91
+ await fs.access(citadelDir);
92
+ }
93
+ catch {
94
+ console.error('Not a Citadel workspace');
95
+ process.exit(1);
96
+ }
97
+ const events = [];
98
+ const outposts = await loadOutposts(citadelDir);
99
+ // 1. CommandBeads from .citadel/commands/*.jsonl
100
+ const commandBeads = await readAllBeadsFromDir(path.join(citadelDir, 'commands'));
101
+ for (const cb of commandBeads) {
102
+ if (commandBeadReferencesTask(cb, opts.task)) {
103
+ events.push({
104
+ created_at: cb.created_at,
105
+ bead_type: 'COMMAND',
106
+ summary: `${cb.command} (${cb.bead_id})`,
107
+ });
108
+ }
109
+ }
110
+ // 2. MailBeads from all outposts
111
+ for (const op of outposts) {
112
+ const mailDir = path.join(op.path, '.beads', 'mail');
113
+ const mails = await readAllBeadsFromDir(mailDir);
114
+ for (const m of mails) {
115
+ if (m.task_id === opts.task) {
116
+ events.push({
117
+ created_at: m.created_at,
118
+ bead_type: 'MAIL',
119
+ summary: `${m.mail_type} from=${m.from} to=${m.to} "${m.subject}"`,
120
+ });
121
+ }
122
+ }
123
+ }
124
+ // 3. TributeBeads from all outposts
125
+ for (const op of outposts) {
126
+ const tributeDir = path.join(op.path, '.beads', 'tribute');
127
+ const tributes = await readAllBeadsFromDir(tributeDir);
128
+ for (const t of tributes) {
129
+ if (t.task_id === opts.task) {
130
+ events.push({
131
+ created_at: t.created_at,
132
+ bead_type: 'TRIBUTE',
133
+ summary: `attempt=${t.attempt} status=${t.status} "${t.summary}"`,
134
+ });
135
+ }
136
+ }
137
+ }
138
+ // 4. NudgeBeads from .citadel/nudges.jsonl
139
+ const nudges = await readBeads(path.join(citadelDir, 'nudges.jsonl'));
140
+ for (const n of nudges) {
141
+ if (nudgePayloadHasTaskId(n.payload, opts.task)) {
142
+ events.push({
143
+ created_at: n.created_at,
144
+ bead_type: 'NUDGE',
145
+ summary: `${n.signal_type} (${n.bead_id})`,
146
+ });
147
+ }
148
+ }
149
+ // Sort and print
150
+ events.sort((a, b) => a.created_at.localeCompare(b.created_at));
151
+ if (events.length === 0) {
152
+ console.log(`No trace found for task ${opts.task}`);
153
+ return;
154
+ }
155
+ for (const e of events) {
156
+ console.log(`[${e.created_at}] [${e.bead_type}] ${e.summary}`);
157
+ }
158
+ });
159
+ }
160
+ //# sourceMappingURL=tribute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tribute.js","sourceRoot":"","sources":["../../src/cli/tribute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerWorktreeCommand(program: Command): void;
3
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/cli/worktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoE9D"}
@@ -0,0 +1,64 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { WorktreeManager } from '../core/worktree-manager.js';
4
+ export function registerWorktreeCommand(program) {
5
+ const worktree = program
6
+ .command('worktree')
7
+ .description('Manage git worktrees for outposts');
8
+ worktree
9
+ .command('list')
10
+ .description('List worktrees for an outpost')
11
+ .requiredOption('--outpost <slug>', 'Outpost slug')
12
+ .action(async (opts) => {
13
+ const citadelRoot = process.cwd();
14
+ const dotCitadel = path.join(citadelRoot, '.citadel');
15
+ try {
16
+ await fs.access(dotCitadel);
17
+ }
18
+ catch {
19
+ console.error('No .citadel/ directory found in current working directory.');
20
+ process.exit(1);
21
+ }
22
+ const manager = new WorktreeManager(citadelRoot);
23
+ const entries = await manager.list(opts.outpost);
24
+ if (entries.length === 0) {
25
+ console.log(`No worktrees for ${opts.outpost}`);
26
+ return;
27
+ }
28
+ for (const entry of entries) {
29
+ console.log(`${entry.path} ${entry.branch} ${entry.head.slice(0, 8)}`);
30
+ }
31
+ });
32
+ worktree
33
+ .command('prune')
34
+ .description('Prune orphaned worktrees')
35
+ .option('--outpost <slug>', 'Scope to a single outpost')
36
+ .action(async (opts) => {
37
+ const citadelRoot = process.cwd();
38
+ const dotCitadel = path.join(citadelRoot, '.citadel');
39
+ try {
40
+ await fs.access(dotCitadel);
41
+ }
42
+ catch {
43
+ console.error('No .citadel/ directory found in current working directory.');
44
+ process.exit(1);
45
+ }
46
+ const manager = new WorktreeManager(citadelRoot);
47
+ let slugs;
48
+ if (opts.outpost) {
49
+ slugs = [opts.outpost];
50
+ }
51
+ else {
52
+ const raw = await fs.readFile(path.join(dotCitadel, 'outposts.json'), 'utf-8');
53
+ const registry = JSON.parse(raw);
54
+ slugs = registry.outposts
55
+ .filter(o => o.status === 'ACTIVE')
56
+ .map(o => o.slug);
57
+ }
58
+ for (const slug of slugs) {
59
+ const pruned = await manager.pruneOrphaned(slug, new Set());
60
+ console.log(`Pruned ${pruned} worktree(s) from ${slug}`);
61
+ }
62
+ });
63
+ }
64
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/cli/worktree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { BaseBead } from '../types/index.js';
2
+ /** Generate a bead ID with a type-specific prefix per PRD §3.1. */
3
+ export declare function mintBeadId(beadType?: string): string;
4
+ /**
5
+ * Append a bead as a single JSON line to the given file.
6
+ * Acquires a lockfile, appends, git commits, then releases.
7
+ */
8
+ export declare function appendBead<T extends BaseBead>(filePath: string, bead: T): Promise<T>;
9
+ /**
10
+ * Read a JSONL bead file and parse each line into T.
11
+ */
12
+ export declare function readBeads<T extends BaseBead>(filePath: string): Promise<T[]>;
13
+ //# sourceMappingURL=append-bead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append-bead.d.ts","sourceRoot":"","sources":["../../src/core/append-bead.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAYlD,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,QAAQ,EACjD,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAChD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,EAAE,CAAC,CAad"}
@@ -0,0 +1,68 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { execFile as execFileCb } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { lock, unlock } from 'proper-lockfile';
6
+ import { nanoid } from 'nanoid';
7
+ const execFile = promisify(execFileCb);
8
+ const BEAD_PREFIX_MAP = {
9
+ MAIL: 'mail_',
10
+ TRIBUTE: 'tribute_',
11
+ NUDGE: 'nudge_',
12
+ COMMAND: 'cmd_',
13
+ IDENTITY: 'identity_',
14
+ };
15
+ /** Generate a bead ID with a type-specific prefix per PRD §3.1. */
16
+ export function mintBeadId(beadType) {
17
+ const prefix = beadType ? (BEAD_PREFIX_MAP[beadType] ?? 'bead-') : 'bead-';
18
+ return `${prefix}${nanoid()}`;
19
+ }
20
+ /**
21
+ * Append a bead as a single JSON line to the given file.
22
+ * Acquires a lockfile, appends, git commits, then releases.
23
+ */
24
+ export async function appendBead(filePath, bead) {
25
+ const absPath = path.resolve(filePath);
26
+ const dir = path.dirname(absPath);
27
+ // Ensure the parent directory exists
28
+ await fs.mkdir(dir, { recursive: true });
29
+ // Ensure the file exists (lockfile requires it)
30
+ await fs.appendFile(absPath, '');
31
+ await lock(absPath, {
32
+ retries: { retries: 3, minTimeout: 50, maxTimeout: 200, factor: 2 },
33
+ stale: 5000,
34
+ });
35
+ try {
36
+ await fs.appendFile(absPath, JSON.stringify(bead) + '\n');
37
+ // Best-effort git commit
38
+ try {
39
+ await execFile('git', ['add', absPath], { cwd: dir });
40
+ await execFile('git', ['commit', '-m', `bead: ${bead.bead_type} ${bead.bead_id}`], { cwd: dir });
41
+ }
42
+ catch (err) {
43
+ console.warn(`[appendBead] git commit failed: ${err.message}`);
44
+ }
45
+ }
46
+ finally {
47
+ await unlock(absPath);
48
+ }
49
+ return bead;
50
+ }
51
+ /**
52
+ * Read a JSONL bead file and parse each line into T.
53
+ */
54
+ export async function readBeads(filePath) {
55
+ const absPath = path.resolve(filePath);
56
+ let content;
57
+ try {
58
+ content = await fs.readFile(absPath, 'utf-8');
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ return content
64
+ .split('\n')
65
+ .filter((line) => line.trim() !== '')
66
+ .map((line) => JSON.parse(line));
67
+ }
68
+ //# sourceMappingURL=append-bead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append-bead.js","sourceRoot":"","sources":["../../src/core/append-bead.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { MailBead } from '../types/index.js';
2
+ export interface BlockedTask {
3
+ outpost: string;
4
+ taskId: string;
5
+ mail: MailBead;
6
+ }
7
+ /**
8
+ * Find tasks across all ACTIVE outposts that are blocked on the given resolvedTaskId.
9
+ *
10
+ * A task is "blocked" if:
11
+ * 1. It has a TASK_ASSIGNMENT mail whose dependencies[] includes resolvedTaskId
12
+ * 2. It does NOT yet have a SUCCESS tribute
13
+ */
14
+ export declare function getBlockedOutposts(citadelRoot: string, resolvedTaskId: string): Promise<BlockedTask[]>;
15
+ //# sourceMappingURL=blocked-outposts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-outposts.d.ts","sourceRoot":"","sources":["../../src/core/blocked-outposts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAsC,MAAM,mBAAmB,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,EAAE,CAAC,CA+BxB"}
@@ -0,0 +1,77 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads } from './append-bead.js';
4
+ import { getActiveOutposts } from './outpost-registry.js';
5
+ /**
6
+ * Find tasks across all ACTIVE outposts that are blocked on the given resolvedTaskId.
7
+ *
8
+ * A task is "blocked" if:
9
+ * 1. It has a TASK_ASSIGNMENT mail whose dependencies[] includes resolvedTaskId
10
+ * 2. It does NOT yet have a SUCCESS tribute
11
+ */
12
+ export async function getBlockedOutposts(citadelRoot, resolvedTaskId) {
13
+ const activeOutposts = await getActiveOutposts(citadelRoot);
14
+ const blocked = [];
15
+ for (const outpost of activeOutposts) {
16
+ const mailDir = path.join(outpost.path, '.beads', 'mail');
17
+ const tributeDir = path.join(outpost.path, '.beads', 'tribute');
18
+ // Read all mail beads
19
+ const mails = await readMailDir(mailDir);
20
+ // Find TASK_ASSIGNMENT mails that depend on resolvedTaskId
21
+ const dependentMails = mails.filter(m => {
22
+ if (m.mail_type !== 'TASK_ASSIGNMENT')
23
+ return false;
24
+ const payload = m.payload;
25
+ return payload.dependencies.includes(resolvedTaskId);
26
+ });
27
+ if (dependentMails.length === 0)
28
+ continue;
29
+ // Read tributes to check which tasks already succeeded
30
+ const succeededTaskIds = await getSucceededTaskIds(tributeDir);
31
+ for (const mail of dependentMails) {
32
+ const taskId = mail.task_id ?? mail.bead_id;
33
+ if (succeededTaskIds.has(taskId))
34
+ continue;
35
+ blocked.push({ outpost: outpost.slug, taskId, mail });
36
+ }
37
+ }
38
+ return blocked;
39
+ }
40
+ async function readMailDir(mailDir) {
41
+ let files;
42
+ try {
43
+ files = await fs.readdir(mailDir);
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ const mails = [];
49
+ for (const file of files) {
50
+ if (!file.endsWith('.jsonl'))
51
+ continue;
52
+ const beads = await readBeads(path.join(mailDir, file));
53
+ mails.push(...beads);
54
+ }
55
+ return mails;
56
+ }
57
+ async function getSucceededTaskIds(tributeDir) {
58
+ let files;
59
+ try {
60
+ files = await fs.readdir(tributeDir);
61
+ }
62
+ catch {
63
+ return new Set();
64
+ }
65
+ const succeeded = new Set();
66
+ for (const file of files) {
67
+ if (!file.endsWith('.jsonl'))
68
+ continue;
69
+ const beads = await readBeads(path.join(tributeDir, file));
70
+ for (const t of beads) {
71
+ if (t.status === 'SUCCESS')
72
+ succeeded.add(t.task_id);
73
+ }
74
+ }
75
+ return succeeded;
76
+ }
77
+ //# sourceMappingURL=blocked-outposts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-outposts.js","sourceRoot":"","sources":["../../src/core/blocked-outposts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { MailBead } from '../types/index.js';
2
+ export interface CitizenContext {
3
+ citizenId: string;
4
+ outpost: string;
5
+ taskId: string;
6
+ worktree: string;
7
+ beadsRoot: string;
8
+ taskAssignment: MailBead | null;
9
+ isRetry: boolean;
10
+ retryErrors: string[];
11
+ }
12
+ /**
13
+ * Bootstrap a citizen: validate env, scan inbox, synthesize context.
14
+ * Called at the start of a citizen's lifecycle.
15
+ */
16
+ export declare function citizenBootstrap(): Promise<CitizenContext>;
17
+ //# sourceMappingURL=citizen-bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citizen-bootstrap.d.ts","sourceRoot":"","sources":["../../src/core/citizen-bootstrap.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,QAAQ,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,cAAc,CAAC,CA8GhE"}
@@ -0,0 +1,118 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { readBeads, appendBead, mintBeadId } from './append-bead.js';
4
+ import { SCHEMA_VERSION } from '../types/index.js';
5
+ /**
6
+ * Bootstrap a citizen: validate env, scan inbox, synthesize context.
7
+ * Called at the start of a citizen's lifecycle.
8
+ */
9
+ export async function citizenBootstrap() {
10
+ // 1. Check required env vars
11
+ const citizenId = requireEnv('CITADEL_CITIZEN_ID');
12
+ const beadsRoot = requireEnv('CITADEL_BEADS_ROOT');
13
+ const outpost = requireEnv('CITADEL_OUTPOST');
14
+ const taskId = requireEnv('CITADEL_TASK_ID');
15
+ const worktree = requireEnv('CITADEL_WORKTREE');
16
+ // 2. Resolve outpost path from outposts.json
17
+ const outpostsPath = path.join(beadsRoot, '.citadel', 'outposts.json');
18
+ let outpostPath = '';
19
+ try {
20
+ const raw = await fs.readFile(outpostsPath, 'utf-8');
21
+ const registry = JSON.parse(raw);
22
+ const entry = registry.outposts.find((o) => o.slug === outpost);
23
+ if (entry)
24
+ outpostPath = entry.path;
25
+ }
26
+ catch {
27
+ throw new Error('Cannot read outposts.json');
28
+ }
29
+ // 3. Scan inbox: read all mail files, sorted by created_at
30
+ const inboxDir = path.join(outpostPath, '.beads', 'mail');
31
+ const allMail = [];
32
+ try {
33
+ const files = await fs.readdir(inboxDir);
34
+ for (const file of files) {
35
+ if (!file.endsWith('.jsonl'))
36
+ continue;
37
+ const beads = await readBeads(path.join(inboxDir, file));
38
+ allMail.push(...beads);
39
+ }
40
+ }
41
+ catch {
42
+ // no mail dir yet
43
+ }
44
+ // Sort by created_at
45
+ allMail.sort((a, b) => a.created_at.localeCompare(b.created_at));
46
+ // 4. Find TASK_ASSIGNMENT for this citizen
47
+ const taskAssignment = allMail.find(m => m.mail_type === 'TASK_ASSIGNMENT' &&
48
+ m.spawn_hint?.citizen_id === citizenId) ?? null;
49
+ // If no TASK_ASSIGNMENT: write TASK_REPORT BLOCKED and return early
50
+ if (!taskAssignment) {
51
+ const reportMail = {
52
+ bead_id: mintBeadId('MAIL'),
53
+ bead_type: 'MAIL',
54
+ schema_version: SCHEMA_VERSION,
55
+ created_at: new Date().toISOString(),
56
+ mail_type: 'TASK_REPORT',
57
+ from: outpost,
58
+ to: 'citadel',
59
+ subject: `No task assignment found for citizen ${citizenId}`,
60
+ read: false,
61
+ retry_of: null,
62
+ payload: {
63
+ status: 'BLOCKED',
64
+ summary: `Citizen ${citizenId} found no TASK_ASSIGNMENT mail`,
65
+ blockers: ['No TASK_ASSIGNMENT mail in inbox'],
66
+ questions: [],
67
+ context_refs: [],
68
+ },
69
+ };
70
+ await appendBead(path.join(inboxDir, `report-${reportMail.bead_id}.jsonl`), reportMail);
71
+ return {
72
+ citizenId, outpost, taskId, worktree, beadsRoot,
73
+ taskAssignment: null,
74
+ isRetry: false,
75
+ retryErrors: [],
76
+ };
77
+ }
78
+ // 5. Check for TRIBUTE_INVALID (retry scenario)
79
+ let isRetry = false;
80
+ let retryErrors = [];
81
+ const tributeInvalid = allMail.find(m => m.mail_type === 'TRIBUTE_INVALID' && !m.read);
82
+ if (tributeInvalid) {
83
+ isRetry = true;
84
+ const payload = tributeInvalid.payload;
85
+ retryErrors = payload.errors ?? [];
86
+ }
87
+ // 6. Mark unread mail as read by appending a read marker line to the JSONL.
88
+ // PRD §3.4.2 step 6: For each unread Mail, mark read via appendBead().
89
+ const unreadMail = allMail.filter(m => !m.read);
90
+ for (const mail of unreadMail) {
91
+ // Find which file this bead came from and append a read marker
92
+ const files = await fs.readdir(inboxDir).catch(() => []);
93
+ for (const file of files) {
94
+ if (!file.endsWith('.jsonl'))
95
+ continue;
96
+ const filePath = path.join(inboxDir, file);
97
+ const beads = await readBeads(filePath);
98
+ if (beads.some(b => b.bead_id === mail.bead_id)) {
99
+ const readMarker = { ...mail, read: true };
100
+ await appendBead(filePath, readMarker);
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ return {
106
+ citizenId, outpost, taskId, worktree, beadsRoot,
107
+ taskAssignment,
108
+ isRetry,
109
+ retryErrors,
110
+ };
111
+ }
112
+ function requireEnv(name) {
113
+ const value = process.env[name];
114
+ if (!value)
115
+ throw new Error(`Missing required env var: ${name}`);
116
+ return value;
117
+ }
118
+ //# sourceMappingURL=citizen-bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citizen-bootstrap.js","sourceRoot":"","sources":["../../src/core/citizen-bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { TributeBead, TributeStatus } from '../types/index.js';
2
+ export interface WriteTributeOptions {
3
+ originatingMailRef: string;
4
+ status: TributeStatus;
5
+ summary: string;
6
+ artifacts: string[];
7
+ acceptanceMet: boolean[];
8
+ elapsedSeconds: number;
9
+ prUrl?: string;
10
+ }
11
+ /**
12
+ * Write a Tribute bead from within a Citizen process.
13
+ * Reads env vars for context. Writes to <outpost_path>/.beads/tribute/<task_id>_tribute.jsonl
14
+ * Attempt number is determined from existing lines + 1.
15
+ */
16
+ export declare function writeTribute(opts: WriteTributeOptions): Promise<TributeBead>;
17
+ //# sourceMappingURL=citizen-tribute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citizen-tribute.d.ts","sourceRoot":"","sources":["../../src/core/citizen-tribute.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,OAAO,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0ClF"}