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,84 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdtempSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join, resolve } from 'node:path';
5
+ import { debug } from '../../src/debug/log.js';
6
+
7
+ export interface CutBranchOptions { version: string; base: string; pick: string[]; dryRun?: boolean; repoRoot?: string; log?: (line: string) => void }
8
+
9
+ // git-spawn-allow: release branch operations happen only in an isolated temporary worktree; main is never checked out or changed.
10
+ function git(repo: string, args: string[]): string {
11
+ const result = spawnSync('git', args, { cwd: repo, encoding: 'utf8' });
12
+ if (result.status !== 0 || result.error) throw new Error(`git ${args[0]} failed: ${(result.stderr || result.error || result.stdout || 'no output').toString().trim()}`);
13
+ return result.stdout.trim();
14
+ }
15
+
16
+ function ancestor(repo: string, sha: string, ref: string): boolean {
17
+ const result = spawnSync('git', ['merge-base', '--is-ancestor', sha, ref], { cwd: repo });
18
+ if (result.status !== 0 && result.status !== 1) throw new Error(`git merge-base failed: ${result.error || result.stderr || 'unknown'}`);
19
+ return result.status === 0;
20
+ }
21
+
22
+ export function cutReleaseBranch(opts: CutBranchOptions): { branch: string; commit: string | null; dryRun: boolean } {
23
+ const repo = resolve(opts.repoRoot ?? process.cwd());
24
+ const branch = `release/${opts.version}`;
25
+ const log = opts.log ?? console.log;
26
+ const report = (event: 'created' | 'refused' | 'conflict', reason?: string, commit?: string) =>
27
+ debug.log('release-loop.cut-branch', event, { version: opts.version, branch, ...(commit ? { commit } : {}), ...(reason ? { reason } : {}) });
28
+ try {
29
+ if (!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(opts.version)) throw new Error(`invalid release version: ${opts.version}`);
30
+ if (!opts.pick.length) throw new Error('at least one --pick commit is required');
31
+ for (const sha of [opts.base, ...opts.pick]) if (!/^[0-9a-f]{7,40}$/i.test(sha)) throw new Error(`invalid commit SHA: ${sha}`);
32
+ git(repo, ['fetch', 'origin', 'main']);
33
+ const base = git(repo, ['rev-parse', '--verify', `${opts.base}^{commit}`]);
34
+ if (!ancestor(repo, base, 'origin/main')) throw new Error(`base ${base} is not an ancestor of origin/main`);
35
+ const picks = opts.pick.map((sha) => git(repo, ['rev-parse', '--verify', `${sha}^{commit}`]));
36
+ for (const sha of picks) if (!ancestor(repo, sha, 'origin/main')) throw new Error(`pick ${sha} is not an ancestor of origin/main`);
37
+ for (const sha of picks) if (ancestor(repo, sha, base)) throw new Error(`pick ${sha} is already in base ${base}`);
38
+ if (new Set(picks).size !== picks.length) throw new Error('duplicate --pick commit');
39
+ for (const sha of picks) if (git(repo, ['rev-list', '--parents', '-n', '1', sha]).split(' ').length !== 2) throw new Error(`pick ${sha} must have exactly one parent`);
40
+ if (git(repo, ['ls-remote', '--heads', 'origin', `refs/heads/${branch}`])) throw new Error(`${branch} already exists on origin`);
41
+ if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { cwd: repo }).status === 0) throw new Error(`${branch} already exists locally`);
42
+ const pkg = JSON.parse(git(repo, ['show', `${base}:package.json`])) as { version?: unknown };
43
+ if (pkg.version !== opts.version) throw new Error(`base package.json version ${pkg.version} is not ${opts.version}`);
44
+ log(`${branch}: ${base} + ${picks.join(' + ')}${opts.dryRun ? ' (dry-run)' : ''}`);
45
+ if (opts.dryRun) return { branch, commit: null, dryRun: true };
46
+ const temp = mkdtempSync(join(tmpdir(), 'release-cut-branch-'));
47
+ const tree = join(temp, 'tree');
48
+ let added = false;
49
+ let commit: string | undefined;
50
+ try {
51
+ git(repo, ['worktree', 'add', '--detach', tree, base]);
52
+ added = true;
53
+ for (const sha of picks) {
54
+ try { git(tree, ['cherry-pick', sha]); }
55
+ catch (error) {
56
+ const files = git(tree, ['diff', '--name-only', '--diff-filter=U']);
57
+ if (!files) throw error;
58
+ report('conflict', `cherry-pick ${sha}`);
59
+ throw new Error(`cherry-pick ${sha} 충돌 — 손으로 풀 곳: ${files.split('\n').join(', ')} (release/${opts.version} 가지는 만들지 않음)`);
60
+ }
61
+ }
62
+ commit = git(tree, ['rev-parse', 'HEAD']);
63
+ const finalPackage = JSON.parse(git(tree, ['show', 'HEAD:package.json'])) as { version?: unknown };
64
+ if (finalPackage.version !== opts.version) throw new Error(`picked branch package.json version ${finalPackage.version} is not ${opts.version}`);
65
+ } finally {
66
+ try {
67
+ if (added) git(repo, ['worktree', 'remove', '--force', tree]);
68
+ } finally { rmSync(temp, { recursive: true, force: true }); }
69
+ }
70
+ if (!commit) throw new Error('cherry-pick produced no commit');
71
+ const push = git(repo, ['push', '--porcelain', `--force-with-lease=refs/heads/${branch}:`, 'origin', `${commit}:refs/heads/${branch}`]);
72
+ const newBranch = push.split('\n').some((line) => {
73
+ const [flag, ref, summary] = line.split('\t');
74
+ return flag === '*' && ref?.endsWith(`:refs/heads/${branch}`) && summary === '[new branch]';
75
+ });
76
+ if (!newBranch) throw new Error(`${branch} already exists on origin (push did not create a new branch)`);
77
+ report('created', undefined, commit);
78
+ log(`${branch} → ${commit}`);
79
+ return { branch, commit, dryRun: false };
80
+ } catch (error) {
81
+ if (!(error instanceof Error && error.message.includes('충돌'))) report('refused', error instanceof Error ? error.message : String(error));
82
+ throw error;
83
+ }
84
+ }
@@ -124,14 +124,16 @@ export const POD_MEMORY_SOURCE = 'docs/measurements/td1-whole-gate-mechanical-20
124
124
  /** GT1 — files per retry chunk when a root shard fails (0.2.7: bundles of 54+ files OOMed at 16Gi, smaller passed). */
