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
@@ -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
  };
@@ -138,6 +138,7 @@ interface MissionRow {
138
138
  priority: MissionPriority | null;
139
139
  task_ids_json: string; // JSON array of taskId
140
140
  goal_slug: string | null;
141
+ project_id: string | null;
141
142
  notes_json: string; // JSON array of string
142
143
  autopilot_json: string | null; // JSON MissionAutopilot | null (U1)
143
144
  }
@@ -309,6 +310,8 @@ export class TaskStore {
309
310
  // Mission Fabric 통합 U1 (v3) — tox_missions.autopilot_json:
310
311
  // PFC Layer2 자율 메타(apm Mission 흡수). NULL = 일반 Mission.
311
312
  this.addColumnIfMissing('tox_missions', 'autopilot_json', 'TEXT');
313
+ this.addColumnIfMissing('tox_missions', 'project_id', 'TEXT');
314
+ this.db.exec('CREATE INDEX IF NOT EXISTS idx_tox_missions_project ON tox_missions(project_id)');
312
315
  this.addColumnIfMissing('tox_executions', 'host_id', 'TEXT');
313
316
  this.addColumnIfMissing('tox_executions', 'hostname', 'TEXT');
314
317
  this.db.exec('CREATE INDEX IF NOT EXISTS idx_tox_executions_host ON tox_executions(host_id, started_at)');
@@ -587,8 +590,8 @@ export class TaskStore {
587
590
  `INSERT OR REPLACE INTO tox_missions (
588
591
  id, created_at, updated_at, closed_at, title, description, intent,
589
592
  source_json, status, priority, task_ids_json, goal_slug, notes_json,
590
- autopilot_json
591
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
593
+ autopilot_json, project_id
594
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
592
595
  )
593
596
  .run(
594
597
  mission.id,
@@ -605,6 +608,7 @@ export class TaskStore {
605
608
  mission.goalSlug ?? null,
606
609
  JSON.stringify([...mission.notes]),
607
610
  mission.autopilot ? JSON.stringify(mission.autopilot) : null,
611
+ mission.projectId ?? null,
608
612
  ));
609
613
  }
610
614
 
@@ -616,7 +620,7 @@ export class TaskStore {
616
620
  return this.rowToMission(row);
617
621
  }
618
622
 
619
- listMissions(opts: { status?: MissionStatus; goalSlug?: string } = {}): Mission[] {
623
+ listMissions(opts: { status?: MissionStatus; goalSlug?: string; projectId?: string } = {}): Mission[] {
620
624
  const where: string[] = [];
621
625
  const params: Array<string | number | null> = [];
622
626
  if (opts.status !== undefined) {
@@ -627,6 +631,10 @@ export class TaskStore {
627
631
  where.push('goal_slug = ?');
628
632
  params.push(opts.goalSlug);
629
633
  }
634
+ if (opts.projectId !== undefined) {
635
+ where.push('project_id = ?');
636
+ params.push(opts.projectId);
637
+ }
630
638
  const sql =
631
639
  'SELECT * FROM tox_missions' +
632
640
  (where.length > 0 ? ' WHERE ' + where.join(' AND ') : '') +
@@ -729,6 +737,7 @@ export class TaskStore {
729
737
  priority: row.priority ?? undefined,
730
738
  taskIds: Object.freeze(JSON.parse(row.task_ids_json) as string[]),
731
739
  goalSlug: row.goal_slug ?? undefined,
740
+ ...(row.project_id != null ? { projectId: row.project_id } : {}),
732
741
  notes: Object.freeze(JSON.parse(row.notes_json) as string[]),
733
742
  autopilot: row.autopilot_json
734
743
  ? (JSON.parse(row.autopilot_json) as Mission['autopilot'])
@@ -7,14 +7,14 @@
7
7
 
8
8
  import { randomBytes } from 'node:crypto';
9
9
  import { spawnSync } from 'node:child_process';
10
- import { isAbsolute } from 'node:path';
10
+ import { isAbsolute, resolve } from 'node:path';
11
11
  import { getUserConfig } from '../../user-config.js';
12
12
  import { debug } from '../../debug/log.js';
13
13
  import { effectiveInstanceRoot } from '../../instance/resolve.js';
14
14
  import { collectPodArtifacts } from './pod-artifact-return.js';
15
15
  import { podBunCacheVolume } from './pod-bun-cache.js';
16
16
  import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
17
- import { readSkillEnvFiles } from './pod-skills.js';
17
+ import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
18
18
  import { podSourceScript, type PodSource } from './pod-source-receive.js';
19
19
  import {
20
20
  POD_CHILD_REQUESTS,
@@ -30,6 +30,24 @@ import {
30
30
  /** CLI `--deadline` 생략 시 — 기존 Pod Job 수명 상한과 같다. */
31
31
  export const POD_COMMAND_DEADLINE_SECONDS = POD_JOB_DEADLINE_SECONDS;
32
32
 
33
+ export const POD_NETWORK_SKILLS = ['omni-crawl', 'omni-digest'] as const;
34
+ export const POD_LITE_IMAGE = 'elanous-harness-lite:local';
35
+
36
+ export const POD_LITE_MEMORY_LIMIT = '2Gi';
37
+
38
+ /** POD7 must-fix: the skill list alone can't tell a network-only job from one that needs ffmpeg/browser — so lite is
39
+ * only ever chosen when the caller says so (`lite`), and then only for network skills without a clone. Anything we
40
+ * can't judge keeps the full image. A lite request that doesn't fit is refused with the reason, not silently widened. */
41
+ export function podCommandImageFor(skills: readonly string[], clone: boolean, lite = false): string {
42
+ if (!lite) return 'elanous-harness:local';
43
+ if (clone) throw new Error('pod command: --lite 는 clone 없는 명령만 받는다(lite 이미지는 git·빌드 도구가 적다)');
44
+ const outside = skills.filter((skill) => !(POD_NETWORK_SKILLS as readonly string[]).includes(skill));
45
+ if (skills.length === 0 || outside.length > 0) {
46
+ throw new Error(`pod command: --lite 는 네트워크 스킬(${POD_NETWORK_SKILLS.join('·')})만 받는다${outside.length ? ` — 벗어난 스킬: ${outside.join(', ')}` : ' — --skill 이 없다'}`);
47
+ }
48
+ return POD_LITE_IMAGE;
49
+ }
50
+
33
51
  const COMMAND_LOG_CHARS = 80;
34
52
 
35
53
  const GATE = `ok=0
@@ -212,8 +230,10 @@ export interface RunPodCommandOptions {
212
230
  clone?: boolean;
213
231
  hostMirror?: string;
214
232
  bunCache?: string;
215
- /** 컨테이너 메모리 한도(기본 16Gi). */
233
+ /** 컨테이너 메모리 한도(기본 16Gi · lite 면 2Gi). */
216
234
  memoryLimit?: string;
235
+ /** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
236
+ lite?: boolean;
217
237
  source?: PodSource;
218
238
  ghToken?: () => string;
219
239
  deadlineSeconds?: number;
@@ -266,7 +286,8 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
266
286
  const baseKubectl = options.kubectl ?? defaultKubectl;
267
287
  const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
268
288
  const namespace = options.namespace ?? 'elanous-test';
269
- const image = options.image ?? 'elanous-harness:local';
289
+ const image = options.image ?? podCommandImageFor(skills, options.clone === true, options.lite === true);
290
+ const memoryLimit = options.memoryLimit ?? (image === POD_LITE_IMAGE ? POD_LITE_MEMORY_LIMIT : undefined);
270
291
  const repoUrl = options.repoUrl ?? 'https://github.com/ElanvitalAI/elanous';
271
292
  const deadlineSeconds = options.deadlineSeconds ?? POD_COMMAND_DEADLINE_SECONDS;
272
293
  // POD1 (10-01): two launches in the same moment got the same `si-cmd-<time>` and the failing one's cleanup
@@ -328,8 +349,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
328
349
  localImageCommit: () => podImageFreshness({ image }).imageCommit,
329
350
  });
330
351
  if (pool && member) {
331
- const { podSkillsDigest, resolvePodSkills } = await import('./pod-skills.js');
332
- const localSkillsDigest = options.kubectl ? null : podSkillsDigest(resolvePodSkills(env).skills).digest;
352
+ const localSkillsDigest = options.kubectl ? null : image === POD_LITE_IMAGE
353
+ ? podSkillsDigest(POD_NETWORK_SKILLS, resolve(import.meta.dir, '../../../skills')).digest
354
+ : podSkillsDigest(resolvePodSkills(env).skills).digest;
333
355
  const syncs = await (options.syncImages ?? syncPoolImages)([member], image, imageCommit, { localSkillsDigest });
334
356
  const synced = syncs.get(member.context);
335
357
  if (synced && !synced.ok) throw new Error(`pod command: 이미지 판을 못 맞췄다: ${synced.detail}`);
@@ -345,7 +367,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
345
367
  name, namespace, launch, image: member?.imageRef ?? image,
346
368
  ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
347
369
  repoUrl, command, skills, ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
348
- ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(options.memoryLimit ? { memoryLimit: options.memoryLimit } : {}), deadlineSeconds,
370
+ ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(memoryLimit ? { memoryLimit } : {}), deadlineSeconds,
349
371
  ...(options.runId ? { runId: options.runId } : {}),
350
372
  });
351
373
  kubectl(['-n', namespace, 'delete', 'job', '-l', own, '--ignore-not-found']);