elanous 0.2.10 → 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 (584) 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/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  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-54b32bd27726588d.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-35414e0a007b4082.js +1 -0
  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 -1
  152. package/apps/pwa/out/ops/seats/index.txt +22 -22
  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 -1
  178. package/apps/pwa/out/today/index.txt +23 -23
  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/intake/intake-daily.yaml +2 -1
  194. package/graphs/ops/recipes.yaml +3 -0
  195. package/graphs/ops/secret-exposure.yaml +24 -0
  196. package/graphs/release/recipes.yaml +3 -0
  197. package/graphs/release/release-loop.yaml +4 -1
  198. package/graphs/video/explainer-line.yaml +2 -2
  199. package/package.json +2 -1
  200. package/plugins/elanous-hwp/README.md +25 -0
  201. package/plugins/elanous-hwp/cli.ts +22 -0
  202. package/plugins/elanous-hwp/converter.ts +237 -0
  203. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  204. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  205. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  206. package/plugins/elanous-hwp/plugin.json +16 -0
  207. package/plugins/elanous-hwp/plugin.ts +40 -0
  208. package/scripts/ci-public-export-leak-gate.ts +75 -14
  209. package/scripts/ci-public-leak-gate.ts +44 -9
  210. package/scripts/context-hooks/claude-stop.sh +4 -0
  211. package/scripts/context-hooks/emit.ts +24 -0
  212. package/scripts/context-hooks/post-tool-use.sh +4 -0
  213. package/scripts/coord-channel-watch.sh +12 -0
  214. package/scripts/coord-requests-bridge.ts +143 -0
  215. package/scripts/field-feed/lib.ts +4 -0
  216. package/scripts/fleet/node-setup.sh +20 -3
  217. package/scripts/homebrew-formula-bump.ts +69 -0
  218. package/scripts/marketing/measure-site-numbers.ts +169 -0
  219. package/scripts/measure-gate-shards.ts +309 -0
  220. package/scripts/mission-request-judge.ts +31 -1
  221. package/scripts/morning-report.ts +2 -2
  222. package/scripts/opportunity-scan.ts +1 -1
  223. package/scripts/release-loop/auto-approve-node.ts +21 -4
  224. package/scripts/release-loop/cut-branch.ts +84 -0
  225. package/scripts/release-loop/gate-node.ts +14 -13
  226. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  227. package/scripts/release-loop/node-verdict.ts +3 -3
  228. package/scripts/release-loop/tui-node-checks.ts +42 -0
  229. package/scripts/release-loop/tui-sim-node.ts +32 -8
  230. package/scripts/release-loop/unattended-release.ts +5 -3
  231. package/scripts/release-loop/version-node.ts +61 -10
  232. package/scripts/signal-digest-cycle.ts +2 -7
  233. package/scripts/signal-digest-photo.ts +11 -0
  234. package/scripts/tech1-public-measure.ts +94 -0
  235. package/scripts/test-diet/node.ts +1 -1
  236. package/scripts/tui-regress.ts +2 -2
  237. package/scripts/ux/demo-rehearsal.ts +243 -0
  238. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  239. package/skills/diagram-master/SKILL.md +366 -0
  240. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  241. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  242. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  243. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  244. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  245. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  246. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  247. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  248. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  249. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  250. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  251. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  252. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  253. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  254. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  255. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  256. package/skills/diagram-master/references/examples/README.md +69 -0
  257. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  258. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  259. package/skills/diagram-master/references/pyproject.toml +16 -0
  260. package/skills/diagram-master/references/quality-checklist.md +33 -0
  261. package/skills/diagram-master/references/routing-guide.md +164 -0
  262. package/skills/diagram-master/references/uv.lock +1356 -0
  263. package/skills/google-workspace/SKILL.md +33 -0
  264. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  265. package/skills/grill-me/SKILL.md +1 -1
  266. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  267. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  268. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  269. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  270. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  271. package/skills/omni-crawl/SKILL.md +21 -11
  272. package/skills/omni-crawl/scripts/main.ts +6 -6
  273. package/skills/omni-crawl/src/router.ts +3 -3
  274. package/skills/omni-digest/SKILL.md +17 -9
  275. package/skills/omni-digest/digest.md +2 -2
  276. package/skills/omni-digest/src/fetch.ts +30 -3
  277. package/skills/pitch-deck/SKILL.md +2 -2
  278. package/skills/pitch-deck/template.html +2 -2
  279. package/skills/youtube-master/SKILL.md +163 -0
  280. package/skills/youtube-master/package-lock.json +558 -0
  281. package/skills/youtube-master/package.json +13 -0
  282. package/skills/youtube-master/references/study-note-template.md +124 -0
  283. package/skills/youtube-master/scripts/main.ts +435 -0
  284. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  285. package/skills/youtube-master/src/audio.ts +63 -0
  286. package/skills/youtube-master/src/domain-staging.ts +50 -0
  287. package/skills/youtube-master/src/env.ts +36 -0
  288. package/skills/youtube-master/src/obsidian.ts +155 -0
  289. package/skills/youtube-master/src/router.ts +110 -0
  290. package/skills/youtube-master/src/stt.ts +199 -0
  291. package/skills/youtube-master/src/study-note.ts +175 -0
  292. package/skills/youtube-master/src/summarize.ts +358 -0
  293. package/skills/youtube-master/src/transcript.ts +76 -0
  294. package/skills/youtube-master/src/types.ts +91 -0
  295. package/skills/youtube-master/src/util.ts +93 -0
  296. package/skills/youtube-master/src/youtube.ts +70 -0
  297. package/skills/youtube-master/tsconfig.json +13 -0
  298. package/src/acp/server.ts +5 -2
  299. package/src/agent-mission/driver.ts +80 -10
  300. package/src/agent-mission/pty-decision.ts +71 -0
  301. package/src/agent-mission/review-loop.ts +30 -0
  302. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  303. package/src/autopilot/tool-registry.ts +2 -0
  304. package/src/boot/daemon-prompt-turn.ts +5 -0
  305. package/src/boot/daemon-runtime.ts +9 -3
  306. package/src/boot/daemon-tools/web-search.ts +3 -0
  307. package/src/card-followup/core.ts +109 -0
  308. package/src/chat/index.ts +1 -0
  309. package/src/cli/drive-input-jail.ts +101 -0
  310. package/src/cli/hooks-cli.ts +17 -3
  311. package/src/cli/make-cli.ts +43 -0
  312. package/src/cli/persona-cli.ts +90 -4
  313. package/src/cli/plugin-cli.ts +31 -22
  314. package/src/cli/pod-cli.ts +19 -9
  315. package/src/cli/pr-cli.ts +51 -15
  316. package/src/cli/pty-drive-cli.ts +41 -7
  317. package/src/cli/pty-drive-verdict.ts +40 -0
  318. package/src/cli/release-cli.ts +17 -4
  319. package/src/cli/setup-cli.ts +43 -1
  320. package/src/cli/skills-cli.ts +17 -1
  321. package/src/context-bus/claude-hooks-install.ts +10 -0
  322. package/src/context-bus/context-now-surfaces.ts +48 -0
  323. package/src/context-bus/context-now.ts +104 -0
  324. package/src/context-bus/coord-events.ts +2 -2
  325. package/src/context-bus/external-events.ts +52 -0
  326. package/src/context-bus/long-term-memory.ts +108 -0
  327. package/src/dashboard/index.ts +9 -4
  328. package/src/dashboard/slash-runtime/dashboard-handlers.ts +7 -1
  329. package/src/decisions/decision-cards.ts +10 -3
  330. package/src/decisions/decision-ledger.ts +13 -5
  331. package/src/discord/sprint21-runtime.ts +5 -1
  332. package/src/discord-self-message.ts +32 -0
  333. package/src/discord-slash-wire.ts +5 -1
  334. package/src/discord.ts +17 -1
  335. package/src/domains/core-tools.ts +3 -2
  336. package/src/domains/outbound-alert.ts +6 -1
  337. package/src/domains/telegram-kind-route.ts +51 -13
  338. package/src/exec-requests/default-outputs.ts +25 -0
  339. package/src/exec-requests/planner.ts +10 -2
  340. package/src/exec-requests/runner.ts +20 -6
  341. package/src/exec-requests/store.ts +3 -0
  342. package/src/execution-loop/launch-gate.ts +100 -0
  343. package/src/field/field-reel.ts +5 -1
  344. package/src/field-note/index.ts +201 -0
  345. package/src/field-note/transcribe.ts +248 -0
  346. package/src/graph-kinds/registry.ts +3 -3
  347. package/src/graph-runner/graph-cli.ts +61 -1
  348. package/src/graph-runner/graph-grow-llm.ts +37 -0
  349. package/src/graph-runner/graph-grow.ts +47 -0
  350. package/src/graph-runner/runner.ts +317 -25
  351. package/src/grok/agent-search.ts +8 -2
  352. package/src/guardian/secret-exposure-scan.ts +101 -0
  353. package/src/harness/harness-cli-command.ts +247 -7
  354. package/src/harness/harness-pod-dispatch.ts +43 -23
  355. package/src/harness/harness-seams.ts +38 -4
  356. package/src/harness/harness-stop.ts +23 -4
  357. package/src/harness/launch-registry.ts +91 -0
  358. package/src/harness/process-garbage.ts +5 -3
  359. package/src/hooks/dispatch.ts +82 -0
  360. package/src/hooks/expose.ts +254 -0
  361. package/src/hooks/github-shadow.ts +108 -0
  362. package/src/hooks/providers.ts +71 -5
  363. package/src/hooks/queue.ts +1 -1
  364. package/src/hooks/receiver.ts +21 -20
  365. package/src/index.ts +52 -14
  366. package/src/intake-plane/categorize.ts +18 -46
  367. package/src/intake-plane/discord-seat-work.ts +10 -0
  368. package/src/intake-plane/front-route-classifier.ts +33 -39
  369. package/src/intake-plane/persona-answer.ts +30 -0
  370. package/src/intake-plane/runtime-callables.ts +8 -1
  371. package/src/intake-plane/telegram-seat-work.ts +36 -2
  372. package/src/intake-plane/wish-folder.ts +67 -0
  373. package/src/intent-gate/gate.ts +30 -10
  374. package/src/live/detail-switch.ts +5 -0
  375. package/src/llm/difficulty.ts +57 -0
  376. package/src/llm/judge-layer.ts +101 -0
  377. package/src/llm/mission-router.ts +33 -19
  378. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  379. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  380. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  381. package/src/loops/contract/loop-agent.schema.json +138 -0
  382. package/src/loops/contract/validate.ts +64 -0
  383. package/src/loops/registry.ts +20 -6
  384. package/src/market/signed-index.ts +4 -0
  385. package/src/maturity/bot-command-maturity.ts +45 -0
  386. package/src/maturity/feature-maturity.ts +26 -4
  387. package/src/model-tier/index.ts +2 -2
  388. package/src/model-tier/tier-resolver.ts +20 -20
  389. package/src/model-tier/types.ts +6 -6
  390. package/src/mss/logging/log-store.ts +15 -0
  391. package/src/nexus/api/config-model-tier.ts +5 -4
  392. package/src/nexus/api/fabric-plans.ts +53 -0
  393. package/src/nexus/api/harness-api.ts +5 -1
  394. package/src/nexus/api/health.ts +2 -0
  395. package/src/nexus/api/http-server.ts +36 -0
  396. package/src/nexus/api/inside-events.ts +226 -0
  397. package/src/nexus/api/meta-api.ts +21 -8
  398. package/src/nexus/api/missions.ts +6 -1
  399. package/src/nexus/api/ops-seats.ts +33 -0
  400. package/src/nexus/api/outputs-route.ts +44 -0
  401. package/src/nexus/api/seat-requests.ts +44 -2
  402. package/src/nexus/api/sessions-store.ts +17 -38
  403. package/src/nexus/api/sub-seat-charters.ts +34 -0
  404. package/src/nexus/api/tabs-mutations.ts +3 -1
  405. package/src/nexus/api/trace.ts +18 -6
  406. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  407. package/src/nexus/api/workflows.ts +80 -6
  408. package/src/nexus/index.ts +2 -0
  409. package/src/nexus/kinds/webterm.ts +2 -1
  410. package/src/nexus/webterm/pty.ts +6 -2
  411. package/src/onboarding/cli-auth-status.ts +80 -0
  412. package/src/onboarding/voice-ai.ts +3 -3
  413. package/src/org/seat-budget.ts +48 -0
  414. package/src/org/stall-escalation.ts +63 -0
  415. package/src/outputs/ledger.ts +120 -0
  416. package/src/persona/persona-todo.ts +79 -0
  417. package/src/persona/presets.ts +116 -2
  418. package/src/persona/team-set.ts +155 -0
  419. package/src/plugins/install/plugin-install.ts +14 -0
  420. package/src/plugins/maker/market-bundle.ts +109 -0
  421. package/src/plugins/maker/plugin-maker.ts +254 -11
  422. package/src/plugins/maker/wizard-generate.ts +103 -0
  423. package/src/pod-lease/admission.ts +150 -0
  424. package/src/pod-lease/dependency-state.ts +85 -0
  425. package/src/pod-lease/host-lease.ts +127 -0
  426. package/src/project/project-suggestion.ts +16 -0
  427. package/src/project/session-context.ts +24 -0
  428. package/src/release-loop/checklist.ts +2 -2
  429. package/src/release-loop/feature-store.ts +5 -3
  430. package/src/release-loop/next-md-merge.ts +58 -0
  431. package/src/release-loop/release-note.ts +59 -4
  432. package/src/seat-dispatch/seat-ask.ts +130 -0
  433. package/src/seat-dispatch/seat-questions.ts +100 -0
  434. package/src/seat-loop/seat-loop.ts +548 -29
  435. package/src/seat-loop/seat-report.ts +37 -2
  436. package/src/self-dev/dev-cli.ts +4 -1
  437. package/src/self-dev/dev-pipeline.ts +37 -1
  438. package/src/self-dev/draft-sweep.ts +38 -33
  439. package/src/self-dev/draft-triage-rules.ts +8 -5
  440. package/src/self-dev/fabric-plan-core.ts +297 -0
  441. package/src/self-dev/orchestrate.ts +36 -4
  442. package/src/self-dev/release-path-guard.ts +62 -0
  443. package/src/self-dev/shard-aggregate.ts +230 -0
  444. package/src/self-dev/shard-placement.ts +60 -0
  445. package/src/self-dev/shard-plan.ts +48 -0
  446. package/src/self-dev/shard-pod-run.ts +77 -0
  447. package/src/self-dev/shard-run.ts +105 -0
  448. package/src/self-implement/gate-baseline.ts +1 -1
  449. package/src/self-implement/gate-cli.ts +40 -1
  450. package/src/self-implement/gate-scope.ts +37 -7
  451. package/src/self-implement/graph-variant.ts +171 -0
  452. package/src/self-implement/harness-policy-gates.ts +1 -1
  453. package/src/self-implement/headless-elanous-driver.ts +22 -3
  454. package/src/self-implement/host-regate.ts +22 -1
  455. package/src/self-implement/importer-test-index.ts +2 -1
  456. package/src/self-implement/l8-merge-queue.ts +130 -0
  457. package/src/self-implement/orchestrator.ts +242 -9
  458. package/src/self-implement/route-consumer-test-index.ts +122 -0
  459. package/src/self-implement/seams.ts +72 -11
  460. package/src/self-implement/test-seams.ts +1 -0
  461. package/src/self-implement/uncommitted-work.ts +59 -0
  462. package/src/session/index.ts +36 -13
  463. package/src/skills/gift-install.ts +215 -0
  464. package/src/skills/tools/web-search.ts +4 -1
  465. package/src/steward/launch.ts +42 -26
  466. package/src/steward/steward-cards.ts +17 -9
  467. package/src/steward/triage.ts +46 -14
  468. package/src/task-cards/card-cli.ts +25 -1
  469. package/src/task-orchestrator/mission.ts +5 -0
  470. package/src/task-orchestrator/store.ts +12 -3
  471. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  472. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  473. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  474. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  475. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  476. package/src/task-orchestrator/types.ts +2 -0
  477. package/src/telegram-card-followup.ts +16 -96
  478. package/src/telegram-commands.ts +10 -1
  479. package/src/telegram-project-command.ts +71 -0
  480. package/src/telegram-report.ts +21 -17
  481. package/src/telegram.ts +29 -3
  482. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  483. package/src/user-config.ts +102 -20
  484. package/src/version/packed-revision.json +1 -1
  485. package/src/web-search/grok.ts +7 -1
  486. package/src/web-search/index.ts +28 -1
  487. package/src/web-search/provider.ts +4 -0
  488. package/src/web-search/x-intent.ts +5 -0
  489. package/src/workflow-runtime/executor.ts +277 -47
  490. package/src/workflow-runtime/index.ts +1 -0
  491. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  492. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  493. package/src/workflow-runtime/schema.ts +79 -4
  494. package/src/workflow-runtime/types.ts +35 -4
  495. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  505. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  506. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  525. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  583. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  584. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -1,11 +1,20 @@