125
125
  export const POD_SHARD_FILE_CAP = 27;
126
126
 
127
- export const POD_SWEEP_INTEGRATION_ONLY: readonly string[] = ['scripts/install.test.ts'];
128
- /** Whole-repository audits run alone in the nightly test-diet graph, not in release-gate shards. */
127
+ // review-model-ab: Pod 에서 출력 없이 멈춤 2/2(10-04 0.2.11 · 로컬 단독 4/0 · 1.7s) — GATE-STALL 수리 전까지 Pod 밖.
128
+ export const POD_SWEEP_INTEGRATION_ONLY: readonly string[] = ['scripts/install.test.ts', 'scripts/review-model-ab.test.ts'];
129
+ /** Nightly-only whole-repository cases; gate runs the fixture cases in these same files. */
129
130
  export const GATE_NIGHTLY_AUDITS: readonly string[] = [
130
- 'test/f12-sweep.test.ts', // Sweeps the whole repository; 7.8 GB even after TD1a.
131
- 'scripts/unwired-exports.test.ts', // Compiles and scans all exports; 9.9 GB.
132
- 'test/guardian/dispatch-surface-contract.test.ts', // Compiles repository-wide dispatch contracts; 8.3 GB.
133
- 'test/pwa-build-typecheck.test.ts', // Builds and typechecks the whole PWA; 4.2 GB.
134
- 'test/user-config-mcp.test.ts', // 2.1 GB peak; keep the gate below the 2 GB audit budget.
131
+ // Replaces F12's real-repo bucket B apps/pwa scope check and its whole-repo export partition check.
132
+ 'test/f12-sweep.test.ts',
133
+ // Replaces unwired-exports' real src/oauth caller check and its src/ad-pipeline CLI scan.
134
+ 'scripts/unwired-exports.test.ts',
135
+ // Replaces pwa-build-typecheck's full root tsc and PWA tsc sweeps (PWA build also runs in the release loop).
136
+ 'test/pwa-build-typecheck.test.ts',
135
137
  ];
136
138
  const tail40 = (output: string) => output.trimEnd().split(/\r?\n/).slice(-40).join('\n');
137
139
  const lastStartedTestFile = (output: string, paths: string[]): string | undefined => {
@@ -219,15 +221,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
219
221
  // CDP 시험은 `test:deterministic` 이 스스로 뺀다 — 조각에 그것만 남으면 bun «시험 없음» exit 1 을 «불완전»으로 읽었다(09-30 G1d 실측 둘).
220
222
  // bun 의 탐색은 숨은 디렉터리(`.x/`)를 안 연다 — 사람의 `bun test` 가 한 번도 안 돌리는 빈 픽스처가 조각에 혼자 남아 «Ran 0 tests» 를 «불완전»으로 읽었다(09-30 G1e 5번 조각).
221
223
  const assignable = files.filter((file) => !cdpPatterns.includes(file) && !POD_SWEEP_INTEGRATION_ONLY.includes(file)
222
- && !GATE_NIGHTLY_AUDITS.includes(file) && !file.split('/').some((part) => part.startsWith('.')));
224
+ && !file.split('/').some((part) => part.startsWith('.')));
223
225
  const integrationOnly = files.filter((file) => POD_SWEEP_INTEGRATION_ONLY.includes(file));
224
226
  if (integrationOnly.length) debug.log('release-loop.gate', 'pod-sweep-integration-only', { files: integrationOnly });
225
- const nightlyAudits = files.filter((file) => GATE_NIGHTLY_AUDITS.includes(file));
226
- if (nightlyAudits.length) debug.log('release-loop.gate', 'pod-sweep-nightly-audit', { files: nightlyAudits });
227
227
  if (!assignable.length) throw new Error('sweep incomplete: no tests ran');
228
228
  const durations = pod.durationSource ? readFileDurations(pod.durationSource) : new Map<string, number>();
229
229
  const memory = readFileMemory(join(tree, POD_MEMORY_SOURCE));
