elanous 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (615) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  8. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  18. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  19. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  24. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -1
  152. package/apps/pwa/out/ops/seats/index.txt +22 -22
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -1
  178. package/apps/pwa/out/today/index.txt +23 -23
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/context/nightly-condense.yaml +21 -0
  192. package/graphs/context/recipes.yaml +12 -0
  193. package/graphs/demo/inside-seed.yaml +20 -0
  194. package/graphs/demo/recipes.yaml +12 -0
  195. package/graphs/drafts/draft-cleanup.yaml +19 -0
  196. package/graphs/drafts/recipes.yaml +23 -0
  197. package/graphs/intake/intake-daily.yaml +2 -1
  198. package/graphs/ops/recipes.yaml +3 -0
  199. package/graphs/ops/secret-exposure.yaml +24 -0
  200. package/graphs/release/recipes.yaml +3 -0
  201. package/graphs/release/release-loop.yaml +4 -1
  202. package/graphs/video/explainer-line.yaml +2 -2
  203. package/package.json +2 -1
  204. package/plugins/card-followup/examples/sample-card.png +0 -0
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/context-hooks/claude-stop.sh +4 -0
  216. package/scripts/context-hooks/emit.ts +24 -0
  217. package/scripts/context-hooks/post-tool-use.sh +4 -0
  218. package/scripts/coord-channel-watch.sh +12 -0
  219. package/scripts/coord-requests-bridge.ts +143 -0
  220. package/scripts/field-feed/lib.ts +4 -0
  221. package/scripts/fleet/node-setup.sh +20 -3
  222. package/scripts/homebrew-formula-bump.ts +69 -0
  223. package/scripts/lib/telegram-inject-args.ts +31 -0
  224. package/scripts/marketing/measure-site-numbers.ts +169 -0
  225. package/scripts/measure-gate-shards.ts +309 -0
  226. package/scripts/measure-pod-memory-by-goal.ts +130 -0
  227. package/scripts/mission-request-judge.ts +31 -1
  228. package/scripts/morning-report.ts +2 -2
  229. package/scripts/opportunity-scan.ts +1 -1
  230. package/scripts/release-loop/auto-approve-node.ts +21 -4
  231. package/scripts/release-loop/checklist-gate-node.ts +2 -1
  232. package/scripts/release-loop/cut-branch.ts +84 -0
  233. package/scripts/release-loop/gate-node.ts +22 -15
  234. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  235. package/scripts/release-loop/node-verdict.ts +3 -3
  236. package/scripts/release-loop/ops-upgrade-node.ts +47 -6
  237. package/scripts/release-loop/publish-node.ts +4 -1
  238. package/scripts/release-loop/tui-node-checks.ts +42 -0
  239. package/scripts/release-loop/tui-sim-node.ts +32 -8
  240. package/scripts/release-loop/unattended-release.ts +5 -3
  241. package/scripts/release-loop/version-node.ts +74 -13
  242. package/scripts/signal-digest-cycle.ts +2 -7
  243. package/scripts/signal-digest-photo.ts +11 -0
  244. package/scripts/tech1-public-measure.ts +94 -0
  245. package/scripts/telegram-inject.ts +14 -6
  246. package/scripts/test-diet/node.ts +1 -1
  247. package/scripts/test-diet/remeasure-list.ts +112 -0
  248. package/scripts/tui-regress.ts +2 -2
  249. package/scripts/ux/demo-rehearsal.ts +247 -0
  250. package/scripts/ux/demo-seed.ts +108 -0
  251. package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
  252. package/skills/diagram-master/SKILL.md +366 -0
  253. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  254. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  255. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  256. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  257. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  258. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  259. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  260. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  261. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  262. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  263. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  264. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  265. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  266. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  267. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  268. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  269. package/skills/diagram-master/references/examples/README.md +69 -0
  270. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  271. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  272. package/skills/diagram-master/references/pyproject.toml +16 -0
  273. package/skills/diagram-master/references/quality-checklist.md +33 -0
  274. package/skills/diagram-master/references/routing-guide.md +164 -0
  275. package/skills/diagram-master/references/uv.lock +1356 -0
  276. package/skills/google-workspace/SKILL.md +33 -0
  277. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  278. package/skills/grill-me/SKILL.md +1 -1
  279. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  280. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  281. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  282. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  283. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  284. package/skills/omni-crawl/SKILL.md +21 -11
  285. package/skills/omni-crawl/scripts/main.ts +6 -6
  286. package/skills/omni-crawl/src/router.ts +3 -3
  287. package/skills/omni-digest/SKILL.md +17 -9
  288. package/skills/omni-digest/digest.md +2 -2
  289. package/skills/omni-digest/src/fetch.ts +30 -3
  290. package/skills/pitch-deck/SKILL.md +2 -2
  291. package/skills/pitch-deck/template.html +2 -2
  292. package/skills/youtube-master/SKILL.md +163 -0
  293. package/skills/youtube-master/package-lock.json +558 -0
  294. package/skills/youtube-master/package.json +13 -0
  295. package/skills/youtube-master/references/study-note-template.md +124 -0
  296. package/skills/youtube-master/scripts/main.ts +435 -0
  297. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  298. package/skills/youtube-master/src/audio.ts +63 -0
  299. package/skills/youtube-master/src/domain-staging.ts +50 -0
  300. package/skills/youtube-master/src/env.ts +36 -0
  301. package/skills/youtube-master/src/obsidian.ts +155 -0
  302. package/skills/youtube-master/src/router.ts +110 -0
  303. package/skills/youtube-master/src/stt.ts +199 -0
  304. package/skills/youtube-master/src/study-note.ts +175 -0
  305. package/skills/youtube-master/src/summarize.ts +358 -0
  306. package/skills/youtube-master/src/transcript.ts +76 -0
  307. package/skills/youtube-master/src/types.ts +91 -0
  308. package/skills/youtube-master/src/util.ts +93 -0
  309. package/skills/youtube-master/src/youtube.ts +70 -0
  310. package/skills/youtube-master/tsconfig.json +13 -0
  311. package/src/acp/server.ts +5 -2
  312. package/src/agent-mission/driver.ts +215 -23
  313. package/src/agent-mission/pty-decision.ts +71 -0
  314. package/src/agent-mission/review-loop.ts +30 -0
  315. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  316. package/src/autopilot/pty-control-loop.ts +4 -1
  317. package/src/autopilot/tool-registry.ts +2 -0
  318. package/src/boot/daemon-prompt-turn.ts +5 -0
  319. package/src/boot/daemon-runtime.ts +9 -3
  320. package/src/boot/daemon-tools/web-search.ts +3 -0
  321. package/src/card-followup/core.ts +109 -0
  322. package/src/chat/index.ts +2 -0
  323. package/src/cli/drive-input-jail.ts +101 -0
  324. package/src/cli/hooks-cli.ts +17 -3
  325. package/src/cli/make-cli.ts +43 -0
  326. package/src/cli/persona-cli.ts +98 -9
  327. package/src/cli/plugin-cli.ts +31 -22
  328. package/src/cli/pod-cli.ts +36 -9
  329. package/src/cli/pod-memory-advice.ts +35 -0
  330. package/src/cli/pr-cli.ts +51 -15
  331. package/src/cli/pty-drive-cli.ts +41 -7
  332. package/src/cli/pty-drive-verdict.ts +40 -0
  333. package/src/cli/release-cli.ts +63 -10
  334. package/src/cli/setup-cli.ts +43 -1
  335. package/src/cli/skills-cli.ts +17 -1
  336. package/src/context-bus/claude-hooks-install.ts +10 -0
  337. package/src/context-bus/context-now-surfaces.ts +65 -0
  338. package/src/context-bus/context-now.ts +104 -0
  339. package/src/context-bus/coord-events.ts +2 -2
  340. package/src/context-bus/external-events.ts +52 -0
  341. package/src/context-bus/long-term-memory.ts +108 -0
  342. package/src/context-bus/nightly-condense.ts +153 -0
  343. package/src/context-bus/session-events.ts +35 -0
  344. package/src/dashboard/dashboard-status-lines.ts +2 -0
  345. package/src/dashboard/index.ts +17 -4
  346. package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
  347. package/src/decisions/decision-cards.ts +10 -3
  348. package/src/decisions/decision-ledger.ts +13 -5
  349. package/src/discord/sprint21-runtime.ts +5 -1
  350. package/src/discord-self-message.ts +32 -0
  351. package/src/discord-slash-wire.ts +5 -1
  352. package/src/discord.ts +17 -1
  353. package/src/domains/core-tools.ts +3 -2
  354. package/src/domains/outbound-alert.ts +105 -32
  355. package/src/domains/outbound-log-probe.ts +8 -0
  356. package/src/domains/telegram-kind-route.ts +51 -13
  357. package/src/exec-requests/default-outputs.ts +25 -0
  358. package/src/exec-requests/planner.ts +10 -2
  359. package/src/exec-requests/runner.ts +20 -6
  360. package/src/exec-requests/store.ts +3 -0
  361. package/src/execution-loop/launch-gate.ts +109 -0
  362. package/src/field/field-reel.ts +5 -1
  363. package/src/field-note/index.ts +201 -0
  364. package/src/field-note/telegram.ts +142 -0
  365. package/src/field-note/transcribe.ts +248 -0
  366. package/src/graph-kinds/registry.ts +3 -3
  367. package/src/graph-runner/graph-cli.ts +61 -1
  368. package/src/graph-runner/graph-grow-llm.ts +47 -0
  369. package/src/graph-runner/graph-grow.ts +50 -0
  370. package/src/graph-runner/runner.ts +329 -33
  371. package/src/grok/agent-search.ts +8 -2
  372. package/src/guardian/secret-exposure-scan.ts +101 -0
  373. package/src/harness/harness-cli-command.ts +375 -13
  374. package/src/harness/harness-pod-dispatch.ts +43 -23
  375. package/src/harness/harness-seams.ts +38 -4
  376. package/src/harness/harness-stop.ts +23 -4
  377. package/src/harness/launch-registry.ts +91 -0
  378. package/src/harness/process-garbage.ts +5 -3
  379. package/src/hooks/consult-intake.ts +153 -0
  380. package/src/hooks/dispatch.ts +82 -0
  381. package/src/hooks/expose.ts +254 -0
  382. package/src/hooks/github-shadow.ts +108 -0
  383. package/src/hooks/providers.ts +71 -5
  384. package/src/hooks/queue.ts +1 -1
  385. package/src/hooks/receiver.ts +94 -16
  386. package/src/index.ts +76 -14
  387. package/src/intake-plane/categorize.ts +18 -46
  388. package/src/intake-plane/discord-seat-work.ts +38 -2
  389. package/src/intake-plane/front-route-classifier.ts +33 -39
  390. package/src/intake-plane/persona-answer.ts +30 -0
  391. package/src/intake-plane/runtime-callables.ts +8 -1
  392. package/src/intake-plane/telegram-seat-work.ts +36 -2
  393. package/src/intake-plane/wish-card.ts +33 -0
  394. package/src/intake-plane/wish-folder.ts +67 -0
  395. package/src/intent-gate/gate.ts +30 -10
  396. package/src/live/detail-switch.ts +5 -0
  397. package/src/llm/difficulty.ts +57 -0
  398. package/src/llm/judge-layer.ts +101 -0
  399. package/src/llm/mission-router.ts +33 -19
  400. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  401. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  402. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  403. package/src/loops/contract/loop-agent.schema.json +138 -0
  404. package/src/loops/contract/validate.ts +64 -0
  405. package/src/loops/registry.ts +20 -6
  406. package/src/market/signed-index.ts +4 -0
  407. package/src/maturity/bot-command-maturity.ts +45 -0
  408. package/src/maturity/feature-maturity.ts +27 -4
  409. package/src/model-tier/index.ts +2 -2
  410. package/src/model-tier/tier-resolver.ts +20 -20
  411. package/src/model-tier/types.ts +6 -6
  412. package/src/mss/logging/log-store.ts +15 -0
  413. package/src/nexus/api/config-model-tier.ts +5 -4
  414. package/src/nexus/api/fabric-plans.ts +53 -0
  415. package/src/nexus/api/harness-api.ts +5 -1
  416. package/src/nexus/api/health.ts +2 -0
  417. package/src/nexus/api/http-server.ts +67 -8
  418. package/src/nexus/api/inside-events.ts +226 -0
  419. package/src/nexus/api/meta-api.ts +21 -8
  420. package/src/nexus/api/missions.ts +6 -1
  421. package/src/nexus/api/ops-seats.ts +33 -0
  422. package/src/nexus/api/outbound-report.ts +40 -7
  423. package/src/nexus/api/outputs-route.ts +44 -0
  424. package/src/nexus/api/personas.ts +95 -53
  425. package/src/nexus/api/seat-requests.ts +44 -2
  426. package/src/nexus/api/sessions-store.ts +17 -38
  427. package/src/nexus/api/sub-seat-charters.ts +34 -0
  428. package/src/nexus/api/tabs-mutations.ts +3 -1
  429. package/src/nexus/api/task-cards-api.ts +19 -0
  430. package/src/nexus/api/trace.ts +18 -6
  431. package/src/nexus/api/workflow-history.ts +88 -0
  432. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  433. package/src/nexus/api/workflows.ts +132 -6
  434. package/src/nexus/index.ts +2 -0
  435. package/src/nexus/kinds/webterm.ts +2 -1
  436. package/src/nexus/outbound/delivery-ledger.ts +17 -8
  437. package/src/nexus/outbound/router.ts +8 -3
  438. package/src/nexus/webterm/pty.ts +6 -2
  439. package/src/onboarding/cli-auth-status.ts +80 -0
  440. package/src/onboarding/voice-ai.ts +3 -3
  441. package/src/org/seat-budget.ts +48 -0
  442. package/src/org/stall-escalation.ts +63 -0
  443. package/src/outputs/ledger.ts +120 -0
  444. package/src/persona/persona-todo.ts +79 -0
  445. package/src/persona/presets.ts +123 -2
  446. package/src/persona/team-set.ts +155 -0
  447. package/src/plugins/install/plugin-install.ts +14 -0
  448. package/src/plugins/maker/market-bundle.ts +110 -0
  449. package/src/plugins/maker/plugin-maker.ts +254 -11
  450. package/src/plugins/maker/wizard-generate.ts +103 -0
  451. package/src/pod-lease/admission.ts +150 -0
  452. package/src/pod-lease/dependency-state.ts +85 -0
  453. package/src/pod-lease/host-lease.ts +127 -0
  454. package/src/project/project-suggestion.ts +16 -0
  455. package/src/project/session-context.ts +24 -0
  456. package/src/release-loop/checklist.ts +17 -5
  457. package/src/release-loop/feature-store.ts +29 -13
  458. package/src/release-loop/landed-but-yellow.ts +48 -0
  459. package/src/release-loop/next-md-merge.ts +58 -0
  460. package/src/release-loop/release-note.ts +59 -4
  461. package/src/seat-dispatch/seat-ask.ts +130 -0
  462. package/src/seat-dispatch/seat-questions.ts +100 -0
  463. package/src/seat-loop/seat-loop.ts +709 -29
  464. package/src/seat-loop/seat-report.ts +37 -2
  465. package/src/self-dev/dev-cli.ts +4 -1
  466. package/src/self-dev/dev-pipeline.ts +37 -1
  467. package/src/self-dev/draft-sweep.ts +79 -40
  468. package/src/self-dev/draft-triage-rules.ts +62 -7
  469. package/src/self-dev/fabric-plan-core.ts +297 -0
  470. package/src/self-dev/orchestrate.ts +36 -4
  471. package/src/self-dev/release-path-guard.ts +62 -0
  472. package/src/self-dev/shard-aggregate.ts +230 -0
  473. package/src/self-dev/shard-placement.ts +60 -0
  474. package/src/self-dev/shard-plan.ts +48 -0
  475. package/src/self-dev/shard-pod-run.ts +77 -0
  476. package/src/self-dev/shard-run.ts +105 -0
  477. package/src/self-implement/budget-gate.ts +29 -12
  478. package/src/self-implement/gate-baseline.ts +1 -1
  479. package/src/self-implement/gate-candidate-ranking.ts +60 -0
  480. package/src/self-implement/gate-cli.ts +40 -1
  481. package/src/self-implement/gate-scope.ts +44 -13
  482. package/src/self-implement/graph-variant.ts +171 -0
  483. package/src/self-implement/harness-policy-gates.ts +1 -1
  484. package/src/self-implement/headless-elanous-driver.ts +27 -3
  485. package/src/self-implement/host-regate.ts +22 -1
  486. package/src/self-implement/importer-test-index.ts +2 -1
  487. package/src/self-implement/l8-merge-queue.ts +130 -0
  488. package/src/self-implement/orchestrator.ts +257 -9
  489. package/src/self-implement/route-consumer-test-index.ts +122 -0
  490. package/src/self-implement/seams.ts +72 -11
  491. package/src/self-implement/test-seams.ts +2 -0
  492. package/src/self-implement/uncommitted-work.ts +59 -0
  493. package/src/session/index.ts +36 -13
  494. package/src/skills/gift-install.ts +215 -0
  495. package/src/skills/tools/web-search.ts +4 -1
  496. package/src/steward/launch.ts +42 -26
  497. package/src/steward/steward-cards.ts +17 -9
  498. package/src/steward/triage.ts +46 -14
  499. package/src/task-cards/card-cli.ts +25 -1
  500. package/src/task-orchestrator/mission.ts +5 -0
  501. package/src/task-orchestrator/store.ts +12 -3
  502. package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
  503. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  504. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  505. package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
  506. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  507. package/src/task-orchestrator/types.ts +2 -0
  508. package/src/telegram-card-followup.ts +16 -96
  509. package/src/telegram-commands.ts +31 -1
  510. package/src/telegram-project-command.ts +145 -0
  511. package/src/telegram-report.ts +21 -17
  512. package/src/telegram.ts +61 -8
  513. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  514. package/src/user-config.ts +110 -24
  515. package/src/version/packed-revision.json +1 -1
  516. package/src/web-search/grok.ts +7 -1
  517. package/src/web-search/index.ts +28 -1
  518. package/src/web-search/provider.ts +4 -0
  519. package/src/web-search/x-intent.ts +5 -0
  520. package/src/workflow-runtime/executor.ts +277 -47
  521. package/src/workflow-runtime/index.ts +1 -0
  522. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  523. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  524. package/src/workflow-runtime/schema.ts +79 -4
  525. package/src/workflow-runtime/types.ts +35 -4
  526. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  536. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  537. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  556. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  614. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  615. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