1
1
  import { createHmac, timingSafeEqual } from 'node:crypto';
2
2
 
3
- export type HookProvider = 'linear' | 'asana';
3
+ export type HookProvider = 'linear' | 'asana' | 'github';
4
+ export const PUBLIC_GITHUB_REPO = 'ElanvitalAI/elanous';
5
+ /** Links to documentation and reproductions are not spam signals. */
6
+ export function isGithubSpamText(value: string): boolean {
7
+ return /\b(?:casino|crypto giveaway|free money|seo backlinks|airdrop)\b/i.test(value);
8
+ }
4
9
  export interface ExternalTask {
5
10
  eventId: string;
6
11
  title: string;
7
12
  description?: string;
8
13
  external: { provider: HookProvider; ref: string; url?: string };
14
+ /** Linear issue assignee ID, resolved by the configured seat mapping; events.routes takes precedence. */
15
+ assigneeId?: string;
16
+ /** L14: an opened PR/issue on the public repository — shadow intake only, never dispatched to seats. */
17
+ github?: { repository: string; number: number; type: 'pull_request' | 'issue'; spamSignal?: boolean };
9
18
  }
10
19
  export type Verification = { ok: true; body: unknown; eventIds: string[]; ignored?: string } | { ok: false; reason: 'bad-signature' | 'stale' | 'invalid-body' };
