elanous 0.2.9 → 0.2.11

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 (694) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  7. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  20. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  25. package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f972fc1c00a62e88.js → page-b12b6d2f8d2d1aea.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/{page-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -0
  152. package/apps/pwa/out/ops/seats/index.txt +30 -0
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -0
  178. package/apps/pwa/out/today/index.txt +33 -0
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/field/field-feed.yaml +2 -0
  194. package/graphs/implement-loop.yaml +1 -1
  195. package/graphs/intake/intake-daily.yaml +2 -1
  196. package/graphs/ops/recipes.yaml +3 -0
  197. package/graphs/ops/secret-exposure.yaml +24 -0
  198. package/graphs/release/recipes.yaml +3 -0
  199. package/graphs/release/release-loop.yaml +4 -1
  200. package/graphs/video/explainer-line.yaml +2 -2
  201. package/package.json +2 -1
  202. package/plugins/card-followup/graphs/run-step.ts +48 -13
  203. package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
  204. package/plugins/doc-draft/graphs/run-step.ts +13 -6
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/ci-pwa-build-gate.ts +160 -0
  216. package/scripts/context-hooks/claude-stop.sh +4 -0
  217. package/scripts/context-hooks/emit.ts +24 -0
  218. package/scripts/context-hooks/post-tool-use.sh +4 -0
  219. package/scripts/coord-channel-watch.sh +54 -8
  220. package/scripts/coord-digest.ts +199 -0
  221. package/scripts/coord-post.sh +60 -3
  222. package/scripts/coord-requests-bridge.ts +143 -0
  223. package/scripts/field-feed/lib.ts +4 -0
  224. package/scripts/fleet/node-setup.sh +20 -3
  225. package/scripts/homebrew-formula-bump.ts +69 -0
  226. package/scripts/install.ps1 +68 -9
  227. package/scripts/install.sh +39 -12
  228. package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
  229. package/scripts/lib/tui-regress-checks.ts +146 -0
  230. package/scripts/marketing/measure-site-numbers.ts +169 -0
  231. package/scripts/measure-gate-shards.ts +309 -0
  232. package/scripts/memory-lifecycle-cycle.ts +2 -2
  233. package/scripts/mission-request-judge.ts +31 -1
  234. package/scripts/morning-report.ts +2 -2
  235. package/scripts/opportunity-scan.ts +1 -1
  236. package/scripts/ops-now-probe.ts +327 -0
  237. package/scripts/publish-internal-dist.ts +11 -1
  238. package/scripts/release-loop/auto-approve-node.ts +21 -4
  239. package/scripts/release-loop/cut-branch.ts +84 -0
  240. package/scripts/release-loop/cutoff.ts +19 -8
  241. package/scripts/release-loop/gate-node.ts +14 -13
  242. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  243. package/scripts/release-loop/node-verdict.ts +3 -3
  244. package/scripts/release-loop/ops-upgrade-node.ts +72 -16
  245. package/scripts/release-loop/release-readiness.ts +9 -0
  246. package/scripts/release-loop/tui-node-checks.ts +42 -0
  247. package/scripts/release-loop/tui-sim-node.ts +32 -8
  248. package/scripts/release-loop/unattended-release.ts +5 -3
  249. package/scripts/release-loop/version-node.ts +112 -13
  250. package/scripts/repo-watch-cycle.ts +1 -1
  251. package/scripts/retro-cycle.ts +2 -2
  252. package/scripts/schedule-health-report.ts +1 -1
  253. package/scripts/signal-digest-cycle.ts +2 -7
  254. package/scripts/signal-digest-photo.ts +11 -0
  255. package/scripts/storyboard/storyboard.ts +5 -161
  256. package/scripts/tech1-public-measure.ts +94 -0
  257. package/scripts/test-diet/lib.ts +30 -1
  258. package/scripts/test-diet/node.ts +83 -8
  259. package/scripts/test-timeout-audit.ts +114 -0
  260. package/scripts/tree-sync-alert.ts +1 -1
  261. package/scripts/tui-regress.ts +71 -0
  262. package/scripts/ux/demo-rehearsal.ts +243 -0
  263. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  264. package/scripts/waitlist-daily-digest.ts +1 -1
  265. package/skills/diagram-master/SKILL.md +366 -0
  266. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  267. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  268. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  269. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  270. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  271. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  272. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  273. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  274. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  275. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  276. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  277. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  278. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  279. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  280. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  281. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  282. package/skills/diagram-master/references/examples/README.md +69 -0
  283. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  284. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  285. package/skills/diagram-master/references/pyproject.toml +16 -0
  286. package/skills/diagram-master/references/quality-checklist.md +33 -0
  287. package/skills/diagram-master/references/routing-guide.md +164 -0
  288. package/skills/diagram-master/references/uv.lock +1356 -0
  289. package/skills/explainer-video/SKILL.md +4 -0
  290. package/skills/explainer-video/engine/reel.mjs +18 -13
  291. package/skills/explainer-video/engine/reel.sh +24 -5
  292. package/skills/explainer-video/engine/stitch.mjs +145 -0
  293. package/skills/google-workspace/SKILL.md +33 -0
  294. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  295. package/skills/grill-me/SKILL.md +1 -1
  296. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  297. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  298. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  299. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  300. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  301. package/skills/omni-crawl/SKILL.md +21 -11
  302. package/skills/omni-crawl/scripts/main.ts +6 -6
  303. package/skills/omni-crawl/src/router.ts +3 -3
  304. package/skills/omni-digest/SKILL.md +17 -9
  305. package/skills/omni-digest/digest.md +2 -2
  306. package/skills/omni-digest/src/fetch.ts +30 -3
  307. package/skills/pitch-deck/SKILL.md +36 -0
  308. package/skills/pitch-deck/template.html +80 -0
  309. package/skills/youtube-master/SKILL.md +163 -0
  310. package/skills/youtube-master/package-lock.json +558 -0
  311. package/skills/youtube-master/package.json +13 -0
  312. package/skills/youtube-master/references/study-note-template.md +124 -0
  313. package/skills/youtube-master/scripts/main.ts +435 -0
  314. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  315. package/skills/youtube-master/src/audio.ts +63 -0
  316. package/skills/youtube-master/src/domain-staging.ts +50 -0
  317. package/skills/youtube-master/src/env.ts +36 -0
  318. package/skills/youtube-master/src/obsidian.ts +155 -0
  319. package/skills/youtube-master/src/router.ts +110 -0
  320. package/skills/youtube-master/src/stt.ts +199 -0
  321. package/skills/youtube-master/src/study-note.ts +175 -0
  322. package/skills/youtube-master/src/summarize.ts +358 -0
  323. package/skills/youtube-master/src/transcript.ts +76 -0
  324. package/skills/youtube-master/src/types.ts +91 -0
  325. package/skills/youtube-master/src/util.ts +93 -0
  326. package/skills/youtube-master/src/youtube.ts +70 -0
  327. package/skills/youtube-master/tsconfig.json +13 -0
  328. package/src/acp/codex-approval-adapter.ts +9 -3
  329. package/src/acp/core-turn-bridge.ts +117 -18
  330. package/src/acp/fact-question.ts +11 -0
  331. package/src/acp/server.ts +53 -9
  332. package/src/acp/tool-approval.ts +126 -0
  333. package/src/acp/turn-runner.ts +36 -0
  334. package/src/agent/monad-agent-turn.ts +8 -0
  335. package/src/agent-mission/driver.ts +80 -10
  336. package/src/agent-mission/pty-decision.ts +71 -0
  337. package/src/agent-mission/review-loop.ts +30 -0
  338. package/src/ask-user-question/pending-questions.ts +25 -10
  339. package/src/ask-user-question/types.ts +9 -0
  340. package/src/auth/setup-link-tokens.ts +16 -5
  341. package/src/autopilot/build/integrity-gate.ts +12 -0
  342. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  343. package/src/autopilot/tool-registry.ts +2 -0
  344. package/src/boot/daemon-prompt-turn.ts +8 -0
  345. package/src/boot/daemon-runtime.ts +9 -3
  346. package/src/boot/daemon-tools/index.ts +8 -0
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/boot/daemon-tools/web-search.ts +4 -0
  349. package/src/card-followup/core.ts +109 -0
  350. package/src/chat/ctrl-c-in-input.ts +14 -0
  351. package/src/chat/index.ts +53 -0
  352. package/src/chat/pickers/state.ts +6 -2
  353. package/src/cli/agent-cli.ts +7 -0
  354. package/src/cli/decisions-cli.ts +25 -3
  355. package/src/cli/doctor-bundle-upload.ts +68 -0
  356. package/src/cli/doctor-cli.ts +38 -4
  357. package/src/cli/drive-input-jail.ts +101 -0
  358. package/src/cli/hooks-cli.ts +17 -3
  359. package/src/cli/make-cli.ts +43 -0
  360. package/src/cli/ops-cli.ts +20 -0
  361. package/src/cli/persona-cli.ts +90 -4
  362. package/src/cli/plugin-cli.ts +31 -22
  363. package/src/cli/pod-cli.ts +61 -2
  364. package/src/cli/pr-cli.ts +82 -17
  365. package/src/cli/pty-drive-cli.ts +41 -7
  366. package/src/cli/pty-drive-verdict.ts +40 -0
  367. package/src/cli/pwa-stop.ts +163 -13
  368. package/src/cli/pwa-test.ts +3 -0
  369. package/src/cli/release-cli.ts +80 -24
  370. package/src/cli/self-update.ts +14 -0
  371. package/src/cli/setup-cli.ts +43 -1
  372. package/src/cli/skills-cli.ts +17 -1
  373. package/src/cli/storyboard-cli.ts +37 -0
  374. package/src/cli/test-state-dir-flag.ts +11 -4
  375. package/src/connectors/linear.ts +146 -0
  376. package/src/context-bus/claude-hooks-install.ts +10 -0
  377. package/src/context-bus/context-now-surfaces.ts +48 -0
  378. package/src/context-bus/context-now.ts +104 -0
  379. package/src/context-bus/coord-events.ts +115 -0
  380. package/src/context-bus/external-events.ts +52 -0
  381. package/src/context-bus/long-term-memory.ts +108 -0
  382. package/src/dashboard/dashboard-boot-fixture.ts +23 -0
  383. package/src/dashboard/index.ts +63 -21
  384. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
  385. package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
  386. package/src/decisions/decision-cards.ts +58 -3
  387. package/src/decisions/decision-ledger.ts +85 -6
  388. package/src/decisions/decision-linear-projection.ts +157 -0
  389. package/src/decisions/web-push-decision-cards.ts +50 -0
  390. package/src/directive/interpretation-card.ts +36 -0
  391. package/src/discord/sprint21-runtime.ts +5 -1
  392. package/src/discord-self-message.ts +32 -0
  393. package/src/discord-slash-wire.ts +5 -1
  394. package/src/discord.ts +19 -2
  395. package/src/domains/coo-admin-tool.ts +62 -0
  396. package/src/domains/core-tools.ts +13 -4
  397. package/src/domains/elanous-card.ts +29 -0
  398. package/src/domains/ops-facts-tool.ts +76 -0
  399. package/src/domains/outbound-alert.ts +46 -13
  400. package/src/domains/release-tool.ts +168 -0
  401. package/src/domains/telegram-kind-route.ts +65 -9
  402. package/src/exec-requests/default-outputs.ts +25 -0
  403. package/src/exec-requests/planner.ts +106 -28
  404. package/src/exec-requests/runner.ts +123 -12
  405. package/src/exec-requests/store.ts +11 -2
  406. package/src/execution-loop/launch-gate.ts +100 -0
  407. package/src/field/field-media.ts +10 -7
  408. package/src/field/field-reel.ts +19 -5
  409. package/src/field-note/index.ts +201 -0
  410. package/src/field-note/transcribe.ts +248 -0
  411. package/src/git-fs/worktree.ts +45 -6
  412. package/src/graph-kinds/registry.ts +3 -3
  413. package/src/graph-runner/graph-approval-card.ts +113 -0
  414. package/src/graph-runner/graph-cli.ts +189 -4
  415. package/src/graph-runner/graph-grow-llm.ts +37 -0
  416. package/src/graph-runner/graph-grow.ts +47 -0
  417. package/src/graph-runner/graph-notify.ts +25 -3
  418. package/src/graph-runner/runner.ts +453 -35
  419. package/src/grok/agent-search.ts +8 -2
  420. package/src/guardian/secret-exposure-scan.ts +101 -0
  421. package/src/harness/browser-verify.ts +25 -2
  422. package/src/harness/harness-cli-command.ts +478 -42
  423. package/src/harness/harness-incidents-writer.fixture.ts +24 -0
  424. package/src/harness/harness-incidents.ts +129 -0
  425. package/src/harness/harness-pod-dispatch.ts +43 -23
  426. package/src/harness/harness-seams.ts +38 -4
  427. package/src/harness/harness-stop.ts +75 -6
  428. package/src/harness/launch-registry.ts +91 -0
  429. package/src/harness/process-garbage.ts +5 -3
  430. package/src/hitl/clarification-policy.ts +3 -1
  431. package/src/hooks/dispatch.ts +82 -0
  432. package/src/hooks/expose.ts +254 -0
  433. package/src/hooks/github-shadow.ts +108 -0
  434. package/src/hooks/providers.ts +71 -5
  435. package/src/hooks/queue.ts +1 -1
  436. package/src/hooks/receiver.ts +21 -20
  437. package/src/index.ts +206 -49
  438. package/src/intake-plane/author-goals.ts +37 -4
  439. package/src/intake-plane/categorize.ts +18 -46
  440. package/src/intake-plane/check.ts +3 -0
  441. package/src/intake-plane/discord-seat-work.ts +57 -2
  442. package/src/intake-plane/front-route-classifier.ts +33 -39
  443. package/src/intake-plane/persona-answer.ts +30 -0
  444. package/src/intake-plane/runtime-callables.ts +8 -1
  445. package/src/intake-plane/seat-doc-route.ts +170 -6
  446. package/src/intake-plane/telegram-seat-work.ts +80 -4
  447. package/src/intake-plane/telegram-work.ts +1 -0
  448. package/src/intake-plane/wish-folder.ts +67 -0
  449. package/src/intent-gate/gate.ts +30 -10
  450. package/src/live/detail-switch.ts +5 -0
  451. package/src/llm/difficulty.ts +57 -0
  452. package/src/llm/judge-layer.ts +101 -0
  453. package/src/llm/mission-router.ts +33 -19
  454. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  455. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  456. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  457. package/src/loops/contract/loop-agent.schema.json +138 -0
  458. package/src/loops/contract/validate.ts +64 -0
  459. package/src/loops/registry.ts +20 -6
  460. package/src/market/signed-index.ts +4 -0
  461. package/src/maturity/bot-command-maturity.ts +45 -0
  462. package/src/maturity/cli-maturity.ts +34 -0
  463. package/src/maturity/feature-maturity.ts +120 -1
  464. package/src/maturity/tui-slash-maturity.ts +31 -0
  465. package/src/memory.ts +32 -4
  466. package/src/model-tier/index.ts +2 -2
  467. package/src/model-tier/tier-resolver.ts +20 -20
  468. package/src/model-tier/types.ts +6 -6
  469. package/src/mss/logging/log-store.ts +15 -0
  470. package/src/nexus/api/config-model-tier.ts +5 -4
  471. package/src/nexus/api/exec-requests.ts +33 -3
  472. package/src/nexus/api/fabric-plans.ts +53 -0
  473. package/src/nexus/api/harness-api.ts +5 -1
  474. package/src/nexus/api/health.ts +2 -0
  475. package/src/nexus/api/http-server.ts +89 -1
  476. package/src/nexus/api/inside-events.ts +226 -0
  477. package/src/nexus/api/meta-api.ts +32 -8
  478. package/src/nexus/api/missions.ts +6 -1
  479. package/src/nexus/api/ops-api.ts +10 -1
  480. package/src/nexus/api/ops-seats-sources.ts +37 -7
  481. package/src/nexus/api/ops-seats.ts +49 -6
  482. package/src/nexus/api/outputs-route.ts +44 -0
  483. package/src/nexus/api/seat-requests.ts +132 -10
  484. package/src/nexus/api/sessions-store.ts +42 -0
  485. package/src/nexus/api/setup-codex-login.ts +160 -0
  486. package/src/nexus/api/sub-seat-charters.ts +34 -0
  487. package/src/nexus/api/tabs-mutations.ts +3 -1
  488. package/src/nexus/api/trace.ts +18 -6
  489. package/src/nexus/api/usage-api.ts +102 -0
  490. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  491. package/src/nexus/api/workflows.ts +80 -6
  492. package/src/nexus/index.ts +47 -4
  493. package/src/nexus/kinds/webterm.ts +2 -1
  494. package/src/nexus/webterm/pty.ts +6 -2
  495. package/src/onboarding/cli-auth-status.ts +80 -0
  496. package/src/onboarding/first-run.ts +89 -0
  497. package/src/onboarding/lan-address.ts +45 -0
  498. package/src/onboarding/voice-ai.ts +3 -3
  499. package/src/onboarding/web-first.ts +119 -24
  500. package/src/onboarding.ts +4 -0
  501. package/src/ops-now/ops-now-refresh.ts +100 -0
  502. package/src/org/seat-budget.ts +48 -0
  503. package/src/org/stall-escalation.ts +63 -0
  504. package/src/outputs/ledger.ts +120 -0
  505. package/src/persona/persona-todo.ts +79 -0
  506. package/src/persona/presets.ts +116 -2
  507. package/src/persona/team-set.ts +155 -0
  508. package/src/plugins/install/plugin-install.ts +14 -0
  509. package/src/plugins/maker/market-bundle.ts +109 -0
  510. package/src/plugins/maker/plugin-maker.ts +254 -11
  511. package/src/plugins/maker/wizard-generate.ts +103 -0
  512. package/src/pod-lease/admission.ts +150 -0
  513. package/src/pod-lease/dependency-state.ts +85 -0
  514. package/src/pod-lease/host-lease.ts +127 -0
  515. package/src/project/project-store.ts +115 -0
  516. package/src/project/project-suggestion.ts +16 -0
  517. package/src/project/session-context.ts +24 -0
  518. package/src/release-loop/checklist.ts +79 -5
  519. package/src/release-loop/feature-store.ts +159 -24
  520. package/src/release-loop/next-md-merge.ts +58 -0
  521. package/src/release-loop/release-note.ts +59 -4
  522. package/src/release-loop/release-schedule.ts +53 -0
  523. package/src/repl/index.ts +7 -0
  524. package/src/seat-dispatch/ceo-commands.ts +41 -8
  525. package/src/seat-dispatch/ceo-intent.ts +38 -0
  526. package/src/seat-dispatch/seat-ask.ts +130 -0
  527. package/src/seat-dispatch/seat-questions.ts +100 -0
  528. package/src/seat-loop/seat-loop.ts +750 -0
  529. package/src/seat-loop/seat-report.ts +99 -0
  530. package/src/self-dev/decompose.ts +66 -11
  531. package/src/self-dev/dev-cli.ts +4 -1
  532. package/src/self-dev/dev-pipeline.ts +37 -1
  533. package/src/self-dev/draft-sweep.ts +38 -33
  534. package/src/self-dev/draft-triage-rules.ts +8 -5
  535. package/src/self-dev/fabric-plan-core.ts +297 -0
  536. package/src/self-dev/orchestrate.ts +36 -4
  537. package/src/self-dev/release-path-guard.ts +62 -0
  538. package/src/self-dev/run-store.ts +10 -1
  539. package/src/self-dev/shard-aggregate.ts +230 -0
  540. package/src/self-dev/shard-placement.ts +60 -0
  541. package/src/self-dev/shard-plan.ts +48 -0
  542. package/src/self-dev/shard-pod-run.ts +77 -0
  543. package/src/self-dev/shard-run.ts +105 -0
  544. package/src/self-implement/execution-clarification.ts +115 -0
  545. package/src/self-implement/gate-baseline.ts +1 -1
  546. package/src/self-implement/gate-cli.ts +46 -4
  547. package/src/self-implement/gate-scope.ts +37 -7
  548. package/src/self-implement/graph-variant.ts +171 -0
  549. package/src/self-implement/harness-policy-gates.ts +1 -1
  550. package/src/self-implement/headless-elanous-driver.ts +22 -3
  551. package/src/self-implement/host-regate.ts +22 -1
  552. package/src/self-implement/importer-test-index.ts +2 -1
  553. package/src/self-implement/l8-merge-queue.ts +130 -0
  554. package/src/self-implement/orchestrator.ts +279 -12
  555. package/src/self-implement/pipeline-shape.ts +1 -1
  556. package/src/self-implement/route-consumer-test-index.ts +122 -0
  557. package/src/self-implement/run-status-mapping.ts +5 -3
  558. package/src/self-implement/seams.ts +72 -11
  559. package/src/self-implement/test-seams.ts +1 -0
  560. package/src/self-implement/uncommitted-work.ts +59 -0
  561. package/src/session/chat.ts +2 -0
  562. package/src/session/index.ts +45 -13
  563. package/src/shell-env-bootstrap.ts +17 -0
  564. package/src/skills/gift-install.ts +215 -0
  565. package/src/skills/tools/web-search.ts +4 -1
  566. package/src/steward/directive.ts +51 -2
  567. package/src/steward/launch.ts +266 -0
  568. package/src/steward/outcome-notify.ts +115 -0
  569. package/src/steward/steward-cards.ts +25 -11
  570. package/src/steward/triage-plan.ts +32 -4
  571. package/src/steward/triage.ts +129 -13
  572. package/src/steward/working-backwards.ts +64 -0
  573. package/src/storyboard/storyboard.ts +141 -0
  574. package/src/task-cards/card-cli.ts +25 -1
  575. package/src/task-cards/card-store.ts +2 -2
  576. package/src/task-orchestrator/mission.ts +5 -0
  577. package/src/task-orchestrator/store.ts +12 -3
  578. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  579. package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
  580. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  581. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  582. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  583. package/src/task-orchestrator/types.ts +2 -0
  584. package/src/telegram-card-followup.ts +153 -0
  585. package/src/telegram-commands.ts +10 -1
  586. package/src/telegram-project-command.ts +71 -0
  587. package/src/telegram-report.ts +29 -19
  588. package/src/telegram-run.ts +7 -0
  589. package/src/telegram.ts +58 -11
  590. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  591. package/src/tool-runtime/types.ts +4 -0
  592. package/src/tui-client/dashboard-session.ts +2 -0
  593. package/src/user-config.ts +216 -27
  594. package/src/version/packed-revision.json +1 -1
  595. package/src/web-push/notify-exec-request.ts +32 -0
  596. package/src/web-search/grok.ts +7 -1
  597. package/src/web-search/index.ts +28 -1
  598. package/src/web-search/provider.ts +4 -0
  599. package/src/web-search/x-intent.ts +5 -0
  600. package/src/workflow-runtime/executor.ts +277 -47
  601. package/src/workflow-runtime/index.ts +1 -0
  602. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  603. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  604. package/src/workflow-runtime/schema.ts +79 -4
  605. package/src/workflow-runtime/types.ts +35 -4
  606. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  617. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  618. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
  622. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  692. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
  693. package/src/dashboard/turn-typeahead-echo.ts +0 -23
  694. /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -1,4 +1,6 @@
1
1
  import type { SlashCommand } from '../../chat/index.js';
2
+ import { readTuiSlashAudience, slashMaturity, slashVisibleFor } from '../../maturity/tui-slash-maturity.js';
3
+ import type { Role } from '../../maturity/feature-maturity.js';
2
4
  import { visibleWidth } from '../../tui.js';
3
5
 
4
6
  const ESSENTIAL_KEYS = [
@@ -34,46 +36,59 @@ export function buildEssentialHelpLines({
34
36
  names,
35
37
  descriptions,
36
38
  width,
39
+ audience = readTuiSlashAudience(),
37
40
  }: {
38
41
  names: readonly string[];
39
42
  descriptions: readonly Pick<SlashCommand, 'name' | 'aliases' | 'description'>[];
40
43
  width: number;
44
+ audience?: { role: Role; showBeta: boolean };
41
45
  }): string[] {
42
- const descriptionsByName = new Map<string, string>();
43
- for (const command of descriptions) {
44
- for (const name of [command.name, ...(command.aliases ?? [])]) {
45
- descriptionsByName.set(name, command.description);
46
- }
47
- }
48
- const entries = [...new Set(names)]
49
- .sort((a, b) => a.localeCompare(b))
50
- .flatMap((name) => {
51
- // Removing border glyphs from a name would invent a different, unregistered slash.
52
- if (/[│╭╮╰╯┌┐└┘─]/.test(name)) return [];
53
- const description = descriptionsByName.get(name)?.replace(/\s+/g, ' ').trim();
54
- return description ? [{ name, description }] : [];
55
- });
56
- // Pack alphabetically in reading order across columns; the handler checks
57
- // the modal's row budget and uses scrollable chat if the result outgrows it.
58
- const longestName = Math.max(22, ...entries.map(({ name }) => visibleWidth(`/${name} `) + 1));
59
- const columns = Math.max(1, Math.min(Math.ceil(entries.length / 20), Math.floor(width / longestName)));
46
+ const registered = new Set(names);
47
+ const entries = descriptions
48
+ .filter((command) => registered.has(command.name) &&
49
+ ((audience.role === 'owner' && slashMaturity(command.name) === undefined) || slashVisibleFor(command.name, audience.role, { showBeta: audience.showBeta })))
50
+ .map((command) => {
51
+ const aliases = [...new Set(command.aliases ?? [])].filter((alias) => registered.has(alias) && alias !== command.name);
52
+ const label = `/${command.name}${aliases.length ? ` (${aliases.join(', ')})` : ''}`;
53
+ const description = command.description.replace(/\s+/g, ' ').trim()
54
+ .replace(/^(?:(?:H\d+\s+P\d+|CV-\d+|Sprint\s+\d+|Showroom\s+v2)(?:\s*[·—:]\s*|\s+))+/i, '')
55
+ .trim();
56
+ return { label, name: command.name, description };
57
+ })
58
+ .filter(({ label, description }) => description && !/[│╭╮╰╯┌┐└┘─]/.test(label))
59
+ .sort((a, b) => a.name.localeCompare(b.name));
60
+ // Reserve the longest label, 28 description characters, and an ellipsis
61
+ // in each cell. Never trade a missing label for a shorter modal.
62
+ const widestLabel = Math.max(0, ...entries.map(({ label }) => visibleWidth(label)));
63
+ const readableCellWidth = widestLabel + 2 + 28 + 1;
64
+ const columns = entries.length >= 40 && width >= 100
65
+ ? Math.max(1, Math.floor(width / (readableCellWidth + 1)))
66
+ : 1;
60
67
  const columnWidth = Math.floor(width / columns);
61
68
  const commandLines: string[] = [];
62
69
  for (let start = 0; start < entries.length; start += columns) {
63
- const cells = entries.slice(start, start + columns).map(({ name, description }) => {
70
+ const cells = entries.slice(start, start + columns).map(({ label, description }) => {
64
71
  const cellWidth = columnWidth - (columns > 1 ? 1 : 0);
65
- if (visibleWidth(`/${name} `) > cellWidth) return '';
66
- return fitLine(`/${name} ${description}`, cellWidth);
72
+ return visibleWidth(`${label} `) > cellWidth ? '' : fitLine(`${label} ${description}`, cellWidth);
67
73
  });
68
74
  commandLines.push(cells.map((cell, index) =>
69
75
  index === cells.length - 1 ? cell : cell + ' '.repeat(columnWidth - visibleWidth(cell)),
70
76
  ).join('').trimEnd());
71
77
  }
72
- return [
73
- fitLine('Commands', width),
74
- ...commandLines,
75
- '',
76
- fitLine('Keys', width),
77
- ...ESSENTIAL_KEYS.map(([key, description]) => fitLine(`${key} ${description}`, width)),
78
- ];
78
+ const keyItems = ESSENTIAL_KEYS.map(([key, description]) => `${key} ${description}`);
79
+ const keyLines: string[] = [];
80
+ if (entries.length >= 40 && width >= 100) {
81
+ let keyRow = '';
82
+ for (const item of keyItems) {
83
+ if (keyRow && visibleWidth(keyRow) + 2 + visibleWidth(item) > width) {
84
+ keyLines.push(keyRow);
85
+ keyRow = '';
86
+ }
87
+ keyRow += (keyRow ? ' ' : '') + fitLine(item, width);
88
+ }
89
+ if (keyRow) keyLines.push(keyRow);
90
+ } else {
91
+ keyLines.push(...keyItems.map((item) => fitLine(item, width)));
92
+ }
93
+ return [fitLine('Commands', width), ...commandLines, '', fitLine('Keys', width), ...keyLines];
79
94
  }
@@ -6,9 +6,10 @@
6
6
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
8
  import { debug } from '../debug/log.js';
9
+ import { readPendingQuestions } from '../ask-user-question/pending-questions.js';
9
10
  import { DecisionLedger, type DecisionEntry } from './decision-ledger.js';
10
11
 
11
- export type CardPlatform = 'telegram' | 'discord';
12
+ export type CardPlatform = 'telegram' | 'discord' | 'webpush';
12
13
  export interface CardButton { label: string; data: string }
13
14
  export interface CardView { text: string; buttons: CardButton[][] }
14
15
  export interface CardRef { chat: string; message: string }
@@ -42,6 +43,7 @@ export function renderCardText(e: DecisionEntry, extra: { note?: string; confirm
42
43
  '',
43
44
  `상황: ${e.scqa.s}`,
44
45
  `문제: ${e.scqa.c}`,
46
+ ...(e.pendingQuestion ? ['', `대기 질문 전문:\n${e.pendingQuestion}`] : []),
45
47
  ...(e.scqa.q ? [`질문: ${e.scqa.q}`] : []),
46
48
  ...(e.scqa.a ? [`제안: ${e.scqa.a}`] : []),
47
49
  '',
@@ -99,6 +101,7 @@ export interface DecisionCardServiceOptions {
99
101
  /** Owner user ids for this platform — taps from anyone else are refused and observed. */
100
102
  ownerIds: readonly string[];
101
103
  ledger?: DecisionLedger;
104
+ pendingQuestions?: typeof readPendingQuestions;
102
105
  /** Where this platform keeps which card it sent (one file per platform — the two bots may run in different processes). */
103
106
  statePath?: string;
104
107
  now?: () => Date;
@@ -149,6 +152,53 @@ export class DecisionCardService {
149
152
  }
150
153
  let dirty = false;
151
154
  if (!state.since) { state.since = this.now().toISOString(); dirty = true; debug.log('decisions.telegram', 'baseline', { platform, since: state.since }); }
155
+ // Same state root as the ledger — the H2 answer writer delivers under the ledger's stateDir, so the questions are read there too.
156
+ const pending = this.opts.pendingQuestions ? this.opts.pendingQuestions() : readPendingQuestions({ root: () => join(this.ledger.path, '..', '..') });
157
+ if (pending.ok) {
158
+ const seen = new Set(all.flatMap(entry => entry.resume ? [entry.resume.questionId] : []));
159
+ for (const record of pending.questions) {
160
+ for (const question of record.questions) {
161
+ const data = { questionId: record.id, runId: record.runId };
162
+ if (record.expiresAt && record.expiresAt <= this.now().toISOString()) {
163
+ debug.log('hitl.card-bridge', 'skipped', { ...data, reason: 'expired' });
164
+ continue;
165
+ }
166
+ if (question.impact !== 'high' && question.impact !== 'critical') {
167
+ debug.log('hitl.card-bridge', 'skipped', { ...data, reason: 'impact' });
168
+ continue;
169
+ }
170
+ if (record.questions.length !== 1 || question.options.length < 2 || question.options.length > 4) {
171
+ debug.log('hitl.card-bridge', 'skipped', { ...data, reason: 'options' });
172
+ continue;
173
+ }
174
+ if (seen.has(record.id)) {
175
+ debug.log('hitl.card-bridge', 'dedup', { ...data, decisionId: all.find(entry => entry.resume?.questionId === record.id)?.id, reason: 'already-raised' });
176
+ continue;
177
+ }
178
+ try {
179
+ const keys = ['a', 'b', 'c', 'd'];
180
+ const recommended = question.recommendedIndex;
181
+ const entry = this.ledger.raise({
182
+ title: question.question.split(/\r?\n/, 1)[0]!.slice(0, 120),
183
+ category: question.impact === 'critical' ? 'irreversible' : 'scope',
184
+ scqa: { s: Array.from(question.question.split(/\r?\n/, 1)[0]!).slice(0, 200).join(''), c: 'The requesting run is waiting for this choice.' },
185
+ pendingQuestion: question.question,
186
+ options: question.options.map((option, index) => ({ key: keys[index]!, label: option.label, consequence: option.description })),
187
+ recommendation: recommended !== undefined && Number.isInteger(recommended) && recommended >= 0 && recommended < question.options.length
188
+ ? { option: keys[recommended]!, why: '런이 추천' } : { skipped: true, reason: '추천 없음' },
189
+ raisedBy: { agent: 'harness' },
190
+ resume: { questionId: record.id, ...(record.runId === undefined ? {} : { runId: record.runId }) },
191
+ ...(record.expiresAt ? { dueAt: record.expiresAt } : {}),
192
+ });
193
+ seen.add(record.id);
194
+ all.unshift(entry);
195
+ debug.log('hitl.card-bridge', 'raised', { ...data, decisionId: entry.id });
196
+ } catch (error) {
197
+ debug.log('hitl.card-bridge', 'skipped', { ...data, reason: error instanceof Error ? error.name : 'unknown' });
198
+ }
199
+ }
200
+ }
201
+ } else debug.log('hitl.card-bridge', 'skipped', { reason: 'pending-unreadable' });
152
202
  const chats = await this.opts.transport.ownerChats().catch(() => [] as string[]);
153
203
  for (const e of all) {
154
204
  const card = state.cards[e.id];
@@ -203,9 +253,12 @@ export class DecisionCardService {
203
253
  return { kind: 'confirm', view: renderCard(entry, { confirm: parsed.key, ...(card?.note ? { note: card.note } : {}) }), toast: '되돌릴 수 없는 결정 — 한 번 더 확인해 주세요' };
204
254
  }
205
255
  let decided: DecisionEntry;
256
+ let answerDelivery: ReturnType<DecisionLedger['decideWithDelivery']>['delivery'] = null;
206
257
  try {
207
258
  // Same ledger method the CLI `decide` uses — one record path.
208
- decided = this.ledger.decide(entry.id, parsed.key, { kind: 'human' }, card?.note);
259
+ const recorded = this.ledger.decideWithDelivery(entry.id, parsed.key, { kind: 'human' }, card?.note);
260
+ decided = recorded.entry;
261
+ answerDelivery = recorded.delivery;
209
262
  } catch (error) {
210
263
  debug.log('decisions.telegram', 'decide-failed', { platform, id: entry.id, reason: error instanceof Error ? error.message.slice(0, 80) : 'unknown' }, { level: 'warn' });
211
264
  try { const now = this.ledger.show(entry.id); if (now.status !== 'open') return { kind: 'closed', view: renderCard(now), toast: '이미 정해진 결정입니다' }; } catch { /* fall through */ }
@@ -221,7 +274,9 @@ export class DecisionCardService {
221
274
  await this.opts.replyToRaiser?.(decided, platform).catch((error: unknown) => {
222
275
  debug.log('decisions.telegram', 'reply-failed', { platform, id: decided.id, reason: error instanceof Error ? error.message.slice(0, 80) : 'unknown' }, { level: 'warn' });
223
276
  });
224
- return { kind: 'decided', view, toast: `결정했습니다: ${decided.choice?.toUpperCase()}` };
277
+ return { kind: 'decided', view, toast: answerDelivery && !answerDelivery.ok
278
+ ? `결정은 기록됐지만 런 답 전달 실패 — decisions retry-answer ${decided.id}`
279
+ : `결정했습니다: ${decided.choice?.toUpperCase()}` };
225
280
  }
226
281
 
227
282
  /** Store a memo typed after «메모 달기»; the card shows it and the eventual decision carries it. */
@@ -1,12 +1,14 @@
1
1
  import { closeSync, existsSync, fstatSync, ftruncateSync, mkdirSync, openSync, readFileSync, realpathSync, statSync, unlinkSync, writeSync } from 'node:fs';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { elanousStateRoot } from '../autopilot/state-paths.js';
4
+ import { readPendingQuestionAnswer, readPendingQuestions, writePendingQuestionAnswer } from '../ask-user-question/pending-questions.js';
4
5
  import { debug, redactSecretText } from '../debug/log.js';
5
6
  import { createVersionResolver, type VersionOptions, type Versions } from '../directives/version-at.js';
6
7
  import { getUserConfig } from '../user-config.js';
7
8
 
8
9
  export type DecisionCategory = 'secret' | 'publish' | 'money' | 'security' | 'scope' | 'irreversible' | 'other';
9
- export type DecisionTrack = 'S' | 'T' | 'F' | 'O';
10
+ /** Old track letters (S·T·F·O) stay readable; seat names (OP·MK·TC·UX) are the current identities. */
11
+ export type DecisionTrack = 'S' | 'T' | 'F' | 'O' | 'OP' | 'MK' | 'TC' | 'UX';
10
12
  export interface DecisionOption { key: string; label: string; consequence: string }
11
13
  export type Recommendation = { option: string; why: string } | { skipped: true; reason: string };
12
14
  export type DecisionActor = { kind: 'human' } | { kind: 'auto'; agent: string; track?: DecisionTrack; delegation: string };
@@ -15,17 +17,31 @@ export interface DecisionEntry {
15
17
  options: DecisionOption[]; recommendation: Recommendation; raisedAt?: string; importedAt?: string;
16
18
  raisedBy: { agent: string; track?: DecisionTrack; session?: string }; version?: Versions;
17
19
  status: 'open' | 'decided' | 'withdrawn'; refs?: string[];
20
+ resume?: { questionId: string; runId?: string };
21
+ /** Original pending question, including its newlines; SCQA fields are short summaries. */
22
+ pendingQuestion?: string;
18
23
  /** DEC-TG — optional deadline (UTC). Cards remind the owner two hours before it. */
19
24
  dueAt?: string;
20
25
  decidedAt?: string; decidedBy?: DecisionActor; choice?: string; note?: string; versionAtDecision?: Versions;
21
26
  withdrawnAt?: string; withdrawReason?: string;
22
27
  history: Array<{ type: 'raised' | 'options-added' | 'decided' | 'withdrawn'; at?: string; by: string; version?: Versions; choice?: string; reason?: string }>;
23
28
  }
24
- export type RaiseInput = Pick<DecisionEntry, 'title' | 'category' | 'scqa' | 'options' | 'recommendation' | 'raisedBy' | 'refs' | 'dueAt'> & { raisedAt?: string };
29
+ export type RaiseInput = Pick<DecisionEntry, 'title' | 'category' | 'scqa' | 'options' | 'recommendation' | 'raisedBy' | 'refs' | 'dueAt' | 'resume' | 'pendingQuestion'> & { raisedAt?: string };
25
30
  type Event = { type: 'raised'; entry: DecisionEntry } | { type: 'options-added'; id: string; at: string; options: DecisionOption[]; by: string } | { type: 'decided'; id: string; at?: string; by: DecisionActor; choice?: string; version?: Versions; note?: string } | { type: 'withdrawn'; id: string; at: string; reason: string; version: Versions };
26
- export interface DecisionLedgerOptions extends VersionOptions { stateDir?: string; now?: () => Date; resolveVersion?: (at: string) => Versions }
31
+ export interface DecisionLedgerOptions extends VersionOptions { stateDir?: string; now?: () => Date; resolveVersion?: (at: string) => Versions; writeAnswer?: typeof writePendingQuestionAnswer }
32
+
33
+ /** null = the decision resumes no run; otherwise whether the answer file was written (or already matched). */
34
+ export type AnswerDelivery = null | { ok: true; questionId: string } | { ok: false; questionId: string; reason: string };
35
+
36
+ /** The decision is durable even when delivery fails; retryAnswer(id) only retries delivery. */
37
+ export class DecisionAnswerDeliveryError extends Error {
38
+ constructor(readonly decisionId: string, readonly questionId: string) {
39
+ super(`decision ${decisionId} recorded but answer delivery failed for ${questionId}; retry with decisions retry-answer ${decisionId}`);
40
+ this.name = 'DecisionAnswerDeliveryError';
41
+ }
42
+ }
27
43
  const CATEGORIES: readonly string[] = ['secret', 'publish', 'money', 'security', 'scope', 'irreversible', 'other'];
28
- const TRACKS: readonly string[] = ['S', 'T', 'F', 'O'];
44
+ const TRACKS: readonly string[] = ['S', 'T', 'F', 'O', 'OP', 'MK', 'TC', 'UX'];
29
45
 
30
46
  function required(value: string, name: string): string {
31
47
  if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} is required`);
@@ -73,7 +89,13 @@ function validate(input: RaiseInput, historical = false): RaiseInput {
73
89
  ? { skipped: true as const, reason: safe(single(input.recommendation.reason, 'skip reason')) }
74
90
  : { option: input.recommendation.option, why: safe(single(input.recommendation.why, 'recommendation why')) };
75
91
  if ('option' in recommendation && !options.some(o => o.key === recommendation.option)) throw new Error('recommended option not found');
92
+ if (input.resume && !/^(?:auq:[0-9a-z]+:[0-9a-z]{5}|execution:[A-Za-z0-9_-]+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?![\s\S])/.test(input.resume.questionId)) throw new Error('invalid resume questionId');
93
+ const resume = input.resume ? { questionId: input.resume.questionId,
94
+ ...(input.resume.runId === undefined ? {} : { runId: single(input.resume.runId, 'resume runId') }) } : undefined;
95
+ if (input.pendingQuestion !== undefined) required(input.pendingQuestion, 'pending question');
76
96
  return { ...input, title, scqa: { s, c, ...(q ? { q } : {}), ...(a ? { a } : {}) }, options, recommendation,
97
+ ...(input.pendingQuestion === undefined ? {} : { pendingQuestion: safe(input.pendingQuestion) }),
98
+ ...(resume ? { resume } : {}),
77
99
  raisedBy: { agent: safe(single(input.raisedBy.agent, 'agent')), ...(input.raisedBy.track ? { track: input.raisedBy.track } : {}), ...(input.raisedBy.session ? { session: safe(single(input.raisedBy.session, 'session')) } : {}) },
78
100
  ...(input.refs ? { refs: input.refs.map(r => safe(single(r, 'ref'))) } : {}),
79
101
  ...(input.dueAt ? { dueAt: utc(input.dueAt) } : {}) };
@@ -83,12 +105,16 @@ export class DecisionLedger {
83
105
  readonly path: string;
84
106
  private readonly lockPath: string;
85
107
  private readonly now: () => Date;
108
+ private readonly writeAnswer: typeof writePendingQuestionAnswer;
109
+ private readonly stateDir: string;
86
110
  private versionResolver?: (at: string) => Versions;
87
111
  private readonly versionOptions: DecisionLedgerOptions;
88
112
  constructor(options: DecisionLedgerOptions = {}) {
89
- this.path = join(options.stateDir ?? elanousStateRoot(), 'decisions', 'decisions.jsonl');
113
+ this.stateDir = options.stateDir ?? elanousStateRoot();
114
+ this.path = join(this.stateDir, 'decisions', 'decisions.jsonl');
90
115
  this.lockPath = `${this.path}.lock`;
91
116
  this.now = options.now ?? (() => new Date());
117
+ this.writeAnswer = options.writeAnswer ?? writePendingQuestionAnswer;
92
118
  this.versionOptions = options;
93
119
  this.versionResolver = options.resolveVersion;
94
120
  }
@@ -196,7 +222,14 @@ export class DecisionLedger {
196
222
  return entry;
197
223
  });
198
224
  }
225
+ /** Record the decision and say whether its answer reached the waiting run (null = the decision resumes nothing). */
226
+ decideWithDelivery(id: string, choice: string, by: DecisionActor, note?: string, decidedAt?: string): { entry: DecisionEntry; delivery: AnswerDelivery } {
227
+ return this.decideLocked(id, choice, by, note, decidedAt);
228
+ }
199
229
  decide(id: string, choice: string, by: DecisionActor, note?: string, decidedAt?: string): DecisionEntry {
230
+ return this.decideLocked(id, choice, by, note, decidedAt).entry;
231
+ }
232
+ private decideLocked(id: string, choice: string, by: DecisionActor, note?: string, decidedAt?: string): { entry: DecisionEntry; delivery: AnswerDelivery } {
200
233
  if (!by || (by.kind !== 'human' && by.kind !== 'auto')) throw new Error('decidedBy is required');
201
234
  if (by.kind === 'auto') {
202
235
  single(by.delegation, 'delegation'); single(by.agent, 'agent');
@@ -211,9 +244,55 @@ export class DecisionLedger {
211
244
  if (old.raisedAt && at < old.raisedAt) throw new Error('decision before raise');
212
245
  this.append({ type: 'decided', id, at, by, choice, version: this.version(at), ...(note ? { note: safe(single(note, 'note')) } : {}) });
213
246
  debug.log('decisions', 'decided', { id, category: old.category, by: by.kind });
214
- return this.show(id);
247
+ const decided = this.show(id);
248
+ return { entry: decided, delivery: this.deliverAnswer(decided) };
215
249
  });
216
250
  }
251
+ /** Retry delivery of the recorded choice without adding another decided event or changing its actor/note. */
252
+ retryAnswer(id: string): DecisionEntry {
253
+ return this.locked(() => {
254
+ const entry = this.show(id);
255
+ if (entry.status !== 'decided' || !entry.resume || !entry.choice || !entry.decidedBy) throw new Error(`decision has no recorded resume answer: ${id}`);
256
+ this.deliverAnswer(entry, true);
257
+ return entry;
258
+ });
259
+ }
260
+ private deliverAnswer(entry: DecisionEntry, throwOnFailure = false): AnswerDelivery {
261
+ if (!entry.resume) return null;
262
+ const { questionId, runId } = entry.resume;
263
+ try {
264
+ const label = entry.options.find(option => option.key === entry.choice)?.label;
265
+ if (!label || !entry.choice) throw new Error('recorded choice not found');
266
+ const deps = { root: () => this.stateDir };
267
+ const pending = readPendingQuestions(deps);
268
+ if (!pending.ok) throw new Error(pending.error);
269
+ const target = pending.questions.find(item => item.id === questionId);
270
+ if (!target || target.questions.length !== 1 || !target.questions[0]?.id) throw new Error('pending question target not found or ambiguous');
271
+ if (questionId.startsWith('execution:') && (!runId || target.runId !== runId || !questionId.startsWith(`execution:${runId}:`))) throw new Error('pending question run differs from decision');
272
+ if (!questionId.startsWith('execution:') && runId !== undefined && target.runId !== undefined && target.runId !== runId) throw new Error('pending question run differs from decision');
273
+ if (target.expiresAt && Date.parse(target.expiresAt) <= this.now().getTime()) throw new Error('pending question expired');
274
+ const question = target.questions[0];
275
+ if (question.options.length !== entry.options.length || question.options.some((option, index) =>
276
+ entry.options[index]?.key !== String.fromCharCode(97 + index) || entry.options[index]?.label !== option.label)) {
277
+ throw new Error('pending question options differ from decision');
278
+ }
279
+ const answerKey = question.id;
280
+ const answer = { id: questionId, result: { answers: { [answerKey]: questionId.startsWith('execution:') ? label : `${entry.choice}) ${label}` },
281
+ ...(entry.note ? { otherText: { [answerKey]: entry.note } } : {}) } };
282
+ const existing = readPendingQuestionAnswer(questionId, deps);
283
+ if (!existing.ok) throw new Error('existing answer unreadable');
284
+ if (existing.answer) {
285
+ if (JSON.stringify(existing.answer) !== JSON.stringify(answer)) throw new Error('pending question already answered differently');
286
+ } else this.writeAnswer(answer, deps);
287
+ debug.log('hitl.card-bridge', 'answered', { decisionId: entry.id, questionId, runId, via: entry.decidedBy?.kind });
288
+ return { ok: true, questionId };
289
+ } catch (error) {
290
+ const reason = error instanceof Error ? (error as NodeJS.ErrnoException).code ?? error.name : typeof error;
291
+ debug.log('hitl.card-bridge', 'answer-write-failed', { decisionId: entry.id, questionId, reason });
292
+ if (throwOnFailure) throw new DecisionAnswerDeliveryError(entry.id, questionId);
293
+ return { ok: false, questionId, reason: error instanceof Error ? error.message.slice(0, 120) : String(reason) };
294
+ }
295
+ }
217
296
  /** Import an open historical request with known alternatives and an unknown original time. */
218
297
  importOpen(input: RaiseInput): DecisionEntry {
219
298
  const clean = validate(input);
@@ -0,0 +1,157 @@
1
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from 'node:fs';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { join } from 'node:path';
4
+ import { elanousStateRoot } from '../autopilot/state-paths.js';
5
+ import { createLinearIssue, commentLinearIssue, findLinearDecisionIssue, moveLinearIssueToStateType, resolveLinearProjectId } from '../connectors/linear.js';
6
+ import { debug } from '../debug/log.js';
7
+ import { getSecretAsync } from '../nexus/config/secrets/index.js';
8
+ import { getUserConfig, type UserConfig } from '../user-config.js';
9
+ import { DecisionLedger, type DecisionEntry } from './decision-ledger.js';
10
+
11
+ interface ProjectionRecord { issue: string; closedAt?: string; commentPosted?: boolean }
12
+ type ProjectionState = Record<string, ProjectionRecord>;
13
+ export interface DecisionLinearProjectionDeps {
14
+ stateDir?: string;
15
+ ledger?: Pick<DecisionLedger, 'list'>;
16
+ config?: Pick<UserConfig, 'decisions' | 'coo'>;
17
+ getSecret?: (id: string) => Promise<string | undefined>;
18
+ fetch?: typeof fetch;
19
+ dryRun?: boolean;
20
+ }
21
+ export interface DecisionLinearProjectionResult {
22
+ created: number; closed: number; skipped: number; failed: number;
23
+ reason?: string;
24
+ plan?: Array<{ decisionId: string; action: 'create' | 'close'; issue?: string }>;
25
+ }
26
+
27
+ function readState(path: string): ProjectionState {
28
+ if (!existsSync(path)) return {};
29
+ const value: unknown = JSON.parse(readFileSync(path, 'utf8'));
30
+ if (!value || typeof value !== 'object' || Array.isArray(value) || Object.entries(value).some(([id, row]) =>
31
+ !/^D-\d{8}-\d+$/.test(id) || !row || typeof row !== 'object' || Array.isArray(row) ||
32
+ typeof (row as ProjectionRecord).issue !== 'string' || !(row as ProjectionRecord).issue ||
33
+ ((row as ProjectionRecord).closedAt !== undefined && typeof (row as ProjectionRecord).closedAt !== 'string') ||
34
+ ((row as ProjectionRecord).commentPosted !== undefined && typeof (row as ProjectionRecord).commentPosted !== 'boolean'))) {
35
+ throw new Error('invalid decision Linear projection state');
36
+ }
37
+ return value as ProjectionState;
38
+ }
39
+
40
+ function saveState(path: string, state: ProjectionState): void {
41
+ mkdirSync(join(path, '..'), { recursive: true });
42
+ const temp = `${path}.${randomUUID()}.tmp`;
43
+ try {
44
+ writeFileSync(temp, JSON.stringify(state), { mode: 0o600 });
45
+ renameSync(temp, path);
46
+ } finally { if (existsSync(temp)) unlinkSync(temp); }
47
+ }
48
+
49
+ function description(entry: DecisionEntry): string {
50
+ return [`카테고리: ${entry.category}`, ...(entry.dueAt ? [`기한: ${entry.dueAt}`] : []),
51
+ `결정 id: ${entry.id}`, '텔레그램/디스코드 카드에서 정한다',
52
+ ...(entry.refs ?? []).filter(ref => ref.startsWith('http'))].join('\n');
53
+ }
54
+
55
+ /** A single writer holds the file lock across remote creation and local persistence. */
56
+ export async function projectDecisionsToLinear(deps: DecisionLinearProjectionDeps = {}): Promise<DecisionLinearProjectionResult> {
57
+ const result: DecisionLinearProjectionResult = { created: 0, closed: 0, skipped: 0, failed: 0 };
58
+ const config = deps.config ?? getUserConfig();
59
+ if (config.decisions?.linearProjection?.enabled !== true) {
60
+ result.reason = 'decisions.linearProjection.enabled 꺼짐';
61
+ debug.log('decisions.linear', 'skipped', { decisionId: null, issue: null, reason: 'disabled' });
62
+ return result;
63
+ }
64
+ // A dry run only reads the local ledger and state — it must work before a key is set.
65
+ const apiKey = (deps.dryRun ? '' : await (deps.getSecret ?? getSecretAsync)('connector.linear.apiKey')) ?? '';
66
+ if (!deps.dryRun && !apiKey) {
67
+ result.reason = 'Linear 키가 없습니다 — `elanous connector linear set-key`';
68
+ debug.log('decisions.linear', 'skipped', { decisionId: null, issue: null, reason: 'missing-key' });
69
+ return result;
70
+ }
71
+ const stateDir = deps.stateDir ?? elanousStateRoot();
72
+ const path = join(stateDir, 'decisions', 'linear-projection.json');
73
+ const ledger = deps.ledger ?? new DecisionLedger({ stateDir });
74
+ const entries = ledger.list({ status: 'all' });
75
+ const fetchFn = deps.fetch ?? fetch;
76
+ const lockPath = `${path}.lock`;
77
+ let lock: number | undefined;
78
+ if (!deps.dryRun) {
79
+ mkdirSync(join(path, '..'), { recursive: true });
80
+ const deadline = Date.now() + 10_000;
81
+ for (;;) {
82
+ try { lock = openSync(lockPath, 'wx', 0o600); writeSync(lock, `${process.pid}`); break; }
83
+ catch (error) {
84
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
85
+ try {
86
+ const pid = Number(readFileSync(lockPath, 'utf8'));
87
+ if (Number.isSafeInteger(pid) && pid > 0 && Date.now() - statSync(lockPath).mtimeMs > 30_000) {
88
+ try { process.kill(pid, 0); }
89
+ catch (e) { if ((e as NodeJS.ErrnoException).code === 'ESRCH') { unlinkSync(lockPath); continue; } }
90
+ }
91
+ } catch (e) { if ((e as NodeJS.ErrnoException).code === 'ENOENT') continue; }
92
+ if (Date.now() >= deadline) throw new Error('decision Linear projection lock timeout');
93
+ await Bun.sleep(25);
94
+ }
95
+ }
96
+ }
97
+ try {
98
+ const state = readState(path);
99
+ if (deps.dryRun) result.plan = [];
100
+ let projectId: string | undefined;
101
+ for (const entry of entries) {
102
+ let issue = state[entry.id]?.issue;
103
+ try {
104
+ const record = state[entry.id];
105
+ if (entry.status === 'open' && !record) {
106
+ if (deps.dryRun) {
107
+ result.plan!.push({ decisionId: entry.id, action: 'create' });
108
+ result.created++;
109
+ } else {
110
+ projectId ??= await resolveLinearProjectId({ apiKey, project: config.coo?.linearProject ?? '외부 행정·큰 일 (COO)', fetch: fetchFn });
111
+ const existing = await findLinearDecisionIssue({ apiKey, projectId, decisionId: entry.id, fetch: fetchFn });
112
+ issue = existing ?? await createLinearIssue({ apiKey, projectId, title: `[결정] ${entry.title}`, description: description(entry),
113
+ ...(entry.dueAt ? { dueDate: entry.dueAt.slice(0, 10) } : {}), fetch: fetchFn });
114
+ state[entry.id] = { issue };
115
+ saveState(path, state);
116
+ if (existing) {
117
+ result.skipped++;
118
+ debug.log('decisions.linear', 'skipped', { decisionId: entry.id, issue, reason: 'recovered' });
119
+ continue;
120
+ }
121
+ result.created++;
122
+ }
123
+ debug.log('decisions.linear', 'created', { decisionId: entry.id, issue: issue ?? null, reason: deps.dryRun ? 'dry-run' : 'created' });
124
+ } else if (entry.status !== 'open' && record && !record.closedAt) {
125
+ if (deps.dryRun) {
126
+ result.plan!.push({ decisionId: entry.id, action: 'close', issue: record.issue });
127
+ } else {
128
+ if (!record.commentPosted) {
129
+ const body = entry.status === 'withdrawn' ? '철회됨'
130
+ : `결정됨: ${entry.choice ?? '선택 키 미상'} · ${entry.decidedBy?.kind ?? '주체 미상'} · ${entry.decidedAt ?? '시각 미상'}`;
131
+ await commentLinearIssue({ apiKey, issueId: record.issue, body, fetch: fetchFn });
132
+ record.commentPosted = true;
133
+ saveState(path, state);
134
+ }
135
+ await moveLinearIssueToStateType({ apiKey, issueId: record.issue, type: entry.status === 'decided' ? 'completed' : 'canceled', fetch: fetchFn });
136
+ record.closedAt = new Date().toISOString();
137
+ saveState(path, state);
138
+ }
139
+ result.closed++;
140
+ debug.log('decisions.linear', 'closed', { decisionId: entry.id, issue: record.issue, reason: deps.dryRun ? 'dry-run' : entry.status });
141
+ } else {
142
+ result.skipped++;
143
+ debug.log('decisions.linear', 'skipped', { decisionId: entry.id, issue: issue ?? null, reason: record?.closedAt ? 'already-closed' : record ? 'already-created' : 'not-projected' });
144
+ }
145
+ } catch (error) {
146
+ result.failed++;
147
+ const reason = error instanceof Error
148
+ ? (error as NodeJS.ErrnoException).code ?? (/^Linear GraphQL HTTP \d{3}$/.test(error.message) ? error.message : error.name)
149
+ : 'unknown';
150
+ debug.log('decisions.linear', 'failed', { decisionId: entry.id, issue: issue ?? null, reason });
151
+ }
152
+ }
153
+ return result;
154
+ } finally {
155
+ if (lock !== undefined) { closeSync(lock); unlinkSync(lockPath); }
156
+ }
157
+ }
@@ -0,0 +1,50 @@
1
+ import { debug } from '../debug/log.js';
2
+ import { listSubscriptions } from '../web-push/subscriptions.js';
3
+ import { sendPushToAll } from '../web-push/sender.js';
4
+ import { type CardTransport, type CardView } from './decision-cards.js';
5
+ import { DecisionLedger } from './decision-ledger.js';
6
+
7
+ const ID_IN_CARD = /^🗳 결정 요청 (D-\d{8}-\d+)(?: ·|\n)/;
8
+ const ID_IN_REMINDER = /^⏰ 기한 2시간 전 — (D-\d{8}-\d+) /;
9
+ const TITLE_LIMIT = 60;
10
+
11
+ export function webPushDecisionTransport(
12
+ ledger: DecisionLedger,
13
+ deps: { subscriptions?: typeof listSubscriptions; push?: typeof sendPushToAll } = {},
14
+ ): CardTransport {
15
+ const subscriptions = deps.subscriptions ?? listSubscriptions;
16
+ const push = deps.push ?? sendPushToAll;
17
+ const title = (prefix: string, name: string) => prefix + Array.from(name).slice(0, TITLE_LIMIT - Array.from(prefix).length).join('');
18
+ const url = (id: string) => `/approvals?decision=${encodeURIComponent(id)}`;
19
+ const tag = (id: string) => `decision-${id}`;
20
+ return {
21
+ platform: 'webpush',
22
+ ownerChats: async () => subscriptions().length ? ['webpush'] : [],
23
+ send: async (_chat, view: CardView) => {
24
+ const id = ID_IN_CARD.exec(view.text)?.[1];
25
+ if (!id || !subscriptions().length) return null;
26
+ const entry = ledger.show(id);
27
+ if (entry.status !== 'open') return null;
28
+ const recommendation = 'skipped' in entry.recommendation ? '추천안 없음' : `추천안: ${entry.recommendation.option.toUpperCase()}`;
29
+ const body = `${recommendation}${entry.dueAt ? ` · 기한: ${new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(entry.dueAt))}` : ''}`;
30
+ const result = await push({ title: title('대표 결정 · ', entry.title), body, url: url(id), tag: tag(id) });
31
+ debug.log('decisions.webpush', 'card-sent', { id, delivered: result.delivered });
32
+ return result.delivered ? { chat: 'webpush', message: id } : null;
33
+ },
34
+ edit: async (ref, _view) => {
35
+ const id = ref.message;
36
+ const entry = ledger.show(id);
37
+ if (entry.status === 'open' || !subscriptions().length) return;
38
+ const result = await push({ title: title('결정됨 · ', entry.title), url: url(id), tag: tag(id), data: { silent: true } });
39
+ debug.log('decisions.webpush', 'card-closed', { id, delivered: result.delivered });
40
+ },
41
+ notify: async (_chat, text) => {
42
+ const id = ID_IN_REMINDER.exec(text)?.[1];
43
+ if (!id || !subscriptions().length) return;
44
+ const entry = ledger.show(id);
45
+ if (entry.status !== 'open') return;
46
+ const result = await push({ title: title('기한 알림 · ', entry.title), body: `기한 2시간 전 · ${id}`, url: url(id), tag: tag(id) });
47
+ debug.log('decisions.webpush', 'card-sent', { id, delivered: result.delivered });
48
+ },
49
+ };
50
+ }
@@ -0,0 +1,36 @@
1
+ import { listChecklist, type ChecklistItem } from '../release-loop/checklist.js';
2
+
3
+ export interface InterpretationCard {
4
+ what: string;
5
+ cell: string | null;
6
+ unknowns: string[];
7
+ }
8
+
9
+ export type CellCandidate = Pick<ChecklistItem, 'id' | 'title'>;
10
+
11
+ /** The same SQLite-backed cells exposed by `elanous release checklist list --version <v>`. */
12
+ export function readCellCandidates(version: string): CellCandidate[] {
13
+ return listChecklist(version).items.map(({ id, title }) => ({ id, title }));
14
+ }
15
+
16
+ /** Interpret a single directive without querying state or inventing a release cell. */
17
+ export function interpretDirective(line: string, candidates: readonly CellCandidate[]): InterpretationCard {
18
+ if (/\r|\n/.test(line)) throw new Error('지시는 한 줄이어야 한다');
19
+ const what = line.trim();
20
+ if (!what) throw new Error('빈 지시는 해석할 수 없다');
21
+
22
+ const matches = candidates.filter(({ id, title }) =>
23
+ (id && new RegExp(`(^|[^\\p{L}\\p{N}])${id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?=$|[^\\p{L}\\p{N}]|[을를은는이가에의와과])`, 'u').test(what)) ||
24
+ (title && what.includes(title)));
25
+
26
+ if (matches.length === 1) return { what, cell: matches[0]!.id, unknowns: [] };
27
+ return {
28
+ what,
29
+ cell: null,
30
+ unknowns: [matches.length ? `칸 후보가 여럿이다: ${matches.map(({ id }) => id).join(', ')}` : '연결할 칸을 확인해야 한다'],
31
+ };
32
+ }
33
+
34
+ export function renderInterpretationCard(card: InterpretationCard): string {
35
+ return `무엇: ${card.what}\n칸: ${card.cell ?? '확인 필요'}\n미확인: ${card.unknowns.join(', ') || '없음'}`;
36
+ }
@@ -21,6 +21,7 @@
21
21
  // ⏳ Mention parser → persona LLM dispatch wire
22
22
 
23
23
  import { debug } from '../debug/log.js';
24
+ import { botAudienceFor, gateDiscordSchemas } from '../maturity/bot-command-maturity.js';
24
25
  import type { DiscordBot } from '../discord.js';
25
26
  import {
26
27
  loadLayeredPersonaDirs,
@@ -204,7 +205,10 @@ export async function wireSprint21Runtime(opts: WireSprint21Opts): Promise<Sprin
204
205
  // 6. Slash command registration
205
206
  const cmdRest = makeCommandRest({ token: opts.token, fetchImpl: opts.fetchImpl });
206
207
  async function registerSlashCommands(): Promise<number> {
207
- const schemas = router.schemas();
208
+ const allSchemas = router.schemas();
209
+ const audience = botAudienceFor('discord');
210
+ const { schemas, hidden } = gateDiscordSchemas(allSchemas, audience);
211
+ debug.log('discord.command', 'menu-filtered', { total: allSchemas.length, shown: schemas.length - hidden, ...audience });
208
212
  if (opts.devGuildId) {
209
213
  const out = await cmdRest.bulkOverwriteGuild(opts.appId, opts.devGuildId, schemas);
210
214
  log(`[sprint21-wire] registered ${out.length} slash commands to guild ${opts.devGuildId}`);