@@ -0,0 +1,60 @@
1
+ import type { GateCallerReason } from './gate-scope.js';
2
+
3
+ export interface GateCallerCandidate {
4
+ readonly file: string;
5
+ readonly reasons: readonly GateCallerReason[];
6
+ }
7
+
8
+ /** Path segments between `file` and the nearest changed path's directory (0 = same directory). */
9
+ function directoryDistance(file: string, changedPaths: readonly string[]): number {
10
+ const dir = file.split('/').slice(0, -1);
11
+ let best = Infinity;
12
+ for (const changed of changedPaths) {
13
+ const other = changed.split('/').slice(0, -1);
14
+ let shared = 0;
15
+ while (shared < dir.length && shared < other.length && dir[shared] === other[shared]) shared += 1;
16
+ best = Math.min(best, dir.length - shared + other.length - shared);
17
+ }
18
+ return best;
19
+ }
20
+
21
+ /**
22
+ * Rank gate caller tests by closeness to the change, nearest first (GATE-CALLERS2 — the cap keeps the head).
23
+ * A `route` candidate names a route on a changed diff line, so it ranks with touched tests (distance 0);
24
+ * otherwise the distance is the shortest reverse-import path from a changed file (direct importer = 1,
25
+ * unreachable = after every reachable candidate). Equal distances prefer the test nearest a changed file
26
+ * in the directory tree, then numeric-aware path order. Inputs are not modified.
27
+ * `importersByFile` maps each imported file to its immediate importers (tests or sources).
28
+ */
29
+ export function rankGateCallerCandidates<T extends GateCallerCandidate>(
30
+ changedPaths: readonly string[],
31
+ candidates: readonly T[],
32
+ importersByFile: ReadonlyMap<string, readonly string[]>,
33
+ ): T[] {
34
+ const distances = new Map<string, number>();
35
+ const queue: string[] = [];
36
+ for (const path of changedPaths) {
37
+ if (distances.has(path)) continue;
38
+ distances.set(path, 0);
39
+ queue.push(path);
40
+ }
41
+ for (let index = 0; index < queue.length; index += 1) {
42
+ const source = queue[index]!;
43
+ const nextDistance = distances.get(source)! + 1;
44
+ for (const importer of importersByFile.get(source) ?? []) {
45
+ if (distances.has(importer)) continue;
46
+ distances.set(importer, nextDistance);
47
+ queue.push(importer);
48
+ }
49
+ }
50
+ const keys = new Map(candidates.map((candidate) => [candidate, {
51
+ distance: candidate.reasons.includes('route') ? 0 : distances.get(candidate.file) ?? Infinity,
52
+ directory: directoryDistance(candidate.file, changedPaths),
53
+ }]));
54
+ return [...candidates].sort((left, right) => {
55
+ const a = keys.get(left)!;
56
+ const b = keys.get(right)!;
57
+ return (a.distance - b.distance || 0) || (a.directory - b.directory || 0)
58
+ || left.file.localeCompare(right.file, undefined, { numeric: true });
59
+ });
60
+ }
@@ -15,16 +15,19 @@ import { resolveGateScope } from './gate-scope.js';
15
15
  import { debug } from '../debug/log.js';