11
20
 
@@ -29,7 +38,9 @@ export function asanaEventId(event: unknown): string | undefined {
29
38
  }
30
39
 
31
40
  export function verifyWebhook(provider: HookProvider, raw: Buffer, headers: Headers, secret: string, now = Date.now()): Verification {
32
- if (!equalSignature(raw, secret, headers.get(provider === 'linear' ? 'linear-signature' : 'x-hook-signature')))
41
+ const signature = headers.get(provider === 'linear' ? 'linear-signature' : provider === 'github' ? 'x-hub-signature-256' : 'x-hook-signature');
42
+ const digest = provider === 'github' ? (signature?.startsWith('sha256=') ? signature.slice(7) : null) : signature;
43
+ if (!equalSignature(raw, secret, digest))
33
44
  return { ok: false, reason: 'bad-signature' };
34
45
  let parsed: unknown;
35
46
  try { parsed = JSON.parse(raw.toString('utf8')); } catch { return { ok: false, reason: 'invalid-body' }; }
@@ -39,15 +50,45 @@ export function verifyWebhook(provider: HookProvider, raw: Buffer, headers: Head
39
50
  const timestamp = body.webhookTimestamp;
40
51
  if (typeof timestamp !== 'number' || !Number.isFinite(timestamp) || Math.abs(now - timestamp) > 60_000)
41
52
  return { ok: false, reason: 'stale' };
42
- // Linear 은 실패 응답이 쌓이면 웹훅을 꺼 버린다 — 서명이 맞는 «대상 아닌» 이벤트(댓글·수정 등)는
43
- // 거절하지 않고 받아서 버린다. 지금 태스크로 만드는 것은 이슈 생성뿐이다.
44
- if (body.type !== 'Issue' || body.action !== 'create')
53
+ // Acknowledge signed, out-of-scope events so Linear does not disable the webhook.
54
+ const previous = object(body.updatedFrom);
55
+ const relevantUpdate = body.action === 'update' && previous &&
56
+ ('assigneeId' in previous || 'stateId' in previous);
57
+ if (body.type !== 'Issue' || (body.action !== 'create' && !relevantUpdate))
45
58
  return { ok: true, body, eventIds: [], ignored: `${String(body.type)}:${String(body.action)}` };
46
59
  const eventId = text(headers.get('linear-delivery')) ?? (text(body.webhookId) && text(body.createdAt) ? `${body.webhookId}:${body.createdAt}` : undefined);
47
60
  if (!eventId || !object(body.data) || !text(object(body.data)?.id) || !text(object(body.data)?.title))
48
61
  return { ok: false, reason: 'invalid-body' };
49
62
  return { ok: true, body, eventIds: [eventId] };
50
63
  }
64
+ if (provider === 'github' && object(body.repository)?.full_name === PUBLIC_GITHUB_REPO) {
65
+ // L14: the public repository's newly opened PRs/issues go to the shadow intake (no seat dispatch, no outside writes).
66
+ const kind = headers.get('x-github-event');
67
+ if (!['pull_request', 'issues'].includes(kind ?? '') || body.action !== 'opened')
68
+ return { ok: true, body, eventIds: [], ignored: `${kind ?? 'unknown'}:${String(body.action)}` };
69
+ const item = object(body[kind === 'pull_request' ? 'pull_request' : 'issue']);
70
+ const delivery = headers.get('x-github-delivery');
71
+ if (!delivery || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(delivery) || !Number.isSafeInteger(body.number) ||
72
+ (body.number as number) < 1 || !item || item.number !== body.number || !text(item.title) ||
73
+ !text(item.html_url) || !text(object(item.user)?.login) ||
74
+ item.html_url !== `https://github.com/${PUBLIC_GITHUB_REPO}/${kind === 'pull_request' ? 'pull' : 'issues'}/${body.number}`)
75
+ return { ok: false, reason: 'invalid-body' };
76
+ return { ok: true, body: { ...body, githubEvent: kind, publicIntake: true }, eventIds: [delivery] };
77
+ }
78
+ if (provider === 'github') {
79
+ const event = headers.get('x-github-event');
80
+ const action = text(body.action);
81
+ if (!((event === 'pull_request' && action === 'review_requested') ||
82
+ (event === 'check_run' && action === 'completed' && object(body.check_run)?.conclusion === 'failure') ||
83
+ (event === 'check_suite' && action === 'completed' && object(body.check_suite)?.conclusion === 'failure')))
84
+ return { ok: true, body, eventIds: [], ignored: `${String(event)}:${String(action)}` };
85
+ const delivery = text(headers.get('x-github-delivery'));
86
+ const resource = object(event === 'pull_request' ? body.pull_request : event === 'check_run' ? body.check_run : body.check_suite);
87
+ if (!delivery || !resource || typeof resource.id !== 'number' ||
88
+ !(text(resource.html_url) ?? text(resource.details_url) ?? text(object(body.repository)?.html_url)))
89
+ return { ok: false, reason: 'invalid-body' };
90
+ return { ok: true, body: { ...body, githubEvent: event }, eventIds: [delivery] };
91
+ }
51
92
  if (!Array.isArray(body.events)) return { ok: false, reason: 'invalid-body' };
52
93
  const ids = body.events.map(asanaEventId);
53
94
  if (ids.some(id => !id)) return { ok: false, reason: 'invalid-body' };
@@ -63,9 +104,34 @@ export function toExternalTask(provider: HookProvider, body: unknown): ExternalT
63
104
  const title = text(issue?.title);
64
105
  const eventId = text(row.eventId) ?? (text(row.webhookId) && text(row.createdAt) ? `${row.webhookId}:${row.createdAt}` : undefined);
65
106
  if (!ref || !title || !eventId) throw new Error('invalid linear issue');
107
+ const assigneeId = text(issue?.assigneeId) ?? text(object(issue?.assignee)?.id);
66
108
  return { eventId, title, ...(text(issue?.description) ? { description: text(issue?.description) } : {}),
109
+ ...(assigneeId ? { assigneeId } : {}),
67
110
  external: { provider, ref, ...(text(issue?.url) ? { url: text(issue?.url) } : {}) } };
68
111
  }