230
- const heavy = new Set(assignable.filter((file) => (memory.get(file) ?? 0) >= POD_HEAVY_FILE_MB));
230
+ // The TD1 measurements predate the fixture-only gate; do not isolate those five files at their old 2–13 GB peaks.
231
+ const fixtureOnly = new Set([...GATE_NIGHTLY_AUDITS, 'test/guardian/dispatch-surface-contract.test.ts', 'test/user-config-mcp.test.ts']);
232
+ const heavy = new Set(assignable.filter((file) => !fixtureOnly.has(file) && (memory.get(file) ?? 0) >= POD_HEAVY_FILE_MB));
231
233
  const light = assignable.filter((file) => !heavy.has(file));
232
234
  const shards = [
233
235
  ...(light.length ? planShards(light, durations, shardCount) : []),
@@ -266,7 +268,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
266
268
  }, 0);
267
269
  const knownTimes = assignable.map((file) => durations.get(file)).filter((value): value is number => value !== undefined && Number.isFinite(value) && value >= 0).sort((a, b) => a - b);
268
270
  const unknownSeconds = knownTimes.length ? (knownTimes[Math.floor((knownTimes.length - 1) / 2)]! + knownTimes[Math.floor(knownTimes.length / 2)]!) / 2 : 1;
269
- const runShard = async (paths: string[], shard: number, depth = 0, branch = ''): Promise<{ runs: ShardRun[]; stalled: NonNullable<GateResult['stalledShards']> }> => {
271
+ const runShard = async (paths: string[], shard: number, depth = 0, branch = '', retriedNoOutput = false): Promise<{ runs: ShardRun[]; stalled: NonNullable<GateResult['stalledShards']> }> => {
270
272
  const ignores = cdpPatterns.filter((pattern) => paths.includes(pattern))
271
273
  .flatMap((pattern) => ['--path-ignore-patterns', pattern]);
272
274
  // 파일별 소요는 junit 으로 남긴다 — 콘솔 요약(판정 원천)은 그대로이고, 느린 시험 목록(K10 D4)·계층 분리(D2)의 자가 된다.
@@ -353,6 +355,11 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
353
355
  }
354
356
  }
355
357
  }