16
16
  import { buildDocumentGuardianIndex, formatDocumentGuardians } from './document-guardian-index.js';
17
17
  import { buildImporterTestIndex, isTestPath, type ImporterTestIndex } from './importer-test-index.js';
18
+ import { buildRouteConsumerTestIndex } from './route-consumer-test-index.js';
18
19
  import { gitChangedFiles, observeGateBaselineLocation } from './seams.js';
19
20
  import {
20
21
  collectBaseLandingCommits,
21
22
  overlapWithCurrentChanges,
22
23
  } from '../cli/pr-granularity.js';
23
24
  import { listWorktrees } from '../git-fs/worktree.js';
25
+ import { runShardedGateTests } from '../self-dev/shard-run.js';
24
26
 
25
27
  interface SelfGateCliOptions {
26
28
  base?: string;
27
29
  pr?: string;
30
+ shards?: number;
28
31
  }
29
32
 
30
33
  interface ProcessResult {
@@ -74,6 +77,7 @@ interface SelfGateCliDeps {
74
77
  readFile?: (path: string) => string | undefined;
75
78
  runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
76
79
  runBaseline?: (cwd: string, files: readonly string[], baseRef: string) => BaselineProcessResult;
80
+ runShards?: typeof runShardedGateTests;
77
81
  runIsolationGate?: (out: GateOutput) => number;
78
82
  runMockModuleRestoreGate?: (out: GateOutput) => number;
79
83
  /** 모델 이름 하드코딩 래칫(🅕 #20521) — `pr land` 만 물고 하니스 무인 병합은 안 물면 위반이 main 에 들어가 남의 착지를 막는다(🅣 2026-09-25). */
@@ -571,11 +575,16 @@ function logGateCliBaseline(cwd: string, payload: GateCliBaselinePayload): void
571
575
 
572
576
  export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): SelfGateCliResult {
573
577
  if (options.base && options.pr) throw new Error('use either --base <ref> or --pr <number>, not both');
578
+ if (options.shards !== undefined && (!Number.isSafeInteger(options.shards) || options.shards < 1)) throw new Error('invalid --shards count');
574
579
  const selection = (deps.changedFiles ?? ((dir, input) => defaultChangedFiles(dir, input, deps.runCommand)))(cwd, options);
575
580
  const exists = deps.exists ?? ((path) => existsSync(`${cwd}/${path}`));
576
581
  const importerIndex = buildGateImporterTestIndex(selection.files, cwd, deps.runCommand);
577
582
  const lookupFailed = importerIndex && 'lookupFailed' in importerIndex ? importerIndex.lookupFailed : undefined;
578
- const scope = resolveGateScope(selection.files, exists, importerIndex && !('lookupFailed' in importerIndex) ? importerIndex : undefined);
583
+ const availableIndex = importerIndex && !('lookupFailed' in importerIndex) ? importerIndex : undefined;
584
+ const routeIndex = availableIndex?.testPaths
585
+ ? buildRouteConsumerTestIndex(cwd, availableIndex.testPaths, selection.files, selection.baseRef) : null;
586
+ const scope = resolveGateScope(selection.files, exists, availableIndex,
587
+ { routeConsumerTestIndex: routeIndex ?? undefined });
579
588
  const testFiles = [...(scope.testArgs ?? [])];
580
589
  const unrunImporterTotal = lookupFailed ? null : (scope.importerTestsNotRun?.total ?? 0);
581
590
  const importerLookupFailed = Boolean(lookupFailed);
@@ -601,6 +610,9 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
601
610
  // 🚨 러너 우주 «밖» — 형제들과 같은 정책으로 «말만» 한다(`OBS-T418`).
602
611
  formatUnrunnableChangeKinds(selection.files),
603
612
  formatUnrunImporterTests(scope.importerTestsNotRun, lookupFailed),
613
+ `caller tests: ${lookupFailed ? `lookup failed (${lookupFailed})` : scope.callerTests.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ') || (routeIndex?.lookupFailures.length ? 'route lookup incomplete' : '(none)')}`,
614
+ ...(routeIndex?.lookupFailures.length ? [`⚠️ caller route base lookup failed — unmeasured: ${routeIndex.lookupFailures.map(({ source, reason }) => `${source} (${reason})`).join(', ')}`] : []),
615
+ ...(scope.callerTestsOverflow.length ? [`⚠️ caller test cap exceeded — not run: ${scope.callerTestsOverflow.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ')}`] : []),
604
616
  changedTestCountNote(cwd, selection.files, selection.baseRef, deps.runCommand, deps.readFile),
605
617
  ];
606
618
  if (options.pr) {
@@ -629,6 +641,33 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
629
641
  return { exitCode: androidPassed && iosPassed && pwaPassed && policyPassed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests };
630
642
  }
631
643
 
644
+ if (options.shards !== undefined) {
645
+ const sharded = (deps.runShards ?? runShardedGateTests)(cwd, testFiles, selection.baseRef, options.shards);
646
+ lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})`);
647
+ for (const attempt of sharded.attempts) lines.push(`shard attempt: ${attempt.shardId} #${attempt.attempt}`);
648
+ const { aggregate } = sharded;
649
+ if (aggregate.status === 'unmeasured') lines.push(`shards: unmeasured (${aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit'})`);
650
+ else if (aggregate.report) {
651
+ const report = aggregate.report;
652
+ logGateCliBaseline(cwd, {
653
+ introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown,
654
+ preconditionUnmet: report.preconditionUnmet, timedOut: report.timedOut,
655
+ timeoutPassedAtBase: report.timeoutPassedAtBase, failures: report.failures.slice(0, 20),
656
+ baselineFiles: report.files, baselineStatus: report.baselineStatus, unrunImporterTotal, lookupFailed: importerLookupFailed,
657
+ });
658
+ lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
659
+ } else {
660
+ lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
661
+ logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
662
+ }
663
+ const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
664
+ return {
665
+ exitCode: aggregate.status !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed ? 1 : 0,
666
+ lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
667
+ documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
668
+ };
669
+ }
670
+
632
671
  const test = (deps.runTests ?? ((dir, files) => (deps.runCommand ?? defaultRunCommand)('bun', ['test', ...files], dir)))(cwd, testFiles);