112
+ if (provider === 'github' && row.publicIntake === true) {
113
+ const type = row.githubEvent === 'pull_request' ? 'pull_request' : 'issue';
114
+ const item = object(type === 'pull_request' ? row.pull_request : row.issue);
115
+ const number = row.number;
116
+ const eventId = text(row.eventId);
117
+ if (!Number.isSafeInteger(number) || !item || !eventId || !text(item.title) || !text(item.html_url))
118
+ throw new Error('invalid github event');
119
+ return { eventId, title: item.title as string,
120
+ external: { provider, ref: `${PUBLIC_GITHUB_REPO}#${number}`, url: item.html_url as string },
121
+ github: { repository: PUBLIC_GITHUB_REPO, number: number as number, type,
122
+ spamSignal: typeof item.body === 'string' && isGithubSpamText(item.body) } };
123
+ }
124
+ if (provider === 'github') {
125
+ const event = text(row.githubEvent);
126
+ const resource = object(event === 'pull_request' ? row.pull_request : event === 'check_run' ? row.check_run : row.check_suite);
127
+ const ref = resource?.id;
128
+ const eventId = text(row.eventId);
129
+ const url = text(resource?.html_url) ?? text(resource?.details_url) ?? text(object(row.repository)?.html_url);
130
+ if (typeof ref !== 'number' || !eventId || !url) throw new Error('invalid github event');
131
+ const title = event === 'pull_request' ? `PR review requested: ${text(resource?.title) ?? url}`
132
+ : `Check failed: ${text(resource?.name) ?? text(resource?.head_branch) ?? url}`;
133
+ return { eventId, title, external: { provider, ref: String(ref), url } };
134
+ }
69
135
  const event = object(row.event);
70
136
  const task = object(row.task);
71
137
  const ref = text(object(event?.resource)?.gid);
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path';
4
4
  import { effectiveInstanceRoot } from '../instance/resolve.js';
5
5
  import type { ExternalTask } from './providers.js';
6
6
 
7
- export interface QueuedHook { provider: ExternalTask['external']['provider']; eventId: string; task: ExternalTask }
7
+ export interface QueuedHook { provider: ExternalTask['external']['provider']; eventId: string; kind?: string; task: ExternalTask }
8
8
 