358
+ if (reason === 'no-output' && !retriedNoOutput) {
359
+ const retry = await runShard(paths, shard, depth, `${branch}-retry`, true);
360
+ debug.log('release-loop.gate', 'pod-shard-retry', { shard, files: paths, reason, outcome: retry.stalled[0]?.reason ?? 'ok' });
361
+ return retry;
362
+ }
356
363
  if (reason) {
357
364
  // 깊이 2 에서 «이름 없는 실패»·«불완전»도 파일 단위로 가른다 — 아니면 149파일 조각의 실패 하나가 끝까지 주인 없이 남는다(09-30 G1e 7번 조각: 요약 28 · 이름 27).
358
365
  // 로그 없이 죽은 조각(`no-output` · OOM)도 같다 — 09-30 G1f ② 4-0-0 은 150파일이 격리 0 으로 남았다.
@@ -437,9 +444,9 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
437
444
  const outputs: string[] = [];
438
445
  let total = { pass: 0, fail: 0, errors: 0, ran: 0, files: 0 };
439
446
  for (const group of groups) {
440
- if (!group.paths.length || !files.some((f) => !GATE_NIGHTLY_AUDITS.includes(f) && group.paths.some((p) => f === p || f.startsWith(`${p}/`)))) continue;
447
+ if (!group.paths.length || !files.some((f) => group.paths.some((p) => f === p || f.startsWith(`${p}/`)))) continue;
441
448
  const start = Date.now();
442
- const groupIgnores = [...new Set([...cdpPatterns, ...GATE_NIGHTLY_AUDITS])]
449
+ const groupIgnores = [...new Set(cdpPatterns)]
443
450
  .filter((pattern) => files.includes(pattern) && group.paths.some((p) => pattern === p || pattern.startsWith(`${p}/`)))
444
451
  .flatMap((pattern) => ['--path-ignore-patterns', pattern]);
445
452
  const run = await command('bun', ['run', 'test:deterministic', ...groupIgnores, ...group.paths.map(asPath)], tree);
@@ -508,7 +515,7 @@ function readBaseline(root: string, version: string): { commit: string; failures
508
515
  return record;
509
516
  }
510
517
 
511
- function baselineCommit(root: string, version: string): string {
518
+ export function baselineCommit(root: string, version: string): string {
512
519
  const path = join(root, 'release', version, 'release.json');
513
520
  const manifest: unknown = JSON.parse(readFileSync(path, 'utf8'));
514
521
  const commit = manifest && typeof manifest === 'object' && 'sourceCommit' in manifest ? manifest.sourceCommit : undefined;
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env bun
2
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { basename, join, posix, resolve } from 'node:path';
5
+ import { debug } from '../../src/debug/log.js';
6
+ import { getUserConfig } from '../../src/user-config.js';
7
+ import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
8
+ import { getElanousConfigDirOverride } from '../../src/elanous-config-dir.js';
9
+ import { baselineCommit } from './gate-node.js';
10
+ import { diffFailures, junitFailures } from './gate-diff.js';
11
+ import { finishNode, readGraphContext, runCommand, type CommandResult, type CommandRunner, type GraphContext } from './node-verdict.js';
12
+
13
+ const sha = /^[a-f0-9]{7,40}$/i;
14
+ const testFile = /\.test\.tsx?$/;
15
+ const hostName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
16
+ const quote = (s: string) => `'${s.replaceAll("'", "'\\''")}'`;
17
+
18
+ export interface MacSmokeDeps {
19
+ context?: GraphContext;
20
+ configHost?: () => unknown;
21
+ baseline?: (version: string) => string;
22
+ changedFiles?: (baseline: string, commit: string) => string[];
23
+ findImporters?: (sources: string[], commit: string) => string[];
24
+ repo?: string;
25
+ }
26
+
27
+ export interface MacSmokeResult extends Record<string, unknown> {
28
+ outcome: 'ok' | 'fail' | 'error';
29
+ verdict: 'pass' | 'fail';
30
+ summary: string;
31
+ files: number;
32
+ newFailures: number;
33
+ preexisting: number;
34
+ smoke: 'pass' | 'fail' | 'unmeasured' | 'skipped';
35
+ }
36
+
37
+ function requireOk(result: CommandResult, stage: string): string {
38
+ if (result.status !== 0) throw new Error(`${stage} 실패`);
39
+ return result.stdout;
40
+ }
41
+
42
+ function names(output: string): string[] {
43
+ return output.split('\0').filter(Boolean);
44
+ }
45
+
46
+ function safeFile(file: string): boolean {
47
+ return !file.startsWith('/') && !file.split('/').includes('..') && /^[\w./@+-]+$/.test(file);
48
+ }
49
+
50
+ function changedTests(run: CommandRunner, repo: string, base: string, cut: string): string[] {
51
+ return names(requireOk(run('git', ['diff', '--name-only', '-z', `${base}..${cut}`], repo), '변경 파일 조회'));
52
+ }
53
+
54
+ function importers(run: CommandRunner, repo: string, sources: string[], commit: string): string[] {
55
+ const picked = new Set<string>();
56
+ for (const source of sources) {
57
+ const stem = source.replace(/\.(?:tsx?|jsx?|mjs|cjs)$/, '');
58
+ const directoryIndex = basename(stem) === 'index' ? posix.dirname(stem) : undefined;
59
+ const search = run('git', ['grep', '-l', '-z', '-F', '-e', basename(stem), '-e', source, '-e', stem, ...(directoryIndex ? ['-e', directoryIndex] : []), commit, '--', '*.test.ts', '*.test.tsx'], repo);
60
+ // git grep returns 1 for no matches; other errors mean the selection could not be measured.
61
+ if (search.status !== 0 && search.status !== 1) throw new Error('시험 import 검색 실패');
62
+ for (const entry of names(search.stdout)) {
63
+ if (!entry.startsWith(`${commit}:`)) throw new Error('시험 import 경로 측정 불가');
64
+ const file = entry.slice(commit.length + 1);
65
+ if (!safeFile(file) || !testFile.test(file)) throw new Error('시험 import 경로 측정 불가');
66
+ const contents = requireOk(run('git', ['show', `${commit}:${file}`], repo), '컷 시험 읽기');
67
+ if (contents.includes(source)) { picked.add(file); continue; }
68
+ for (const match of contents.matchAll(/(?:\bfrom\s*|\bimport\s*(?:\(\s*)?|\brequire\s*\()\s*['"]([^'"]+)['"]/g)) {
69
+ const spec = match[1]!;
70
+ const target = spec.startsWith('.') ? posix.normalize(posix.join(posix.dirname(file), spec)) : spec.replace(/^@\//, '');
71
+ const targetStem = target.replace(/\.(?:tsx?|jsx?|mjs|cjs)$/, '');
72
+ if (target === source || targetStem === stem || (directoryIndex && targetStem === directoryIndex)) { picked.add(file); break; }
73
+ }
74
+ }
75
+ }
76
+ return [...picked];
77
+ }
78
+
79
+ // Collection proof comes from bun's junit file (one top-level <testsuite file=…> per collected file):
80
+ // non-TTY bun prints no per-file headers when everything passes, so stdout cannot prove which files ran (10-03 real run).
81
+ export function testFailures(result: CommandResult, junit: string | null, selected: string[]): string[] {
82
+ const output = `${result.stdout}\n${result.stderr}`.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
83
+ const summary = /Ran \d+ tests? across (\d+) files?/.exec(output);
84
+ if (junit === null || result.status === null || !summary || Number(summary[1]) !== selected.length) throw new Error('시험 결과 측정 불가');
85
+ const observed = new Set<string>();
86
+ let depth = 0;
87
+ for (const match of junit.matchAll(/<(\/?)testsuite\b([^>]*?)(\/?)>/g)) {
88
+ const [, closing, attrs, selfClosing] = match;
89
+ if (closing) { depth = Math.max(0, depth - 1); continue; }
90
+ if (depth === 0) {
91
+ const file = /\bfile="([^"]*)"/.exec(attrs!)?.[1] ?? /\bname="([^"]*)"/.exec(attrs!)?.[1];
92
+ if (file) observed.add(file.replace(/^\.\//, ''));
93
+ }
94
+ if (!selfClosing) depth += 1;
95
+ }
96
+ const failures = junitFailures(junit);
97
+ if (observed.size !== selected.length || selected.some((file) => !observed.has(file))
98
+ || (result.status !== 0 && failures.length === 0)) {
99
+ throw new Error('시험 결과 측정 불가');
100
+ }
101
+ return failures;
102
+ }
103
+
104
+ export function runMacSmoke(run: CommandRunner = runCommand, deps: MacSmokeDeps = {}): MacSmokeResult {
105
+ const start = Date.now();
106
+ let version = '';
107
+ let host = '';
108
+ let files = 0;
109
+ let newFailures = 0;
110
+ let preexisting = 0;
111
+ let smoke: MacSmokeResult['smoke'] = 'unmeasured';
112
+ let result: MacSmokeResult;
113
+ let work: string | undefined;
114
+ let cutCreated = false;
115
+ let baseCreated = false;
116
+ let remote = '';
117
+ let remoteAttempt = false;
118
+ const repo = resolve(deps.repo ?? process.cwd());
119
+ const command = (cmd: string, args: string[], cwd: string, timeoutMs?: number): CommandResult => host === 'local'
120
+ ? run(cmd, args, cwd, timeoutMs)
121
+ : run('ssh', [host, `PATH="$HOME/.bun/bin:$HOME/.local/bin:$PATH"; export PATH; cd ${quote(cwd)} && ${[cmd, ...args].map(quote).join(' ')}`], undefined, timeoutMs);
122
+ try {
123
+ const context = deps.context ?? readGraphContext();
124
+ version = context.input.version;
125
+ const configured = context.input.macSmokeHost ?? (deps.configHost ?? (() => (getUserConfig().raw.release as { macSmoke?: { host?: unknown } } | undefined)?.macSmoke?.host))();
126
+ if (configured === undefined || configured === null || configured === '') {
127
+ smoke = 'skipped';
128
+ result = { outcome: 'ok', verdict: 'pass', summary: 'macOS 대상 없음 — 건너뜀', files, newFailures, preexisting, smoke };
129
+ } else {
130
+ if (typeof configured !== 'string' || !hostName.test(configured)) throw new Error('macSmokeHost 호스트 이름이 유효하지 않음');
131
+ host = configured;
132
+ const commit = context.input.commit ?? context.outputs['version-release']?.commit;
133
+ if (typeof commit !== 'string' || !sha.test(commit)) throw new Error('컷 커밋 없음 또는 유효하지 않음 — 측정 불가');
134
+ const platform = host === 'local' ? run('uname', ['-s'], repo) : run('ssh', [host, 'uname -s'], repo);
135
+ if (requireOk(platform, '호스트 플랫폼 확인').trim() !== 'Darwin') throw new Error('macOS 호스트 아님 — 측정 불가');
136
+ const instance = effectiveInstanceRoot();
137
+ const root = getElanousConfigDirOverride() ? instance : releaseLedgerRoot();
138
+ const base = (deps.baseline ?? ((v) => baselineCommit(existsSync(join(root, 'release', v, 'release.json')) ? root : instance, v)))(context.input.previousVersion);
139
+ if (!sha.test(base)) throw new Error('지난 판 커밋 측정 불가');
140
+ const changed = (deps.changedFiles ?? ((b, c) => changedTests(run, repo, b, c)))(base, commit);
141
+ if (!changed.every(safeFile)) throw new Error('변경 파일 경로 측정 불가');
142
+ const sources = changed.filter((file) => /\.(?:tsx?|jsx?|mjs|cjs)$/.test(file) && !testFile.test(file));
143
+ const candidates = [...new Set([...changed.filter((file) => testFile.test(file)), ...(deps.findImporters ?? ((paths, revision) => importers(run, repo, paths, revision)))(sources, commit)])].sort();
144
+ if (!candidates.every(safeFile)) throw new Error('시험 파일 경로 측정 불가');
145
+ const cutFiles = new Set(requireOk(run('git', ['ls-tree', '-r', '--name-only', '-z', commit], repo), '컷 파일 조회').split('\0'));
146
+ const selected = candidates.filter((file) => cutFiles.has(file));
147
+ const clipped = Math.max(0, selected.length - 200);
148
+ const tests = selected.slice(0, 200);
149
+ files = tests.length;
150
+ const baseFiles = new Set(requireOk(run('git', ['ls-tree', '-r', '--name-only', '-z', base], repo), '기준 파일 조회').split('\0'));
151
+ work = mkdtempSync(join(tmpdir(), 'release-mac-smoke-'));
152
+ let source = repo;
153
+ if (host !== 'local') {
154
+ remoteAttempt = true;
155
+ remote = requireOk(run('ssh', [host, 'mktemp -d /tmp/release-mac-smoke-XXXXXXXX'], repo), '호스트 연결').trim();
156
+ if (!/^\/tmp\/release-mac-smoke-[\w-]+$/.test(remote)) throw new Error('원격 임시 경로 측정 불가');
157
+ requireOk(command('git', ['init', '--bare', `${remote}/mirror.git`], remote), '원격 저장소 생성');
158
+ for (const revision of new Set([commit, base])) {
159
+ requireOk(run('git', ['push', `${host}:${remote}/mirror.git`, `${revision}:refs/heads/mac-smoke-${revision}`], repo), '원격 커밋 전송');
160
+ }
161
+ requireOk(command('git', ['clone', '-q', '--no-checkout', `${remote}/mirror.git`, `${remote}/repo`], remote), '원격 복제');
162
+ source = `${remote}/repo`;
163
+ }
164
+ const cutTree = host === 'local' ? join(work, 'cut') : `${remote}/cut`;
165
+ requireOk(command('git', ['-C', source, 'worktree', 'add', '--detach', cutTree, commit], source), '체크아웃');
166
+ cutCreated = true;
167
+ requireOk(command('bun', ['install'], cutTree), '설치');
168
+ const execute = (tree: string, paths: string[]): string[] => {
169
+ const failures: string[] = [];
170
+ for (let i = 0; i < paths.length; i += 50) {
171
+ const batch = paths.slice(i, i + 50);
172
+ const report = `.mac-smoke-junit-${i}.xml`;
173
+ // `./` makes each path exact — bare paths are substring filters and also run same-named copies (10-03 nested worktrees).
174
+ const tested = command('bun', ['test', '--reporter=junit', `--reporter-outfile=${report}`, ...batch.map((file) => `./${file}`)], tree, 1_200_000);
175
+ const xml = command('cat', [report], tree);
176
+ failures.push(...testFailures(tested, xml.status === 0 ? xml.stdout : null, batch));
177
+ }
178
+ return failures;
179
+ };
180
+ const cutFailures = execute(cutTree, tests);
181
+ const versionSmoke = command('bun', ['bin/elanous.mjs', '--test', '--version'], cutTree);
182
+ const scheduleSmoke = command('bun', ['bin/elanous.mjs', '--test', 'release', 'schedule', 'list', '--json'], cutTree);
183
+ smoke = versionSmoke.status === 0 && scheduleSmoke.status === 0 ? 'pass' : 'fail';
184
+ let baselineFailures: string[] = [];
185
+ if (cutFailures.length) {
186
+ const baseTree = host === 'local' ? join(work, 'base') : `${remote}/base`;
187
+ requireOk(command('git', ['-C', source, 'worktree', 'add', '--detach', baseTree, base], source), '기준 체크아웃');
188
+ baseCreated = true;
189
+ requireOk(command('bun', ['install'], baseTree), '기준 설치');
190
+ baselineFailures = execute(baseTree, tests.filter((file) => baseFiles.has(file)));
191
+ }
192
+ const delta = diffFailures(cutFailures, baselineFailures);
193
+ newFailures = delta.newFailures.length;
194
+ preexisting = delta.common.length;
195
+ const outcome = newFailures || smoke !== 'pass' ? 'fail' : 'ok';
196
+ result = { outcome, verdict: outcome === 'ok' ? 'pass' : 'fail', files, newFailures, preexisting, smoke,
197
+ summary: `macOS ${outcome} · 새 실패 ${newFailures} · 기존 실패 ${preexisting} · 스모크 ${smoke}${clipped ? ` · 잘림 ${clipped}` : ''}${newFailures ? ` · ${delta.newFailures.slice(0, 5).map((id) => id.split(' > ')[0]).join(', ')}` : ''}` };
198
+ }
199
+ } catch {
200
+ result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (연결·체크아웃·설치·시험 결과 확인 필요)', files, newFailures, preexisting, smoke };
201
+ } finally {
202
+ if (remoteAttempt && remote) {
203
+ try {
204
+ const cleanup = run('ssh', [host, `rm -rf -- ${quote(remote)}`]);
205
+ if (cleanup.status !== 0) result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (임시 작업 정리 실패)', files, newFailures, preexisting, smoke };
206
+ } catch { result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (임시 작업 정리 실패)', files, newFailures, preexisting, smoke }; }
207
+ }
208
+ if (work) {
209
+ if (host === 'local') {
210
+ for (const tree of [cutCreated && 'cut', baseCreated && 'base'].filter((name): name is string => Boolean(name))) {
211
+ try {
212
+ const removed = run('git', ['worktree', 'remove', '--force', join(work, tree)], repo);
213
+ if (removed.status !== 0) result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (임시 작업 정리 실패)', files, newFailures, preexisting, smoke };
214
+ } catch { result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (임시 작업 정리 실패)', files, newFailures, preexisting, smoke }; }
215
+ }
216
+ }
217
+ try { rmSync(work, { recursive: true, force: true }); }
218
+ catch { result = { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가 (임시 작업 정리 실패)', files, newFailures, preexisting, smoke }; }
219
+ }
220
+ debug.log('release-loop.mac-smoke', 'judged', { version, host, files, newFailures, smoke, outcome: result!.outcome, ms: Date.now() - start });
221
+ }
222
+ return result!;
223
+ }
224
+
225
+ if (import.meta.main) {
226
+ let version = '';
227
+ try { version = readGraphContext().input.version; process.exitCode = finishNode('mac-smoke', version, runMacSmoke()); }
228
+ catch { process.exitCode = finishNode('mac-smoke', version, { outcome: 'error', verdict: 'fail', summary: 'macOS 측정 불가' }); }
229
+ }
@@ -33,9 +33,9 @@ export function emitNodeResult<T extends Record<string, unknown>>(result: T & {
33
33
  }
34
34
 
35
35
  export interface CommandResult { status: number | null; stdout: string; stderr: string }
36
- export type CommandRunner = (command: string, args: string[], cwd?: string) => CommandResult;
37
- export const runCommand: CommandRunner = (command, args, cwd) => {
38
- const result = spawnSync(command, args, { cwd, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
36
+ export type CommandRunner = (command: string, args: string[], cwd?: string, timeoutMs?: number) => CommandResult;
37
+ export const runCommand: CommandRunner = (command, args, cwd, timeoutMs) => {
38
+ const result = spawnSync(command, args, { cwd, timeout: timeoutMs, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
39
39
  return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr || (result.error ? String(result.error) : '') };
40
40
  };
41
41
 
@@ -1,12 +1,43 @@
1
1
  #!/usr/bin/env bun
2
- import { existsSync, readFileSync } from 'node:fs';
3
- import { homedir } from 'node:os';
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync, symlinkSync } from 'node:fs';
3
+ import { homedir, tmpdir } from 'node:os';
4
4
  import { join, isAbsolute } from 'node:path';
5
5
  import { debug } from '../../src/debug/log.js';
6
6
  import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandResult, type CommandRunner } from './node-verdict.js';
7
7
 
8
8
  interface HostResult { host: string; ok: boolean; before: string; after: string; error?: string; skipped?: string; hooks?: string; restart?: 'no-service' }
9
- interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null }
9
+ /** Where the internal feed is packed from: a checkout of the release tag, never the run's working tree. */
10
+ export interface FeedSource { checkout: string; commit: string; cleanup: () => void }
11
+ interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null; feedSource?: (version: string) => FeedSource }
12
+
13
+ /** Detached worktree at refs/tags/v<version> with the PWA built — the feed ships what was released (10-04 0.2.11:
14
+ * packing process.cwd() shipped main HEAD ee689ad2 as «0.2.11» to node-b·cloud-vm instead of the cut 31129c91). */
15
+ export function tagFeedSource(run: CommandRunner, repo: string = process.cwd()): (version: string) => FeedSource {
16
+ return (version) => {
17
+ const tag = run('git', ['rev-parse', '--verify', `refs/tags/v${version}^{commit}`], repo);
18
+ const commit = tag.stdout.trim();
19
+ if (tag.status !== 0 || !/^[0-9a-f]{40,64}$/.test(commit)) throw new Error(`태그 없음: v${version}`);
20
+ const dir = mkdtempSync(join(tmpdir(), 'ops-feed-'));
21
+ const tree = join(dir, 'tree');
22
+ const cleanup = () => {
23
+ run('git', ['worktree', 'remove', '--force', tree], repo);
24
+ rmSync(dir, { recursive: true, force: true });
25
+ };
26
+ try {
27
+ const added = run('git', ['worktree', 'add', '--detach', tree, commit], repo);
28
+ if (added.status !== 0) throw new Error(`태그 체크아웃 실패: ${reason(added)}`);
29
+ symlinkSync(join(repo, 'node_modules'), join(tree, 'node_modules'));
30
+ if (existsSync(join(repo, 'apps/pwa/node_modules'))) symlinkSync(join(repo, 'apps/pwa/node_modules'), join(tree, 'apps/pwa/node_modules'));
31
+ // The feed carries the PWA build (apps/pwa/out is ignored, so a fresh tag checkout has none until built).
32
+ const built = run('bun', ['bin/elanous.mjs', 'nexus', 'build'], tree, 900_000);
33
+ if (built.status !== 0) throw new Error(`태그 PWA 빌드 실패: ${reason(built)}`);
34
+ } catch (error) {
35
+ cleanup();
36
+ throw error;
37
+ }
38
+ return { checkout: tree, commit, cleanup };
39
+ };
40
+ }
10
41
 
11
42
  function localInstallSource(): string | null {
12
43
  try {
@@ -54,11 +85,21 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
54
85
  : (deps.exists ?? existsSync)(defaultFeed) ? defaultFeed : undefined;
55
86
  let feedError = '';
56
87
  if (feedPath !== undefined) {
88
+ let source: FeedSource | undefined;
57
89
  try {
58
- const feed = run('bun', ['scripts/publish-internal-dist.ts', '--checkout', process.cwd(), '--out', feedPath]);
59
- const data = lastResult(feed);
60
- if (feed.status !== 0 || data?.ok !== true || data.version !== version) feedError = `내부 피드 발행 실패: ${feed.status === 0 && data?.ok === true ? `판 불일치 (${String(data.version)})` : reason(feed)}`;
90
+ source = (deps.feedSource ?? tagFeedSource(run))(version);
91
+ const released = context.outputs['version-release']?.commit;
92
+ if (typeof released === 'string' && released && released !== source.commit) {
93
+ feedError = `내부 피드 발행 실패: 태그 v${version}(${source.commit.slice(0, 12)})가 컷(${released.slice(0, 12)})과 다르다`;
94
+ } else {
95
+ const feed = run('bun', ['scripts/publish-internal-dist.ts', '--checkout', source.checkout, '--out', feedPath]);
96
+ const data = lastResult(feed);
97
+ if (feed.status !== 0 || data?.ok !== true || data.version !== version) feedError = `내부 피드 발행 실패: ${feed.status === 0 && data?.ok === true ? `판 불일치 (${String(data.version)})` : reason(feed)}`;
98
+ else if (data.commit !== source.commit) feedError = `내부 피드 발행 실패: 묶은 커밋 ${String(data.commit).slice(0, 12)} ≠ 태그 ${source.commit.slice(0, 12)}`;
99
+ debug.log('release-loop.ops-upgrade', 'feed-source', { version, commit: source.commit, source: `refs/tags/v${version}`, packed: data?.commit, pwaBuild: data?.pwaBuild });
100
+ }
61
101
  } catch (error) { feedError = `내부 피드 발행 실패: ${firstLine(String(error))}`; }
102
+ finally { source?.cleanup(); }
62
103
  }
63
104
  const results: HostResult[] = [];
64
105
  for (const host of hosts as string[]) {
@@ -2,6 +2,7 @@
2
2
  import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
+ import { WARNING_ONLY } from './auto-approve-node.js';
5
6
  import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
6
7
 
7
8
  export function publicNotes(markdown: string, pages: { pages: Array<{ id: string; slug?: string; source?: string }> }): string {
@@ -40,7 +41,9 @@ export function runPublish(run: CommandRunner = runCommand) {
40
41
  const auto = context.outputs['auto-approve'];
41
42
  if (context.outputs['approve-publish']?.outcome !== 'approved' &&
42
43
  !(auto?.outcome === 'ok' && auto.decidedBy === 'release-loop metrics'
43
- && Array.isArray(auto.metrics) && auto.metrics.length === 8
44
+ // The 8 blocking metrics; warning-only rows (tui-regress · mac-smoke) are shown but never counted (V1g · MAC1).
45
+ && Array.isArray(auto.metrics)
46
+ && auto.metrics.filter((metric: unknown) => !(metric && typeof metric === 'object' && 'name' in metric && WARNING_ONLY.has(String(metric.name)))).length === 8
44
47
  && auto.metrics.every((metric: unknown) => metric && typeof metric === 'object' && 'verdict' in metric && metric.verdict === 'pass'))) {
45
48
  return { outcome: 'fail' as const, verdict: 'fail' as const, summary: 'publish blocked: neither auto-approve nor approve-publish approved' };
46
49
  }
@@ -27,3 +27,45 @@ export function tuiChecks(s: TuiScreens, readyLimitMs = 60_000): TuiCheck[] {
27
27
  export function tuiVerdict(checks: readonly TuiCheck[]): 'pass' | 'fail' {
28
28
  return checks.every((c) => c.pass) ? 'pass' : 'fail';
29
29
  }
30
+
31
+ export type TuiRegress = {
32
+ pass: number;
33
+ fail: number;
34
+ results: Array<{ id: string; title: string; ok: boolean; reason: string }>;
35
+ } | { unmeasured: string };
36
+
37
+ export function validatedTuiRegress(data: unknown): TuiRegress {
38
+ const invalid = { unmeasured: 'tui.regress 결과 없음' };
39
+ if (!data || typeof data !== 'object' || Array.isArray(data)) return invalid;
40
+ const value = data as Record<string, unknown>;
41
+ if (typeof value.unmeasured === 'string' && value.unmeasured.trim()) return { unmeasured: value.unmeasured };
42
+ if (!Array.isArray(value.results) || value.results.length !== 7
43
+ || !Number.isInteger(value.pass) || !Number.isInteger(value.fail)
44
+ || (value.pass as number) < 0 || (value.fail as number) < 0
45
+ || (value.pass as number) + (value.fail as number) !== 7
46
+ || value.results.some((r: unknown) => !r || typeof r !== 'object'
47
+ || typeof (r as Record<string, unknown>).id !== 'string'
48
+ || !/^R[1-7]$/.test((r as Record<string, unknown>).id as string)
49
+ || typeof (r as Record<string, unknown>).title !== 'string'
50
+ || typeof (r as Record<string, unknown>).ok !== 'boolean'
51
+ || typeof (r as Record<string, unknown>).reason !== 'string')
52
+ || value.pass !== value.results.filter((r: { ok: boolean }) => r.ok).length
53
+ || value.fail !== value.results.filter((r: { ok: boolean }) => !r.ok).length
54
+ || new Set(value.results.map((r: { id: string }) => r.id)).size !== 7) return invalid;
55
+ return value as { pass: number; fail: number; results: Array<{ id: string; title: string; ok: boolean; reason: string }> };
56
+ }
57
+
58
+ export function parseTuiRegress(stdout: string): TuiRegress {
59
+ const lines = stdout.trim().split('\n');
60
+ if (lines.length !== 1) return { unmeasured: 'JSON 한 줄이 아니다' };
61
+ try { return validatedTuiRegress(JSON.parse(lines[0]!)); }
62
+ catch { return { unmeasured: 'JSON 결과를 읽을 수 없다' }; }
63
+ }
64
+
65
+ export function regressWarning(regress: TuiRegress): { level: 'ok' | 'warn' | 'unmeasured'; line: string } {
66
+ if ('unmeasured' in regress) return { level: 'unmeasured', line: `tui-regress: unmeasured — ${regress.unmeasured}` };
67
+ const failed = regress.results.filter((result) => !result.ok).map((result) => result.id);
68
+ return failed.length
69
+ ? { level: 'warn', line: `tui-regress: warn — ${failed.join(', ')}` }
70
+ : { level: 'ok', line: `tui-regress: ok — ${regress.pass} pass · 0 fail` };
71
+ }