elanous 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (694) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  7. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  20. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  25. package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f972fc1c00a62e88.js → page-b12b6d2f8d2d1aea.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/{page-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -0
  152. package/apps/pwa/out/ops/seats/index.txt +30 -0
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -0
  178. package/apps/pwa/out/today/index.txt +33 -0
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/field/field-feed.yaml +2 -0
  194. package/graphs/implement-loop.yaml +1 -1
  195. package/graphs/intake/intake-daily.yaml +2 -1
  196. package/graphs/ops/recipes.yaml +3 -0
  197. package/graphs/ops/secret-exposure.yaml +24 -0
  198. package/graphs/release/recipes.yaml +3 -0
  199. package/graphs/release/release-loop.yaml +4 -1
  200. package/graphs/video/explainer-line.yaml +2 -2
  201. package/package.json +2 -1
  202. package/plugins/card-followup/graphs/run-step.ts +48 -13
  203. package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
  204. package/plugins/doc-draft/graphs/run-step.ts +13 -6
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/ci-pwa-build-gate.ts +160 -0
  216. package/scripts/context-hooks/claude-stop.sh +4 -0
  217. package/scripts/context-hooks/emit.ts +24 -0
  218. package/scripts/context-hooks/post-tool-use.sh +4 -0
  219. package/scripts/coord-channel-watch.sh +54 -8
  220. package/scripts/coord-digest.ts +199 -0
  221. package/scripts/coord-post.sh +60 -3
  222. package/scripts/coord-requests-bridge.ts +143 -0
  223. package/scripts/field-feed/lib.ts +4 -0
  224. package/scripts/fleet/node-setup.sh +20 -3
  225. package/scripts/homebrew-formula-bump.ts +69 -0
  226. package/scripts/install.ps1 +68 -9
  227. package/scripts/install.sh +39 -12
  228. package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
  229. package/scripts/lib/tui-regress-checks.ts +146 -0
  230. package/scripts/marketing/measure-site-numbers.ts +169 -0
  231. package/scripts/measure-gate-shards.ts +309 -0
  232. package/scripts/memory-lifecycle-cycle.ts +2 -2
  233. package/scripts/mission-request-judge.ts +31 -1
  234. package/scripts/morning-report.ts +2 -2
  235. package/scripts/opportunity-scan.ts +1 -1
  236. package/scripts/ops-now-probe.ts +327 -0
  237. package/scripts/publish-internal-dist.ts +11 -1
  238. package/scripts/release-loop/auto-approve-node.ts +21 -4
  239. package/scripts/release-loop/cut-branch.ts +84 -0
  240. package/scripts/release-loop/cutoff.ts +19 -8
  241. package/scripts/release-loop/gate-node.ts +14 -13
  242. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  243. package/scripts/release-loop/node-verdict.ts +3 -3
  244. package/scripts/release-loop/ops-upgrade-node.ts +72 -16
  245. package/scripts/release-loop/release-readiness.ts +9 -0
  246. package/scripts/release-loop/tui-node-checks.ts +42 -0
  247. package/scripts/release-loop/tui-sim-node.ts +32 -8
  248. package/scripts/release-loop/unattended-release.ts +5 -3
  249. package/scripts/release-loop/version-node.ts +112 -13
  250. package/scripts/repo-watch-cycle.ts +1 -1
  251. package/scripts/retro-cycle.ts +2 -2
  252. package/scripts/schedule-health-report.ts +1 -1
  253. package/scripts/signal-digest-cycle.ts +2 -7
  254. package/scripts/signal-digest-photo.ts +11 -0
  255. package/scripts/storyboard/storyboard.ts +5 -161
  256. package/scripts/tech1-public-measure.ts +94 -0
  257. package/scripts/test-diet/lib.ts +30 -1
  258. package/scripts/test-diet/node.ts +83 -8
  259. package/scripts/test-timeout-audit.ts +114 -0
  260. package/scripts/tree-sync-alert.ts +1 -1
  261. package/scripts/tui-regress.ts +71 -0
  262. package/scripts/ux/demo-rehearsal.ts +243 -0
  263. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  264. package/scripts/waitlist-daily-digest.ts +1 -1
  265. package/skills/diagram-master/SKILL.md +366 -0
  266. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  267. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  268. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  269. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  270. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  271. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  272. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  273. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  274. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  275. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  276. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  277. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  278. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  279. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  280. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  281. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  282. package/skills/diagram-master/references/examples/README.md +69 -0
  283. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  284. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  285. package/skills/diagram-master/references/pyproject.toml +16 -0
  286. package/skills/diagram-master/references/quality-checklist.md +33 -0
  287. package/skills/diagram-master/references/routing-guide.md +164 -0
  288. package/skills/diagram-master/references/uv.lock +1356 -0
  289. package/skills/explainer-video/SKILL.md +4 -0
  290. package/skills/explainer-video/engine/reel.mjs +18 -13
  291. package/skills/explainer-video/engine/reel.sh +24 -5
  292. package/skills/explainer-video/engine/stitch.mjs +145 -0
  293. package/skills/google-workspace/SKILL.md +33 -0
  294. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  295. package/skills/grill-me/SKILL.md +1 -1
  296. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  297. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  298. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  299. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  300. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  301. package/skills/omni-crawl/SKILL.md +21 -11
  302. package/skills/omni-crawl/scripts/main.ts +6 -6
  303. package/skills/omni-crawl/src/router.ts +3 -3
  304. package/skills/omni-digest/SKILL.md +17 -9
  305. package/skills/omni-digest/digest.md +2 -2
  306. package/skills/omni-digest/src/fetch.ts +30 -3
  307. package/skills/pitch-deck/SKILL.md +36 -0
  308. package/skills/pitch-deck/template.html +80 -0
  309. package/skills/youtube-master/SKILL.md +163 -0
  310. package/skills/youtube-master/package-lock.json +558 -0
  311. package/skills/youtube-master/package.json +13 -0
  312. package/skills/youtube-master/references/study-note-template.md +124 -0
  313. package/skills/youtube-master/scripts/main.ts +435 -0
  314. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  315. package/skills/youtube-master/src/audio.ts +63 -0
  316. package/skills/youtube-master/src/domain-staging.ts +50 -0
  317. package/skills/youtube-master/src/env.ts +36 -0
  318. package/skills/youtube-master/src/obsidian.ts +155 -0
  319. package/skills/youtube-master/src/router.ts +110 -0
  320. package/skills/youtube-master/src/stt.ts +199 -0
  321. package/skills/youtube-master/src/study-note.ts +175 -0
  322. package/skills/youtube-master/src/summarize.ts +358 -0
  323. package/skills/youtube-master/src/transcript.ts +76 -0
  324. package/skills/youtube-master/src/types.ts +91 -0
  325. package/skills/youtube-master/src/util.ts +93 -0
  326. package/skills/youtube-master/src/youtube.ts +70 -0
  327. package/skills/youtube-master/tsconfig.json +13 -0
  328. package/src/acp/codex-approval-adapter.ts +9 -3
  329. package/src/acp/core-turn-bridge.ts +117 -18
  330. package/src/acp/fact-question.ts +11 -0
  331. package/src/acp/server.ts +53 -9
  332. package/src/acp/tool-approval.ts +126 -0
  333. package/src/acp/turn-runner.ts +36 -0
  334. package/src/agent/monad-agent-turn.ts +8 -0
  335. package/src/agent-mission/driver.ts +80 -10
  336. package/src/agent-mission/pty-decision.ts +71 -0
  337. package/src/agent-mission/review-loop.ts +30 -0
  338. package/src/ask-user-question/pending-questions.ts +25 -10
  339. package/src/ask-user-question/types.ts +9 -0
  340. package/src/auth/setup-link-tokens.ts +16 -5
  341. package/src/autopilot/build/integrity-gate.ts +12 -0
  342. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  343. package/src/autopilot/tool-registry.ts +2 -0
  344. package/src/boot/daemon-prompt-turn.ts +8 -0
  345. package/src/boot/daemon-runtime.ts +9 -3
  346. package/src/boot/daemon-tools/index.ts +8 -0
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/boot/daemon-tools/web-search.ts +4 -0
  349. package/src/card-followup/core.ts +109 -0
  350. package/src/chat/ctrl-c-in-input.ts +14 -0
  351. package/src/chat/index.ts +53 -0
  352. package/src/chat/pickers/state.ts +6 -2
  353. package/src/cli/agent-cli.ts +7 -0
  354. package/src/cli/decisions-cli.ts +25 -3
  355. package/src/cli/doctor-bundle-upload.ts +68 -0
  356. package/src/cli/doctor-cli.ts +38 -4
  357. package/src/cli/drive-input-jail.ts +101 -0
  358. package/src/cli/hooks-cli.ts +17 -3
  359. package/src/cli/make-cli.ts +43 -0
  360. package/src/cli/ops-cli.ts +20 -0
  361. package/src/cli/persona-cli.ts +90 -4
  362. package/src/cli/plugin-cli.ts +31 -22
  363. package/src/cli/pod-cli.ts +61 -2
  364. package/src/cli/pr-cli.ts +82 -17
  365. package/src/cli/pty-drive-cli.ts +41 -7
  366. package/src/cli/pty-drive-verdict.ts +40 -0
  367. package/src/cli/pwa-stop.ts +163 -13
  368. package/src/cli/pwa-test.ts +3 -0
  369. package/src/cli/release-cli.ts +80 -24
  370. package/src/cli/self-update.ts +14 -0
  371. package/src/cli/setup-cli.ts +43 -1
  372. package/src/cli/skills-cli.ts +17 -1
  373. package/src/cli/storyboard-cli.ts +37 -0
  374. package/src/cli/test-state-dir-flag.ts +11 -4
  375. package/src/connectors/linear.ts +146 -0
  376. package/src/context-bus/claude-hooks-install.ts +10 -0
  377. package/src/context-bus/context-now-surfaces.ts +48 -0
  378. package/src/context-bus/context-now.ts +104 -0
  379. package/src/context-bus/coord-events.ts +115 -0
  380. package/src/context-bus/external-events.ts +52 -0
  381. package/src/context-bus/long-term-memory.ts +108 -0
  382. package/src/dashboard/dashboard-boot-fixture.ts +23 -0
  383. package/src/dashboard/index.ts +63 -21
  384. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
  385. package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
  386. package/src/decisions/decision-cards.ts +58 -3
  387. package/src/decisions/decision-ledger.ts +85 -6
  388. package/src/decisions/decision-linear-projection.ts +157 -0
  389. package/src/decisions/web-push-decision-cards.ts +50 -0
  390. package/src/directive/interpretation-card.ts +36 -0
  391. package/src/discord/sprint21-runtime.ts +5 -1
  392. package/src/discord-self-message.ts +32 -0
  393. package/src/discord-slash-wire.ts +5 -1
  394. package/src/discord.ts +19 -2
  395. package/src/domains/coo-admin-tool.ts +62 -0
  396. package/src/domains/core-tools.ts +13 -4
  397. package/src/domains/elanous-card.ts +29 -0
  398. package/src/domains/ops-facts-tool.ts +76 -0
  399. package/src/domains/outbound-alert.ts +46 -13
  400. package/src/domains/release-tool.ts +168 -0
  401. package/src/domains/telegram-kind-route.ts +65 -9
  402. package/src/exec-requests/default-outputs.ts +25 -0
  403. package/src/exec-requests/planner.ts +106 -28
  404. package/src/exec-requests/runner.ts +123 -12
  405. package/src/exec-requests/store.ts +11 -2
  406. package/src/execution-loop/launch-gate.ts +100 -0
  407. package/src/field/field-media.ts +10 -7
  408. package/src/field/field-reel.ts +19 -5
  409. package/src/field-note/index.ts +201 -0
  410. package/src/field-note/transcribe.ts +248 -0
  411. package/src/git-fs/worktree.ts +45 -6
  412. package/src/graph-kinds/registry.ts +3 -3
  413. package/src/graph-runner/graph-approval-card.ts +113 -0
  414. package/src/graph-runner/graph-cli.ts +189 -4
  415. package/src/graph-runner/graph-grow-llm.ts +37 -0
  416. package/src/graph-runner/graph-grow.ts +47 -0
  417. package/src/graph-runner/graph-notify.ts +25 -3
  418. package/src/graph-runner/runner.ts +453 -35
  419. package/src/grok/agent-search.ts +8 -2
  420. package/src/guardian/secret-exposure-scan.ts +101 -0
  421. package/src/harness/browser-verify.ts +25 -2
  422. package/src/harness/harness-cli-command.ts +478 -42
  423. package/src/harness/harness-incidents-writer.fixture.ts +24 -0
  424. package/src/harness/harness-incidents.ts +129 -0
  425. package/src/harness/harness-pod-dispatch.ts +43 -23
  426. package/src/harness/harness-seams.ts +38 -4
  427. package/src/harness/harness-stop.ts +75 -6
  428. package/src/harness/launch-registry.ts +91 -0
  429. package/src/harness/process-garbage.ts +5 -3
  430. package/src/hitl/clarification-policy.ts +3 -1
  431. package/src/hooks/dispatch.ts +82 -0
  432. package/src/hooks/expose.ts +254 -0
  433. package/src/hooks/github-shadow.ts +108 -0
  434. package/src/hooks/providers.ts +71 -5
  435. package/src/hooks/queue.ts +1 -1
  436. package/src/hooks/receiver.ts +21 -20
  437. package/src/index.ts +206 -49
  438. package/src/intake-plane/author-goals.ts +37 -4
  439. package/src/intake-plane/categorize.ts +18 -46
  440. package/src/intake-plane/check.ts +3 -0
  441. package/src/intake-plane/discord-seat-work.ts +57 -2
  442. package/src/intake-plane/front-route-classifier.ts +33 -39
  443. package/src/intake-plane/persona-answer.ts +30 -0
  444. package/src/intake-plane/runtime-callables.ts +8 -1
  445. package/src/intake-plane/seat-doc-route.ts +170 -6
  446. package/src/intake-plane/telegram-seat-work.ts +80 -4
  447. package/src/intake-plane/telegram-work.ts +1 -0
  448. package/src/intake-plane/wish-folder.ts +67 -0
  449. package/src/intent-gate/gate.ts +30 -10
  450. package/src/live/detail-switch.ts +5 -0
  451. package/src/llm/difficulty.ts +57 -0
  452. package/src/llm/judge-layer.ts +101 -0
  453. package/src/llm/mission-router.ts +33 -19
  454. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  455. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  456. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  457. package/src/loops/contract/loop-agent.schema.json +138 -0
  458. package/src/loops/contract/validate.ts +64 -0
  459. package/src/loops/registry.ts +20 -6
  460. package/src/market/signed-index.ts +4 -0
  461. package/src/maturity/bot-command-maturity.ts +45 -0
  462. package/src/maturity/cli-maturity.ts +34 -0
  463. package/src/maturity/feature-maturity.ts +120 -1
  464. package/src/maturity/tui-slash-maturity.ts +31 -0
  465. package/src/memory.ts +32 -4
  466. package/src/model-tier/index.ts +2 -2
  467. package/src/model-tier/tier-resolver.ts +20 -20
  468. package/src/model-tier/types.ts +6 -6
  469. package/src/mss/logging/log-store.ts +15 -0
  470. package/src/nexus/api/config-model-tier.ts +5 -4
  471. package/src/nexus/api/exec-requests.ts +33 -3
  472. package/src/nexus/api/fabric-plans.ts +53 -0
  473. package/src/nexus/api/harness-api.ts +5 -1
  474. package/src/nexus/api/health.ts +2 -0
  475. package/src/nexus/api/http-server.ts +89 -1
  476. package/src/nexus/api/inside-events.ts +226 -0
  477. package/src/nexus/api/meta-api.ts +32 -8
  478. package/src/nexus/api/missions.ts +6 -1
  479. package/src/nexus/api/ops-api.ts +10 -1
  480. package/src/nexus/api/ops-seats-sources.ts +37 -7
  481. package/src/nexus/api/ops-seats.ts +49 -6
  482. package/src/nexus/api/outputs-route.ts +44 -0
  483. package/src/nexus/api/seat-requests.ts +132 -10
  484. package/src/nexus/api/sessions-store.ts +42 -0
  485. package/src/nexus/api/setup-codex-login.ts +160 -0
  486. package/src/nexus/api/sub-seat-charters.ts +34 -0
  487. package/src/nexus/api/tabs-mutations.ts +3 -1
  488. package/src/nexus/api/trace.ts +18 -6
  489. package/src/nexus/api/usage-api.ts +102 -0
  490. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  491. package/src/nexus/api/workflows.ts +80 -6
  492. package/src/nexus/index.ts +47 -4
  493. package/src/nexus/kinds/webterm.ts +2 -1
  494. package/src/nexus/webterm/pty.ts +6 -2
  495. package/src/onboarding/cli-auth-status.ts +80 -0
  496. package/src/onboarding/first-run.ts +89 -0
  497. package/src/onboarding/lan-address.ts +45 -0
  498. package/src/onboarding/voice-ai.ts +3 -3
  499. package/src/onboarding/web-first.ts +119 -24
  500. package/src/onboarding.ts +4 -0
  501. package/src/ops-now/ops-now-refresh.ts +100 -0
  502. package/src/org/seat-budget.ts +48 -0
  503. package/src/org/stall-escalation.ts +63 -0
  504. package/src/outputs/ledger.ts +120 -0
  505. package/src/persona/persona-todo.ts +79 -0
  506. package/src/persona/presets.ts +116 -2
  507. package/src/persona/team-set.ts +155 -0
  508. package/src/plugins/install/plugin-install.ts +14 -0
  509. package/src/plugins/maker/market-bundle.ts +109 -0
  510. package/src/plugins/maker/plugin-maker.ts +254 -11
  511. package/src/plugins/maker/wizard-generate.ts +103 -0
  512. package/src/pod-lease/admission.ts +150 -0
  513. package/src/pod-lease/dependency-state.ts +85 -0
  514. package/src/pod-lease/host-lease.ts +127 -0
  515. package/src/project/project-store.ts +115 -0
  516. package/src/project/project-suggestion.ts +16 -0
  517. package/src/project/session-context.ts +24 -0
  518. package/src/release-loop/checklist.ts +79 -5
  519. package/src/release-loop/feature-store.ts +159 -24
  520. package/src/release-loop/next-md-merge.ts +58 -0
  521. package/src/release-loop/release-note.ts +59 -4
  522. package/src/release-loop/release-schedule.ts +53 -0
  523. package/src/repl/index.ts +7 -0
  524. package/src/seat-dispatch/ceo-commands.ts +41 -8
  525. package/src/seat-dispatch/ceo-intent.ts +38 -0
  526. package/src/seat-dispatch/seat-ask.ts +130 -0
  527. package/src/seat-dispatch/seat-questions.ts +100 -0
  528. package/src/seat-loop/seat-loop.ts +750 -0
  529. package/src/seat-loop/seat-report.ts +99 -0
  530. package/src/self-dev/decompose.ts +66 -11
  531. package/src/self-dev/dev-cli.ts +4 -1
  532. package/src/self-dev/dev-pipeline.ts +37 -1
  533. package/src/self-dev/draft-sweep.ts +38 -33
  534. package/src/self-dev/draft-triage-rules.ts +8 -5
  535. package/src/self-dev/fabric-plan-core.ts +297 -0
  536. package/src/self-dev/orchestrate.ts +36 -4
  537. package/src/self-dev/release-path-guard.ts +62 -0
  538. package/src/self-dev/run-store.ts +10 -1
  539. package/src/self-dev/shard-aggregate.ts +230 -0
  540. package/src/self-dev/shard-placement.ts +60 -0
  541. package/src/self-dev/shard-plan.ts +48 -0
  542. package/src/self-dev/shard-pod-run.ts +77 -0
  543. package/src/self-dev/shard-run.ts +105 -0
  544. package/src/self-implement/execution-clarification.ts +115 -0
  545. package/src/self-implement/gate-baseline.ts +1 -1
  546. package/src/self-implement/gate-cli.ts +46 -4
  547. package/src/self-implement/gate-scope.ts +37 -7
  548. package/src/self-implement/graph-variant.ts +171 -0
  549. package/src/self-implement/harness-policy-gates.ts +1 -1
  550. package/src/self-implement/headless-elanous-driver.ts +22 -3
  551. package/src/self-implement/host-regate.ts +22 -1
  552. package/src/self-implement/importer-test-index.ts +2 -1
  553. package/src/self-implement/l8-merge-queue.ts +130 -0
  554. package/src/self-implement/orchestrator.ts +279 -12
  555. package/src/self-implement/pipeline-shape.ts +1 -1
  556. package/src/self-implement/route-consumer-test-index.ts +122 -0
  557. package/src/self-implement/run-status-mapping.ts +5 -3
  558. package/src/self-implement/seams.ts +72 -11
  559. package/src/self-implement/test-seams.ts +1 -0
  560. package/src/self-implement/uncommitted-work.ts +59 -0
  561. package/src/session/chat.ts +2 -0
  562. package/src/session/index.ts +45 -13
  563. package/src/shell-env-bootstrap.ts +17 -0
  564. package/src/skills/gift-install.ts +215 -0
  565. package/src/skills/tools/web-search.ts +4 -1
  566. package/src/steward/directive.ts +51 -2
  567. package/src/steward/launch.ts +266 -0
  568. package/src/steward/outcome-notify.ts +115 -0
  569. package/src/steward/steward-cards.ts +25 -11
  570. package/src/steward/triage-plan.ts +32 -4
  571. package/src/steward/triage.ts +129 -13
  572. package/src/steward/working-backwards.ts +64 -0
  573. package/src/storyboard/storyboard.ts +141 -0
  574. package/src/task-cards/card-cli.ts +25 -1
  575. package/src/task-cards/card-store.ts +2 -2
  576. package/src/task-orchestrator/mission.ts +5 -0
  577. package/src/task-orchestrator/store.ts +12 -3
  578. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  579. package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
  580. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  581. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  582. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  583. package/src/task-orchestrator/types.ts +2 -0
  584. package/src/telegram-card-followup.ts +153 -0
  585. package/src/telegram-commands.ts +10 -1
  586. package/src/telegram-project-command.ts +71 -0
  587. package/src/telegram-report.ts +29 -19
  588. package/src/telegram-run.ts +7 -0
  589. package/src/telegram.ts +58 -11
  590. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  591. package/src/tool-runtime/types.ts +4 -0
  592. package/src/tui-client/dashboard-session.ts +2 -0
  593. package/src/user-config.ts +216 -27
  594. package/src/version/packed-revision.json +1 -1
  595. package/src/web-push/notify-exec-request.ts +32 -0
  596. package/src/web-search/grok.ts +7 -1
  597. package/src/web-search/index.ts +28 -1
  598. package/src/web-search/provider.ts +4 -0
  599. package/src/web-search/x-intent.ts +5 -0
  600. package/src/workflow-runtime/executor.ts +277 -47
  601. package/src/workflow-runtime/index.ts +1 -0
  602. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  603. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  604. package/src/workflow-runtime/schema.ts +79 -4
  605. package/src/workflow-runtime/types.ts +35 -4
  606. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  617. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  618. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
  622. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  692. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
  693. package/src/dashboard/turn-typeahead-echo.ts +0 -23
  694. /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -26,6 +26,7 @@ import { buildAutonomousToolSpecs, dispatchAutonomousTool, isAutonomousTool, del
26
26
  import { isToolSearchCall, routeToolSearch } from '../skills/tools/tool-search-route.js';
27
27
  import { financeEnabled, financeAgentSystemPrompt, marketClock } from '../domains/finance.js';
28
28
  import { buildFinanceTools } from '../domains/finance-tools.js';
29
+ import { dispatchReleaseChange } from '../domains/release-tool.js';
29
30
  import { surfaceEventsDbPath, openSurfaceEventsDb, recentSentDigest, recordInboundTurn } from '../domains/surface-events.js';
30
31
  import { elanousSelfAccessPrompt, elanousSelfAmbientParts } from './self-ambient.js';
31
32
  import { localRefGroundingAmbient } from './ref-grounding.js';
@@ -188,6 +189,13 @@ export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource,
188
189
  },
189
190
  });
