elanous 0.2.10 → 0.2.12

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 (615) 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/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  8. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  18. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  19. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  24. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.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-cb169620945d1952.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.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-1efd0cb9e0ed9d13.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.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-9547b5cec7cf76bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.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/128fb7fb670b2fbf.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/context/nightly-condense.yaml +21 -0
  192. package/graphs/context/recipes.yaml +12 -0
  193. package/graphs/demo/inside-seed.yaml +20 -0
  194. package/graphs/demo/recipes.yaml +12 -0
  195. package/graphs/drafts/draft-cleanup.yaml +19 -0
  196. package/graphs/drafts/recipes.yaml +23 -0
  197. package/graphs/intake/intake-daily.yaml +2 -1
  198. package/graphs/ops/recipes.yaml +3 -0
  199. package/graphs/ops/secret-exposure.yaml +24 -0
  200. package/graphs/release/recipes.yaml +3 -0
  201. package/graphs/release/release-loop.yaml +4 -1
  202. package/graphs/video/explainer-line.yaml +2 -2
  203. package/package.json +2 -1
  204. package/plugins/card-followup/examples/sample-card.png +0 -0
  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/context-hooks/claude-stop.sh +4 -0
  216. package/scripts/context-hooks/emit.ts +24 -0
  217. package/scripts/context-hooks/post-tool-use.sh +4 -0
  218. package/scripts/coord-channel-watch.sh +12 -0
  219. package/scripts/coord-requests-bridge.ts +143 -0
  220. package/scripts/field-feed/lib.ts +4 -0
  221. package/scripts/fleet/node-setup.sh +20 -3
  222. package/scripts/homebrew-formula-bump.ts +69 -0
  223. package/scripts/lib/telegram-inject-args.ts +31 -0
  224. package/scripts/marketing/measure-site-numbers.ts +169 -0
  225. package/scripts/measure-gate-shards.ts +309 -0
  226. package/scripts/measure-pod-memory-by-goal.ts +130 -0
  227. package/scripts/mission-request-judge.ts +31 -1
  228. package/scripts/morning-report.ts +2 -2
  229. package/scripts/opportunity-scan.ts +1 -1
  230. package/scripts/release-loop/auto-approve-node.ts +21 -4
  231. package/scripts/release-loop/checklist-gate-node.ts +2 -1
  232. package/scripts/release-loop/cut-branch.ts +84 -0
  233. package/scripts/release-loop/gate-node.ts +22 -15
  234. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  235. package/scripts/release-loop/node-verdict.ts +3 -3
  236. package/scripts/release-loop/ops-upgrade-node.ts +47 -6
  237. package/scripts/release-loop/publish-node.ts +4 -1
  238. package/scripts/release-loop/tui-node-checks.ts +42 -0
  239. package/scripts/release-loop/tui-sim-node.ts +32 -8
  240. package/scripts/release-loop/unattended-release.ts +5 -3
  241. package/scripts/release-loop/version-node.ts +74 -13
  242. package/scripts/signal-digest-cycle.ts +2 -7
  243. package/scripts/signal-digest-photo.ts +11 -0
  244. package/scripts/tech1-public-measure.ts +94 -0
  245. package/scripts/telegram-inject.ts +14 -6
  246. package/scripts/test-diet/node.ts +1 -1
  247. package/scripts/test-diet/remeasure-list.ts +112 -0
  248. package/scripts/tui-regress.ts +2 -2
  249. package/scripts/ux/demo-rehearsal.ts +247 -0
  250. package/scripts/ux/demo-seed.ts +108 -0
  251. package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
  252. package/skills/diagram-master/SKILL.md +366 -0
  253. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  254. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  255. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  256. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  257. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  258. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  259. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  260. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  261. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  262. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  263. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  264. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  265. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  266. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  267. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  268. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  269. package/skills/diagram-master/references/examples/README.md +69 -0
  270. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  271. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  272. package/skills/diagram-master/references/pyproject.toml +16 -0
  273. package/skills/diagram-master/references/quality-checklist.md +33 -0
  274. package/skills/diagram-master/references/routing-guide.md +164 -0
  275. package/skills/diagram-master/references/uv.lock +1356 -0
  276. package/skills/google-workspace/SKILL.md +33 -0
  277. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  278. package/skills/grill-me/SKILL.md +1 -1
  279. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  280. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  281. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  282. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  283. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  284. package/skills/omni-crawl/SKILL.md +21 -11
  285. package/skills/omni-crawl/scripts/main.ts +6 -6
  286. package/skills/omni-crawl/src/router.ts +3 -3
  287. package/skills/omni-digest/SKILL.md +17 -9
  288. package/skills/omni-digest/digest.md +2 -2
  289. package/skills/omni-digest/src/fetch.ts +30 -3
  290. package/skills/pitch-deck/SKILL.md +2 -2
  291. package/skills/pitch-deck/template.html +2 -2
  292. package/skills/youtube-master/SKILL.md +163 -0
  293. package/skills/youtube-master/package-lock.json +558 -0
  294. package/skills/youtube-master/package.json +13 -0
  295. package/skills/youtube-master/references/study-note-template.md +124 -0
  296. package/skills/youtube-master/scripts/main.ts +435 -0
  297. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  298. package/skills/youtube-master/src/audio.ts +63 -0
  299. package/skills/youtube-master/src/domain-staging.ts +50 -0
  300. package/skills/youtube-master/src/env.ts +36 -0
  301. package/skills/youtube-master/src/obsidian.ts +155 -0
  302. package/skills/youtube-master/src/router.ts +110 -0
  303. package/skills/youtube-master/src/stt.ts +199 -0
  304. package/skills/youtube-master/src/study-note.ts +175 -0
  305. package/skills/youtube-master/src/summarize.ts +358 -0
  306. package/skills/youtube-master/src/transcript.ts +76 -0
  307. package/skills/youtube-master/src/types.ts +91 -0
  308. package/skills/youtube-master/src/util.ts +93 -0
  309. package/skills/youtube-master/src/youtube.ts +70 -0
  310. package/skills/youtube-master/tsconfig.json +13 -0
  311. package/src/acp/server.ts +5 -2
  312. package/src/agent-mission/driver.ts +215 -23
  313. package/src/agent-mission/pty-decision.ts +71 -0
  314. package/src/agent-mission/review-loop.ts +30 -0
  315. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  316. package/src/autopilot/pty-control-loop.ts +4 -1
  317. package/src/autopilot/tool-registry.ts +2 -0
  318. package/src/boot/daemon-prompt-turn.ts +5 -0
  319. package/src/boot/daemon-runtime.ts +9 -3
  320. package/src/boot/daemon-tools/web-search.ts +3 -0
  321. package/src/card-followup/core.ts +109 -0
  322. package/src/chat/index.ts +2 -0
  323. package/src/cli/drive-input-jail.ts +101 -0
  324. package/src/cli/hooks-cli.ts +17 -3
  325. package/src/cli/make-cli.ts +43 -0
  326. package/src/cli/persona-cli.ts +98 -9
  327. package/src/cli/plugin-cli.ts +31 -22
  328. package/src/cli/pod-cli.ts +36 -9
  329. package/src/cli/pod-memory-advice.ts +35 -0
  330. package/src/cli/pr-cli.ts +51 -15
  331. package/src/cli/pty-drive-cli.ts +41 -7
  332. package/src/cli/pty-drive-verdict.ts +40 -0
  333. package/src/cli/release-cli.ts +63 -10
  334. package/src/cli/setup-cli.ts +43 -1
  335. package/src/cli/skills-cli.ts +17 -1
  336. package/src/context-bus/claude-hooks-install.ts +10 -0
  337. package/src/context-bus/context-now-surfaces.ts +65 -0
  338. package/src/context-bus/context-now.ts +104 -0
  339. package/src/context-bus/coord-events.ts +2 -2
  340. package/src/context-bus/external-events.ts +52 -0
  341. package/src/context-bus/long-term-memory.ts +108 -0
  342. package/src/context-bus/nightly-condense.ts +153 -0
  343. package/src/context-bus/session-events.ts +35 -0
  344. package/src/dashboard/dashboard-status-lines.ts +2 -0
  345. package/src/dashboard/index.ts +17 -4
  346. package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
  347. package/src/decisions/decision-cards.ts +10 -3
  348. package/src/decisions/decision-ledger.ts +13 -5
  349. package/src/discord/sprint21-runtime.ts +5 -1
  350. package/src/discord-self-message.ts +32 -0
  351. package/src/discord-slash-wire.ts +5 -1
  352. package/src/discord.ts +17 -1
  353. package/src/domains/core-tools.ts +3 -2
  354. package/src/domains/outbound-alert.ts +105 -32
  355. package/src/domains/outbound-log-probe.ts +8 -0
  356. package/src/domains/telegram-kind-route.ts +51 -13
  357. package/src/exec-requests/default-outputs.ts +25 -0
  358. package/src/exec-requests/planner.ts +10 -2
  359. package/src/exec-requests/runner.ts +20 -6
  360. package/src/exec-requests/store.ts +3 -0
  361. package/src/execution-loop/launch-gate.ts +109 -0
  362. package/src/field/field-reel.ts +5 -1
  363. package/src/field-note/index.ts +201 -0
  364. package/src/field-note/telegram.ts +142 -0
  365. package/src/field-note/transcribe.ts +248 -0
  366. package/src/graph-kinds/registry.ts +3 -3
  367. package/src/graph-runner/graph-cli.ts +61 -1
  368. package/src/graph-runner/graph-grow-llm.ts +47 -0
  369. package/src/graph-runner/graph-grow.ts +50 -0
  370. package/src/graph-runner/runner.ts +329 -33
  371. package/src/grok/agent-search.ts +8 -2
  372. package/src/guardian/secret-exposure-scan.ts +101 -0
  373. package/src/harness/harness-cli-command.ts +375 -13
  374. package/src/harness/harness-pod-dispatch.ts +43 -23
  375. package/src/harness/harness-seams.ts +38 -4
  376. package/src/harness/harness-stop.ts +23 -4
  377. package/src/harness/launch-registry.ts +91 -0
  378. package/src/harness/process-garbage.ts +5 -3
  379. package/src/hooks/consult-intake.ts +153 -0
  380. package/src/hooks/dispatch.ts +82 -0
  381. package/src/hooks/expose.ts +254 -0
  382. package/src/hooks/github-shadow.ts +108 -0
  383. package/src/hooks/providers.ts +71 -5
  384. package/src/hooks/queue.ts +1 -1
  385. package/src/hooks/receiver.ts +94 -16
  386. package/src/index.ts +76 -14
  387. package/src/intake-plane/categorize.ts +18 -46
  388. package/src/intake-plane/discord-seat-work.ts +38 -2
  389. package/src/intake-plane/front-route-classifier.ts +33 -39
  390. package/src/intake-plane/persona-answer.ts +30 -0
  391. package/src/intake-plane/runtime-callables.ts +8 -1
  392. package/src/intake-plane/telegram-seat-work.ts +36 -2
  393. package/src/intake-plane/wish-card.ts +33 -0
  394. package/src/intake-plane/wish-folder.ts +67 -0
  395. package/src/intent-gate/gate.ts +30 -10
  396. package/src/live/detail-switch.ts +5 -0
  397. package/src/llm/difficulty.ts +57 -0
  398. package/src/llm/judge-layer.ts +101 -0
  399. package/src/llm/mission-router.ts +33 -19
  400. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  401. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  402. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  403. package/src/loops/contract/loop-agent.schema.json +138 -0
  404. package/src/loops/contract/validate.ts +64 -0
  405. package/src/loops/registry.ts +20 -6
  406. package/src/market/signed-index.ts +4 -0
  407. package/src/maturity/bot-command-maturity.ts +45 -0
  408. package/src/maturity/feature-maturity.ts +27 -4
  409. package/src/model-tier/index.ts +2 -2
  410. package/src/model-tier/tier-resolver.ts +20 -20
  411. package/src/model-tier/types.ts +6 -6
  412. package/src/mss/logging/log-store.ts +15 -0
  413. package/src/nexus/api/config-model-tier.ts +5 -4
  414. package/src/nexus/api/fabric-plans.ts +53 -0
  415. package/src/nexus/api/harness-api.ts +5 -1
  416. package/src/nexus/api/health.ts +2 -0
  417. package/src/nexus/api/http-server.ts +67 -8
  418. package/src/nexus/api/inside-events.ts +226 -0
  419. package/src/nexus/api/meta-api.ts +21 -8
  420. package/src/nexus/api/missions.ts +6 -1
  421. package/src/nexus/api/ops-seats.ts +33 -0
  422. package/src/nexus/api/outbound-report.ts +40 -7
  423. package/src/nexus/api/outputs-route.ts +44 -0
  424. package/src/nexus/api/personas.ts +95 -53
  425. package/src/nexus/api/seat-requests.ts +44 -2
  426. package/src/nexus/api/sessions-store.ts +17 -38
  427. package/src/nexus/api/sub-seat-charters.ts +34 -0
  428. package/src/nexus/api/tabs-mutations.ts +3 -1
  429. package/src/nexus/api/task-cards-api.ts +19 -0
  430. package/src/nexus/api/trace.ts +18 -6
  431. package/src/nexus/api/workflow-history.ts +88 -0
  432. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  433. package/src/nexus/api/workflows.ts +132 -6
  434. package/src/nexus/index.ts +2 -0
  435. package/src/nexus/kinds/webterm.ts +2 -1
  436. package/src/nexus/outbound/delivery-ledger.ts +17 -8
  437. package/src/nexus/outbound/router.ts +8 -3
  438. package/src/nexus/webterm/pty.ts +6 -2
  439. package/src/onboarding/cli-auth-status.ts +80 -0
  440. package/src/onboarding/voice-ai.ts +3 -3
  441. package/src/org/seat-budget.ts +48 -0
  442. package/src/org/stall-escalation.ts +63 -0
  443. package/src/outputs/ledger.ts +120 -0
  444. package/src/persona/persona-todo.ts +79 -0
  445. package/src/persona/presets.ts +123 -2
  446. package/src/persona/team-set.ts +155 -0
  447. package/src/plugins/install/plugin-install.ts +14 -0
  448. package/src/plugins/maker/market-bundle.ts +110 -0
  449. package/src/plugins/maker/plugin-maker.ts +254 -11
  450. package/src/plugins/maker/wizard-generate.ts +103 -0
  451. package/src/pod-lease/admission.ts +150 -0
  452. package/src/pod-lease/dependency-state.ts +85 -0
  453. package/src/pod-lease/host-lease.ts +127 -0
  454. package/src/project/project-suggestion.ts +16 -0
  455. package/src/project/session-context.ts +24 -0
  456. package/src/release-loop/checklist.ts +17 -5
  457. package/src/release-loop/feature-store.ts +29 -13
  458. package/src/release-loop/landed-but-yellow.ts +48 -0
  459. package/src/release-loop/next-md-merge.ts +58 -0
  460. package/src/release-loop/release-note.ts +59 -4
  461. package/src/seat-dispatch/seat-ask.ts +130 -0
  462. package/src/seat-dispatch/seat-questions.ts +100 -0
  463. package/src/seat-loop/seat-loop.ts +709 -29
  464. package/src/seat-loop/seat-report.ts +37 -2
  465. package/src/self-dev/dev-cli.ts +4 -1
  466. package/src/self-dev/dev-pipeline.ts +37 -1
  467. package/src/self-dev/draft-sweep.ts +79 -40
  468. package/src/self-dev/draft-triage-rules.ts +62 -7
  469. package/src/self-dev/fabric-plan-core.ts +297 -0
  470. package/src/self-dev/orchestrate.ts +36 -4
  471. package/src/self-dev/release-path-guard.ts +62 -0
  472. package/src/self-dev/shard-aggregate.ts +230 -0
  473. package/src/self-dev/shard-placement.ts +60 -0
  474. package/src/self-dev/shard-plan.ts +48 -0
  475. package/src/self-dev/shard-pod-run.ts +77 -0
  476. package/src/self-dev/shard-run.ts +105 -0
  477. package/src/self-implement/budget-gate.ts +29 -12
  478. package/src/self-implement/gate-baseline.ts +1 -1
  479. package/src/self-implement/gate-candidate-ranking.ts +60 -0
  480. package/src/self-implement/gate-cli.ts +40 -1
  481. package/src/self-implement/gate-scope.ts +44 -13
  482. package/src/self-implement/graph-variant.ts +171 -0
  483. package/src/self-implement/harness-policy-gates.ts +1 -1
  484. package/src/self-implement/headless-elanous-driver.ts +27 -3
  485. package/src/self-implement/host-regate.ts +22 -1
  486. package/src/self-implement/importer-test-index.ts +2 -1
  487. package/src/self-implement/l8-merge-queue.ts +130 -0
  488. package/src/self-implement/orchestrator.ts +257 -9
  489. package/src/self-implement/route-consumer-test-index.ts +122 -0
  490. package/src/self-implement/seams.ts +72 -11
  491. package/src/self-implement/test-seams.ts +2 -0
  492. package/src/self-implement/uncommitted-work.ts +59 -0
  493. package/src/session/index.ts +36 -13
  494. package/src/skills/gift-install.ts +215 -0
  495. package/src/skills/tools/web-search.ts +4 -1
  496. package/src/steward/launch.ts +42 -26
  497. package/src/steward/steward-cards.ts +17 -9
  498. package/src/steward/triage.ts +46 -14
  499. package/src/task-cards/card-cli.ts +25 -1
  500. package/src/task-orchestrator/mission.ts +5 -0
  501. package/src/task-orchestrator/store.ts +12 -3
  502. package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
  503. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  504. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  505. package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
  506. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  507. package/src/task-orchestrator/types.ts +2 -0
  508. package/src/telegram-card-followup.ts +16 -96
  509. package/src/telegram-commands.ts +31 -1
  510. package/src/telegram-project-command.ts +145 -0
  511. package/src/telegram-report.ts +21 -17
  512. package/src/telegram.ts +61 -8
  513. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  514. package/src/user-config.ts +110 -24
  515. package/src/version/packed-revision.json +1 -1
  516. package/src/web-search/grok.ts +7 -1
  517. package/src/web-search/index.ts +28 -1
  518. package/src/web-search/provider.ts +4 -0
  519. package/src/web-search/x-intent.ts +5 -0
  520. package/src/workflow-runtime/executor.ts +277 -47
  521. package/src/workflow-runtime/index.ts +1 -0
  522. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  523. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  524. package/src/workflow-runtime/schema.ts +79 -4
  525. package/src/workflow-runtime/types.ts +35 -4
  526. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  536. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  537. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  556. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  614. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  615. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