633
672
  const worktreeLog = formatProcessOutput(test);
634
673
  if (test.status === 0 && !test.error) {
@@ -29,6 +29,11 @@
29
29
  // → 유도 결과는 **반드시 존재하는 파일**이어야 한다.
30
30
 
31
31
  import { importerTestsNotInRunSet, type ImporterTestIndex } from './importer-test-index.js';
32
+ import type { RouteConsumerTestIndex } from './route-consumer-test-index.js';
33
+ import { rankGateCallerCandidates } from './gate-candidate-ranking.js';
34
+
35
+ export const GATE_CALLER_TEST_LIMIT = 30;
36
+ export type GateCallerReason = 'import' | 'route';
32
37
 
33
38
  /** 테스트 파일 판정(기존 `seams.ts` 정규식과 동일 — 어휘 분기 금지). */
34
39
  const TEST_RE = /\.(test|spec)\.[cm]?[tj]sx?$/;
@@ -245,11 +250,7 @@ interface GateScopeDecision {
245
250
  readonly unverified: readonly string[];
246
251
  /** elanous 자체가 남긴 런타임 산출물. 미검증 사용자 변경에서 제외하되 경로를 보존한다. */
247
252
  readonly elanousRuntimeArtifacts: readonly string[];
248
- /** ⭐ **편집되지 않았는데 함께 끌어와 돌린** 연관 테스트(`changed-tests` 분기 전용).
249
- * ⚠️ 직전 판본은 이 자리에 `unrunRelatedTests`(=실행집합에 없는 연관 테스트)를 뒀는데,
250
- * 실행집합이 연관 테스트를 **전부 포함**하도록 바뀌었으므로 그 값은 **정의상 항상 빈 배열**이었다.
251
- * 빈 배열을 보고 *"안 돈 게 없다"* 고 읽게 되지만 그건 사실 확인이 아니라 계산의 결과였다
252
- * (관측이 사실 아닌 값을 나르는 형태). ⇒ **실제로 일어난 일**을 센다: 합집합이 구제한 파일들. */
253
+ /** ⭐ 편집되지 않았는데 함께 끌어와 돌린 연관 테스트(`changed-tests` 분기) — 합집합이 실제로 구제한 파일들. */
253
254
  readonly pulledInRelatedTests: readonly string[];
254
255
  /** 실행 집합에 없는, 변경 소스를 상대 import 하는 테스트. 색인이 주입되지 않으면 null. */
255
256
  readonly importerTestsNotRun: {
@@ -258,6 +259,10 @@ interface GateScopeDecision {
258
259
  readonly truncated: boolean;
259
260
  readonly unresolvedRelativeSpecifiers: number;
260
261
  } | null;
262
+ /** Selected reverse-dependent tests and why they were pulled into the gate. */
263
+ readonly callerTests: readonly { readonly file: string; readonly reasons: readonly GateCallerReason[] }[];
264
+ /** Caller tests exceeding the cap, retained in full for warning and diagnosis. */
265
+ readonly callerTestsOverflow: readonly { readonly file: string; readonly reasons: readonly GateCallerReason[] }[];
261
266
  }
262
267
 
263
268
  /**
@@ -274,7 +279,7 @@ export function resolveGateScope(
274
279
  changed: readonly string[],
275
280
  exists: (path: string) => boolean,
276
281
  importerTestIndex?: ImporterTestIndex,
277
- opts?: { mode?: GateScopeMode; isDeleted?: (path: string) => boolean },
282
+ opts?: { mode?: GateScopeMode; isDeleted?: (path: string) => boolean; routeConsumerTestIndex?: RouteConsumerTestIndex },
278
283
  ): GateScopeDecision {
279
284
  // ⚠️ **실존 검증(리뷰 must-fix 4R)** — `gitChangedFiles` 는 `git diff --name-only HEAD` 라
280
285
  // **삭제·rename 前 경로도 포함**한다. 그걸 그대로 `testArgs` 로 넘기면 필터가 아무것도 매치하지
@@ -328,18 +333,43 @@ export function resolveGateScope(
328
333
  const observationFor = (runSet: readonly string[]) => importerTestIndex
329
334
  ? importerTestsNotInRunSet(importerTestIndex, userChanged, runSet)
330
335
  : null;
331
- const base = { sourceFiles, documentPaths, ignoredOutsideSrc, missingTestFiles, elanousRuntimeArtifacts,
336
+ const conventional = deriveRelatedTests(userChanged, exists);
337
+ const alreadySelected = new Set([...testFiles, ...conventional]);
338
+ const callers = new Map<string, Set<GateCallerReason>>();
339
+ for (const source of userChanged) {
340
+ for (const [reason, tests] of [
341
+ ['import', importerTestIndex?.testsBySource.get(source) ?? []],
342
+ ['route', opts?.routeConsumerTestIndex?.testsBySource.get(source) ?? []],
343
+ ] as const) {
344
+ for (const test of tests) {
345
+ if (!exists(test) || alreadySelected.has(test)) continue;
346
+ const reasons = callers.get(test) ?? new Set<GateCallerReason>();
347
+ reasons.add(reason);
348
+ callers.set(test, reasons);
349
+ }
350
+ }
351
+ }
352
+ // GATE-CALLERS2 — the cap keeps the candidates closest to the change, not the alphabetically first.
353
+ const candidates = rankGateCallerCandidates(userChanged, [...callers].map(([file, reasons]) => ({ file, reasons: [...reasons] })),
354
+ importerTestIndex?.testsBySource ?? new Map());
355
+ const callerTests = candidates.slice(0, GATE_CALLER_TEST_LIMIT);
356
+ const callerTestsOverflow = candidates.slice(GATE_CALLER_TEST_LIMIT);
357
+ const runWithCallers = (tests: readonly string[]) => [...new Set([...tests, ...callerTests.map(({ file }) => file)])];
358
+ const base = { sourceFiles, documentPaths, ignoredOutsideSrc, missingTestFiles, elanousRuntimeArtifacts, callerTests, callerTestsOverflow,
332
359
  unverified: [] as readonly string[], derived: [] as readonly string[], pulledInRelatedTests: [] as readonly string[] };
333
360
  const withDocumentNonContribution = (runSet: readonly string[]) => ({
334
361
  documentsWithoutDerivedTests: documentsWithoutDerivedTestsFor(runSet),
335
362
  });
336
363
 
337
364
  if (testFiles.length > 0) {
338
- const allRelatedTests = deriveRelatedTests(userChanged, exists);
339
- const runSet = [...new Set([...testFiles, ...allRelatedTests])];
365
+ // Edited tests ⊕ every related test of the changed sources ⊕ capped callers (restored 10-04: #23467 narrowed this
366
+ // to edited tests only, so a co-located sibling of a changed source stopped running — 0.2.12 gate introduced).
367
+ const allRelatedTests = conventional;
368
+ const runSet = runWithCallers([...testFiles, ...allRelatedTests]);
340
369
  // 편집된 테스트만 돌렸다면 빠졌을 것들 — 이 목록이 비어있지 않다는 것은 합집합이 실제로 구제했다는 뜻이다.
341
370
  const pulledInRelatedTests = allRelatedTests.filter((f) => !testFiles.includes(f));
342
- return { ...base, ...withDocumentNonContribution(runSet), testArgs: runSet, unverified: unverifiedFor(runSet), pulledInRelatedTests, importerTestsNotRun: observationFor(runSet), skipTestStep: false, reason: 'changed-tests' };
371
+ return { ...base, ...withDocumentNonContribution(runSet), testArgs: runSet, unverified: unverifiedFor(runSet), pulledInRelatedTests,
372
+ importerTestsNotRun: observationFor(runSet), skipTestStep: false, reason: 'changed-tests' };
343
373
  }
344
374
  if (userChanged.length === 0) {
345
375
  // postsync 빈 범위는 기존 no-changes(깨끗함)와 다른 값이다. 일반 호출자는 계속 no-changes를 읽는다.
@@ -348,9 +378,10 @@ export function resolveGateScope(
348
378
  if (nonDoc.length === 0) {
349
379
  return { ...base, ...withDocumentNonContribution([]), importerTestsNotRun: observationFor([]), skipTestStep: true, reason: 'docs-only' };
350
380
  }
351
- const derived = deriveRelatedTests(userChanged, exists);
352
- if (derived.length > 0) {
353
- return { ...base, ...withDocumentNonContribution(derived), derived, testArgs: derived, unverified: unverifiedFor(derived), importerTestsNotRun: observationFor(derived), skipTestStep: false, reason: 'derived' };
381
+ const derived = conventional;
382
+ const runSet = runWithCallers(derived);
383
+ if (runSet.length > 0) {
384
+ return { ...base, ...withDocumentNonContribution(runSet), derived, testArgs: runSet, unverified: unverifiedFor(runSet), importerTestsNotRun: observationFor(runSet), skipTestStep: false, reason: 'derived' };
354
385
  }
355
386
  // 실행 집합이 비었으므로 비문서 전부가 미검증이다.
356
387
  return { ...base, ...withDocumentNonContribution([]), unverified: unverifiedFor([]), importerTestsNotRun: observationFor([]), skipTestStep: true, reason: 'no-related-tests' };
@@ -0,0 +1,171 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { applyGraphOverlays, type GraphOverlaySpec, type OverlayPatchOp, type OverlayRejection } from './graph-overlay-yaml.js';
3
+ import { edgeMapOf, graphVersionHash, type GraphEdgeSpec, type GraphNodeSpec, type GraphTemplateSpec } from './graph-yaml.js';
4
+ import { inspectPipelineGraph } from './pipeline-shape.js';
5
+ import { hasNodeKind } from '../graph-kinds/registry.js';
6
+
7
+ /** A proposed change to one existing outcome of a conditional route. Unconditional and fallback edges are protected. */
8
+ export interface GraphVariantRoute {
9
+ readonly from: string;
10
+ readonly outcome: string;
11
+ readonly to: string;
12
+ }
13
+
14
+ export interface GraphVariantGrowth {
15
+ readonly node: GraphNodeSpec;
16
+ readonly from: string;
17
+ readonly outcome: string;
18
+ readonly returnTo?: string;
19
+ }
20
+
21
+ export interface GraphVariantPlan {
22
+ readonly maxVisits?: Readonly<Record<string, number>>;
23
+ readonly routes?: readonly GraphVariantRoute[];
24
+ readonly growth?: GraphVariantGrowth;
25
+ }
26
+
27
+ export type GraphVariantRejection =
28
+ | { readonly kind: 'invalid-goal' }
29
+ | { readonly kind: 'unknown-node'; readonly node: string }
30
+ | { readonly kind: 'invalid-budget'; readonly node: string; readonly value: number }
31
+ | { readonly kind: 'protected-edge'; readonly from: string; readonly outcome: string }
32
+ | { readonly kind: 'unknown-outcome'; readonly from: string; readonly outcome: string }
33
+ | { readonly kind: 'duplicate-route'; readonly from: string; readonly outcome: string }
34
+ | { readonly kind: 'ambiguous-outcome'; readonly from: string; readonly outcome: string }
35
+ | { readonly kind: 'unreachable-terminal'; readonly node: string }
36
+ | { readonly kind: 'invalid-graph'; readonly defects: ReturnType<typeof inspectPipelineGraph> }
37
+ | { readonly kind: 'overlay-rejected'; readonly rejections: readonly OverlayRejection[] }
38
+ | { readonly kind: 'invalid-growth'; readonly reason: string };
39
+
40
+ export type GraphVariantResult =
41
+ | { readonly ok: true; readonly overlay: GraphOverlaySpec; readonly template: GraphTemplateSpec; readonly patches: readonly OverlayPatchOp[] }
42
+ | { readonly ok: false; readonly rejections: readonly GraphVariantRejection[] };
43
+
44
+ /** Pure, deterministic variant authoring. Never mutates the supplied template and never writes an overlay. */
45
+ export function createGraphVariant(input: {
46
+ readonly template: GraphTemplateSpec;
47
+ readonly goal: string;
48
+ readonly plan: GraphVariantPlan;
49
+ }): GraphVariantResult {
50
+ const { template, goal, plan } = input;
51
+ const known = new Set(template.nodes.map((node) => node.nodeId));
52
+ const rejections: GraphVariantRejection[] = [];
53
+ if (!/^g_[a-z0-9_-]+$/i.test(goal)) rejections.push({ kind: 'invalid-goal' });
54
+ if (plan.growth) {
55
+ const { node, from, outcome, returnTo } = plan.growth;
56
+ if (!node || typeof node !== 'object') return { ok: false, rejections: [{ kind: 'invalid-growth', reason: 'growth requires one new contracted node' }] };
57
+ const edgeIndex = template.edges.findIndex((edge) => edge.from === from);
58
+ const edge = template.edges[edgeIndex];
59
+ if (!known.has(from) || known.has(node.nodeId) || template.terminalNodes.includes(from) ||
60
+ typeof node.nodeId !== 'string' || !node.nodeId || typeof node.recipe !== 'string' || !node.recipe ||
61
+ typeof node.kind !== 'string' || !hasNodeKind('harness', node.kind) || !Number.isSafeInteger(node.maxVisits) || node.maxVisits < 1 ||
62
+ typeof node.contract?.tools !== 'string' || !node.contract.tools.trim() || !Array.isArray(node.contract.inputs) ||
63
+ !Array.isArray(node.contract.outputs) || typeof outcome !== 'string' || !outcome || !edge || edge.to !== undefined || edge.on !== 'outcome' ||
64
+ !edge.map || Object.hasOwn(edge.map, outcome) ||
65
+ template.edges.filter((candidate) => candidate.from === from).length !== 1 ||
66
+ typeof returnTo !== 'string' || !known.has(returnTo) || plan.routes?.length || Object.keys(plan.maxVisits ?? {}).length) {
67
+ rejections.push({ kind: 'invalid-growth', reason: 'growth requires one new contracted node, one missing conditional outcome and an existing return destination' });
68
+ }
69
+ if (rejections.length) return { ok: false, rejections };
70
+ const addedEdge: GraphEdgeSpec = { from: node.nodeId, to: returnTo as string };
71
+ const patches: OverlayPatchOp[] = [
72
+ { op: 'add', path: '/nodes/-', value: node },
73
+ { op: 'add', path: `/edges/${edgeIndex}/map/${outcome.replace(/~/g, '~0').replace(/\//g, '~1')}`, value: node.nodeId },
74
+ { op: 'add', path: '/edges/-', value: addedEdge },
75
+ ];
76
+ const normalized = JSON.stringify({ graph: graphVersionHash(template), goal, patches });
77
+ const overlay: GraphOverlaySpec = { overlayId: `variant-${createHash('sha256').update(normalized).digest('hex').slice(0, 16)}`,
78
+ target: template.graphId, stage: 'runtime', appliesWhen: `goal_key == ${goal}`, patch: patches };
79
+ // Existing YAML runner nodes predate contracts; only the newly proposed node must supply one.
80
+ const validationTemplate: GraphTemplateSpec = { ...template, nodes: template.nodes.map((existing) => ({
81
+ ...existing, contract: existing.contract?.tools ? existing.contract : { inputs: [], tools: 'existing', outputs: [] },
82
+ })) };
83
+ const applied = applyGraphOverlays(validationTemplate, [overlay]);
84
+ if (!applied.ok) return { ok: false, rejections: [{ kind: 'overlay-rejected', rejections: applied.rejections }] };
85
+ const projected: GraphTemplateSpec = { ...applied.template, nodes: [...template.nodes, node] };
86
+ const edges = edgeMapOf(projected);
87
+ const reached = new Set<string>();
88
+ const pending = [projected.entryNode];
89
+ while (pending.length) {
90
+ const at = pending.pop()!;
91
+ if (reached.has(at)) continue;
92
+ reached.add(at);
93
+ pending.push(...(edges[at] ?? []));
94
+ }
95
+ const unreachable = projected.terminalNodes.filter((terminal) => !reached.has(terminal) || (edges[terminal]?.length ?? 0) !== 0);
96
+ if (unreachable.length) return { ok: false, rejections: unreachable.map((terminal) => ({ kind: 'unreachable-terminal', node: terminal })) };
97
+ return { ok: true, overlay, template: projected, patches };
98
+ }
99
+ const patches: OverlayPatchOp[] = [];
100
+
101
+ for (const [node, value] of Object.entries(plan.maxVisits ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
102
+ if (!known.has(node)) { rejections.push({ kind: 'unknown-node', node }); continue; }
103
+ if (!Number.isSafeInteger(value) || value < 1) { rejections.push({ kind: 'invalid-budget', node, value }); continue; }
104
+ const index = template.nodes.findIndex((candidate) => candidate.nodeId === node);
105
+ if (template.nodes[index]!.maxVisits !== value) patches.push({ op: 'replace', path: `/nodes/${index}/maxVisits`, value });
106
+ }
107
+
108
+ const seen = new Set<string>();
109
+ for (const route of [...(plan.routes ?? [])].sort((a, b) => {
110
+ const left = JSON.stringify([a.from, a.outcome, a.to]);
111
+ const right = JSON.stringify([b.from, b.outcome, b.to]);
112
+ return left < right ? -1 : left > right ? 1 : 0;
113
+ })) {
114
+ if (!known.has(route.from)) { rejections.push({ kind: 'unknown-node', node: route.from }); continue; }
115
+ if (!known.has(route.to)) { rejections.push({ kind: 'unknown-node', node: route.to }); continue; }
116
+ const key = JSON.stringify([route.from, route.outcome]);
117
+ if (seen.has(key)) { rejections.push({ kind: 'duplicate-route', from: route.from, outcome: route.outcome }); continue; }
118
+ seen.add(key);
119
+ const matches = template.edges.filter((edge) => edge.from === route.from && edge.map && Object.hasOwn(edge.map, route.outcome));
120
+ // One patch addresses one edge, so an outcome declared on two conditional edges would validate a graph we do not return.
121
+ if (matches.length > 1) { rejections.push({ kind: 'ambiguous-outcome', from: route.from, outcome: route.outcome }); continue; }
122
+ const conditional = matches[0];
123
+ if (!conditional) {
124
+ const protectedEdge = template.edges.some((edge) => edge.from === route.from && (edge.to !== undefined || edge.fallback?.length));
125
+ rejections.push(protectedEdge
126
+ ? { kind: 'protected-edge', from: route.from, outcome: route.outcome }
127
+ : { kind: 'unknown-outcome', from: route.from, outcome: route.outcome });
128
+ continue;
129
+ }
130
+ const index = template.edges.indexOf(conditional);
131
+ if (conditional.map![route.outcome] !== route.to) {
132
+ // JSON Pointer escaping keeps even unusual, already-declared outcome labels addressable.
133
+ const label = route.outcome.replace(/~/g, '~0').replace(/\//g, '~1');
134
+ patches.push({ op: 'replace', path: `/edges/${index}/map/${label}`, value: route.to });
135
+ }
136
+ }
137
+ if (rejections.length > 0) return { ok: false, rejections };
138
+
139
+ const projected: GraphTemplateSpec = {
140
+ ...template,
141
+ nodes: template.nodes.map((node) => ({ ...node, maxVisits: plan.maxVisits?.[node.nodeId] ?? node.maxVisits })),
142
+ edges: template.edges.map((edge) => edge.map === undefined ? edge : {
143
+ ...edge,
144
+ map: Object.fromEntries(Object.entries(edge.map).map(([outcome, to]) => [outcome,
145
+ plan.routes?.find((route) => route.from === edge.from && route.outcome === outcome)?.to ?? to])),
146
+ }),
147
+ };
148
+ const edges = edgeMapOf(projected);
149
+ const defects = inspectPipelineGraph(edges, projected.entryNode);
150
+ const reached = new Set<string>();
151
+ const pending = [projected.entryNode];
152
+ while (pending.length) {
153
+ const node = pending.pop()!;
154
+ if (reached.has(node)) continue;
155
+ reached.add(node);
156
+ for (const to of edges[node] ?? []) pending.push(to);
157
+ }
158
+ const unreachable = projected.terminalNodes.filter((node) => !reached.has(node) || (edges[node]?.length ?? 0) !== 0);
159
+ if (unreachable.length > 0) return { ok: false, rejections: unreachable.map((node) => ({ kind: 'unreachable-terminal', node })) };
160
+ if (defects.length > 0) return { ok: false, rejections: [{ kind: 'invalid-graph', defects }] };
161
+ const normalized = JSON.stringify({ graph: graphVersionHash(template), goal, patches });
162
+ const overlayId = `variant-${createHash('sha256').update(normalized).digest('hex').slice(0, 16)}`;
163
+ const overlay: GraphOverlaySpec = { overlayId, target: template.graphId, stage: 'launch', appliesWhen: `goal_key == ${goal}`, patch: patches };
164
+ // Existing runner YAML nodes may predate contracts; the plan only changes routes and visits.
165
+ const validationTemplate: GraphTemplateSpec = { ...template, nodes: template.nodes.map((node) => ({
166
+ ...node, contract: node.contract?.tools ? node.contract : { inputs: [], tools: 'existing', outputs: [] },
167
+ })) };
168
+ const applied = applyGraphOverlays(validationTemplate, [overlay]);
169
+ if (!applied.ok) return { ok: false, rejections: [{ kind: 'overlay-rejected', rejections: applied.rejections }] };
170
+ return { ok: true, overlay, template: projected, patches };
171
+ }
@@ -28,7 +28,7 @@ export function runHarnessPolicyGates(input: {
28
28
  ['mock-module-restore-gate', input.gates?.['mock-module-restore-gate'] ?? runMockModuleRestoreGate],
29
29
  ['model-hardcode-gate', input.gates?.['model-hardcode-gate'] ?? runModelHardcodeGate],
30
30
  ['daemon-port-gate', input.gates?.['daemon-port-gate'] ?? ((out) => runDaemonPortGate({ log: out.log, error: out.error, cwd: out.cwd, args: [] }))],
31
- // LEAK1 — the check release prepare fails on, before the harness lands (0.2.7: a mark in a test title).
31
+ // LEAK1 — the same pre-export check as pr land; an unmeasured result is a nonzero failure, not a pass.
32
32
  ['public-export-leak', input.gates?.['public-export-leak'] ?? runPublicExportLeakGate],
33
33
  ];
34
34
  const failures: Array<{ gate: GateName; lines: string[] }> = [];
@@ -58,11 +58,13 @@ import { childRunContextEnv, childProviderKeyEnv, childLlmSelectionEnv, type Chi
58
58
  import { childToolProfile } from '../agent/tool-profile.js';
59
59
  import { escalationAllowedForProvider } from './rework-policy.js';
60
60
  import { getUserConfig, resolveActiveProvider, resolveRoleLlm } from '../user-config.js';
61
+ import { goalDifficultySignals, classifyGoalDifficulty, resolveImplementDifficulty } from '../llm/difficulty.js';
61
62
  import { childNestEnv } from '../agent/nest-depth.js';
62
63
  import { childPtyIdentityEnv } from '../agent/pty-identity.js';
63
64
  import { elanousTuiSpawnOptions } from './elanous-tui-spawn.js';
64
65
  import { describeGrokCredentialFreshness, readGrokTokenFreshness, type GrokCredentialFreshnessSnapshot } from '../acp/grok-auth.js';
65
66
  import { debug } from '../debug/log.js';
67
+ import { observeExternalEvent } from '../context-bus/external-events.js';
66
68
  import { sendOutbound } from '../domains/outbound-alert.js';
67
69
  import { formatPtyLinkMessage, readReportOrigin } from './report-origin.js';
68
70
  import { DETACHED_PROGRESS_FRAME_PREFIX, decodeDetachedProgressFrame } from '../harness/dispatch-detached.js';
@@ -920,6 +922,8 @@ export interface HeadlessGoalLoopPtyOptions {
920
922
  cwd: string;
921
923
  /** 이미 featurePrompt() 적용된 프롬프트(범위제한·클린빌드 앵커 포함). */
922
924
  featurePrompt: string;
925
+ /** Original goal document before the execution prompt is decorated. */
926
+ goalDocument?: string;
923
927
  configDir?: string;
924
928
  /** ★ K run-identity — 이 실행이 속한 per-run join anchor. 미지정 시 상속(env) → 없으면 canonical mint
925
929
  * (`perCallRunId`). 호출자(runSelfImplement)가 지정하면 **리워크 라운드가 하나의 runId 를 공유**해
@@ -1164,14 +1168,30 @@ export interface HeadlessGoalLoopPtyResult {
1164
1168
  ptyId: string;
1165
1169
  }
1166
1170
 
1171
+ export function pickImplementRoleForGoal(document: string): ReturnType<typeof resolveRoleLlm> | undefined {
1172
+ try {
1173
+ const config = getUserConfig();
1174
+ const role = resolveRoleLlm('implement', { config });
1175
+ if (config.harness?.difficultyPlacement !== true || role.source !== 'default') return role;
1176
+ const signals = goalDifficultySignals(document);
1177
+ const level = classifyGoalDifficulty(signals);
1178
+ const picked = resolveImplementDifficulty(role, level);
1179
+ try {
1180
+ debug.log('llm.difficulty', 'pick', { level, tier: picked.tier ?? null, signals });
1181
+ debug.log('harness.role-llm', 'difficulty-placement', { difficulty: level, tier: picked.tier, source: role.source });
1182
+ } catch { /* observation is fail-soft */ }
1183
+ return picked;
1184
+ } catch { return undefined; }
1185
+ }
1186
+
1167
1187
  export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions): Promise<HeadlessGoalLoopPtyResult> {
1168
1188
  const childLlm = opts.childLlm;
1169
1189
  if (childLlm && (typeof childLlm.provider !== 'string' || typeof childLlm.model !== 'string' || !childLlm.provider.trim() || !childLlm.model.trim())) {
1170
1190
  throw new Error('childLlm.provider and childLlm.model must both be non-empty');
1171
1191
  }
1172
- // ⭐ B14 — 역할 `implement` 해석(명시 자식 LLM · 런 단위 모델이 없을 때만). 실패하면 종전(주 모델 상속)으로.
1192
+ // ⭐ B14 — 명시 자식 LLM · 런 단위 모델이 없을 때 골 난이도에 따라 역할 `implement` 기본 등급을 고른다.
1173
1193
  const implementRole = !childLlm && !process.env.ELANOUS_LLM_MODEL?.trim()
1174
- ? (() => { try { return resolveRoleLlm('implement'); } catch { return undefined; } })()
1194
+ ? pickImplementRoleForGoal(opts.goalDocument ?? opts.featurePrompt)
1175
1195
  : undefined;
1176
1196
  // ⭐ B9 — 승급 판정에 쓸 «유효 provider»: 명시 자식 → 역할 → 런 env → config(auto 는 실제 결정으로).
1177
1197
  const effectiveChildProvider = childLlm?.provider ?? implementRole?.provider ?? process.env.ELANOUS_LLM_PROVIDER?.trim()
@@ -1202,6 +1222,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
1202
1222
  const controlInboxDir = resolveControlInboxDir(space.id);
1203
1223
  const { key: screenKey } = resolveHarnessScreenKey(space.id, opts.cwd);
1204
1224
  const executionId = mintPtyId('self');
1225
+ const contextSource = `elanous://harness/${encodeURIComponent(runId)}/${encodeURIComponent(executionId)}`;
1205
1226
  const boundaryRequestsEnv = harnessBoundaryRequestsEnv(executionId);
1206
1227
  const boundaryResponsesEnv = harnessBoundaryResponsesEnv(executionId);
1207
1228
  const boundaryRequestsPath = boundaryRequestsEnv.ELANOUS_HARNESS_BOUNDARY_REQUESTS ?? '';
@@ -1213,6 +1234,8 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
1213
1234
  const emitDone = (data: Record<string, unknown>): void => {
1214
1235
  if (doneEmitted) return;
1215
1236
  doneEmitted = true;
1237
+ if (spawned) observeExternalEvent({ origin: 'harness-child', kind: 'finished',
1238
+ summary: `Harness child finished: ${String(data.exitReason ?? 'unknown').slice(0, 60)}`, source: contextSource });
1216
1239
  debug.log('self-implement', 'headless.done', {
1217
1240
  ptyId: executionId,
1218
1241
  runId,
@@ -1326,7 +1349,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
1326
1349
  ...(space ? harnessSpaceEnv(space.kind, space.id, runId) : {}), // 자식 goal-loop 자기인지(#4948 프리앰블) + ★K runId 명시 전파(captured-env 경계)
1327
1350
  ...harnessBoundaryEnv(opts.cwd), // ★ #4 명시 쓰기 경계 — worktree(cwd) 전파 → 자식 부팅 시 결정론 경계 활성(정본 오염 봉쇄)
1328
1351
  ...(opts.documentReferences?.length ? { ELANOUS_DOCUMENT_REFERENCES: JSON.stringify(opts.documentReferences) } : {}),
1329
- // ⭐ BACKLOG B14 (대표 2026-09-25) — 명시 자식 LLM 도 런 단위 모델(`ELANOUS_LLM_MODEL`)도 없으면 역할 `implement`(better)로 고른다.
1352
+ // ⭐ B14/E2 — 명시 자식 LLM·런 단위 모델이 없으면 골 난이도를 적용한 구현 역할 모델을 릴레이한다.
1330
1353
  ...childLlmSelectionEnv(childLlm ?? (implementRole ? { provider: implementRole.provider, model: implementRole.model, source: 'config' } : undefined)),
1331
1354
  // 결정 2026-09-23 — 명시 childLlm 은 «같은 provider» 사다리 안에서만 한 칸 승급한다(없으면 승급 안 함).
1332
1355
  // 미지정 경로는 기존 티어(codex sol 등)를 그대로 쓴다.
@@ -1351,6 +1374,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
1351
1374
  },
1352
1375
  });
1353
1376
  spawned = true;
1377
+ observeExternalEvent({ origin: 'harness-child', kind: 'started', summary: 'Harness child started', source: contextSource });
1354
1378
  phase = 'initialization';
1355
1379
  const ptyId = h.id;
1356
1380
  // ⭐⭐ M5 — 그 판정을 «런 슈퍼바이저 레코드»로 올린다. 종전엔 경계 판정이 자기 로그에만 남아
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync,
3
3
  import { tmpdir } from 'node:os';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { debug } from '../debug/log.js';
6
+ import { releaseGitDiffPaths, releasePathHold, releasePathHoldShouldPost, releasePathHoldComment, releasePathHoldCommentsArgs, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
6
7
  import { detectTestInterference, parseFailureCount, runBunTest } from '../../scripts/detect-test-interference.js';
7
8
  import { runTestInterferenceGate } from '../../scripts/ci-test-interference-gate.js';
8
9
 
@@ -158,6 +159,26 @@ export async function runHostRegate(input: HostRegateInput, deps: HostRegateDeps
158
159
  base = run('git', ['merge-base', baseCommit, input.headCommit], worktree);
159
160
  files = run('git', ['diff', '--name-only', base, input.headCommit], worktree).split('\n').filter(Boolean);
160
161
  if (!files.length) throw new Error('changed files unavailable');
162
+ if (!input.verifyOnly) {
163
+ // --name-only lists only the destination of a rename. Inspect both sides without
164
+ // changing the gate's existing changed-file list or its test selection.
165
+ const guardPaths = releaseGitDiffPaths(run('git', ['diff', '--find-renames', '--name-status', '-z', base, input.headCommit], worktree));
166
+ const heldPath = releasePathHold(guardPaths);
167
+ if (heldPath) {
168
+ debug.log('self-dev.merge', 'release-path-hold', { number: input.prNumber, path: heldPath, label: RELEASE_PATH_LABEL, surface: 'host-regate' });
169
+ try {
170
+ const existing: unknown = JSON.parse(run('gh', ['label', 'list', '--search', RELEASE_PATH_LABEL, '--json', 'name'], input.repoRoot));
171
+ if (!Array.isArray(existing)) throw new Error('invalid label list');
172
+ if (!existing.some((item: unknown) => !!item && typeof item === 'object' && 'name' in item && item.name === RELEASE_PATH_LABEL)) {
173
+ run('gh', ['label', 'create', RELEASE_PATH_LABEL, '--color', 'D93F0B', '--description', 'Release path requires OP approval'], input.repoRoot);
174
+ }
175
+ run('gh', ['pr', 'edit', String(input.prNumber), '--add-label', RELEASE_PATH_LABEL], input.repoRoot);
176
+ } catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number: input.prNumber, action: 'label', error: String(error) }); }
177
+ try { if (releasePathHoldShouldPost(() => JSON.parse(run('gh', releasePathHoldCommentsArgs(input.prNumber), input.repoRoot)))) run('gh', ['pr', 'comment', String(input.prNumber), '--body', releasePathHoldComment(heldPath)], input.repoRoot); }
178
+ catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number: input.prNumber, action: 'comment', error: String(error) }); }
179
+ return result('failed', 'release-path-hold', `OP approval required: ${heldPath}`);
180
+ }
181
+ }
161
182
  // Materialize the proposed merge of this exact PR head into the observed base.