190
191
  }
192
+ if (name === 'release_change') {
193
+ return dispatchReleaseChange(args, {
194
+ surface: 'chat', sessionId: opts.sessionId,
195
+ ...(opts.verifiedOwner ? { verifiedOwner: opts.verifiedOwner } : {}),
196
+ ...(surfaceChannels ? { confirmChannels: surfaceChannels } : {}),
197
+ });
198
+ }
191
199
  // Thread the turn's abort signal so a long in-flight Bash is killed by
192
200
  // `/cancel` (dispatchBash SIGTERMs its child on abort).
193
201
  return baseDispatch(name, args, opts.signal);
@@ -20,6 +20,8 @@ import { configuredWorktreeRoot } from '../user-config.js';
20
20
  import { worktreeHasChanges, commitWorktree, changedFiles } from '../self-implement/seams.js';
21
21
  import { streamLLM, type LLMMessage } from '../llm.js';
22
22
  import { debug } from '../debug/log.js';
23
+ import { emitPtyDecision, type DecisionInput } from './pty-decision.js';
24
+ import { observeExternalEvent } from '../context-bus/external-events.js';
23
25
  import { emitDecision } from '../live/detail-switch.js';
24
26
  import { resolvePtyWebAddress } from '../cli/pty-web-address.js';