@@ -0,0 +1,215 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { cpSync, existsSync, lstatSync, mkdtempSync, mkdirSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { homedir, tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { debug } from '../debug/log.js';
7
+
8
+ export interface GiftInstallOptions {
9
+ pack: string;
10
+ code?: string;
11
+ email?: string;
12
+ agree?: boolean;
13
+ endpoint?: string;
14
+ fetch?: typeof fetch;
15
+ targets?: string[];
16
+ /** Caps (defaults below); tests pass small values. */
17
+ maxDownloadBytes?: number;
18
+ maxUnpackedBytes?: number;
19
+ maxEntries?: number;
20
+ }
21
+
22
+ export type GiftInstallResult =
23
+ | { ok: true; names: string[]; paths: string[]; collisions: string[]; needsKeys: boolean; message: string }
24
+ | { ok: false; reason: string; message: string };
25
+
26
+ // GK1 public bundle: packs/elanous-essentials/plugin.json extensions.ai.elanous.bundle.
27
+ const ESSENTIAL_SKILLS = ['youtube-master', 'omni-crawl', 'omni-digest', 'diagram-master', 'lecture-note-digitizer'];
28
+ // A malicious or broken gift must not exhaust the temp disk: cap the download, the unpacked total and the entry count.
29
+ export const MAX_DOWNLOAD_BYTES = 20 * 1024 * 1024;
30
+ export const MAX_UNPACKED_BYTES = 100 * 1024 * 1024;
31
+ export const MAX_ENTRIES = 5000;
32
+ const CONSENT_NOTICE = '선물 스킬 전달과 안내 메일을 위해 이메일을 받습니다 · 보관은 알림 신청과 같은 기간 · 동의하면 --agree 를 붙여 다시 시도해 주세요.';
33
+ const ERROR_MESSAGES: Record<string, string> = {
34
+ 'email-required': CONSENT_NOTICE,
35
+ 'consent-required': CONSENT_NOTICE,
36
+ 'unknown-code': '코드를 다시 확인해 주세요.',
37
+ 'used-up': '이미 다 쓴 코드예요 · 업데이트 소식 신청을 확인해 주세요.',
38
+ expired: '만료된 코드예요.',
39
+ };
40
+
41
+ /** Redeem, verify and install a gift without modifying an existing skill directory. */
42
+ export async function installGiftPack({
43
+ pack, code, email, agree, endpoint = 'https://elanous.ai', fetch: fetchImpl = fetch,
44
+ targets = [join(homedir(), '.agents', 'skills'), join(homedir(), '.claude', 'skills')],
45
+ maxDownloadBytes = MAX_DOWNLOAD_BYTES, maxUnpackedBytes = MAX_UNPACKED_BYTES, maxEntries = MAX_ENTRIES,
46
+ }: GiftInstallOptions): Promise<GiftInstallResult> {
47
+ const codePrefix = code && code.length > 4 ? code.slice(0, 4) : undefined;
48
+ const reject = (reason: string, message: string): GiftInstallResult => {
49
+ debug.log('skills.gift', 'rejected', { pack, reason, count: 0, codePrefix });
50
+ return { ok: false, reason, message };
51
+ };
52
+ if (!email?.trim() || !agree) return reject(!email?.trim() ? 'email-required' : 'consent-required', CONSENT_NOTICE);
53
+ if (!code?.trim()) return reject('unknown-code', ERROR_MESSAGES['unknown-code']!);
54
+ let gift: Record<string, unknown>;
55
+ try {
56
+ const response = await fetchImpl(`${endpoint.replace(/\/$/, '')}/api/gift`, {
57
+ method: 'POST', headers: { 'content-type': 'application/json' },
58
+ body: JSON.stringify({ code, email, consent: true }),
59
+ });
60
+ // The gift API assigns these reasons by HTTP status; error bodies may be absent or malformed.
61
+ const statusReason = ({ 404: 'unknown-code', 409: 'used-up', 410: 'expired' } as Record<number, string | undefined>)[response.status];
62
+ if (statusReason) return reject(statusReason, ERROR_MESSAGES[statusReason]!);
63
+ const payload: unknown = await response.json();
64
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
65
+ return reject('invalid-response', '선물 응답을 확인할 수 없습니다. 다시 시도해 주세요.');
66
+ }
67
+ gift = payload as Record<string, unknown>;
68
+ if (!response.ok) {
69
+ const reason = response.status === 400 && (gift.reason === 'email-required' || gift.reason === 'consent-required')
70
+ ? gift.reason : 'request-rejected';
71
+ return reject(reason, ERROR_MESSAGES[reason] ?? '선물을 받을 수 없습니다. 다시 시도해 주세요.');
72
+ }
73
+ } catch {
74
+ return reject('network-error', '네트워크에 연결할 수 없습니다. 다시 시도해 주세요.');
75
+ }
76
+ if (gift.ok !== true || gift.pack !== pack || typeof gift.zipUrl !== 'string' || !/^https?:\/\//.test(gift.zipUrl)
77
+ || typeof gift.sha256 !== 'string' || !/^[a-f0-9]{64}$/i.test(gift.sha256)) {
78
+ return reject('invalid-response', '선물 응답을 확인할 수 없습니다. 다시 시도해 주세요.');
79
+ }
80
+ let zip: Buffer;
81
+ const tooLarge = () => reject('too-large', '선물 zip 이 허용 크기를 넘습니다. 설치하지 않았습니다.');
82
+ try {
83
+ const response = await fetchImpl(gift.zipUrl, { redirect: 'error' });
84
+ if (!response.ok) throw new Error('download-failed');
85
+ const declared = Number(response.headers.get('content-length'));
86
+ if (Number.isFinite(declared) && declared > maxDownloadBytes) return tooLarge();
87
+ // Count the bytes actually received too — a missing or lying Content-Length must not bypass the cap.
88
+ const chunks: Uint8Array[] = [];
89
+ let received = 0;
90
+ if (response.body) {
91
+ const reader = response.body.getReader();
92
+ for (;;) {
93
+ const { done, value } = await reader.read();
94
+ if (done) break;
95
+ received += value.byteLength;
96
+ if (received > maxDownloadBytes) { await reader.cancel().catch(() => {}); return tooLarge(); }
97
+ chunks.push(value);
98
+ }
99
+ }
100
+ zip = Buffer.concat(chunks);
101
+ } catch {
102
+ return reject('network-error', '다운로드에 실패했습니다. 다시 시도해 주세요.');
103
+ }
104
+ if (createHash('sha256').update(zip).digest('hex').toLowerCase() !== gift.sha256.toLowerCase()) {
105
+ debug.log('skills.gift', 'checksum-mismatch', { pack, reason: 'sha256', count: 0, codePrefix });
106
+ return { ok: false, reason: 'checksum-mismatch', message: '다운로드 검증(sha256)에 실패했습니다. 설치하지 않았습니다.' };
107
+ }
108
+ const temp = mkdtempSync(join(tmpdir(), 'elanous-gift-'));
109
+ const created: string[] = [];
110
+ let incomplete: string | undefined;
111
+ try {
112
+ const zipPath = join(temp, 'gift.zip');
113
+ const extracted = join(temp, 'extracted');
114
+ mkdirSync(extracted);
115
+ writeFileSync(zipPath, zip);
116
+ // Reject archive symlinks and traversal paths before extracting any entry.
117
+ execFileSync('python3', ['-c', `import os, stat, sys, zipfile
118
+ root = sys.argv[2]
119
+ max_unpacked = int(sys.argv[3]); max_entries = int(sys.argv[4])
120
+ with zipfile.ZipFile(sys.argv[1]) as archive:
121
+ entries = archive.infolist()
122
+ if len(entries) > max_entries or sum(entry.file_size for entry in entries) > max_unpacked:
123
+ sys.exit(3)
124
+ for entry in entries:
125
+ parts = entry.filename.split('/')
126
+ mode = entry.external_attr >> 16
127
+ if (not entry.filename or entry.filename.startswith('/') or '\\u005c' in entry.filename
128
+ or any(part in ('', '.', '..') for part in parts[:-1])
129
+ or parts[-1] in ('.', '..') or (not entry.is_dir() and not parts[-1])
130
+ or stat.S_ISLNK(mode)):
131
+ raise ValueError('invalid archive entry')
132
+ written = 0
133
+ for entry in entries:
134
+ path = os.path.join(root, entry.filename)
135
+ if entry.is_dir():
136
+ os.makedirs(path, exist_ok=True)
137
+ else:
138
+ os.makedirs(os.path.dirname(path), exist_ok=True)
139
+ with archive.open(entry) as source, open(path, 'xb') as target:
140
+ while True:
141
+ block = source.read(65536)
142
+ if not block:
143
+ break
144
+ written += len(block)
145
+ if written > max_unpacked:
146
+ sys.exit(3)
147
+ target.write(block)
148
+ `, zipPath, extracted, String(maxUnpackedBytes), String(maxEntries)], { stdio: 'pipe' });
149
+ const skillDirs = (root: string) => readdirSync(root, { withFileTypes: true })
150
+ // SKILL.md must be a regular file — a `SKILL.md/` directory or a symlink is not a skill.
151
+ .filter((entry) => entry.isDirectory() && lstatSync(join(root, entry.name, 'SKILL.md'), { throwIfNoEntry: false })?.isFile() === true)
152
+ .map((entry) => ({ name: entry.name, path: join(root, entry.name) }));
153
+ let skills = skillDirs(extracted);
154
+ if (!skills.length) {
155
+ const roots = readdirSync(extracted, { withFileTypes: true })
156
+ .filter((entry) => entry.isDirectory()).map((entry) => join(extracted, entry.name));
157
+ if (roots.length === 1) {
158
+ skills = skillDirs(roots[0]!);
159
+ if (!skills.length && existsSync(join(roots[0]!, 'skills'))) skills = skillDirs(join(roots[0]!, 'skills'));
160
+ }
161
+ }
162
+ // Directory listing order differs between filesystems — keep the bundle order, then names.
163
+ const rank = (name: string) => { const i = ESSENTIAL_SKILLS.indexOf(name); return i < 0 ? ESSENTIAL_SKILLS.length : i; };
164
+ skills = [...skills].sort((a, b) => rank(a.name) - rank(b.name) || a.name.localeCompare(b.name));
165
+ if (!skills.length || !targets.length) return reject('invalid-pack', '설치할 스킬 폴더나 대상 경로를 찾지 못했습니다.');
166
+ if (pack === 'essential' && (skills.length !== ESSENTIAL_SKILLS.length
167
+ || ESSENTIAL_SKILLS.some((name) => !skills.some((skill) => skill.name === name)))) {
168
+ return reject('invalid-pack', '필수 스킬 다섯이 모두 들어 있지 않습니다. 설치하지 않았습니다.');
169
+ }
170
+ const paths: string[] = [];
171
+ const collisions: string[] = [];
172
+ const date = new Date().toISOString().slice(0, 10);
173
+ for (const target of targets) {
174
+ mkdirSync(target, { recursive: true });
175
+ for (const skill of skills) {
176
+ const desired = join(target, skill.name);
177
+ let dest = desired;
178
+ if (lstatSync(desired, { throwIfNoEntry: false })) {
179
+ dest = `${desired}.gift-${date}`;
180
+ let n = 2;
181
+ while (lstatSync(dest, { throwIfNoEntry: false })) dest = `${desired}.gift-${date}-${n++}`;
182
+ collisions.push(`${skill.name} → ${dest}`);
183
+ }
184
+ // Reserve the destination exclusively: a concurrent installer must not be overwritten.
185
+ mkdirSync(dest);
186
+ incomplete = dest;
187
+ for (const entry of readdirSync(skill.path)) {
188
+ cpSync(join(skill.path, entry), join(dest, entry), { recursive: true, errorOnExist: true, force: false });
189
+ }
190
+ created.push(dest);
191
+ incomplete = undefined;
192
+ paths.push(dest);
193
+ }
194
+ }
195
+ const names = skills.map((skill) => skill.name);
196
+ const needsKeys = skills.some((skill) => existsSync(join(skill.path, '.env.example')));
197
+ const message = `${collisions.length ? `기존 폴더는 그대로 두고 옆에 설치했습니다: ${collisions.join(', ')}\n` : ''}${needsKeys ? '.env.example 이 있습니다 — 키는 가이드대로 설정해 주세요.\n' : ''}설치한 스킬: ${names.join(', ')}`;
198
+ debug.log('skills.gift', 'installed', { pack, reason: 'ok', count: paths.length, codePrefix });
199
+ return { ok: true, names, paths, collisions, needsKeys, message };
200
+ } catch (error) {
201
+ if ((error as { status?: number }).status === 3 && !created.length) return tooLarge();
202
+ const remaining: string[] = [];
203
+ for (const path of [...(incomplete ? [incomplete] : []), ...created.reverse()]) {
204
+ try { rmSync(path, { recursive: true }); }
205
+ catch { remaining.push(path); }
206
+ }
207
+ if (remaining.length) {
208
+ debug.log('skills.gift', 'rejected', { pack, reason: 'partial-install', count: remaining.length, codePrefix });
209
+ return { ok: false, reason: 'partial-install', message: `일부 설치된 스킬을 되돌리지 못했습니다: ${remaining.join(', ')}` };
210
+ }
211
+ return reject('invalid-pack', '선물 zip 을 안전하게 풀 수 없습니다. 설치하지 않았습니다.');
212
+ } finally {
213
+ rmSync(temp, { recursive: true, force: true });
214
+ }
215
+ }
@@ -101,7 +101,10 @@ export async function dispatchWebSearch(args: Record<string, unknown>, ctx: { si
101
101
  });
102
102
 
103
103
  const notePrefix = result.note ? `\n\n${result.note}\n` : '';
104
- const output = [header, notePrefix.trim(), ...hitLines].filter(Boolean).join('\n\n');
104
+ const xStatus = result.xSearch === 'unavailable'
105
+ ? 'X search unavailable: these results do not establish reactions on X; do not cite them as X posts.'
106
+ : '';
107
+ const output = [header, xStatus, notePrefix.trim(), ...hitLines].filter(Boolean).join('\n\n');
105
108
 
106
109
  return {
107
110
  output,
@@ -2,11 +2,14 @@ import { randomUUID } from 'node:crypto';
2
2
  import { closeSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { debug } from '../debug/log.js';
5
+ import { publishInsideEvent } from '../nexus/api/inside-events.js';
5
6
  import { redactSecrets } from '../task-cards/card-store.js';
7
+ import { preLaunchGate, type PreLaunchGateDecision } from '../execution-loop/launch-gate.js';
8
+ import type { BudgetDecision } from '../self-implement/budget-gate.js';
6
9
  import type { ScheduledDecision, StewardSettings, TriageIssue } from './triage.js';
7
10
 
8
11
  /** `completed` = the run finished without a merge (a non-code artifact, or nothing to deliver) — never reported as a failure. */
9
- export type LaunchStatus = 'shadow' | 'launched' | 'skipped-budget' | 'failed' | 'running' | 'merged' | 'completed';
12
+ export type LaunchStatus = 'shadow' | 'launched' | 'skipped-budget' | 'blocked-duplicate' | 'blocked-location' | 'failed' | 'running' | 'merged' | 'completed';
10
13
  export interface LaunchEntry {
11
14
  issue: string;
12
15
  title: string;
@@ -40,12 +43,14 @@ export interface LaunchDeps {
40
43
  /** Injected command boundary; the production adapter runs only argv, never a shell. */
41
44
  command?: (args: string[]) => { exitCode: number; stdout: string; stderr?: string };
42
45
  spawn?: (args: string[], log: string) => { pid: number };
46
+ gate?: (goalId: string, budget: BudgetDecision | 'unknown') => PreLaunchGateDecision;
43
47
  }
44
48
 
45
49
  const RUN_ID = /\brun-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
46
50
  const DEFAULT_POOL = 'pool-node-b@node-b:8';
47
51
  // `harness budget --json` outcomes: proceed | next-provider | wait-reset | stop. next-provider still runs (the harness switches provider itself).
48
52
  const BUDGET_PROCEED: readonly string[] = ['proceed', 'next-provider'];
53
+ const launchMode = (settings: StewardSettings): 'off' | 'shadow' | 'live' => settings.mode ?? settings.launch ?? 'shadow';
49
54
  const cli = (args: string[]) => ['bun', 'bin/elanous.mjs', ...(process.env.NODE_ENV === 'test' ? ['--test'] : []), ...args];
50
55
  const sourceOf = (issue: TriageIssue): string => /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1] ?? `linear:${issue.identifier}`;
51
56
  const promptOf = (issue: TriageIssue): string => `${issue.title}\n${issue.body.slice(0, 1500)}`;
@@ -83,10 +88,10 @@ export function planLaunches(rows: ScheduledDecision[], issues: TriageIssue[], l
83
88
  const issue = byId.get(row.issue);
84
89
  if (!issue) continue;
85
90
  if (row.rung === 'hitl' || row.hitlReason || row.disposition === 'hitl') {
86
- if (settings.launch !== 'off' && (!ledger.hitl[row.issue] || settings.launch === 'live' && !ledger.hitl[row.issue].attempted)) hitl.push({ issue, row });
91
+ if (launchMode(settings) !== 'off' && (!ledger.hitl[row.issue] || launchMode(settings) === 'live' && !ledger.hitl[row.issue].attempted)) hitl.push({ issue, row });
87
92
  continue;
88
93
  }
89
- if ((settings.launch ?? 'shadow') === 'off' || row.disposition !== 'now' || row.rung !== 4 || (ledger.launches[row.issue] && ledger.launches[row.issue].status !== 'skipped-budget' && !(settings.launch === 'live' && ledger.launches[row.issue].status === 'shadow')) || launches.length >= available) continue;
94
+ if (launchMode(settings) === 'off' || row.disposition !== 'now' || row.rung !== 4 || (ledger.launches[row.issue] && !['skipped-budget', 'blocked-duplicate', 'blocked-location'].includes(ledger.launches[row.issue].status) && !(launchMode(settings) === 'live' && ledger.launches[row.issue].status === 'shadow')) || launches.length >= available) continue;
90
95
  const args = argvFor(issue, settings);
91
96
  launches.push({ issue, row, source: sourceOf(issue), command: args.map(arg => JSON.stringify(arg)).join(' ') });
92
97
  }
@@ -118,37 +123,46 @@ function lastJson(stdout: string): Record<string, unknown> {
118
123
  /** One issue is reserved before any side effect; budget skips are retriable, never counted as a launch. */
119
124
  export function launch(item: LaunchItem, deps: LaunchDeps): LaunchEntry {
120
125
  const { ledger, settings, root } = deps;
121
- if (item.row.rung !== 4 || item.row.hitlReason || item.row.disposition !== 'now' || (ledger.launches[item.issue.identifier] && ledger.launches[item.issue.identifier].status !== 'skipped-budget' && !(settings.launch === 'live' && ledger.launches[item.issue.identifier].status === 'shadow'))) throw new Error('steward launch is not eligible');
122
- if (settings.launch === 'off') throw new Error('steward launch is off');
126
+ if (item.row.rung !== 4 || item.row.hitlReason || item.row.disposition !== 'now' || (ledger.launches[item.issue.identifier] && !['skipped-budget', 'blocked-duplicate', 'blocked-location'].includes(ledger.launches[item.issue.identifier].status) && !(launchMode(settings) === 'live' && ledger.launches[item.issue.identifier].status === 'shadow'))) throw new Error('steward launch is not eligible');
127
+ if (launchMode(settings) === 'off') throw new Error('steward launch is off');
123
128
  const key = item.issue.identifier;
124
129
  const entry: LaunchEntry = { issue: key, title: redactSecrets(item.issue.title), source: item.source, command: redactSecrets(item.command), status: 'shadow' };
125
- if (settings.launch !== 'live') {
130
+ if (launchMode(settings) !== 'live') {
126
131
  ledger.launches[key] = entry;
127
132
  saveLaunchLedger(root, ledger);
128
133
  debug.log('steward.launch', 'shadow', { issue: key, command: entry.command });
134
+ publishInsideEvent({ kind: 'steward', issue: key, status: entry.status });
129
135
  return entry;
130
136
  }
131
137
  const command = deps.command ?? runCommand;
132
- try {
133
- const budget = command(cli(['harness', 'budget', '--json']));
134
- const decision = budget.exitCode === 0 ? lastJson(budget.stdout) : {};
135
- if (!BUDGET_PROCEED.includes(String(decision.outcome))) {
136
- entry.status = 'skipped-budget';
137
- entry.reason = redactSecrets(budget.exitCode === 0 ? JSON.stringify(decision.reasons ?? ['budget unavailable']) : budget.stderr ?? 'budget unavailable');
138
- // A budget skip may be reconsidered on the next cycle, but the reason remains observable now.
139
- ledger.launches[key] = entry;
140
- saveLaunchLedger(root, ledger);
141
- debug.log('steward.launch', 'skipped-budget', { issue: key, reason: entry.reason });
142
- return entry;
143
- }
144
- } catch (error) {
145
- entry.status = 'skipped-budget';
146
- entry.reason = redactSecrets(String(error));
138
+ const blocked = (status: LaunchStatus, reason: string): LaunchEntry => {
139
+ entry.status = status;
140
+ entry.reason = redactSecrets(reason);
147
141
  ledger.launches[key] = entry;
148
142
  saveLaunchLedger(root, ledger);
149
- debug.log('steward.launch', 'skipped-budget', { issue: key, reason: entry.reason });
143
+ debug.log('steward.launch', status, { issue: key, reason: entry.reason });
144
+ publishInsideEvent({ kind: 'steward', issue: key, status: entry.status, reason: entry.reason });
150
145
  return entry;
146
+ };
147
+ // L6: a launch must remain on the isolated Pod pool, never fall back to the host or another substrate.
148
+ if (!/^[a-zA-Z0-9_-]+(?:@[a-zA-Z0-9._-]+(?::[1-9][0-9]*)?)?$/.test(settings.podPool ?? DEFAULT_POOL))
149
+ return blocked('blocked-location', 'invalid steward pod pool');
150
+ let budget: BudgetDecision | 'unknown' = 'unknown';
151
+ try {
152
+ const result = command(cli(['harness', 'budget', '--json']));
153
+ const decision = result.exitCode === 0 ? lastJson(result.stdout) : {};
154
+ if (!BUDGET_PROCEED.includes(String(decision.outcome)))
155
+ return blocked('skipped-budget', result.exitCode === 0 ? JSON.stringify(decision.reasons ?? ['budget unavailable']) : result.stderr ?? 'budget unavailable');
156
+ budget = { action: decision.outcome as 'proceed' | 'next-provider', reasons: Array.isArray(decision.reasons) ? decision.reasons.map(String) : [] };
157
+ } catch (error) {
158
+ return blocked('skipped-budget', String(error));
151
159
  }
160
+ // L6: the shared gate checks active same-goal runs and the budget decision immediately before spawn.
161
+ let gate: PreLaunchGateDecision;
162
+ try { gate = (deps.gate ?? ((goalId, decision) => preLaunchGate({ goalId, budget: decision })))(`linear:${key}`, budget); }
163
+ catch (error) { return blocked('blocked-duplicate', `launch gate unavailable: ${String(error)}`); }
164
+ if (gate.action !== 'proceed' || gate.sameGoalActiveRuns === 'unknown')
165
+ return blocked(gate.action === 'blocked-budget' || gate.action === 'wait-reset' ? 'skipped-budget' : 'blocked-duplicate', gate.sameGoalActiveRuns === 'unknown' ? 'active runs unknown' : gate.reason);
152
166
  entry.status = 'launched';
153
167
  entry.log = join(root, 'steward', 'launch', `${key.replace(/[^a-zA-Z0-9_-]/g, '_')}.log`);
154
168
  mkdirSync(join(root, 'steward', 'launch'), { recursive: true });
@@ -166,15 +180,16 @@ export function launch(item: LaunchItem, deps: LaunchDeps): LaunchEntry {
166
180
  }
167
181
  saveLaunchLedger(root, ledger);
168
182
  debug.log('steward.launch', 'launched', { issue: key, runId: entry.runId, pid: entry.pid, status: entry.status });
183
+ publishInsideEvent({ kind: 'steward', issue: key, status: entry.status, ...(entry.runId ? { runId: entry.runId } : {}) });
169
184
  return entry;
170
185
  }
171
186
 
172
187
  export function raiseHitl(issue: TriageIssue, row: ScheduledDecision, deps: LaunchDeps): HitlEntry {
173
188
  const old = deps.ledger.hitl[issue.identifier];
174
- if (old && (old.attempted || deps.settings.launch !== 'live')) return old;
189
+ if (old && (old.attempted || launchMode(deps.settings) !== 'live')) return old;
175
190
  const entry: HitlEntry = old ?? { issue: issue.identifier, reason: redactSecrets(row.hitlReason ?? row.why), raised: false };
176
191
  deps.ledger.hitl[issue.identifier] = entry;
177
- if (deps.settings.launch !== 'live') {
192
+ if (launchMode(deps.settings) !== 'live') {
178
193
  saveLaunchLedger(deps.root, deps.ledger);
179
194
  return entry;
180
195
  }
@@ -199,10 +214,10 @@ function alive(pid: number | undefined): boolean {
199
214
  }
200
215
 
201
216
  export function collectOutcomes(ledger: LaunchLedger, deps: LaunchDeps): LaunchEntry[] {
202
- if (deps.settings.launch !== 'live') return [];
217
+ if (launchMode(deps.settings) !== 'live') return [];
203
218
  const done: LaunchEntry[] = [];
204
219
  for (const entry of Object.values(ledger.launches)) {
205
- if (entry.reported || entry.status === 'shadow' || entry.status === 'skipped-budget') continue;
220
+ if (entry.reported || entry.status === 'shadow' || entry.status === 'skipped-budget' || entry.status === 'blocked-duplicate' || entry.status === 'blocked-location') continue;
206
221
  if (!entry.runId && entry.log) {
207
222
  try { entry.runId = readFileSync(entry.log, 'utf8').match(RUN_ID)?.[0]; } catch { /* Wait for log. */ }
208
223
  }
@@ -244,6 +259,7 @@ export function collectOutcomes(ledger: LaunchLedger, deps: LaunchDeps): LaunchE
244
259
  if (entry.status === 'running') continue;
245
260
  done.push(entry);
246
261
  debug.log('steward.launch', 'outcome', { issue: entry.issue, status: entry.status, runId: entry.runId, prNumber: entry.prNumber });
262
+ publishInsideEvent({ kind: 'steward', issue: entry.issue, status: entry.status, ...(entry.runId ? { runId: entry.runId } : {}) });
247
263
  }
248
264
  saveLaunchLedger(deps.root, ledger);
249
265
  return done;
@@ -15,6 +15,22 @@ export interface StewardCardDeps {
15
15
  now?: () => Date;
16
16
  }
17
17
 
18
+ /** Record the first intake for each polled issue, independently of LLM triage. */
19
+ export function recordIntakeOnCards(store: StewardCardStore, issues: TriageIssue[], now: () => Date = () => new Date()): void {
20
+ for (const issue of issues) {
21
+ const card = store.createCard({ goalId: `linear:${issue.identifier}`, title: redactSecrets(issue.title) });
22
+ const intakeKey = `intake:${issue.identifier}`;
23
+ if (!card.sections.some(section => section.key === intakeKey)) {
24
+ const directiveSource = /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1];
25
+ const directiveTime = /^시각: (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)$/m.exec(issue.body)?.[1];
26
+ store.appendSection(card.id, {
27
+ key: intakeKey, owner: 'steward',
28
+ content: JSON.stringify({ summary: redactSecrets(issue.title), source: directiveSource ?? `linear:${issue.identifier}`, at: directiveTime ?? now().toISOString() }),
29
+ });
30
+ }
31
+ }
32
+ }
33
+
18
34
  /** Record observe-only intake and the latest scheduled judgment without launching any work. */
19
35
  export function recordTriageOnCards(decisions: ScheduledDecision[], issues: TriageIssue[], deps: StewardCardDeps = {}): void {
20
36
  const store = deps.store ?? new CardStore(deps.root);
@@ -23,16 +39,8 @@ export function recordTriageOnCards(decisions: ScheduledDecision[], issues: Tria
23
39
  for (const decision of decisions) {
24
40
  const issue = byIssue.get(decision.issue);
25
41
  if (!issue) throw new Error(`Missing issue ${decision.issue}`);
42
+ recordIntakeOnCards(store, [issue], deps.now);
26
43
  const card = store.createCard({ goalId: `linear:${issue.identifier}`, title: redactSecrets(issue.title) });
27
- const intakeKey = `intake:${issue.identifier}`;
28
- if (!card.sections.some(section => section.key === intakeKey)) {
29
- const directiveSource = /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1];
30
- const directiveTime = /^시각: (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)$/m.exec(issue.body)?.[1];
31
- store.appendSection(card.id, {
32
- key: intakeKey, owner: 'steward',
33
- content: JSON.stringify({ summary: redactSecrets(issue.title), source: directiveSource ?? `linear:${issue.identifier}`, at: directiveTime ?? (deps.now ?? (() => new Date()))().toISOString() }),
34
- });
35
- }
36
44
  const { rung, dependsOn, priority, disposition, hitlReason, why, owner } = decision;
37
45
  const judgment = { rung, dependsOn, priority, disposition: rung === 'hitl' || hitlReason ? 'hitl' : disposition, hitlReason: hitlReason ?? null, why: redactSecrets(why), ...(owner ? { owner } : {}), ...(decision.capability ? { capability: decision.capability } : {}) };
38
46
  const key = `triage:${createHash('sha256').update(JSON.stringify(judgment)).digest('hex')}`;
@@ -9,8 +9,9 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
9
9
  import { redactSecrets } from '../task-cards/card-store.js';
10
10
  import { directiveHash } from './directive.js';
11
11
  import { notifyOutcome, type OutcomeNotifyDeps } from './outcome-notify.js';
12
- import { recordTriageOnCards, recordLaunchOnCard, recordOutcomeOnCard, recordHitlOnCard, type StewardCardDeps } from './steward-cards.js';
12
+ import { recordIntakeOnCards, recordTriageOnCards, recordLaunchOnCard, recordOutcomeOnCard, recordHitlOnCard, type StewardCardDeps } from './steward-cards.js';
13
13
  import { planLaunches, launch, collectOutcomes, raiseHitl, readLaunchLedger, saveLaunchLedger, type LaunchDeps } from './launch.js';
14
+ import { listFabricExecutionCandidates } from '../self-dev/fabric-plan-core.js';
14
15
  import { InvalidWorkingBackwardsDraft, recordWorkingBackwardsOnCards } from './working-backwards.js';
15
16
  import { CardStore } from '../task-cards/card-store.js';
16
17
  import { triageWithinBudget } from './triage-budget.js';
@@ -32,7 +33,7 @@ export interface TriageDecision {
32
33
  }
33
34
  export interface ScheduledDecision extends TriageDecision { disposition: 'now' | 'wait' | 'hitl' }
34
35
  export interface StewardSettings {
35
- mode?: 'observe' | 'act'; linearTeam?: string;
36
+ mode?: 'off' | 'shadow' | 'live'; linearTeam?: string;
36
37
  roles?: Record<string, { maxConcurrent?: number }>;
37
38
  budget?: number;
38
39
  tracks?: Record<string, string>;
@@ -52,18 +53,28 @@ export interface StewardDeps {
52
53
  cardStore?: StewardCardDeps['store'];
53
54
  warn?: (message: string) => void;
54
55
  ask?: StewardAsk;
55
- launchSettings?: Pick<StewardSettings, 'launch' | 'maxParallel' | 'podPool'>;
56
+ launchSettings?: Pick<StewardSettings, 'mode' | 'launch' | 'maxParallel' | 'podPool'>;
56
57
  launchCommand?: LaunchDeps['command'];
57
58
  spawnLaunch?: LaunchDeps['spawn'];
59
+ launchGate?: LaunchDeps['gate'];
58
60
  outcomeNotify?: Pick<OutcomeNotifyDeps, 'document' | 'message' | 'worktreeCommand' | 'loadOrigin' | 'loadOrigins'>;
59
61
  /** Internal command boundary: the current sync has already claimed this pid. */
60
62
  stageOwnedByCommand?: boolean;
61
63
  }
62
64
 
63
65
  export function stewardSettings(): StewardSettings {
64
- return getUserConfig().loops?.steward ?? {};
66
+ return getUserConfig().loops?.steward ?? { mode: 'shadow' };
65
67
  }
66
68
 
69
+ function effectiveStewardMode(settings: StewardSettings): 'off' | 'shadow' | 'live' {
70
+ return settings.mode ?? settings.launch ?? 'shadow';
71
+ }
72
+
73
+ function resolvedStewardSettings(override?: StewardDeps['launchSettings']): StewardSettings {
74
+ const settings = { ...stewardSettings(), ...override };
75
+ if (override?.launch !== undefined && override.mode === undefined) settings.mode = override.launch;
76
+ return { ...settings, mode: effectiveStewardMode(settings) };
77
+ }
67
78
 
68
79
  function parseJudgment(issue: TriageIssue, raw: unknown, tracks?: Record<string, string>): TriageDecision {
69
80
  const value = typeof raw === 'string' ? JSON.parse(raw) as unknown : raw;
@@ -247,10 +258,10 @@ function readState(path: string): { issues: Record<string, string>; digestDay?:
247
258
  catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { issues: {} }; throw error; }
248
259
  }
249
260
 
250
- /** Each command node invokes one stage. Only the launch setting permits spawn; merge and approval remain with the harness and human. */
261
+ /** Each command node invokes one stage. Live launch still requires the launch gate; merge and approval remain with the harness and human. */
251
262
  export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'report', deps: StewardDeps = {}): Promise<void> {
252
- const settings = { ...stewardSettings(), ...deps.launchSettings };
253
- if ((settings.mode ?? 'observe') !== 'observe') throw new Error('steward act mode is out of scope');
263
+ const settings = resolvedStewardSettings(deps.launchSettings);
264
+ if (settings.mode === 'off') return;
254
265
  const root = deps.root ?? effectiveInstanceRoot();
255
266
  if (stage === 'sync' && !deps.stageOwnedByCommand) {
256
267
  return withStageSlot(root, async () => {
@@ -272,7 +283,25 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
272
283
  if (!key) throw new Error('connector.linear.apiKey missing');
273
284
  if (stage === 'sync') {
274
285
  const events = await fetchLinearIssues({ apiKey: key, teamKey: settings.linearTeam ?? 'ELA', fetch: fetchFn });
275
- writeFileSync(snapshot, JSON.stringify(events.map(e => ({ identifier: e.identifier, ref: e.ref, title: e.title, body: e.body }))));
286
+ const issues = events.map(e => ({ identifier: e.identifier, ref: e.ref, title: e.title, body: e.body }));
287
+ writeFileSync(snapshot, JSON.stringify(issues));
288
+ const cardIssues = issues.filter((issue): issue is TriageIssue => typeof issue.identifier === 'string');
289
+ if (cardIssues.length) {
290
+ const observeCardFailure = (error: unknown, issue?: string): void => {
291
+ const message = `steward sync: card write failed${issue ? ` (${issue})` : ''}: ${redactSecrets(error instanceof Error ? error.message : String(error))}`;
292
+ try { debug.log('steward.cards', 'write-failed', { error: message }); } catch { /* observation must not fail sync */ }
293
+ try { (deps.warn ?? console.warn)(message); } catch { /* observation must not fail sync */ }
294
+ };
295
+ try {
296
+ const store = deps.cardStore ?? new CardStore(root);
297
+ try {
298
+ for (const issue of cardIssues) {
299
+ try { recordIntakeOnCards(store, [issue], deps.now); }
300
+ catch (error) { observeCardFailure(error, issue.identifier); }
301
+ }
302
+ } finally { if (!deps.cardStore) store.close(); }
303
+ } catch (error) { observeCardFailure(error); }
304
+ }
276
305
  } else if (stage === 'triage') {
277
306
  const issues = JSON.parse(readFileSync(snapshot, 'utf8')) as TriageIssue[];
278
307
  const judge = deps.judge;
@@ -341,10 +370,12 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
341
370
  }
342
371
  writeFileSync(schedule, JSON.stringify(rows));
343
372
  const ledger = readLaunchLedger(root);
344
- const launchDeps: LaunchDeps = { root, settings, ledger, command: deps.launchCommand, spawn: deps.spawnLaunch };
373
+ const launchDeps: LaunchDeps = { root, settings, ledger, command: deps.launchCommand, spawn: deps.spawnLaunch, gate: deps.launchGate };
345
374
  const cardDeps = { root, store: deps.cardStore, now: deps.now };
346
375
  collectOutcomes(ledger, launchDeps);
347
376
  const plan = planLaunches(rows, issues, ledger, settings);
377
+ // Keep fabric candidates distinct from Linear launches until a fabric executor is wired.
378
+ writeFileSync(join(dir, 'fabric-candidates.json'), JSON.stringify(listFabricExecutionCandidates(root)));
348
379
  for (const { issue, row } of plan.hitl) {
349
380
  const entry = raiseHitl(issue, row, launchDeps);
350
381
  recordHitlOnCard(issue, entry, cardDeps);
@@ -391,7 +422,7 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
391
422
  const issue = issues.find(item => item.identifier === outcome.issue) ??
392
423
  { identifier: outcome.issue, title: outcome.title, ref: '', body: '' };
393
424
  recordOutcomeOnCard(issue, outcome, { root, store: deps.cardStore, now: deps.now });
394
- notifyOutcome(outcome, { root, ledger, shadow: settings.launch !== 'live', ...deps.outcomeNotify });
425
+ notifyOutcome(outcome, { root, ledger, shadow: settings.mode !== 'live', ...deps.outcomeNotify });
395
426
  const prefix = ['telegram', 'pwa', 'tui', 'cli'].includes(outcome.source) ? `${outcome.source} · ` : '';
396
427
  await (deps.sendDigest ?? sendStewardDigest)(`${prefix}${issue.title} · PR ${outcome.prNumber ?? '없음'} · ${outcome.status}`);
397
428
  outcome.reported = true;
@@ -399,11 +430,11 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
399
430
  }
400
431
  const justCollected = new Set(outcomes.map(outcome => outcome.issue));
401
432
  for (const outcome of Object.values(ledger.launches)) {
402
- if ((settings.launch !== 'live' && outcome.status === 'shadow' && !outcome.notified) ||
403
- (settings.launch === 'live' && !justCollected.has(outcome.issue) && outcome.reported && outcome.notified !== 'shadow') ||
433
+ if ((settings.mode !== 'live' && outcome.status === 'shadow' && !outcome.notified) ||
434
+ (settings.mode === 'live' && !justCollected.has(outcome.issue) && outcome.reported && outcome.notified !== 'shadow') ||
404
435
  // A finished run whose PR waits for merge still owes the wish's chat its PR link (once; failures retry).
405
- (settings.launch === 'live' && outcome.awaitingMerge === true && !outcome.reported && outcome.notified !== 'sent')) {
406
- notifyOutcome(outcome, { root, ledger, shadow: settings.launch !== 'live', ...deps.outcomeNotify });
436
+ (settings.mode === 'live' && outcome.awaitingMerge === true && !outcome.reported && outcome.notified !== 'sent')) {
437
+ notifyOutcome(outcome, { root, ledger, shadow: settings.mode !== 'live', ...deps.outcomeNotify });
407
438
  }
408
439
  }
409
440
  const day = at.slice(0, 10);
@@ -455,6 +486,7 @@ async function withStageSlot<T>(root: string, run: () => Promise<T>, onBusy?: ()
455
486
 
456
487
  /** The command-node boundary records both normal exits and an unclosed stage from a killed process. */
457
488
  export async function runStewardStageCommand(stage: StewardStage, deps: StewardCommandDeps = {}): Promise<0 | 1> {
489
+ if (resolvedStewardSettings(deps.launchSettings).mode === 'off') return 0;
458
490
  const root = deps.root ?? effectiveInstanceRoot();
459
491
  if (stage !== 'sync' && existsSync(skippedPath(root))) return 0;
460
492
  return withStageSlot(root, async () => {
@@ -1,4 +1,6 @@
1
1
  import type { Command } from 'commander';
2
+ import { join, resolve } from 'node:path';
3
+ import { scanWishFolder } from '../intake-plane/wish-folder.js';
2
4
  import { CardStore, type TaskCard } from './card-store.js';
3
5
 
4
6
  export interface CardCliDeps {
@@ -20,7 +22,7 @@ function formatCard(card: TaskCard): string {
20
22
  return lines.join('\n') + '\n';
21
23
  }
22
24
 
23
- /** Register read-only card inspection commands without changing other task commands. */
25
+ /** Register card inspection and Wish note import commands. */
24
26
  export function registerCardCommand(program: Command, deps: CardCliDeps = {}): Command {
25
27
  const createStore = deps.createStore ?? (() => new CardStore());
26
28
  const write = deps.write ?? ((text: string) => { process.stdout.write(text); });
@@ -60,5 +62,27 @@ export function registerCardCommand(program: Command, deps: CardCliDeps = {}): C
60
62
  }
61
63
  });
62
64
 
65
+ card.command('wish-scan')
66
+ .description('Create task cards from Obsidian Wish notes')
67
+ .option('--dir <path>', 'Wish folder path')
68
+ .option('--json', 'Output JSON')
69
+ .action((options: { dir?: string; json?: boolean }) => {
70
+ const dir = resolve(options.dir ?? join(process.env.OBSIDIAN_VAULT_ROOT ?? '', '00. Inbox', '00. Wish'));
71
+ let store: CardStore | undefined;
72
+ try {
73
+ const result = scanWishFolder({ dir, store: (store = createStore()) });
74
+ write(options.json ? `${JSON.stringify(result)}\n` : `추가 ${result.added} · 갱신 ${result.updated} · 건너뜀 ${result.skipped}\n`);
75
+ } catch (error) {
76
+ if (error instanceof Error && error.message.startsWith('Wish 폴더를 찾지 못했습니다: ')) {
77
+ process.stderr.write(`${error.message}\n`);
78
+ process.exitCode = 2;
79
+ return;
80
+ }
81
+ throw error;
82
+ } finally {
83
+ store?.close();
84
+ }
85
+ });
86
+
63
87
  return card;
64
88
  }
@@ -264,6 +264,8 @@ export interface Mission {
264
264
 
265
265
  /** Optional bind to an existing goal (S2 auto-research / PFC). */
266
266
  goalSlug?: string;
267
+ /** Project association; absent on legacy and unassigned missions. */
268
+ projectId?: string;
267
269
 
268
270
  /** Free-form notes (append-only). */
269
271
  notes: readonly string[];
@@ -296,6 +298,7 @@ export interface MissionInit {
296
298
  priority?: MissionPriority;
297
299
  taskIds?: readonly string[];
298
300
  goalSlug?: string;
301
+ projectId?: string;
299
302
  notes?: readonly string[];
300
303
  /** Cascade-zyu Z0 — see {@link Mission.showroomSessionId}. */
301
304
  showroomSessionId?: string;
@@ -370,6 +373,7 @@ export function createMission(
370
373
  priority: init.priority,
371
374
  taskIds: Object.freeze([...(init.taskIds ?? [])]),
372
375
  goalSlug: init.goalSlug,
376
+ ...(init.projectId !== undefined ? { projectId: init.projectId } : {}),
373
377
  notes: Object.freeze([...(init.notes ?? [])]),
374
378
  showroomSessionId: init.showroomSessionId,
375
379
  autopilot: init.autopilot ? { ...init.autopilot } : undefined,
@@ -471,6 +475,7 @@ export function serializeMission(m: Mission): Record<string, unknown> {
471
475
  priority: m.priority,
472
476
  taskIds: [...m.taskIds],
473
477
  goalSlug: m.goalSlug,
478
+ ...(m.projectId !== undefined ? { projectId: m.projectId } : {}),
474
479
  notes: [...m.notes],
475
480
  showroomSessionId: m.showroomSessionId,
476
481
  };