162
183
  // A clean head checkout cannot expose integration breaks introduced by the base.
163
184
  try { run('git', ['merge', '--no-ff', '--no-commit', input.headCommit], worktree); }
@@ -234,7 +255,7 @@ export async function runHostRegate(input: HostRegateInput, deps: HostRegateDeps
234
255
  catch (e) { log('unmeasured', { pr: input.prNumber, files, os: process.platform, failedStep: 'cleanup', detail: String(e) }); }
235
256
  try { release?.(); }
236
257
  catch (e) { log('unmeasured', { pr: input.prNumber, files, os: process.platform, failedStep: 'lock', detail: String(e) }); }
237
- if (failures.length) {
258
+ if (failures.length && failures[0]?.step !== 'release-path-hold') {
238
259
  const { step, detail } = failures[0]!;
239
260
  const body = `호스트 재게이트 실패(${process.platform}): ${step} — ${detail.replace(/\s+/g, ' ').slice(0, 180)}`;
240
261
  try { run('gh', ['pr', 'comment', String(input.prNumber), '--body', body], input.repoRoot); }
@@ -6,6 +6,7 @@ const IMPORTER_TEST_DISPLAY_LIMIT = 20;
6
6
 
7
7
  export interface ImporterTestIndex {
8
8
  readonly testsBySource: ReadonlyMap<string, readonly string[]>;
9
+ readonly testPaths?: readonly string[];
9
10
  readonly unresolvedRelativeSpecifiers: number;
10
11
  }
11
12
 
@@ -105,7 +106,7 @@ export function buildImporterTestIndex(cwd: string, testPaths: readonly string[]
105
106
  testsBySource.set(source, importers);
106
107
  }
107
108
  }
108
- return { testsBySource, unresolvedRelativeSpecifiers };
109
+ return { testsBySource, testPaths, unresolvedRelativeSpecifiers };
109
110
  }
110
111
 
111
112
  export function importerTestsNotInRunSet(