25
27
  import { reemitPtyUsage } from '../budget/pty-usage-reemit.js';
@@ -522,6 +524,8 @@ export interface AgentMissionDeps {
522
524
  createWorktree?: typeof createWorktree;
523
525
  recordWorktreeProvenance?: typeof recordHarnessWorktreeProvenance;
524
526
  runControlLoop?: typeof runPtyControlLoop;
527
+ /** Capture decisions in tests without replacing the process-wide debug logger. */
528
+ emitPtyDecision?: typeof emitPtyDecision;
525
529
  /** Inject controller responses while keeping the production control loop. */
526
530
  controlStream?: StreamLLMFn;
527
531
  resolvePtyWebAddress?: typeof resolvePtyWebAddress;
@@ -830,6 +834,7 @@ export interface MissionControlBrainOpts {
830
834
  readonly handoffEnabled?: boolean;
831
835
  /** Screen-grounded brain summary for the next backend, never the raw PTY screen. */
832
836
  readonly onSummary?: (summary: string) => void;
837
+ readonly onDecision?: (text: string, reply?: { question: string; answer: string }) => void;
833
838
  }
834
839
 
835
840
  /** 기존 5-action mission 판단을 canonical PTY control-loop 결정으로 축소한다. search는 이 경계에서만
@@ -855,7 +860,7 @@ export function createMissionControlBrain(opts: MissionControlBrainOpts): RunSup
855
860
  행동(action):
856
861
  - "wait": ${backendName} 가 아직 작업 중(도구 실행/생성)이면 대기.
857
862
  - "verify": ${backendName} 가 MISSION-COMPLETE/완료를 주장하면 증거 게이트(내가 실행)로 검증. 완료주장 시 이걸 우선.
858
- - "send": ${backendName} 가 멈추거나 계속 진행이 필요하면 짧고 명확한 지시(text).
863
+ - "send": ${backendName} 가 멈추거나 계속 진행이 필요하면 짧고 명확한 지시(text). 화면의 질문에 직접 답하는 경우에만 reason 을 Answering question: <화면의 질문 원문> 으로 기록하라. 다른 send 의 reason 은 종전처럼 행동 이유를 적어라.
859
864
  - "search": ${backendName} 가 정보/라이브러리/문법/외부자원에 막혔으면 omni-crawl 로 조사(query). ⭐외부 힌트 없이 스스로 판단.
860
865
  ${opts.handoffEnabled ? ` - "handoff": 다른 담당자로 넘길 때 to(codex/claude/elanous), mission(다음 지시), carry(diff/summary 선택). carry=summary 면 reason 에 화면에서 확인한 리뷰 지적을 구체적으로 요약하라(다음 backend 에 전달된다). claude 리뷰 뒤 지적은 codex 에 summary 로 되돌려라. elanous 는 증거 게이트와 PR.
861
866
  - "ask-human": 화면에 로그인 URL/장치 코드가 보이면 reason, url/code(보이는 것만). 토큰·자격파일을 열지 마라.` : ''}${opts.provision ? `
@@ -873,6 +878,12 @@ ${opts.handoffEnabled ? ` - "handoff": 다른 담당자로 넘길 때 to(codex/c
873
878
  history.push(`s${obs.step}:${decision.action}`);
874
879
  debug.log('agent-mission', 'brain', { step: obs.step, action: decision.action,
875
880
  ...(decision.action === 'ask-human' ? {} : { reason: decision.reason.slice(0, 120) }) });
881
+ // A '?' on screen alone does not establish that this send answered it. Only an
882
+ // explicit question citation in the brain's reason can attribute the reply.
883
+ const citedQuestion = /^Answering question:\s*(.+\?)\s*$/i.exec(decision.reason)?.[1]?.trim();
884
+ const question = citedQuestion && classifierFrameLines(obs.screen).find((line) => line === citedQuestion);
885
+ opts.onDecision?.(`step ${obs.step}: ${decision.action}${decision.action === 'ask-human' ? '' : ` — ${decision.reason || decision.text || decision.query || ''}`}`,
886
+ decision.action === 'send' && decision.text?.trim() && question ? { question, answer: decision.text } : undefined);
876
887
  if (decision.reason && decision.action !== 'ask-human') opts.onSummary?.(decision.reason.slice(0, 2000));
877
888
  if (decision.action === 'handoff' && decision.to && decision.mission) return { action: 'handoff', to: decision.to, mission: decision.mission, ...(decision.carry ? { carry: decision.carry } : {}) };
878
889
  if (decision.action === 'ask-human') return { action: 'ask-human', reason: decision.reason, ...(decision.url ? { url: decision.url } : {}), ...(decision.code ? { code: decision.code } : {}) };
@@ -974,6 +985,7 @@ export function makeMissionObserveStep(deps: {
974
985
  bus: ChannelBus;
975
986
  ident: { ptyId: string; instance: string; runId?: string };
976
987
  now?: () => number;
988
+ onPublishedFrame?: (obs: ControlObservation) => void;
977
989
  }): (obs: ControlObservation, decision: ControlDecision) => Promise<void> {
978
990
  const now = deps.now ?? ((): number => Date.now());
979
991
  let lastFrameState: FrameState | null = null;
@@ -1008,6 +1020,7 @@ export function makeMissionObserveStep(deps: {
1008
1020
  ...(deps.ident.runId ? { runId: deps.ident.runId } : {}),
1009
1021
  ...(pngRef ? { pngRef } : {}),
1010
1022
  });
1023
+ deps.onPublishedFrame?.(obs);
1011
1024
  // capture 는 원 semantics 유지 — 예외 전파(증거/전사 계약 불변).
1012
1025
  await deps.capture(`s${obs.step}-${decision.action}`);
1013
1026
  };
@@ -1574,9 +1587,19 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1574
1587
  if (deps.isMissionAborted?.()) { offLive(); throw new Error('MISSION_ABORTED'); }
1575
1588
  try { h = spawnPty(ptyOpts); }
1576
1589
  catch (error) { offLive(); throw error; }
1577
- deps.onPtyStarted?.(h, () => { if (liveTimer) clearInterval(liveTimer); offLive(); });
1578
- if (deps.isMissionAborted?.()) return { ok: false, reason: 'aborted', worktree: wt.path, branch: wt.branch,
1579
- rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
1590
+ if (backend.name === 'codex') observeExternalEvent({ origin: 'codex-agent-mission', kind: 'started',
1591
+ summary: 'Codex agent mission started', source: `elanous://agent-mission/${encodeURIComponent(runId)}/${encodeURIComponent(h.id)}` });
1592
+ let contextFinished = false;
1593
+ const finishContext = (ok: boolean): void => {
1594
+ if (contextFinished || backend.name !== 'codex') return;
1595
+ contextFinished = true;
1596
+ observeExternalEvent({ origin: 'codex-agent-mission', kind: 'finished',
1597
+ summary: `Codex agent mission ${ok ? 'completed' : 'failed'}`,
1598
+ source: `elanous://agent-mission/${encodeURIComponent(runId)}/${encodeURIComponent(h.id)}` });
1599
+ };
1600
+ deps.onPtyStarted?.(h, () => { if (liveTimer) clearInterval(liveTimer); offLive(); finishContext(false); });
1601
+ if (deps.isMissionAborted?.()) { finishContext(false); return { ok: false, reason: 'aborted', worktree: wt.path, branch: wt.branch,
1602
+ rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' }; }
1580
1603
  const executorRef = buildExecutorPtyRef({
1581
1604
  ptyId: h.id,
1582
1605
  backend: backend.name,
@@ -1589,6 +1612,12 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1589
1612
  process.stderr.write(`[agent-mission] pty=${h.id} watch=${webAddress.webUrl ?? `(web unavailable: ${webAddress.pwaUnavailableReason ?? 'not-resolved'})`}\n`);
1590
1613
  debug.log('agent-mission', 'pty-link', { id: h.id, webUrl: webAddress.webUrl, webUrlSource: webAddress.webUrlSource });
1591
1614
 
1615
+ const decisionIdentity = { missionId: runId, sessionId: runId, terminalId: h.id, agent: backend.name };
1616
+ const decisionEvent = (event: Omit<DecisionInput, keyof typeof decisionIdentity>): void => {
1617
+ try { (deps.emitPtyDecision ?? emitPtyDecision)({ ...decisionIdentity, ...event } as DecisionInput); }
1618
+ catch { /* Observation must not change mission control or handoff. */ }
1619
+ };
1620
+
1592
1621
  // ⭐P2 arbiter: the child is accessMode='auto' (brain-owned), so the driver —