9
9
  export class HookQueue {
10
10
  readonly directory: string;
@@ -1,8 +1,10 @@
1
1
  import { debug } from '../debug/log.js';
2
2
  import { readFileSync } from 'node:fs';
3
- import { userConfigPath } from '../user-config.js';
3
+ import { getUserConfig, parseEventsConfig, userConfigPath, type EventsConfig } from '../user-config.js';
4
+ import { dispatchHook, type HookWake } from './dispatch.js';
4
5
  import { getSecretAsync } from '../nexus/config/secrets/index.js';
5
6
  import { HookQueue, type QueuedHook } from './queue.js';
7
+ import { recordGithubShadow } from './github-shadow.js';
6
8
  import { toExternalTask, verifyWebhook, type HookProvider } from './providers.js';
7
9
  import { drainReports, handleReportPost, ReportLimiter, ReportQueue, type ReceivedReport } from './error-report.js';
8
10
  import { effectiveInstanceRoot } from '../instance/resolve.js';
@@ -10,6 +12,7 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
10
12
  export interface HookSecrets {
11
13
  linear?: string;
12
14
  asana?: string;
15
+ github?: string;
13
16
  saveAsana?: (secret: string) => Promise<void>;
14
17
  }
15
18
  export interface HookReceiverOptions {
@@ -20,8 +23,12 @@ export interface HookReceiverOptions {
20
23
  now?: () => number;
21
24
  root?: string;
22
25
  retryBaseMs?: number;
26
+ events?: EventsConfig;
27
+ wakeSeat?: HookWake;
23
28
  /** ER2 — forward one queued error report to the Primary; default = POST /v1/reports/ingest over the tailnet. */
24
29
  forwardReport?: (item: ReceivedReport) => Promise<boolean>;
30
+ /** GET-only public metadata lookup; failure forces human review. */
31
+ githubFetch?: typeof fetch;
25
32
  }
26
33
 
27
34
  /** `/v1/tasks` lives on the Primary's nexus API, not on the control plane — so the address is its own setting. */
@@ -33,19 +40,6 @@ export function hooksPrimaryUrl(config: { hooks?: { primaryUrl?: unknown } }): U
33
40
  return url;
34
41
  }
35
42
 
36
- async function forwardToPrimary(event: QueuedHook): Promise<Response> {
37
- const config = JSON.parse(readFileSync(userConfigPath(), 'utf8')) as { hooks?: { primaryTokenRef?: string; primaryUrl?: unknown } };
38
- const ref = config.hooks?.primaryTokenRef;
39
- if (!ref) throw new Error('primary token reference missing');
40
- const token = await getSecretAsync(ref);
41
- if (!token) throw new Error('primary token missing');
42
- return fetch(new URL('/v1/tasks', hooksPrimaryUrl(config)), {
43
- method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`,
44
- 'x-elanous-trace-id': `${event.provider}:${event.eventId}` },
45
- body: JSON.stringify({ ...event.task, eventId: `${event.provider}:${event.eventId}` }), signal: AbortSignal.timeout(10_000),
46
- });
47
- }
48
-
49
43
  async function forwardReportToPrimary(item: ReceivedReport): Promise<boolean> {
50
44
  const config = JSON.parse(readFileSync(userConfigPath(), 'utf8')) as { hooks?: { primaryTokenRef?: string; primaryUrl?: unknown } };
51
45
  const ref = config.hooks?.primaryTokenRef;
@@ -81,7 +75,12 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
81
75
  } finally { reportsDraining = false; }
82
76
  }
83
77
  const now = options.now ?? Date.now;
84
- const forward = options.forward ?? forwardToPrimary;
78
+ const events = options.events ?? getUserConfig().events ?? parseEventsConfig(undefined);
79
+ // L14: public-repository intake events take the shadow ledger path; every other event keeps the seat dispatch path.
80
+ const dispatch = options.forward ?? ((event: QueuedHook) => dispatchHook(event, options.root ?? effectiveInstanceRoot(), events, options.wakeSeat).then(() => 204));
81
+ const forward = (event: QueuedHook) => event.provider === 'github' && event.task.github
82
+ ? recordGithubShadow(event, options.root ?? effectiveInstanceRoot(), options.githubFetch).then(() => 204)
83
+ : dispatch(event);
85
84
  const attempts = new Map<string, { next: number; failures: number }>();
86
85
  const pending = new Set<string>();
87
86
  let stopped = false;
@@ -124,7 +123,7 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
124
123
  if (request.method === 'POST' && url.pathname === '/v1/reports')
125
124
  return handleReportPost(request, { limiter: reportLimiter, queue: reportQueue, ...(options.now ? { now: options.now } : {}),
126
125
  log: (event, data) => debug.log('hooks.reports', event, data), wake: () => { reportNextAt = 0; void drainReportQueue(); } });
127
- if (request.method !== 'POST' || !/^\/hooks\/(linear|asana)$/.test(url.pathname)) return new Response('Not Found', { status: 404 });
126
+ if (request.method !== 'POST' || !/^\/hooks\/(linear|asana|github)$/.test(url.pathname)) return new Response('Not Found', { status: 404 });
128
127
  const provider = url.pathname.slice('/hooks/'.length) as HookProvider;
129
128
  const reject = (reason: string) => {
130
129
  debug.log('hooks.receiver', 'rejected', { provider, reason });
@@ -150,13 +149,15 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
150
149
  debug.log('hooks.receiver', 'ignored', { provider, kind: verified.ignored });
151
150
  return new Response(null, { status: 200 });
152
151
  }
153
- if (provider === 'linear') {
152
+ if (provider === 'linear' || provider === 'github') {
154
153
  const eventId = verified.eventIds[0]!;
155
- queue.enqueue({ provider, eventId, task: toExternalTask(provider, { ...(verified.body as object), eventId }) });
154
+ const body = verified.body as { type?: string; action: string; githubEvent?: string };
155
+ const kind = provider === 'linear' ? `${body.type}:${body.action}` : `${body.githubEvent}:${body.action}`;
156
+ queue.enqueue({ provider, eventId, kind, task: toExternalTask(provider, { ...body, eventId }) });
156
157
  } else {
157
158
  const body = verified.body as { events: unknown[] };
158
- const tasks = body.events.map(event => toExternalTask(provider, { event, task: (event as { task?: unknown }).task }));
159
- for (const task of tasks) queue.enqueue({ provider, eventId: task.eventId, task });
159
+ const tasks = body.events.map(event => ({ event: event as { action?: string }, task: toExternalTask(provider, { event, task: (event as { task?: unknown }).task }) }));
160
+ for (const { event, task } of tasks) queue.enqueue({ provider, eventId: task.eventId, kind: `task:${event.action ?? 'unknown'}`, task });
160
161
  }
161
162
  if (!draining) {
162
163
  if (timer) clearTimeout(timer);
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import { LOGS_SINCE_OPTION, registerLogsCommands } from './cli/logs-cli.js';
9
9
  import { registerDocsCommands } from './cli/docs-cli.js';
10
10
  import { registerA2ACommands } from './cli/a2a-cli.js';
11
11
  import { registerPluginCommands } from './cli/plugin-cli.js';
12
+ import { registerMakeCommand } from './cli/make-cli.js';
12
13
  import { registerConnectCommand, registerSkillsCommands } from './cli/skills-cli.js';
13
14
  import { registerImportCommand } from './cli/import-cli.js';
14
15
  import { registerPersonaCommands } from './cli/persona-cli.js';
@@ -873,8 +874,10 @@ seatCmd.command('loop').requiredOption('--seat <SEAT>', 'MK|OP|TC|UX')
873
874
  .option('--json', 'JSON 출력')
874
875
  .action(async (opts: { seat: string; once: boolean; json?: boolean }) => {
875
876
  try {
876
- const { runSeatLoopOnce } = await import('./seat-loop/seat-loop.js');
877
- const result = await runSeatLoopOnce(opts.seat);
877
+ // V3 F5: without the sink, the seat loop's judgment lines (seat.loop) never reach the log store when cron runs it.
878
+ await (await import('./domains/standalone-log-sink.js')).registerStandaloneLogSink('seat-loop');
879
+ const { runSeatLoopTurn } = await import('./seat-loop/seat-loop.js');
880
+ const result = await runSeatLoopTurn(opts.seat);
878
881
  if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
879
882
  else console.log(`seat loop ${opts.seat}: ${result.status}${'runId' in result && result.runId ? ` ${result.runId}` : ''}`);
880
883
  } catch (error) { console.error(`seat loop: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
@@ -913,6 +916,7 @@ registerCardCommand(program);
913
916
  registerLaunchHeadCommands(program);
914
917
  registerA2ACommands(program);
915
918
  registerPluginCommands(program);
919
+ registerMakeCommand(program);
916
920
  registerSkillsCommands(program);
917
921
  registerConnectCommand(program);
918
922
  registerImportCommand(program);
@@ -3024,6 +3028,24 @@ const harnessOrchestrateCmd = registerHarnessOrchestrateCapabilityOptions(
3024
3028
  await runHarnessOrchestrateExecution(plan, parts);
3025
3029
  });
3026
3030
 
3031
+ const contextCmd = program.command('context').description('외부 에이전트 맥락 이벤트');
3032
+ contextCmd.command('hooks').description('Claude Code 맥락 훅 설정').command('install')
3033
+ .requiredOption('--print', '설정 조각만 출력하고 설정 파일은 수정하지 않음')
3034
+ .action(async () => {
3035
+ const { claudeHooksSettings } = await import('./context-bus/claude-hooks-install.js');
3036
+ console.log(claudeHooksSettings(REPOSITORY_ROOT));
3037
+ });
3038
+ contextCmd.command('emit')
3039
+ .requiredOption('--kind <kind>', 'claimed|done|asked|guide-changed')
3040
+ .requiredOption('--summary <line>', '한 줄 요약')
3041
+ .requiredOption('--source <link>', '출처 링크')
3042
+ .action(async (opts: { kind: string; summary: string; source: string }) => {
3043
+ if (!['claimed', 'done', 'asked', 'guide-changed'].includes(opts.kind)) throw new Error('context emit --kind must be claimed|done|asked|guide-changed');
3044
+ const { recordExternalEvent } = await import('./context-bus/external-events.js');
3045
+ recordExternalEvent({ origin: 'claude-code', kind: opts.kind as import('./context-bus/external-events.js').ContextHookKind,
3046
+ summary: opts.summary, source: opts.source });
3047
+ });
3048
+
3027
3049
  const coordCmd = program.command('coord').description('조율 채널 맥락 원장');
3028
3050
  coordCmd.command('event').command('record')
3029
3051
  .requiredOption('--seat <ID>', '발신 자리')
@@ -3975,11 +3997,12 @@ selfCmd
3975
3997
  .option('--changed', '변경 파일 범위 게이트임을 명시한다')
3976
3998
  .option('--base <ref>', '커밋됐지만 PR 없는 변경의 비교 기준(ref...HEAD)')
3977
3999
  .option('--pr <number>', '열린 PR 번호에서 gh pr view files로 변경 파일을 읽는다')
3978
- .action((opts: { changed?: boolean; base?: string; pr?: string }) => {
3979
- if (!opts.changed) { ui.error('self gate requires --changed'); process.exitCode = 2; return; }
4000
+ .option('--shards [number]', '메모리 예산에 맞춰 시험을 별도 프로세스로 분할한다 (기본 2)')
4001
+ .action((opts: { changed?: boolean; base?: string; pr?: string; shards?: string | boolean }) => {
4002
+ if (!opts.changed && opts.shards === undefined) { ui.error('self gate requires --changed or --shards'); process.exitCode = 2; return; }
3980
4003
  try {
3981
4004
  const { runSelfGateCli } = require('./self-implement/gate-cli.js') as typeof import('./self-implement/gate-cli.js');
3982
- const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr });
4005
+ const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr, shards: opts.shards === undefined ? undefined : opts.shards === true ? 2 : Number(opts.shards) });
3983
4006
  console.log(result.lines.join('\n'));
3984
4007
  process.exitCode = result.exitCode;
3985
4008
  } catch (error) {
@@ -4011,7 +4034,8 @@ selfCmd
4011
4034
  // runSelfImplement(내부 SelfImplement 툴과 동일 코어)를 감싼다: fork→worktree→헤드리스 goal-loop
4012
4035
  // (+클린빌드 앵커)→gate(bun test)→PR(HITL). PR-open 은 --open-pr(명시 승인)일 때만·기본 fail-closed.
4013
4036
  selfCmd
4014
- .command('implement <feature...>')
4037
+ .command('implement [feature...]')
4038
+ .option('--feature-file <path>', 'feature 문면을 파일에서 읽는다 (문면을 argv 에 싣지 않음)')
4015
4039
  .description('자율 구현(self-build) — feature 를 격리 worktree 에서 goal-loop + 클린빌드 앵커로 끝까지 구현하고 gate(bun test) 통과까지. --config-dir 의 provider 로 모델 선택(gemma 등). PR-open 은 --open-pr(HITL 명시승인)일 때만. 수분 소요.')
4016
4040
  .option('--base <branch>', 'PR base 브랜치(생략 시 provider 기본)')
4017
4041
  .option('--no-draft', 'non-draft PR (기본 draft)')
@@ -4029,8 +4053,11 @@ selfCmd
4029
4053
  .option('--no-supervise', '⛔ 런 슈퍼바이저를 «끈다»(대표 2026-08-22: ***기본 ON***) — 켜져 있으면 실행이 끝나면 실패를 «트리아지»해서 다시 걸 수 있으면 스스로 재개한다(끝까지). 정지 사유는 converged|needs-human|max-rounds|no-progress 로 각각 «다른 값». 관측=elanous logs --category self-dev.supervisor')
4030
4054
  .option('--supervise-rounds <n>', '슈퍼바이저 재개 라운드 상한 (기본 3 · 끄려면 --no-supervise)')
4031
4055
  .option('--json', '구조화 출력 {stage, ok, branch, worktree, prUrl?, merged?}')
4032
- .action(async (parts: string[], opts: { base?: string; draft?: boolean; openPr?: boolean; autoMerge?: boolean; autoReview?: boolean; maxWait?: string; json?: boolean; plan?: boolean; enhance?: boolean; ground?: boolean; observeOnly?: boolean }) => {
4033
- const feature = parts.join(' ').trim();
4056
+ .action(async (parts: string[], opts: { featureFile?: string; base?: string; draft?: boolean; openPr?: boolean; autoMerge?: boolean; autoReview?: boolean; maxWait?: string; json?: boolean; plan?: boolean; enhance?: boolean; ground?: boolean; observeOnly?: boolean }) => {
4057
+ if (opts.featureFile && parts.length > 0) { ui.error('--feature-file 과 위치 인자 feature 는 함께 줄 수 없다'); process.exit(2); }
4058
+ let feature: string;
4059
+ try { feature = (opts.featureFile ? readFileSync(opts.featureFile, 'utf8') : parts.join(' ')).trim(); }
4060
+ catch (error) { ui.error(`--feature-file 읽기 실패: ${String(error)}`); process.exit(2); return; }
4034
4061
  if (!feature) { ui.error('feature 필요: elanous self implement "<무엇을 구현할지>"'); process.exit(2); }
4035
4062
  // Retired entry points must fail before run identity or log-sink setup creates observable execution state.
4036
4063
  if (opts.plan) { ui.error('self implement --plan is retired and rejected'); process.exit(1); return; }
@@ -4128,8 +4155,14 @@ export function setSelfOrchestrateSpawnForTesting(spawn: typeof selfOrchestrateS
4128
4155
  selfOrchestrateSpawnForTesting = spawn;
4129
4156
  }
4130
4157
 
4158
+ export function readSelfOrchestrateGoals(parts: string[], goalFiles: readonly string[] = []): { request: string; goals: string[] } {
4159
+ const fileGoals = goalFiles.map((path) => readFileSync(path, 'utf8'));
4160
+ return { request: [...parts, ...fileGoals].join(' '), goals: [...splitOrchestrateGoalTexts(parts), ...fileGoals] };
4161
+ }
4162
+
4131
4163
  const selfOrchestrateCmd = selfCmd
4132
4164
  .command('orchestrate [goals...]')
4165
+ .option('--goal-file <path>', '골 문면을 파일에서 읽는다 (반복 가능)', (value: string, acc: string[]) => [...acc, value], [] as string[])
4133
4166
  .description('병렬 self-dev — 여러 goal 을 각자 격리 worktree self-implement 서브프로세스로 동시성캡 병렬 실행. goal 은 `;;` 로 구분(또는 각 인자 1 goal). --concurrency 로 동시 잡 수(기본 2).')
4134
4167
  .option('--concurrency <n>', '동시 실행 잡 수 (기본 2)')
4135
4168
  .option('--auto-merge', '각 잡: 리뷰 clean 시 자동 병합(각 self-implement 에 --auto-merge 전달·리뷰노드 경유)')
@@ -4138,7 +4171,7 @@ const selfOrchestrateCmd = selfCmd
4138
4171
  .option('--base <branch>', '각 잡 PR base 브랜치')
4139
4172
  .option('--decompose', 'S2 — goal 1개를 LLM 으로 의존성 서브-DAG(위상 병렬 + hot-file 직렬)로 분해 후 실행')
4140
4173
  .addOption(new Option('--pod-skill-env', 'pod: 필수 스킬(설정 pod-skills.txt)의 키(.env)를 이 런의 Secret 으로 넘긴다 — 명시 opt-in(유료 크레딧) · 이미지엔 안 들어간다').hideHelp())
4141
- .addOption(new Option('--pod-pool <spec>', 'pod 풀 — 컨텍스트[@ssh호스트][:상한] 을 쉼표로, 앞이 우선(예 pool-node-b@node-b:12,pool-node-c@node-c:3) · 없으면 ELANOUS_POD_POOL · 그것도 없으면 현재 컨텍스트 하나').hideHelp())
4174
+ .addOption(new Option('--pod-pool <spec>', 'pod 풀 — 컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트] 쉼표, 앞이 우선(예 pool-node-b@node-b:12#k3d-elanous-registry:5051,pool-node-c@node-c:3#k3d-elanous-registry:5052) · 없으면 ELANOUS_POD_POOL · 그것도 없으면 현재 컨텍스트 하나').hideHelp())
4142
4175
  .addOption(new Option('--reduce', '끝에 PR 을 연 조각들을 통합 브랜치 하나로 모아(게이트 한 번) PR 하나 — `--open-pr` 과 짝 · `--auto-merge` 와는 함께 못 쓴다(elanous self reduce)').hideHelp())
4143
4176
  .option('--substrate <kind>', '실행 칸: local(기본 · 격리 워크트리) | pod(k8s Job · docker/harness 이미지 · MANUAL-pods-for-elanous-ops-and-dev)')
4144
4177
  .option('--pod-account <name>', 'pod: codex 계정(~/.elanous/auth.json openai-codex:<name> · refresh 제외 사본) · 없으면 브로커가 Job 마다 잔량 많은 계정을 돌려 준다')
@@ -4146,11 +4179,14 @@ const selfOrchestrateCmd = selfCmd
4146
4179
  .option('--pod-pass-env <keys>', 'pod: 호스트 env 에서 Pod 로 넘길 키(쉼표) — 예 OPENROUTER_API_KEY,ANTHROPIC_API_KEY(벤치마크 과금 경로)')
4147
4180
  .option('--bench-arms <spec>', 'pod 벤치마크: 골 1개를 팔마다 «라벨 한 줄만 다르게» 복제해 동시에 — "id=provider[:model][@KEY+KEY];…" (예 codex=openai-codex;or-kimi=openrouter:openrouter/moonshotai/kimi-k3@OPENROUTER_API_KEY) · --auto-merge 거부 · RFC fleet 슈퍼바이저 §A3')
4148
4181
  .option('--help-all', '모든 orchestrate 옵션 표시')
4149
- .action(function (this: Command, parts: string[], opts: { concurrency?: string; autoMerge?: boolean; autoReview?: boolean; openPr?: boolean; base?: string; teardown?: boolean; resume?: string; board?: boolean; decompose?: boolean; fabricDecompose?: boolean; maxTasks?: string; supervise?: boolean; superviseRounds?: string; json?: boolean }) {
4182
+ .action(function (this: Command, parts: string[], opts: { goalFile?: string[]; concurrency?: string; autoMerge?: boolean; autoReview?: boolean; openPr?: boolean; base?: string; teardown?: boolean; resume?: string; board?: boolean; decompose?: boolean; fabricDecompose?: boolean; maxTasks?: string; supervise?: boolean; superviseRounds?: string; json?: boolean }) {
4150
4183
  return (async () => {
4151
- // goal 분리: 단일 인자에 `;;` 가 있으면 그걸로 split, 아니면 각 positional = 1 goal.
4152
- const joined = parts.join(' ');
4153
- let goalTexts = splitOrchestrateGoalTexts(parts);
4184
+ // 위치 인자는 종전처럼 분리하고 파일 입력은 파일당 한 골이다.
4185
+ let inputGoals: ReturnType<typeof readSelfOrchestrateGoals>;
4186
+ try { inputGoals = readSelfOrchestrateGoals(parts, opts.goalFile); }
4187
+ catch (error) { ui.error(`--goal-file 읽기 실패: ${String(error)}`); process.exit(2); return; }
4188
+ const joined = inputGoals.request;
4189
+ let goalTexts = inputGoals.goals;
4154
4190
  if ((opts as { reduce?: boolean }).reduce && opts.autoMerge) { ui.error('--reduce 는 --auto-merge 와 함께 못 쓴다 — 조각을 하나씩 main 에 병합하는 것과 하나로 모으는 것은 반대다(--open-pr 과 짝)'); process.exit(2); }
4155
4191
  // ☸️ 벤치 팔 — 골 1개를 팔마다 라벨 한 줄만 다르게(A/B 매뉴얼 ②) · pod 전용 · 자동 머지 금지(한 팔이 머지되면 다른 팔의 밑 땅이 바뀐다).
4156
4192
  const benchSpec = (opts as { benchArms?: string }).benchArms;
@@ -6298,7 +6334,7 @@ const selfDevCmd = program
6298
6334
  // `drive --help` 에도 그대로 보이고 자식이 그것을 계약으로 읽는다.
6299
6335
  // ⇒ 별칭을 없애지 않는다([[RFC-two-command-convergence-dev-and-pty-2026-07-28]] §6-2 = 층이 다르니
6300
6336
  // `drive` 는 프리미티브로 **유지**한다) — 대신 **도움말이 그 갈림을 먼저 말하게** 한다.
6301
- .description('⛔ `drive` 별칭으로 부르면 옵션은 여덟뿐 (--goal · --attach · --max-steps · --poll-ms · --model · --cwd · --worktree · --json) — `--attach <ref>` 는 이미 있는 PTY 를 몬다(생략하면 셸 명령을 새로 띄운다). 나머지는 전부 `dev` 전용이고 `drive` 에서는 거부된다. dev 와 drive 는 한 명령이라 이 도움말을 공유하므로, 아래 목록은 `dev` 기준이다. ⚠️ 실험 — 통합 self-dev 파이프라인 runDevPipeline. --backend self(디폴트·elanous-chat 자체구현)|codex/claude/gemini/grok(외부). --transport pty(디폴트·worktree·--branch 필수)|acp(cwd 세션·U6·capability 미검증). 미배선 조합은 NotYetUnified 명시 거부. ★self 는 무인 완결이 기본(PR 개설→auto-review 라벨→리뷰 clean 시 병합) — 끄려면 --no-open-pr/--no-auto-review/--no-auto-merge. 관측=elanous logs --category dev-pipeline · 상세=docs/manual/MANUAL-frontdoor-selfdev-dogfood-mechanism-2026-07-25.md')
6337
+ .description('⛔ `drive` 별칭으로 부르면 옵션은 아홉뿐 (--goal · --attach · --max-steps · --poll-ms · --model · --cwd · --worktree · --json · --jail-home) — `--attach <ref>` 는 이미 있는 PTY 를 몬다(생략하면 셸 명령을 새로 띄운다). 나머지는 전부 `dev` 전용이고 `drive` 에서는 거부된다. dev 와 drive 는 한 명령이라 이 도움말을 공유하므로, 아래 목록은 `dev` 기준이다. ⚠️ 실험 — 통합 self-dev 파이프라인 runDevPipeline. --backend self(디폴트·elanous-chat 자체구현)|codex/claude/gemini/grok(외부). --transport pty(디폴트·worktree·--branch 필수)|acp(cwd 세션·U6·capability 미검증). 미배선 조합은 NotYetUnified 명시 거부. ★self 는 무인 완결이 기본(PR 개설→auto-review 라벨→리뷰 clean 시 병합) — 끄려면 --no-open-pr/--no-auto-review/--no-auto-merge. 관측=elanous logs --category dev-pipeline · 상세=docs/manual/MANUAL-frontdoor-selfdev-dogfood-mechanism-2026-07-25.md')
6302
6338
  .option('--file <path>', 'input 파일(verbatim 바이트·<text...> 대신)')
6303
6339
  // ⭐ 대표 2026-08-11 — 발사 절차 «넷»을 한 명령으로. ask 파일을 주면 ⑴저작 → ⑵열린 PR ⊕ ⑶도는 런 검사 → ⑷발사.
6304
6340
  // ⛔ 걸리면 «이름을 대며» 멈춘다(조용히 진행하지 않는다). 우회는 --force-preflight 이고 그 사실이 관측에 남는다.
@@ -6324,6 +6360,7 @@ const selfDevCmd = program
6324
6360
  .option('-n, --max-steps <n>', 'elanous 또는 셸 drive: 최대 제어 스텝(기본 30)')
6325
6361
  .option('-p, --poll-ms <ms>', 'elanous 또는 셸 drive: 제어 스텝 간 폴 간격(ms·0 허용·기본 800)')
6326
6362
  .option('--attach <ref>', 'drive: 이미 있는 PTY 를 몬다(생략하면 셸 명령을 새로 띄운다·pty auto 와 같은 루프)')
6363
+ .option('--jail-home <dir>', 'drive: DRIVE-JAIL — 두뇌 입력에 이 디렉터리 밖 경로가 있으면 PTY 로 보내지 않는다')
6327
6364
  .option('-m, --model <id>', 'elanous 또는 셸 drive: 제어 brain LLM 모델(기본 config)')
6328
6365
  .option('--observe-only', 'elanous: child boot부터 SelfImplement 호출을 기록만 한다')
6329
6366
  .option('--isolated-root <path>', 'elanous: child config/state 격리 루트(설정 실패 시 fail-closed)')
@@ -6620,6 +6657,7 @@ const selfDevCmd = program
6620
6657
  ...(devOpts.worktree === true ? { worktree: true } : {}),
6621
6658
  ...(opts.json === true ? { json: true } : {}),
6622
6659
  attach: devOpts.attach,
6660
+ ...(devOpts.jailHome ? { jailHome: devOpts.jailHome } : {}),
6623
6661
  }, {
6624
6662
  exit: ((code: number): never => {
6625
6663
  completionGuard.conclude();
@@ -25,6 +25,7 @@ import type {
25
25
  } from './enrich.js';
26
26
  import { summariseContext } from './enrich.js';
27
27
  import { buildResponseFormatHeader } from './prompt-format.js';
28
+ import { judge } from '../llm/judge-layer.js';
28
29
 
29
30
  // ──────────────────── Closed sets ──────────────────────────────────────
30
31
 
@@ -69,7 +70,7 @@ export interface CategorizeResult {
69
70
  }
70
71
 
71
72
  export interface CategorizeCallable {
72
- (args: { prompt: string; signal?: AbortSignal }): Promise<{
73
+ (args: { prompt: string; signal?: AbortSignal; provider?: string; model?: string }): Promise<{
73
74
  text: string;
74
75
  promptTokens?: number;
75
76
  completionTokens?: number;
@@ -219,26 +220,6 @@ export function buildCategorizePrompt(decomposition: EnrichedDecomposition): str
219
220
 
220
221
  // ──────────────────── Parse + coerce ──────────────────────────────────
221
222
 
222
- function extractJsonBlock(text: string): unknown | null {
223
- const trimmed = text.trim();
224
- const fence = trimmed.match(/```(?:json)?\n([\s\S]*?)```/);
225
- const candidate = fence ? fence[1]! : trimmed;
226
- try {
227
- return JSON.parse(candidate);
228
- } catch {
229
- const open = candidate.indexOf('{');
230
- const close = candidate.lastIndexOf('}');
231
- if (open >= 0 && close > open) {
232
- try {
233
- return JSON.parse(candidate.slice(open, close + 1));
234
- } catch {
235
- return null;
236
- }
237
- }
238
- return null;
239
- }
240
- }
241
-
242
223
  function coerceConfidence(v: unknown): 'high' | 'medium' | 'low' {
243
224
  if (v === 'high' || v === 'medium' || v === 'low') return v;
244
225
  return 'medium';
@@ -306,27 +287,18 @@ export async function categorizeDecomposition(
306
287
 
307
288
  const prompt = buildCategorizePrompt(decomposition);
308
289
 
309
- let raw;
310
- try {
311
- raw = await opts.callable({ prompt, signal: opts.signal });
312
- } catch (err) {
313
- if (opts.strict) {
314
- throw new CategorizeError(
315
- 'LLM_CALL_FAILED',
316
- err instanceof Error ? err.message : String(err),
317
- );
318
- }
319
- return {
320
- categorizations: Object.fromEntries(tasks.map((t) => [t.key, fallbackRow(t.key)])),
321
- fallback: true,
322
- };
323
- }
324
-
325
- const parsed = extractJsonBlock(raw.text);
326
- const coerced = parsed ? coerceCategorizations(parsed, validKeys) : null;
327
- if (coerced === null) {
290
+ const decision = await judge({
291
+ site: 'intake.categorize', prompt, signal: opts.signal,
292
+ call: ({ prompt, signal, provider, model }) => opts.callable({ prompt, signal, provider, model }),
293
+ schema: (parsed) => coerceCategorizations(parsed, validKeys),
294
+ });
295
+ if (!decision.ok) {
328
296
  if (opts.strict) {
329
- throw new CategorizeError('PARSE_FAILED', 'no usable categorizations', raw.text);
297
+ if (decision.reason === 'call') {
298
+ throw new CategorizeError('LLM_CALL_FAILED',
299
+ decision.error instanceof Error ? decision.error.message : String(decision.error));
300
+ }
301
+ throw new CategorizeError('PARSE_FAILED', 'no usable categorizations', decision.rawText);
330
302
  }
331
303
  return {
332
304
  categorizations: Object.fromEntries(tasks.map((t) => [t.key, fallbackRow(t.key)])),
@@ -336,7 +308,7 @@ export async function categorizeDecomposition(
336
308
 
337
309
  // Backfill any missing tasks with the fallback shape so callers can
338
310
  // index by key without null checks.
339
- const filled: Record<string, TaskCategorization> = { ...coerced };
311
+ const filled: Record<string, TaskCategorization> = { ...decision.value };
340
312
  for (const t of tasks) {
341
313
  if (!filled[t.key]) filled[t.key] = fallbackRow(t.key);
342
314
  }
@@ -344,10 +316,10 @@ export async function categorizeDecomposition(
344
316
  categorizations: filled,
345
317
  fallback: false,
346
318
  usage: {
347
- promptTokens: raw.promptTokens,
348
- completionTokens: raw.completionTokens,
349
- costUsd: raw.costUsd,
350
- modelId: raw.modelId,
319
+ promptTokens: decision.reply.promptTokens,
320
+ completionTokens: decision.reply.completionTokens,
321
+ costUsd: decision.reply.costUsd,
322
+ modelId: decision.reply.modelId,
351
323
  },
352
324
  };
353
325
  }
@@ -3,6 +3,7 @@ import { discordDecisionOwner } from '../decisions/discord-decision-cards.js';
3
3
  import { canonicalSeatId } from '../msg/msg-store.js';
4
4
  import { dispatchCeoTask, type CeoCommandDeps } from '../seat-dispatch/ceo-commands.js';
5
5
  import { ceoTaskDeps, classifyCeoIntent } from '../seat-dispatch/ceo-intent.js';
6
+ import { askSeat, parseSeatAsk, type SeatAskDeps } from '../seat-dispatch/seat-ask.js';
6
7
  import { parseSeatAddress, resolveSeat } from '../seat-address/seat-address.js';
7
8
  import { getUserConfig, type UserConfig } from '../user-config.js';
8
9
  import { answerAsSeat } from './seat-answer.js';
@@ -25,6 +26,7 @@ export interface DiscordSeatWorkDeps extends SubmitIntakeWorkDeps {
25
26
  answer?: typeof answerAsSeat;
26
27
  dispatch?: typeof dispatchCeoTask;
27
28
  commandDeps?: CeoCommandDeps;
29
+ askDeps?: SeatAskDeps;
28
30
  }
29
31
 
30
32
  /** Addressed work preserves graph intake except for one owner's private seat request. */
@@ -44,6 +46,14 @@ export async function handleDiscordSeatWork(
44
46
  debug.log('seat.dispatch', 'intent', { seat, intent: 'task', via: 'discord', outcome: result.channel });
45
47
  return result.reply;
46
48
  };
49
+ if (parseSeatAsk(text)) {
50
+ const auth = owner();
51
+ if (!auth) return null;
52
+ if (!deps.askDeps) throw new Error('seat ask delivery unavailable');
53
+ return askSeat(text, { channel: 'discord', channelId: msg.channelId, messageId: msg.messageId,
54
+ ...(msg.threadId ? { threadId: msg.threadId } : {}) },
55
+ deps.commandDeps ?? ceoTaskDeps(auth.cfg, auth.id), deps.askDeps);
56
+ }
47
57
  const address = parseSeatAddress(text);
48
58
  if (!address) {
49
59
  if (!text.trim() || /^\s*[/@@]/.test(text)) return null;
@@ -1,7 +1,6 @@
1
1
  import { debug } from '../debug/log.js';
2
- import type { ModelRole } from '../user-config.js';
3
- import type { ResolveRoleProviderFn, StreamLlmFn, ProviderRegistry } from './runtime-callables.js';
4
- import { extractJsonBlock } from './decompose.js';
2
+ import type { ResolveRoleProviderFn, StreamLlmFn } from './runtime-callables.js';
3
+ import { judge } from '../llm/judge-layer.js';
5
4
  import {
6
5
  INTAKE_FRONT_ROUTE_TRACKS,
7
6
  type IntakeFrontRouteDecision,
@@ -14,17 +13,6 @@ interface ClassifierDeps {
14
13
  minConfidence?: number;
15
14
  }
16
15
 
17
- function loadRoleProvider(): ResolveRoleProviderFn {
18
- const { resolveRoleLlm } = require('../user-config.js') as {
19
- resolveRoleLlm: (role: ModelRole) => { provider: string; model: string };
20
- };
21
- const { PROVIDERS } = require('../llm.js') as { PROVIDERS: ProviderRegistry };
22
- return (role) => {
23
- const resolved = resolveRoleLlm(role);
24
- return { provider: PROVIDERS[resolved.provider] ?? { name: resolved.provider }, model: resolved.model };
25
- };
26
- }
27
-
28
16
  /** Classify only after the deterministic front-route rules return rule-unknown. */
29
17
  export async function classifyIntakeFrontRoute(
30
18
  text: string,
@@ -43,32 +31,38 @@ export async function classifyIntakeFrontRoute(
43
31
  const failed = (cause: string) => finish('ask-human', 0, `classifier-failed:${cause}`, 'failed');
44
32
 
45
33
  try {
46
- const rolePick = (deps.resolveRoleProvider ?? loadRoleProvider())('classify');
47
- provider = rolePick.provider.name;
48
- const streamLLM = deps.streamLLM ?? (require('../llm.js') as { streamLLM: StreamLlmFn }).streamLLM;
49
- const response = await streamLLM([
50
- { role: 'system', content: [
51
- 'Classify the intake text into exactly one track:',
52
- 'absorb: read, save, or summarize external material.',
53
- 'tasks: a list of independent to-dos.',
54
- 'graph: an implementation or multi-step workflow request.',
55
- 'ask-human: ambiguous intent requiring human choice.',
56
- 'Return only one JSON object: {"track":"...","confidence":0.0,"reason":"..."}. Confidence must be between 0 and 1.',
57
- ].join('\n') },
58
- { role: 'user', content: text },
59
- ], () => {}, { provider: rolePick.provider, ...(rolePick.model ? { model: rolePick.model } : {}), usageRole: 'classify' });
60
-
61
- // 실제 모델은 JSON 을 ```json 펜스로 감싸거나 앞뒤에 말을 붙이곤 한다 — 같은 디렉토리의 다른 호출자와 같은 관대한 추출을 쓴다.
62
- const parsed: unknown = extractJsonBlock(response);
63
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return failed('invalid-json');
64
- const candidate = parsed as Record<string, unknown>;
65
- if (typeof candidate.track !== 'string' ||
66
- !(INTAKE_FRONT_ROUTE_TRACKS as readonly string[]).includes(candidate.track)) return failed('invalid-track');
67
- if (typeof candidate.confidence !== 'number' || !Number.isFinite(candidate.confidence) ||
68
- candidate.confidence < 0 || candidate.confidence > 1) return failed('invalid-confidence');
69
- if (typeof candidate.reason !== 'string') return failed('invalid-reason');
34
+ const decision = await judge({
35
+ site: 'intake.front-route',
36
+ prompt: text,
37
+ messages: [
38
+ { role: 'system', content: [
39
+ 'Classify the intake text into exactly one track:',
40
+ 'absorb: read, save, or summarize external material.',
41
+ 'tasks: a list of independent to-dos.',
42
+ 'graph: an implementation or multi-step workflow request.',
43
+ 'ask-human: ambiguous intent requiring human choice.',
44
+ 'Return only one JSON object: {"track":"...","confidence":0.0,"reason":"..."}. Confidence must be between 0 and 1.',
45
+ ].join('\n') },
46
+ { role: 'user', content: text },
47
+ ],
48
+ streamLLM: deps.streamLLM,
49
+ resolveRoleProvider: deps.resolveRoleProvider,
50
+ schema: (parsed) => {
51
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
52
+ const candidate = parsed as Record<string, unknown>;
53
+ if (typeof candidate.track !== 'string' ||
54
+ !(INTAKE_FRONT_ROUTE_TRACKS as readonly string[]).includes(candidate.track)) return null;
55
+ if (typeof candidate.confidence !== 'number' || !Number.isFinite(candidate.confidence) ||
56
+ candidate.confidence < 0 || candidate.confidence > 1) return null;
57
+ if (typeof candidate.reason !== 'string') return null;
58
+ return { track: candidate.track as IntakeFrontRouteTrack, confidence: candidate.confidence, reason: candidate.reason };
59
+ },
60
+ });
61
+ provider = decision.ok ? decision.provider : provider;
62
+ if (!decision.ok) return failed(decision.reason === 'schema' ? 'invalid-json' : 'llm-error');
63
+ const candidate = decision.value;
70
64
 
71
- const track = candidate.track as IntakeFrontRouteTrack;
65
+ const track = candidate.track;
72
66
  const confidence = candidate.confidence;
73
67
  if (confidence < (deps.minConfidence ?? 0.6)) {
74
68
  return finish('ask-human', confidence, `classifier-low-confidence:${track}`, 'low-confidence');