1593
1622
  // the autonomous brain — must write as 'agent' or the arbiter denies it. This
1594
1623
  // makes "protected autonomy" real: a human attaching mid-mission (read) can't
@@ -1615,6 +1644,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1615
1644
  : 'AGENT_YIELDED: PTY 제어가 사람에게 이양됨(takeover) — 자율 미션 중단');
1616
1645
  }
1617
1646
  h['write'](s, 'agent');
1647
+ decisionEvent({ step: 'input', text: s === '\r' ? 'Sent Enter' : `Sent ${s.startsWith('\x1b') ? 'key' : 'text'}: ${s.startsWith('\x1b') ? 'navigation' : s}` });
1618
1648
  };
1619
1649
 
1620
1650
  let seq = 0;
@@ -1638,7 +1668,8 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1638
1668
  if (liveChunks % 20 === 0) debug.log('agent-mission', 'live', { chunks: liveChunks, tail: s.slice(-80).replace(/\s+/g, ' ') });
1639
1669
  }).catch(() => { /* noop */ });
1640
1670
  }, 800);
1641
- const stopLive = (): void => { if (liveTimer) clearInterval(liveTimer); offLive(); };
1671
+ const stopLive = (ok = false): void => { if (liveTimer) clearInterval(liveTimer); offLive(); if (ok) finishContext(true); };
1672
+ try {
1642
1673
 
1643
1674
  // ready + trust — backend 별 신뢰/권한 프롬프트 처리(codex=1, 이후 백엔드는 자체 handler).
1644
1675
  await (deps.awaitMission ? deps.awaitMission(waitForQuiet(h, 1500, 20000)) : waitForQuiet(h, 1500, 20000));
@@ -1648,7 +1679,11 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1648
1679
  // A trust menu can need more than one key (claude: ↓ to «Yes», then Enter) — answer until it is gone, at most 3 times.
1649
1680
  // 🩸 09-29: one pass sent only ↓, the mission text went into the menu and its Enter confirmed «Yes» instead of
1650
1681
  // submitting the mission, which then sat unsent in the input box.
1651
- for (let pass = 0; pass < 3 && backend.handleTrust?.(screen, (s) => drive(s)); pass++) {
1682
+ for (let pass = 0; pass < 3 && backend.handleTrust?.(screen, (s) => {
1683
+ drive(s);
1684
+ // Moving the selection is only input; the trust question is answered when the choice is confirmed.
1685
+ if (s === '\r') decisionEvent({ step: 'answer', text: 'Answered folder trust prompt', detail: { question: 'Trust this folder?', answer: 'Confirm selected choice' } });
1686
+ }); pass++) {
1652
1687
  debug.log('agent-mission', 'trust', { agent: backend.name, action: 'handled', pass });
1653
1688
  const trusted = (async () => { await waitForQuiet(h, 1500, 15000); return capture('trusted'); })();
1654
1689
  screen = await (deps.awaitMission ? deps.awaitMission(trusted) : trusted);
@@ -1761,6 +1796,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1761
1796
  let controllerSummary = deps.previousSummary ?? '';
1762
1797
  let reviewSummary = '';
1763
1798
  let coverageRetries = enhanceActive && checklist.length ? 2 : 0;
1799
+ let pendingAnswer: { text: string; question: string; answer: string } | undefined;
1764
1800
  const search = createMissionSearch({ worktree: wt.path, omniPath });
1765
1801
  const brain = createMissionControlBrain({
1766
1802
  mission: spec.mission,
@@ -1768,6 +1804,10 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1768
1804
  stream: deps.controlStream,
1769
1805
  handoffEnabled: true,
1770
1806
  onSummary: (summary) => { controllerSummary = summary; },
1807
+ onDecision: (text, reply) => {
1808
+ pendingAnswer = reply ? { text: `${reply.answer || 'continue'}\r`, ...reply } : undefined;
1809
+ decisionEvent({ step: 'judge', text });
1810
+ },
1771
1811
  evidenceReady: () => spec.chain && spec.chain.length > 1 ? true : verifyEvidence(wt.path, spec.evidence).ok,
1772
1812
  search: async (query, step) => {
1773
1813
  usedOmni = true;
@@ -1784,9 +1824,13 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1784
1824
  // before asking the LLM — otherwise the mission text is typed into the prompt and the run stalls.
1785
1825
  const trustAwareBrain: RunSupervisor = {
1786
1826
  decide: (obs, signal) => {
1827
+ pendingAnswer = undefined;
1787
1828
  let answer: string | undefined;
1788
1829
  if (backend.handleTrust?.(obs.screen, (bytes) => { answer = bytes; }) && answer !== undefined) {
1789
1830
  debug.log('agent-mission', 'trust', { agent: backend.name, action: 'handled-in-loop', step: obs.step });
1831
+ decisionEvent({ step: 'judge', text: `step ${obs.step}: trust prompt` });
1832
+ // Only the confirming Enter answers the trust question; a navigation key stays an input event.
1833
+ if (answer === '\r') pendingAnswer = { text: answer, question: 'Trust this folder?', answer: 'Confirm selected choice' };
1790
1834
  emitDecision({ kind: 'ROUTE', what: `${backend.name} 폴더 신뢰 화면 → 계속`, reason: '시작 뒤 늦게 뜬 신뢰 확인', purpose: '미션을 이어 간다', target: backend.name, phase: 'implement' });
1791
1835
  return { action: 'input', text: answer };
1792
1836
  }
@@ -1872,6 +1916,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1872
1916
  renderPng: () => h.renderScreenPng(),
1873
1917
  bus,
1874
1918
  ident: { ptyId: h.id, instance: resolveInstanceName(), runId },
1919
+ onPublishedFrame: (obs) => decisionEvent({ step: 'read', text: `step ${obs.step} (${obs.state}): ${classifierFrameLines(obs.screen).at(-1) ?? 'empty screen'}` }),
1875
1920
  });
1876
1921
  debug.log('agent-mission', 'takeover-wait', { id: h.id, maxWaitMs: AGENT_MISSION_TAKEOVER_WAIT_MS });
1877
1922
  const controlRun = runWithControlObserve(
@@ -1879,9 +1924,24 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1879
1924
  (d) => debug.log('agent-mission.observe', 'progress', { surfaceId: d.surfaceId, state: d.state, summary: d.summary, unknownInput: d.unknownInput, frame: d.frameCount, runId: d.runId }),
1880
1925
  () => {
1881
1926
  const handleDeps = controlDepsForHandle(h);
1927
+ const inject = backend.name === 'claude' ? submitSeparately(handleDeps.inject) : handleDeps.inject;
1882
1928
  const pending = (deps.runControlLoop ?? runPtyControlLoop)(trustAwareBrain, {
1883
1929
  ...handleDeps,
1884
- ...(backend.name === 'claude' ? { inject: submitSeparately(handleDeps.inject) } : {}),
1930
+ inject: (text) => {
1931
+ const reply = pendingAnswer?.text === text ? pendingAnswer : undefined;
1932
+ pendingAnswer = undefined;
1933
+ const accepted = inject(text);
1934
+ if (accepted) {
1935
+ decisionEvent({ step: 'input', text: `Sent ${text.startsWith('\x1b') ? 'key' : 'text'}: ${text.startsWith('\x1b') ? 'navigation' : text}` });
1936
+ if (reply) decisionEvent({ step: 'answer', text: 'Answered agent question', detail: { question: reply.question, answer: reply.answer } });
1937
+ }
1938
+ return accepted;
1939
+ },
1940
+ injectKey: handleDeps.injectKey && ((name, repeat) => {
1941
+ const accepted = handleDeps.injectKey!(name, repeat);
1942
+ if (accepted) decisionEvent({ step: 'input', text: `Pressed ${name}${repeat ? ` ×${repeat}` : ''}`, detail: { keys: name } });
1943
+ return accepted;
1944
+ }),
1885
1945
  ...(deps.isMissionAborted ? {
1886
1946
  controlStance: () => deps.isMissionAborted!() ? 'unknown' as const : probeControlStance(h, 'agent', (e) =>
1887
1947
  debug.log('agent-mission', 'hascontrol-error', { id: h.id, error: (e as Error)?.message ?? String(e) })),
@@ -1903,7 +1963,11 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1903
1963
  }
1904
1964
  }
1905
1965
  },
1906
- verifyDone: spec.chain && spec.chain.length > 1 ? async () => ({ ok: true as const }) : verifyDone,
1966
+ verifyDone: spec.chain && spec.chain.length > 1 ? async () => ({ ok: true as const }) : async (obs) => {
1967
+ const verdict = await verifyDone(obs);
1968
+ if (!verdict.ok) decisionEvent({ step: 'recover', text: 'Evidence check requires another attempt', detail: { blocked: verdict.retry, action: 'Retry after fixing evidence' } });
1969
+ return verdict;
1970
+ },
1907
1971
  handoff: async (decision, obs) => {
1908
1972
  try {
1909
1973
  if (spec.chain && decision.to !== spec.chain[1]) throw new Error(`chain order violation: expected ${spec.chain[1] ?? 'completion'}, got ${decision.to}`);
@@ -1916,6 +1980,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1916
1980
  askHuman: async (decision) => {
1917
1981
  try {
1918
1982
  await waitForHumanLogin(decision, handoffOps);
1983
+ decisionEvent({ step: 'answer', text: 'Human login question resolved', detail: { question: decision.reason, answer: 'Login completed' } });
1919
1984
  } catch (error) {
1920
1985
  transitionFailure = error instanceof Error ? error.message : String(error);
1921
1986
  throw error;
@@ -1954,7 +2019,9 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1954
2019
  }
1955
2020
  // A gate/PR handoff only counts as success when the control loop itself did not end in error.
1956
2021
  if (gatedHandoff && control.termination.kind !== 'error') {
1957
- stopLive();
2022
+ // The gate hands off a branch, not a file: record what is known instead of mislabeling the worktree directory.
2023
+ decisionEvent({ step: 'done', text: 'Mission handoff gate completed', detail: { result: { kind: 'text', ref: `branch ${wt.branch}` } } });
2024
+ stopLive(true);
1958
2025
  try { h.kill(); } catch { /* noop */ }
1959
2026
  return { ok: true, worktree: wt.path, branch: wt.branch, rounds: control.steps, evidencePath: wt.path, committed: true, usedOmniCrawl: usedOmni,
1960
2027
  ...(handoffPrSkipped ? { pr: 'skipped' as const, reason: 'origin-not-github' as const } : {}),
@@ -1985,6 +2052,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
1985
2052
  maxFallbackDescents: runtimeFallback.maxDescents,
1986
2053
  });
1987
2054
  if (nextBackend && !deps.isMissionAborted?.()) {
2055
+ decisionEvent({ step: 'recover', text: `Switching ${backend.name} to ${nextBackend.name}`, detail: { blocked: control.termination.message, action: `Retry with ${nextBackend.name}` } });
1988
2056
  const nextStep: FallbackStep = nextBackend.name === 'grok' ? 'grok' : 'codex-rotate';
1989
2057
  stopLive();
1990
2058
  if (h.pid) await (deps.terminateProcessTree ?? terminateMissionProcessTree)(h.pid);
@@ -2019,7 +2087,8 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
2019
2087
  debug.log('agent-mission', 'commit', { ok: c.ok, out: c.out.slice(0, 120) });
2020
2088
  }
2021
2089
  debug.log('agent-mission', 'result', { ok: finalEv.ok, rounds: round, evidencePath, committed, usedOmni });
2022
- stopLive();
2090
+ decisionEvent({ step: 'done', text: finalEv.ok ? 'Mission evidence accepted' : 'Mission ended without sufficient evidence', detail: { result: { kind: evidencePath ? 'file' : 'text', ref: evidencePath ?? (control.termination.kind === 'error' ? control.termination.message : 'evidence unavailable') } } });
2091
+ stopLive(finalEv.ok);
2023
2092
  if (h.pid) await terminateMissionProcessTree(h.pid);
2024
2093
  try { h.kill(); } catch { /* noop */ }
2025
2094
 
@@ -2029,6 +2098,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
2029
2098
  ptyId: h.id, webUrl: webAddress.webUrl,
2030
2099
  detail: done ? '완료(증거 충족)' : (finalEv.ok ? '증거 충족(루프 종료)' : '미완(증거 부족)'),
2031
2100
  };
2101
+ } finally { stopLive(); finishContext(false); }
2032
2102
  }
2033
2103
 
2034
2104
  /** @deprecated codex 특정 이름 — runAgentMission 을 쓰라(codex 는 기본 backend). */
@@ -0,0 +1,71 @@
1
+ import { debug } from '../debug/log.js';
2
+
3
+ type Identity = {
4
+ ts: string;
5
+ missionId: string;
6
+ seq: number;
7
+ sessionId: string;
8
+ terminalId: string;
9
+ agent: string;
10
+ text: string;
11
+ };
12
+ type Detail = { keys?: string; row?: number };
13
+
14
+ export type PtyDecision = Identity & (
15
+ | { step: 'read' | 'judge' | 'input'; detail?: Detail }
16
+ | { step: 'answer'; detail: Detail & { question: string; answer: string } }
17
+ | { step: 'recover'; detail: Detail & { blocked: string; action: string } }
18
+ | { step: 'done'; detail: Detail & { result: { kind: 'pr' | 'file' | 'text'; ref: string } } }
19
+ );
20
+
21
+ export type DecisionInput = Omit<Identity, 'ts' | 'seq'> & (
22
+ | { step: 'read' | 'judge' | 'input'; detail?: Detail }
23
+ | { step: 'answer'; detail: Detail & { question: string; answer: string } }
24
+ | { step: 'recover'; detail: Detail & { blocked: string; action: string } }
25
+ | { step: 'done'; detail: Detail & { result: { kind: 'pr' | 'file' | 'text'; ref: string } } }
26
+ );
27
+
28
+ const missionStreams = new Map<string, { alias: string; seq: number }>();
29
+ export const PTY_DECISION_TEXT_MAX = 240;
30
+
31
+ function safe(value: string): string {
32
+ const masked = value
33
+ .replace(/\bBearer\s+(?:"[^"]*"|'[^']*'|[^\s"'<>]+)/gi, 'Bearer [redacted]')
34
+ .replace(/\b([a-z0-9_]*(?:token|key(?:[_-]?id)?|secret|password|authorization)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s"'<>]+)/gi, '$1[redacted]')
35
+ .replace(/\b(?:sk-[a-z0-9_-]+|gh[pousr]_[a-z0-9_]+|github_pat_[a-z0-9_]+|AIza[a-z0-9_-]+|xox[baprs]-[a-z0-9-]+)\b/gi, '[redacted]')
36
+ .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, '[redacted]')
37
+ .replace(/[\x00-\x1f\x7f-\x9f]/g, ' ')
38
+ .trim();
39
+ const clipped = masked.slice(0, PTY_DECISION_TEXT_MAX);
40
+ return clipped.replace(/[\uD800-\uDBFF]$/, '') || '[redacted]';
41
+ }
42
+
43
+ /** The only emission point for the inside-PTY decision stream. Never log unsanitized input. */
44
+ export function emitPtyDecision(input: DecisionInput, log: typeof debug.log = debug.log): PtyDecision {
45
+ let stream = missionStreams.get(input.missionId);
46
+ if (!stream) {
47
+ stream = { alias: `mission-${missionStreams.size + 1}`, seq: -1 };
48
+ missionStreams.set(input.missionId, stream);
49
+ }
50
+ stream.seq += 1;
51
+ const base = {
52
+ ts: new Date().toISOString(),
53
+ missionId: stream.alias,
54
+ seq: stream.seq,
55
+ sessionId: safe(input.sessionId),
56
+ terminalId: safe(input.terminalId),
57
+ agent: safe(input.agent),
58
+ text: safe(input.text),
59
+ };
60
+ const common = input.detail ? {
61
+ ...(input.detail.keys !== undefined ? { keys: safe(input.detail.keys) } : {}),
62
+ ...(input.detail.row !== undefined ? { row: input.detail.row } : {}),
63
+ } : {};
64
+ let decision: PtyDecision;
65
+ if (input.step === 'answer') decision = { ...base, step: input.step, detail: { ...common, question: safe(input.detail.question), answer: safe(input.detail.answer) } };
66
+ else if (input.step === 'recover') decision = { ...base, step: input.step, detail: { ...common, blocked: safe(input.detail.blocked), action: safe(input.detail.action) } };
67
+ else if (input.step === 'done') decision = { ...base, step: input.step, detail: { ...common, result: { kind: input.detail.result.kind, ref: safe(input.detail.result.ref) } } };
68
+ else decision = { ...base, step: input.step, ...(input.detail ? { detail: common } : {}) };
69
+ log('pty.decision', decision.step, decision);
70
+ return decision;
71
+ }
@@ -11,6 +11,7 @@ import { runGitCommand } from '../git-fs/runner.js';
11
11
  import * as llm from '../llm.js';
12
12
  import type { LLMMessage } from '../llm.js';
13
13
  import { debug } from '../debug/log.js';
14
+ import { releasePathHold, releasePathHoldShouldPost, releasePathHoldComment, releasePathHoldCommentsArgs, releasePrFilePaths, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
14
15
  import { runAgentMission, resolveBackend, type AgentMissionResult, type EvidenceMode } from './driver.js';
15
16
  import { judgeWithAcp, prepareJudgeDiff } from './acp-judge.js';
16
17
  import { verifyMergeAndMaybeRevert } from './merge-safety.js';
@@ -114,6 +115,31 @@ function gh(args: string[]): string {
114
115
  return execFileSync('gh', args, { encoding: 'utf8', timeout: 60000, maxBuffer: 20 * 1024 * 1024, env: process.env });
115
116
  }
116
117
 
118
+ /** Check every page of the PR file list immediately before an unattended review-loop merge. */
119
+ function holdReleasePathBeforeReviewMerge(pr: string, runGh: (args: string[]) => string): boolean {
120
+ let paths: string[];
121
+ try {
122
+ paths = releasePrFilePaths(JSON.parse(runGh(['api', '--paginate', '--slurp', '--method', 'GET', '-f', 'per_page=100', `repos/{owner}/{repo}/pulls/${pr}/files`])));
123
+ } catch (error) {
124
+ debug.log('self-dev.merge', 'release-path-inspection-failed', { pr, error: String(error) });
125
+ return true;
126
+ }
127
+ const path = releasePathHold(paths);
128
+ if (!path) return false;
129
+ debug.log('self-dev.merge', 'release-path-hold', { pr, path, label: RELEASE_PATH_LABEL, surface: 'review-loop' });
130
+ try {
131
+ const names: unknown = JSON.parse(runGh(['label', 'list', '--search', RELEASE_PATH_LABEL, '--json', 'name']));
132
+ if (!Array.isArray(names)) throw new Error('invalid label list');
133
+ if (!names.some((item: unknown) => !!item && typeof item === 'object' && 'name' in item && item.name === RELEASE_PATH_LABEL)) {
134
+ runGh(['label', 'create', RELEASE_PATH_LABEL, '--color', 'D93F0B', '--description', 'Release path requires OP approval']);
135
+ }
136
+ runGh(['pr', 'edit', pr, '--add-label', RELEASE_PATH_LABEL]);
137
+ } catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { pr, action: 'label', error: String(error) }); }
138
+ try { if (releasePathHoldShouldPost(() => JSON.parse(runGh(releasePathHoldCommentsArgs(pr))))) runGh(['pr', 'comment', pr, '--body', releasePathHoldComment(path)]); }
139
+ catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { pr, action: 'comment', error: String(error) }); }
140
+ return true;
141
+ }
142
+
117
143
  /** ★ G10 안전봉투 — 자율머지 직후 회귀검증(verifyMerge 시). 회귀면 revert PR 이 이미 생성됨(알림 포함) →
118
144
  * 원 PR 에 링크 코멘트만. fail-open(검증 오류는 머지를 막지 않음). */
119
145
  async function runMergeSafety(pr: string, opts: ReviewLoopOpts, depth: ReviewDepth): Promise<void> {
@@ -233,6 +259,7 @@ export async function judgeAndFinalize(
233
259
 
234
260
  if (j.verdict === 'merge') {
235
261
  if (opts.autoMerge) {
262
+ if (holdReleasePathBeforeReviewMerge(pr, runGh)) return { pr, branch, verdict: 'reinforce', asks, action: 'parked', reworkOk: true, pushed: lastPushed, rounds: round, detail: 'OP approval required: release-path hold or PR file inspection unavailable' };
236
263
  const approve = opts.approve ?? approvePr;
237
264
  const recordReviewOutcome = opts.recordReviewOutcome ?? recordOutcome;
238
265
  approve(pr, `2차 ACP 최종심판 MERGE (round ${round})`);
@@ -480,6 +507,9 @@ export async function runReviewLoop(pr: string, opts: ReviewLoopOpts = {}): Prom
480
507
  if (cls.verdict === 'ok') {
481
508
  // light: 1차 clean 으로 충분 → approve + 머지. heavy: 1차 ok 여도 2차 심판 머스트.
482
509
  if (!effectiveFinalJudge) {
510
+ if ((opts.autoMergeOnOk || opts.autoMerge) && holdReleasePathBeforeReviewMerge(pr, runGh)) {
511
+ return { pr, branch, verdict: 'ok', asks: [], action: 'parked', detail: 'OP approval required: release-path hold or PR file inspection unavailable' };
512
+ }
483
513
  approve(pr, `소작업(light)·1차 리뷰 clean`);
484
514
  let merged = false;
485
515
  if (opts.autoMergeOnOk || opts.autoMerge) {
@@ -3,16 +3,13 @@ import { join } from 'node:path';
3
3
 
4
4
  import { elanousStateRoot } from '../autopilot/state-paths.js';
5
5
  import { ASK_USER_QUESTION_DELIVERY_VALUES } from './types.js';
6
- import type { AskUserQuestionRequest, AskUserQuestionResult, HitlDelivery, QuestionOption } from './types.js';
6
+ import type { AskUserQuestionRequest, AskUserQuestionResult, HitlDelivery, Question, QuestionOption } from './types.js';
7
7
 
8
- interface PendingQuestion {
8
+ export interface PendingQuestion {
9
9
  id: string;
10
10
  sessionId?: string;
11
- questions: Array<{
12
- id: string;
13
- question: string;
14
- options: QuestionOption[];
15
- }>;
11
+ runId?: string;
12
+ questions: Array<Pick<Question, 'id' | 'question' | 'options' | 'impact' | 'recommendedIndex'>>;
16
13
  startedAt: string;
17
14
  expiresAt?: string;
18
15
  surface: 'tui' | 'file';
@@ -86,6 +83,7 @@ function isPendingQuestion(value: unknown): value is PendingQuestion {
86
83
  const pending = value as Record<string, unknown>;
87
84
  return typeof pending.id === 'string'
88
85
  && (pending.sessionId === undefined || typeof pending.sessionId === 'string')
86
+ && (pending.runId === undefined || typeof pending.runId === 'string')
89
87
  && Array.isArray(pending.questions)
90
88
  && pending.questions.every((question) => {
91
89
  if (question === null || typeof question !== 'object' || Array.isArray(question)) return false;
@@ -93,7 +91,10 @@ function isPendingQuestion(value: unknown): value is PendingQuestion {
93
91
  return typeof record.id === 'string'
94
92
  && typeof record.question === 'string'
95
93
  && Array.isArray(record.options)
96
- && record.options.every(isQuestionOption);
94
+ && record.options.every(isQuestionOption)
95
+ && (record.impact === undefined || record.impact === 'low' || record.impact === 'medium' || record.impact === 'high' || record.impact === 'critical')
96
+ && (record.recommendedIndex === undefined || (typeof record.recommendedIndex === 'number'
97
+ && Number.isInteger(record.recommendedIndex)));
97
98
  })
98
99
  && isIsoTimestamp(pending.startedAt)
99
100
  && (pending.surface === 'tui' || pending.surface === 'file')
@@ -111,7 +112,15 @@ function isPendingQuestion(value: unknown): value is PendingQuestion {
111
112
  function parsePendingQuestion(contents: string, file: string): PendingQuestion {
112
113
  const value: unknown = JSON.parse(contents);
113
114
  if (!isPendingQuestion(value)) throw new Error(`Invalid pending question record: ${file}`);
114
- return value;
115
+ return {
116
+ ...value,
117
+ questions: value.questions.map((question) => ({
118
+ ...question,
119
+ ...(question.recommendedIndex !== undefined
120
+ && (question.recommendedIndex < 0 || question.recommendedIndex >= question.options.length)
121
+ ? { recommendedIndex: undefined } : {}),
122
+ })),
123
+ };
115
124
  }
116
125
 
117
126
  export function isAskUserQuestionResult(value: unknown): value is AskUserQuestionResult {
@@ -176,7 +185,13 @@ export function createPendingQuestion(
176
185
  return {
177
186
  id,
178
187
  ...(sessionId === undefined ? {} : { sessionId }),
179
- questions: request.questions.map(({ id, question, options }) => ({ id, question, options })),
188
+ ...(request.runId === undefined ? {} : { runId: request.runId }),
189
+ questions: request.questions.map(({ id, question, options, impact, recommendedIndex }) => ({
190
+ id, question, options,
191
+ ...(impact === undefined ? {} : { impact }),
192
+ ...(recommendedIndex !== undefined && Number.isInteger(recommendedIndex) && recommendedIndex >= 0 && recommendedIndex < options.length
193
+ ? { recommendedIndex } : {}),
194
+ })),
180
195
  startedAt: (deps.now ?? (() => new Date()))().toISOString(),
181
196
  ...(presentation.expiresAt === undefined ? {} : { expiresAt: presentation.expiresAt }),
182
197
  surface: presentation.surface,
@@ -13,6 +13,7 @@
13
13
  // behaviour exactly.
14
14
 
15
15
  import type { HitlDelivery } from '../hitl/types.js';
16
+ import type { ClarificationImpact } from '../hitl/clarification-policy.js';
16
17
  export type { HitlDelivery };
17
18
 
18
19
  export interface QuestionOption {
@@ -37,6 +38,9 @@ export interface Question {
37
38
  question: string;
38
39
  /** 2–4 pre-defined choices. */
39
40
  options: QuestionOption[];
41
+ impact?: ClarificationImpact;
42
+ /** Zero-based position in options; an out-of-range value is ignored. */
43
+ recommendedIndex?: number;
40
44
  /** When true, user can pick more than one option; Space toggles,
41
45
  * Enter submits. Default false. */
42
46
  multiSelect?: boolean;
@@ -49,6 +53,7 @@ export interface Question {
49
53
 
50
54
  export interface AskUserQuestionRequest {
51
55
  questions: Question[]; // 1–3
56
+ runId?: string;
52
57
  /** AXON F4 — optional routing hint. When set, callers with HITL
53
58
  * resolvers can fan the prompt out to Telegram/Discord/etc;
54
59
  * omitted (or `'modal'` / `'terminal'`) keeps the existing TUI
@@ -165,6 +170,9 @@ export function parseQuestionRequest(
165
170
  header,
166
171
  question,
167
172
  options,
173
+ ...(item.impact === 'low' || item.impact === 'medium' || item.impact === 'high' || item.impact === 'critical' ? { impact: item.impact } : {}),
174
+ ...(typeof item.recommendedIndex === 'number' && Number.isInteger(item.recommendedIndex)
175
+ && item.recommendedIndex >= 0 && item.recommendedIndex < options.length ? { recommendedIndex: item.recommendedIndex } : {}),
168
176
  multiSelect: item.multiSelect === true,
169
177
  includeOther: item.includeOther !== false, // default true
170
178
  });
@@ -186,5 +194,6 @@ export function parseQuestionRequest(
186
194
 
187
195
  const req: AskUserQuestionRequest = { questions: parsed };
188
196
  if (delivery !== undefined) req.delivery = delivery;
197
+ if (typeof raw.runId === 'string') req.runId = raw.runId;
189
198
  return { ok: true, req };
190
199
  }
@@ -74,15 +74,26 @@ function writeStore(dir: string, tokens: SetupLinkEntry[]): void {
74
74
 
75
75
  // A persistent inode and an OS advisory lock avoid stale owner files after an abrupt process exit.
76
76
  // Never unlink this file: a replacement inode would let two processes hold different locks.
77
- const libc = dlopen(process.platform === 'darwin' ? '/usr/lib/libSystem.B.dylib' : 'libc.so.6', {
78
- flock: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
79
- });
77
+ // Loaded on first use, not at import: libc.so.6 does not exist on Windows and this module sits on the CLI start path (WIN2 10-02).
78
+ type Flock = (fd: number, op: number) => number;
79
+ let flockFn: Flock | null | undefined;
80
+ function osFlock(): Flock | null {
81
+ if (flockFn !== undefined) return flockFn;
82
+ if (process.platform === 'win32') return (flockFn = null);
83
+ const lib = dlopen(process.platform === 'darwin' ? '/usr/lib/libSystem.B.dylib' : 'libc.so.6', {
84
+ flock: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
85
+ });
86
+ return (flockFn = lib.symbols.flock as Flock);
87
+ }
80
88
  const LOCK_EX = 2;
81
89
  const LOCK_NB = 4;
82
90
  const LOCK_UN = 8;
83
91
 
84
92
  function withLock<T>(dir: string, fn: () => T): T {
85
93
  mkdirSync(dir, { recursive: true, mode: 0o700 });
94
+ const flock = osFlock();
95
+ // Windows: no advisory flock and no POSIX modes — the store still writes by atomic rename.
96
+ if (!flock) return fn();
86
97
  const lock = `${storePath(dir)}.lock`;
87
98
  const fd = openSync(lock, constants.O_CREAT | constants.O_RDWR | constants.O_NOFOLLOW, 0o600);
88
99
  try {
@@ -92,7 +103,7 @@ function withLock<T>(dir: string, fn: () => T): T {
92
103
  throw new Error('setup link lock must be a private regular file (0600)');
93
104
  }
94
105
  const until = Date.now() + 3000;
95
- while (libc.symbols.flock(fd, LOCK_EX | LOCK_NB) !== 0) {
106
+ while (flock(fd, LOCK_EX | LOCK_NB) !== 0) {
96
107
  if (Date.now() > until) throw new Error('setup link store is locked — try again');
97
108
  Bun.sleepSync(20);
98
109
  }
@@ -101,7 +112,7 @@ function withLock<T>(dir: string, fn: () => T): T {
101
112
  if (stat.ino !== locked.ino || stat.dev !== locked.dev) throw new Error('setup link lock changed');
102
113
  return fn();
103
114
  } finally {
104
- libc.symbols.flock(fd, LOCK_UN);
115
+ flock(fd, LOCK_UN);
105
116
  }
106
117
  } finally {
107
118
  closeSync(fd);
@@ -255,6 +255,7 @@ const STEP_CMDS: Record<GateStepName, { cmd: string; args: string[]; timeoutMs:
255
255
  'cli-smoke': { cmd: 'bun', args: ['bin/elanous.mjs', '--help'], timeoutMs: 60_000 },
256
256
  };
257
257
 
258
+ const DEPENDENCY_INSTALL_TIMEOUT_MS = 300_000;
258
259
  const MAX_LOGGED_TEST_FILTERS = 6;
259
260
 
260
261
  /** Platform runners own Kotlin/Swift execution; Bun must never receive their paths as test filters. */
@@ -289,6 +290,17 @@ export async function runIntegrityGate(
289
290
  const runCmd = opts.runCmd ?? createRunCmd();
290
291
  const results: GateStep[] = [];
291
292
  const logs: string[] = [];
293
+ // A Pod worktree has no node_modules unless the child happened to install them (the Pod clone has none to link), and Bun
294
+ // then auto-installs at import time — «Unexpected while resolving package 'commander'» failed cli-smoke as an
295
+ // «environment deficiency» three times on 10-02 (#22849 · #22919). Install from the lockfile before measuring instead.
296
+ if (steps.length > 0 && existsSync(join(cwd, 'bin', 'elanous.mjs')) && existsSync(join(cwd, 'bun.lock'))
297
+ && !existsSync(join(cwd, 'node_modules', 'commander', 'package.json'))) {
298
+ const install = await runCmd('bun', ['install', '--frozen-lockfile'], cwd, DEPENDENCY_INSTALL_TIMEOUT_MS);
299
+ const installed = install.code === 0 && !install.timedOut;
300
+ debug.log('gate.deps', 'install', { installed, code: install.code, timedOut: install.timedOut });
301
+ const tail = (install.stderr || install.stdout).split('\n').filter(Boolean).slice(-2).join(' | ').slice(0, 200);
302
+ logs.push(`[deps] ${installed ? 'INSTALLED' : 'FAIL'} bun install --frozen-lockfile — node_modules/commander was missing${installed ? '' : `: ${tail}`}`);
303
+ }
292
304
  let passed = true;
293
305
  let testPassCount: number | undefined;
294
306
  let sawPassCountRegression = false;
@@ -9,6 +9,17 @@ import { join } from 'node:path';
9
9
  import { readFileSync, writeFileSync } from 'node:fs';
10
10
  import { runGitCommand } from '../../git-fs/runner.js';
11
11
  import { countTestDeclarations } from '../../self-implement/test-declarations.js';
12
+ import { NEXT_MD_PATH, resolveNextMdConflict } from '../../release-loop/next-md-merge.js';
13
+
14
+ function deterministicNextMd(git: MergeGitSeam, worktreePath: string, file: string): string | null {
15
+ try {
16
+ const resolved = resolveNextMdConflict(git.readIndexStage(worktreePath, 1, file), git.readIndexStage(worktreePath, 2, file), git.readIndexStage(worktreePath, 3, file));
17
+ void import('../../debug/log.js').then(({ debug }) => debug.log('self-dev.merge', 'next-md-deterministic', { resolved: resolved !== null })).catch(() => {});
18
+ return resolved;
19
+ } catch {
20
+ return null; // a stage is missing (added/deleted on one side) — the usual resolver decides
21
+ }
22
+ }
12
23
 
13
24
  /** 충돌 마커가 남아있나(LLM 이 해결 못 함 판별). ours/base/theirs 3-way 마커 모두. 순수. */
14
25
  export function hasConflictMarkers(s: string): boolean {
@@ -130,8 +141,8 @@ export interface MergeGitSeam {
130
141
  merge: (wt: string, mergeTarget: string) => { ok: boolean; conflict: boolean; stdout: string; errorDetail?: string };
131
142
  /** 충돌(unmerged) 파일 목록(worktree 상대 경로). */
132
143
  conflictedFiles: (wt: string) => string[];
133
- /** Reads an unmerged index stage (2=ours, 3=theirs) for a conflicted file. */
134
- readIndexStage: (wt: string, stage: 2 | 3, file: string) => string;
144
+ /** Reads an unmerged index stage (1=base, 2=ours, 3=theirs) for a conflicted file. */
145
+ readIndexStage: (wt: string, stage: 1 | 2 | 3, file: string) => string;
135
146
  readFile: (absPath: string) => string;
136
147
  writeFile: (absPath: string, content: string) => void;
137
148
  /** 해결된 파일 스테이징. */
@@ -193,7 +204,9 @@ export async function mergeMainWithLlmResolve(
193
204
  let merged: string;
194
205
  try {
195
206
  conflicted = git.readFile(abs);
196
- merged = await resolve(f, conflicted);
207
+ // release/next.md: concurrent landings each append a line — keep both without asking the LLM (REL7c).
208
+ const deterministic = f === NEXT_MD_PATH ? deterministicNextMd(git, worktreePath, f) : null;
209
+ merged = deterministic ?? await resolve(f, conflicted);
197
210
  } catch {
198
211
  git.abort(worktreePath); // LLM 예외 → base 유지
199
212
  return measuredOutcome({ status: 'conflict-unresolved', resolvedFiles });