elanous 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (694) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  7. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  20. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  25. package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f972fc1c00a62e88.js → page-b12b6d2f8d2d1aea.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/{page-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -0
  152. package/apps/pwa/out/ops/seats/index.txt +30 -0
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -0
  178. package/apps/pwa/out/today/index.txt +33 -0
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/field/field-feed.yaml +2 -0
  194. package/graphs/implement-loop.yaml +1 -1
  195. package/graphs/intake/intake-daily.yaml +2 -1
  196. package/graphs/ops/recipes.yaml +3 -0
  197. package/graphs/ops/secret-exposure.yaml +24 -0
  198. package/graphs/release/recipes.yaml +3 -0
  199. package/graphs/release/release-loop.yaml +4 -1
  200. package/graphs/video/explainer-line.yaml +2 -2
  201. package/package.json +2 -1
  202. package/plugins/card-followup/graphs/run-step.ts +48 -13
  203. package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
  204. package/plugins/doc-draft/graphs/run-step.ts +13 -6
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/ci-pwa-build-gate.ts +160 -0
  216. package/scripts/context-hooks/claude-stop.sh +4 -0
  217. package/scripts/context-hooks/emit.ts +24 -0
  218. package/scripts/context-hooks/post-tool-use.sh +4 -0
  219. package/scripts/coord-channel-watch.sh +54 -8
  220. package/scripts/coord-digest.ts +199 -0
  221. package/scripts/coord-post.sh +60 -3
  222. package/scripts/coord-requests-bridge.ts +143 -0
  223. package/scripts/field-feed/lib.ts +4 -0
  224. package/scripts/fleet/node-setup.sh +20 -3
  225. package/scripts/homebrew-formula-bump.ts +69 -0
  226. package/scripts/install.ps1 +68 -9
  227. package/scripts/install.sh +39 -12
  228. package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
  229. package/scripts/lib/tui-regress-checks.ts +146 -0
  230. package/scripts/marketing/measure-site-numbers.ts +169 -0
  231. package/scripts/measure-gate-shards.ts +309 -0
  232. package/scripts/memory-lifecycle-cycle.ts +2 -2
  233. package/scripts/mission-request-judge.ts +31 -1
  234. package/scripts/morning-report.ts +2 -2
  235. package/scripts/opportunity-scan.ts +1 -1
  236. package/scripts/ops-now-probe.ts +327 -0
  237. package/scripts/publish-internal-dist.ts +11 -1
  238. package/scripts/release-loop/auto-approve-node.ts +21 -4
  239. package/scripts/release-loop/cut-branch.ts +84 -0
  240. package/scripts/release-loop/cutoff.ts +19 -8
  241. package/scripts/release-loop/gate-node.ts +14 -13
  242. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  243. package/scripts/release-loop/node-verdict.ts +3 -3
  244. package/scripts/release-loop/ops-upgrade-node.ts +72 -16
  245. package/scripts/release-loop/release-readiness.ts +9 -0
  246. package/scripts/release-loop/tui-node-checks.ts +42 -0
  247. package/scripts/release-loop/tui-sim-node.ts +32 -8
  248. package/scripts/release-loop/unattended-release.ts +5 -3
  249. package/scripts/release-loop/version-node.ts +112 -13
  250. package/scripts/repo-watch-cycle.ts +1 -1
  251. package/scripts/retro-cycle.ts +2 -2
  252. package/scripts/schedule-health-report.ts +1 -1
  253. package/scripts/signal-digest-cycle.ts +2 -7
  254. package/scripts/signal-digest-photo.ts +11 -0
  255. package/scripts/storyboard/storyboard.ts +5 -161
  256. package/scripts/tech1-public-measure.ts +94 -0
  257. package/scripts/test-diet/lib.ts +30 -1
  258. package/scripts/test-diet/node.ts +83 -8
  259. package/scripts/test-timeout-audit.ts +114 -0
  260. package/scripts/tree-sync-alert.ts +1 -1
  261. package/scripts/tui-regress.ts +71 -0
  262. package/scripts/ux/demo-rehearsal.ts +243 -0
  263. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  264. package/scripts/waitlist-daily-digest.ts +1 -1
  265. package/skills/diagram-master/SKILL.md +366 -0
  266. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  267. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  268. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  269. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  270. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  271. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  272. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  273. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  274. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  275. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  276. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  277. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  278. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  279. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  280. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  281. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  282. package/skills/diagram-master/references/examples/README.md +69 -0
  283. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  284. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  285. package/skills/diagram-master/references/pyproject.toml +16 -0
  286. package/skills/diagram-master/references/quality-checklist.md +33 -0
  287. package/skills/diagram-master/references/routing-guide.md +164 -0
  288. package/skills/diagram-master/references/uv.lock +1356 -0
  289. package/skills/explainer-video/SKILL.md +4 -0
  290. package/skills/explainer-video/engine/reel.mjs +18 -13
  291. package/skills/explainer-video/engine/reel.sh +24 -5
  292. package/skills/explainer-video/engine/stitch.mjs +145 -0
  293. package/skills/google-workspace/SKILL.md +33 -0
  294. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  295. package/skills/grill-me/SKILL.md +1 -1
  296. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  297. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  298. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  299. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  300. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  301. package/skills/omni-crawl/SKILL.md +21 -11
  302. package/skills/omni-crawl/scripts/main.ts +6 -6
  303. package/skills/omni-crawl/src/router.ts +3 -3
  304. package/skills/omni-digest/SKILL.md +17 -9
  305. package/skills/omni-digest/digest.md +2 -2
  306. package/skills/omni-digest/src/fetch.ts +30 -3
  307. package/skills/pitch-deck/SKILL.md +36 -0
  308. package/skills/pitch-deck/template.html +80 -0
  309. package/skills/youtube-master/SKILL.md +163 -0
  310. package/skills/youtube-master/package-lock.json +558 -0
  311. package/skills/youtube-master/package.json +13 -0
  312. package/skills/youtube-master/references/study-note-template.md +124 -0
  313. package/skills/youtube-master/scripts/main.ts +435 -0
  314. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  315. package/skills/youtube-master/src/audio.ts +63 -0
  316. package/skills/youtube-master/src/domain-staging.ts +50 -0
  317. package/skills/youtube-master/src/env.ts +36 -0
  318. package/skills/youtube-master/src/obsidian.ts +155 -0
  319. package/skills/youtube-master/src/router.ts +110 -0
  320. package/skills/youtube-master/src/stt.ts +199 -0
  321. package/skills/youtube-master/src/study-note.ts +175 -0
  322. package/skills/youtube-master/src/summarize.ts +358 -0
  323. package/skills/youtube-master/src/transcript.ts +76 -0
  324. package/skills/youtube-master/src/types.ts +91 -0
  325. package/skills/youtube-master/src/util.ts +93 -0
  326. package/skills/youtube-master/src/youtube.ts +70 -0
  327. package/skills/youtube-master/tsconfig.json +13 -0
  328. package/src/acp/codex-approval-adapter.ts +9 -3
  329. package/src/acp/core-turn-bridge.ts +117 -18
  330. package/src/acp/fact-question.ts +11 -0
  331. package/src/acp/server.ts +53 -9
  332. package/src/acp/tool-approval.ts +126 -0
  333. package/src/acp/turn-runner.ts +36 -0
  334. package/src/agent/monad-agent-turn.ts +8 -0
  335. package/src/agent-mission/driver.ts +80 -10
  336. package/src/agent-mission/pty-decision.ts +71 -0
  337. package/src/agent-mission/review-loop.ts +30 -0
  338. package/src/ask-user-question/pending-questions.ts +25 -10
  339. package/src/ask-user-question/types.ts +9 -0
  340. package/src/auth/setup-link-tokens.ts +16 -5
  341. package/src/autopilot/build/integrity-gate.ts +12 -0
  342. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  343. package/src/autopilot/tool-registry.ts +2 -0
  344. package/src/boot/daemon-prompt-turn.ts +8 -0
  345. package/src/boot/daemon-runtime.ts +9 -3
  346. package/src/boot/daemon-tools/index.ts +8 -0
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/boot/daemon-tools/web-search.ts +4 -0
  349. package/src/card-followup/core.ts +109 -0
  350. package/src/chat/ctrl-c-in-input.ts +14 -0
  351. package/src/chat/index.ts +53 -0
  352. package/src/chat/pickers/state.ts +6 -2
  353. package/src/cli/agent-cli.ts +7 -0
  354. package/src/cli/decisions-cli.ts +25 -3
  355. package/src/cli/doctor-bundle-upload.ts +68 -0
  356. package/src/cli/doctor-cli.ts +38 -4
  357. package/src/cli/drive-input-jail.ts +101 -0
  358. package/src/cli/hooks-cli.ts +17 -3
  359. package/src/cli/make-cli.ts +43 -0
  360. package/src/cli/ops-cli.ts +20 -0
  361. package/src/cli/persona-cli.ts +90 -4
  362. package/src/cli/plugin-cli.ts +31 -22
  363. package/src/cli/pod-cli.ts +61 -2
  364. package/src/cli/pr-cli.ts +82 -17
  365. package/src/cli/pty-drive-cli.ts +41 -7
  366. package/src/cli/pty-drive-verdict.ts +40 -0
  367. package/src/cli/pwa-stop.ts +163 -13
  368. package/src/cli/pwa-test.ts +3 -0
  369. package/src/cli/release-cli.ts +80 -24
  370. package/src/cli/self-update.ts +14 -0
  371. package/src/cli/setup-cli.ts +43 -1
  372. package/src/cli/skills-cli.ts +17 -1
  373. package/src/cli/storyboard-cli.ts +37 -0
  374. package/src/cli/test-state-dir-flag.ts +11 -4
  375. package/src/connectors/linear.ts +146 -0
  376. package/src/context-bus/claude-hooks-install.ts +10 -0
  377. package/src/context-bus/context-now-surfaces.ts +48 -0
  378. package/src/context-bus/context-now.ts +104 -0
  379. package/src/context-bus/coord-events.ts +115 -0
  380. package/src/context-bus/external-events.ts +52 -0
  381. package/src/context-bus/long-term-memory.ts +108 -0
  382. package/src/dashboard/dashboard-boot-fixture.ts +23 -0
  383. package/src/dashboard/index.ts +63 -21
  384. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
  385. package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
  386. package/src/decisions/decision-cards.ts +58 -3
  387. package/src/decisions/decision-ledger.ts +85 -6
  388. package/src/decisions/decision-linear-projection.ts +157 -0
  389. package/src/decisions/web-push-decision-cards.ts +50 -0
  390. package/src/directive/interpretation-card.ts +36 -0
  391. package/src/discord/sprint21-runtime.ts +5 -1
  392. package/src/discord-self-message.ts +32 -0
  393. package/src/discord-slash-wire.ts +5 -1
  394. package/src/discord.ts +19 -2
  395. package/src/domains/coo-admin-tool.ts +62 -0
  396. package/src/domains/core-tools.ts +13 -4
  397. package/src/domains/elanous-card.ts +29 -0
  398. package/src/domains/ops-facts-tool.ts +76 -0
  399. package/src/domains/outbound-alert.ts +46 -13
  400. package/src/domains/release-tool.ts +168 -0
  401. package/src/domains/telegram-kind-route.ts +65 -9
  402. package/src/exec-requests/default-outputs.ts +25 -0
  403. package/src/exec-requests/planner.ts +106 -28
  404. package/src/exec-requests/runner.ts +123 -12
  405. package/src/exec-requests/store.ts +11 -2
  406. package/src/execution-loop/launch-gate.ts +100 -0
  407. package/src/field/field-media.ts +10 -7
  408. package/src/field/field-reel.ts +19 -5
  409. package/src/field-note/index.ts +201 -0
  410. package/src/field-note/transcribe.ts +248 -0
  411. package/src/git-fs/worktree.ts +45 -6
  412. package/src/graph-kinds/registry.ts +3 -3
  413. package/src/graph-runner/graph-approval-card.ts +113 -0
  414. package/src/graph-runner/graph-cli.ts +189 -4
  415. package/src/graph-runner/graph-grow-llm.ts +37 -0
  416. package/src/graph-runner/graph-grow.ts +47 -0
  417. package/src/graph-runner/graph-notify.ts +25 -3
  418. package/src/graph-runner/runner.ts +453 -35
  419. package/src/grok/agent-search.ts +8 -2
  420. package/src/guardian/secret-exposure-scan.ts +101 -0
  421. package/src/harness/browser-verify.ts +25 -2
  422. package/src/harness/harness-cli-command.ts +478 -42
  423. package/src/harness/harness-incidents-writer.fixture.ts +24 -0
  424. package/src/harness/harness-incidents.ts +129 -0
  425. package/src/harness/harness-pod-dispatch.ts +43 -23
  426. package/src/harness/harness-seams.ts +38 -4
  427. package/src/harness/harness-stop.ts +75 -6
  428. package/src/harness/launch-registry.ts +91 -0
  429. package/src/harness/process-garbage.ts +5 -3
  430. package/src/hitl/clarification-policy.ts +3 -1
  431. package/src/hooks/dispatch.ts +82 -0
  432. package/src/hooks/expose.ts +254 -0
  433. package/src/hooks/github-shadow.ts +108 -0
  434. package/src/hooks/providers.ts +71 -5
  435. package/src/hooks/queue.ts +1 -1
  436. package/src/hooks/receiver.ts +21 -20
  437. package/src/index.ts +206 -49
  438. package/src/intake-plane/author-goals.ts +37 -4
  439. package/src/intake-plane/categorize.ts +18 -46
  440. package/src/intake-plane/check.ts +3 -0
  441. package/src/intake-plane/discord-seat-work.ts +57 -2
  442. package/src/intake-plane/front-route-classifier.ts +33 -39
  443. package/src/intake-plane/persona-answer.ts +30 -0
  444. package/src/intake-plane/runtime-callables.ts +8 -1
  445. package/src/intake-plane/seat-doc-route.ts +170 -6
  446. package/src/intake-plane/telegram-seat-work.ts +80 -4
  447. package/src/intake-plane/telegram-work.ts +1 -0
  448. package/src/intake-plane/wish-folder.ts +67 -0
  449. package/src/intent-gate/gate.ts +30 -10
  450. package/src/live/detail-switch.ts +5 -0
  451. package/src/llm/difficulty.ts +57 -0
  452. package/src/llm/judge-layer.ts +101 -0
  453. package/src/llm/mission-router.ts +33 -19
  454. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  455. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  456. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  457. package/src/loops/contract/loop-agent.schema.json +138 -0
  458. package/src/loops/contract/validate.ts +64 -0
  459. package/src/loops/registry.ts +20 -6
  460. package/src/market/signed-index.ts +4 -0
  461. package/src/maturity/bot-command-maturity.ts +45 -0
  462. package/src/maturity/cli-maturity.ts +34 -0
  463. package/src/maturity/feature-maturity.ts +120 -1
  464. package/src/maturity/tui-slash-maturity.ts +31 -0
  465. package/src/memory.ts +32 -4
  466. package/src/model-tier/index.ts +2 -2
  467. package/src/model-tier/tier-resolver.ts +20 -20
  468. package/src/model-tier/types.ts +6 -6
  469. package/src/mss/logging/log-store.ts +15 -0
  470. package/src/nexus/api/config-model-tier.ts +5 -4
  471. package/src/nexus/api/exec-requests.ts +33 -3
  472. package/src/nexus/api/fabric-plans.ts +53 -0
  473. package/src/nexus/api/harness-api.ts +5 -1
  474. package/src/nexus/api/health.ts +2 -0
  475. package/src/nexus/api/http-server.ts +89 -1
  476. package/src/nexus/api/inside-events.ts +226 -0
  477. package/src/nexus/api/meta-api.ts +32 -8
  478. package/src/nexus/api/missions.ts +6 -1
  479. package/src/nexus/api/ops-api.ts +10 -1
  480. package/src/nexus/api/ops-seats-sources.ts +37 -7
  481. package/src/nexus/api/ops-seats.ts +49 -6
  482. package/src/nexus/api/outputs-route.ts +44 -0
  483. package/src/nexus/api/seat-requests.ts +132 -10
  484. package/src/nexus/api/sessions-store.ts +42 -0
  485. package/src/nexus/api/setup-codex-login.ts +160 -0
  486. package/src/nexus/api/sub-seat-charters.ts +34 -0
  487. package/src/nexus/api/tabs-mutations.ts +3 -1
  488. package/src/nexus/api/trace.ts +18 -6
  489. package/src/nexus/api/usage-api.ts +102 -0
  490. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  491. package/src/nexus/api/workflows.ts +80 -6
  492. package/src/nexus/index.ts +47 -4
  493. package/src/nexus/kinds/webterm.ts +2 -1
  494. package/src/nexus/webterm/pty.ts +6 -2
  495. package/src/onboarding/cli-auth-status.ts +80 -0
  496. package/src/onboarding/first-run.ts +89 -0
  497. package/src/onboarding/lan-address.ts +45 -0
  498. package/src/onboarding/voice-ai.ts +3 -3
  499. package/src/onboarding/web-first.ts +119 -24
  500. package/src/onboarding.ts +4 -0
  501. package/src/ops-now/ops-now-refresh.ts +100 -0
  502. package/src/org/seat-budget.ts +48 -0
  503. package/src/org/stall-escalation.ts +63 -0
  504. package/src/outputs/ledger.ts +120 -0
  505. package/src/persona/persona-todo.ts +79 -0
  506. package/src/persona/presets.ts +116 -2
  507. package/src/persona/team-set.ts +155 -0
  508. package/src/plugins/install/plugin-install.ts +14 -0
  509. package/src/plugins/maker/market-bundle.ts +109 -0
  510. package/src/plugins/maker/plugin-maker.ts +254 -11
  511. package/src/plugins/maker/wizard-generate.ts +103 -0
  512. package/src/pod-lease/admission.ts +150 -0
  513. package/src/pod-lease/dependency-state.ts +85 -0
  514. package/src/pod-lease/host-lease.ts +127 -0
  515. package/src/project/project-store.ts +115 -0
  516. package/src/project/project-suggestion.ts +16 -0
  517. package/src/project/session-context.ts +24 -0
  518. package/src/release-loop/checklist.ts +79 -5
  519. package/src/release-loop/feature-store.ts +159 -24
  520. package/src/release-loop/next-md-merge.ts +58 -0
  521. package/src/release-loop/release-note.ts +59 -4
  522. package/src/release-loop/release-schedule.ts +53 -0
  523. package/src/repl/index.ts +7 -0
  524. package/src/seat-dispatch/ceo-commands.ts +41 -8
  525. package/src/seat-dispatch/ceo-intent.ts +38 -0
  526. package/src/seat-dispatch/seat-ask.ts +130 -0
  527. package/src/seat-dispatch/seat-questions.ts +100 -0
  528. package/src/seat-loop/seat-loop.ts +750 -0
  529. package/src/seat-loop/seat-report.ts +99 -0
  530. package/src/self-dev/decompose.ts +66 -11
  531. package/src/self-dev/dev-cli.ts +4 -1
  532. package/src/self-dev/dev-pipeline.ts +37 -1
  533. package/src/self-dev/draft-sweep.ts +38 -33
  534. package/src/self-dev/draft-triage-rules.ts +8 -5
  535. package/src/self-dev/fabric-plan-core.ts +297 -0
  536. package/src/self-dev/orchestrate.ts +36 -4
  537. package/src/self-dev/release-path-guard.ts +62 -0
  538. package/src/self-dev/run-store.ts +10 -1
  539. package/src/self-dev/shard-aggregate.ts +230 -0
  540. package/src/self-dev/shard-placement.ts +60 -0
  541. package/src/self-dev/shard-plan.ts +48 -0
  542. package/src/self-dev/shard-pod-run.ts +77 -0
  543. package/src/self-dev/shard-run.ts +105 -0
  544. package/src/self-implement/execution-clarification.ts +115 -0
  545. package/src/self-implement/gate-baseline.ts +1 -1
  546. package/src/self-implement/gate-cli.ts +46 -4
  547. package/src/self-implement/gate-scope.ts +37 -7
  548. package/src/self-implement/graph-variant.ts +171 -0
  549. package/src/self-implement/harness-policy-gates.ts +1 -1
  550. package/src/self-implement/headless-elanous-driver.ts +22 -3
  551. package/src/self-implement/host-regate.ts +22 -1
  552. package/src/self-implement/importer-test-index.ts +2 -1
  553. package/src/self-implement/l8-merge-queue.ts +130 -0
  554. package/src/self-implement/orchestrator.ts +279 -12
  555. package/src/self-implement/pipeline-shape.ts +1 -1
  556. package/src/self-implement/route-consumer-test-index.ts +122 -0
  557. package/src/self-implement/run-status-mapping.ts +5 -3
  558. package/src/self-implement/seams.ts +72 -11
  559. package/src/self-implement/test-seams.ts +1 -0
  560. package/src/self-implement/uncommitted-work.ts +59 -0
  561. package/src/session/chat.ts +2 -0
  562. package/src/session/index.ts +45 -13
  563. package/src/shell-env-bootstrap.ts +17 -0
  564. package/src/skills/gift-install.ts +215 -0
  565. package/src/skills/tools/web-search.ts +4 -1
  566. package/src/steward/directive.ts +51 -2
  567. package/src/steward/launch.ts +266 -0
  568. package/src/steward/outcome-notify.ts +115 -0
  569. package/src/steward/steward-cards.ts +25 -11
  570. package/src/steward/triage-plan.ts +32 -4
  571. package/src/steward/triage.ts +129 -13
  572. package/src/steward/working-backwards.ts +64 -0
  573. package/src/storyboard/storyboard.ts +141 -0
  574. package/src/task-cards/card-cli.ts +25 -1
  575. package/src/task-cards/card-store.ts +2 -2
  576. package/src/task-orchestrator/mission.ts +5 -0
  577. package/src/task-orchestrator/store.ts +12 -3
  578. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  579. package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
  580. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  581. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  582. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  583. package/src/task-orchestrator/types.ts +2 -0
  584. package/src/telegram-card-followup.ts +153 -0
  585. package/src/telegram-commands.ts +10 -1
  586. package/src/telegram-project-command.ts +71 -0
  587. package/src/telegram-report.ts +29 -19
  588. package/src/telegram-run.ts +7 -0
  589. package/src/telegram.ts +58 -11
  590. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  591. package/src/tool-runtime/types.ts +4 -0
  592. package/src/tui-client/dashboard-session.ts +2 -0
  593. package/src/user-config.ts +216 -27
  594. package/src/version/packed-revision.json +1 -1
  595. package/src/web-push/notify-exec-request.ts +32 -0
  596. package/src/web-search/grok.ts +7 -1
  597. package/src/web-search/index.ts +28 -1
  598. package/src/web-search/provider.ts +4 -0
  599. package/src/web-search/x-intent.ts +5 -0
  600. package/src/workflow-runtime/executor.ts +277 -47
  601. package/src/workflow-runtime/index.ts +1 -0
  602. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  603. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  604. package/src/workflow-runtime/schema.ts +79 -4
  605. package/src/workflow-runtime/types.ts +35 -4
  606. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  617. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  618. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
  622. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  692. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
  693. package/src/dashboard/turn-typeahead-echo.ts +0 -23
  694. /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env bun
2
+ import { spawn } from 'node:child_process';
3
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { debug, redactSecrets } from '../src/debug/log.js';
6
+ import { sendOutbound } from '../src/domains/outbound-alert.js';
7
+ import { DecisionLedger } from '../src/decisions/decision-ledger.js';
8
+ import { effectiveInstanceRoot, prodInstanceRoot, releaseLedgerRoot } from '../src/instance/resolve.js';
9
+ import { listMemories } from '../src/memory.js';
10
+ import { listSchedules, getSchedule } from '../src/release-loop/release-schedule.js';
11
+ import { listChecklist, summarizeChecklist } from '../src/release-loop/checklist.js';
12
+ import { getUserConfig } from '../src/user-config.js';
13
+ import { registerStandaloneLogSink } from '../src/domains/standalone-log-sink.js';
14
+
15
+ export type ProbeKind = 'cut' | 'green' | 'open';
16
+ export type ProbeVerdict = 'match' | 'mismatch' | 'pending' | 'unmeasured';
17
+ export interface ProbeRow {
18
+ ts: string;
19
+ question: string;
20
+ verdict: ProbeVerdict;
21
+ botValue: string | number | null;
22
+ ledgerValue: string | number | null;
23
+ opsNowUpdatedAt: string | null;
24
+ reason: string | null;
25
+ botReply: string | null;
26
+ }
27
+ export const STANDARD_QUESTIONS: ReadonlyArray<{ kind: ProbeKind; ask: (version: string) => string }> = [
28
+ { kind: 'cut', ask: (version) => `${version} 컷 언제야?` },
29
+ { kind: 'green', ask: (version) => `${version} 체크리스트 초록 몇 개야?` },
30
+ { kind: 'open', ask: () => '지금 미결 결정 몇 개야?' },
31
+ ];
32
+
33
+ export interface ProbeDeps {
34
+ schedules?: () => Promise<Array<{ version: string; cutAt: string }>> | Array<{ version: string; cutAt: string }>;
35
+ published?: (version: string) => Promise<boolean> | boolean;
36
+ cut?: (version: string) => Promise<string | null> | string | null;
37
+ green?: (version: string) => Promise<number> | number;
38
+ open?: () => Promise<number> | number;
39
+ ask?: (question: string, model?: string) => Promise<string>;
40
+ send?: typeof sendOutbound;
41
+ memoryUpdatedAt?: () => string | null;
42
+ model?: () => string | undefined;
43
+ root?: string;
44
+ now?: () => Date;
45
+ print?: (line: string) => void;
46
+ observe?: (question: string, verdict: ProbeVerdict, reason: string | null) => void;
47
+ }
48
+ export interface ProbeOptions { version?: string; dryRun?: boolean; json?: boolean }
49
+
50
+ function kstDate(date: Date): string {
51
+ return new Date(date.getTime() + 9 * 3_600_000).toISOString().slice(0, 10);
52
+ }
53
+
54
+ const CUT_ISO = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})(?!\d)/g;
55
+ const CUT_LOCAL = /(?:(\d{4})\s*[년./-]\s*)?(\d{1,2})\s*(?:월|[./-])\s*(\d{1,2})\s*(?:일)?(?:\s*\([^)]*\))?(?:\s*(?:오전|오후|AM|PM))?\s*(\d{1,2})\s*(?:시\s*(\d{1,2})\s*분?|:\s*(\d{2}))(?!\d)\s*(?:KST|한국시간)?/gi;
56
+
57
+ function cutValue(text: string): string | null {
58
+ const iso = new RegExp(CUT_ISO.source).exec(text)?.[0];
59
+ if (iso && Number.isFinite(Date.parse(iso))) return new Date(Date.parse(iso) + 9 * 3_600_000).toISOString().slice(0, 16);
60
+ const match = new RegExp(CUT_LOCAL.source, 'i').exec(text);
61
+ if (!match) return null;
62
+ const year = match[1] ? Number(match[1]) : null;
63
+ const month = Number(match[2]), day = Number(match[3]);
64
+ let hour = Number(match[4]);
65
+ const minute = Number(match[5] ?? match[6]);
66
+ if (/오후|PM/i.test(match[0]) && hour < 12) hour += 12;
67
+ if (/오전|AM/i.test(match[0]) && hour === 12) hour = 0;
68
+ if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59) return null;
69
+ return `${year ?? '????'}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}T${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
70
+ }
71
+
72
+ function normalizedCut(value: string, reference?: string): string | null {
73
+ const parsed = cutValue(value);
74
+ if (!parsed) return null;
75
+ if (parsed.startsWith('????-') && reference) return `${reference.slice(0, 4)}${parsed.slice(4)}`;
76
+ return parsed;
77
+ }
78
+
79
+ function ledgerCutValue(value: string): string | null {
80
+ const millis = Date.parse(value);
81
+ if (!Number.isFinite(millis)) return null;
82
+ return new Date(millis + 9 * 3_600_000).toISOString().slice(0, 16);
83
+ }
84
+
85
+ type ParsedValue<T> = { value: T | null; ambiguous: boolean };
86
+ type Candidate<T> = { start: number; end: number; value: T };
87
+
88
+ function selectClaim<T>(reply: string, candidates: Candidate<T>[]): ParsedValue<T> {
89
+ if (candidates.length === 1) {
90
+ const after = reply.slice(candidates[0]!.end);
91
+ if (/^\s*(?:개|건|KST|한국시간)?\s*(?:가|이|은|는)?\s*(?:아닙니다|아니다|아니에요|아님|아닌|말고)/i.test(after)) {
92
+ return { value: null, ambiguous: true };
93
+ }
94
+ return { value: candidates[0]!.value, ambiguous: false };
95
+ }
96
+ if (candidates.length === 2) {
97
+ const between = reply.slice(candidates[0]!.end, candidates[1]!.start);
98
+ // «57개가 아니라 50개» · «3개, 아니 4개» — the later value is the asserted one.
99
+ if (/^(?:\s*(?:개|건|KST|한국시간))?\s*(?:가|이|은|는)?\s*(?:아니라|아닌|말고|[,,]?\s*아니(?:요|고)?\s*[,,]?)\s*$/i.test(between)) {
100
+ return { value: candidates[1]!.value, ambiguous: false };
101
+ }
102
+ }
103
+ return { value: null, ambiguous: candidates.length > 1 };
104
+ }
105
+
106
+ const NEGATED_AFTER = /^\s*(?:개|건)?\s*(?:가|이|은|는)?\s*(?:아닙니다|아니다|아니에요|아님|아닌|말고)/i;
107
+ // A number counts as the metric only when it carries a unit (개·건) or sits right after the label («초록은 57»).
108
+ // Anything else (a version «0.2.10판», a date) is not a claim about the count — unmeasured, never a false drift.
109
+ const DIRECT_AFTER_LABEL = /^\s*(?:은|는|이|가|도|:|=)?\s*(?:총|현재|지금|모두|전부)?\s*$/;
110
+
111
+ function countValue(reply: string, kind: 'green' | 'open'): ParsedValue<number> {
112
+ const label = kind === 'green' ? /(?:초록|녹색|green|🟢)/i : /(?:미결\s*결정|열린\s*결정|open\s*decisions?|미결)/i;
113
+ const found = label.exec(reply);
114
+ if (!found) {
115
+ const bare = /^\s*(\d[\d,]*)\s*(?:개|건)?[.。!\s]*$/.exec(reply);
116
+ if (!bare) return { value: null, ambiguous: false };
117
+ const value = Number(bare[1]!.replaceAll(',', ''));
118
+ return Number.isSafeInteger(value) && value >= 0 ? { value, ambiguous: false } : { value: null, ambiguous: false };
119
+ }
120
+ const answer = reply.slice(found.index + found[0].length);
121
+ const candidates: Candidate<number>[] = [];
122
+ for (const match of answer.matchAll(/(?<![\d.])\d[\d,]*(?![\d.])/g)) {
123
+ const value = Number(match[0].replaceAll(',', ''));
124
+ if (!Number.isSafeInteger(value) || value < 0) continue;
125
+ const end = match.index + match[0].length;
126
+ const unit = /^\s*(?:개|건)/.test(answer.slice(end));
127
+ const direct = DIRECT_AFTER_LABEL.test(answer.slice(0, match.index));
128
+ if (unit || direct) candidates.push({ start: match.index, end, value });
129
+ }
130
+ if (candidates.length) return selectClaim(answer, candidates);
131
+ // Number before the label («57개가 초록», «57개 초록이 아닙니다») — keep the negation that follows the label.
132
+ const reverse = new RegExp(`(?<![\\d.])(\\d[\\d,]*)(?![\\d.])\\s*(?:개|건)?\\s*(?:가|이|의)?\\s*${label.source}`, 'i').exec(reply);
133
+ if (!reverse) return { value: null, ambiguous: false };
134
+ const tail = reply.slice(reverse.index + reverse[0].length);
135
+ if (NEGATED_AFTER.test(tail)) return { value: null, ambiguous: true };
136
+ const value = Number(reverse[1]!.replaceAll(',', ''));
137
+ return Number.isSafeInteger(value) && value >= 0 ? { value, ambiguous: false } : { value: null, ambiguous: false };
138
+ }
139
+
140
+ function replyValue(kind: ProbeKind, reply: string, ledger: string | number): ParsedValue<string | number> {
141
+ if (kind !== 'cut') return countValue(reply, kind);
142
+ const candidates: Candidate<string>[] = [];
143
+ for (const match of reply.matchAll(CUT_ISO)) {
144
+ const value = normalizedCut(match[0], String(ledger));
145
+ if (value) candidates.push({ start: match.index, end: match.index + match[0].length, value });
146
+ }
147
+ for (const match of reply.matchAll(CUT_LOCAL)) {
148
+ if (candidates.some((candidate) => match.index < candidate.end && match.index + match[0].length > candidate.start)) continue;
149
+ let value = normalizedCut(match[0], String(ledger));
150
+ const zone = /^\s*(UTC|GMT|Z\b|[A-Z]{2,4}T\b|[+-]\d{1,2}(?::?\d{2})?\b)\s*([+-]\d{1,2}(?::?\d{2})?)?/i.exec(reply.slice(match.index + match[0].length));
151
+ if (value && zone && !/KST/i.test(match[0])) {
152
+ // A written zone other than KST: UTC/GMT converts (+9h); any other zone or offset is not guessed — unmeasured.
153
+ if (/^(?:UTC|GMT|Z)$/i.test(zone[1]!) && !zone[2] && !value.startsWith('????')) {
154
+ const millis = Date.parse(`${value}:00Z`);
155
+ value = Number.isFinite(millis) ? new Date(millis + 9 * 3_600_000).toISOString().slice(0, 16) : null;
156
+ } else value = null;
157
+ }
158
+ if (value) candidates.push({ start: match.index, end: match.index + match[0].length + (zone && !/KST/i.test(match[0]) ? zone[0].length : 0), value });
159
+ }
160
+ candidates.sort((a, b) => a.start - b.start);
161
+ const valid = candidates.filter(({ value: parsed }) => {
162
+ const millis = Date.parse(`${parsed}:00Z`);
163
+ return Number.isFinite(millis) && new Date(millis).toISOString().slice(0, 16) === parsed;
164
+ });
165
+ return selectClaim(reply, valid);
166
+ }
167
+
168
+ function askBot(question: string, model?: string): Promise<string> {
169
+ const root = effectiveInstanceRoot();
170
+ return new Promise((resolve, reject) => {
171
+ const args = ['bin/elanous.mjs', ...(root === prodInstanceRoot() ? [] : [`--test=${root}`]), 'ask', question, '--json'];
172
+ const child = spawn('bun', args, {
173
+ cwd: join(import.meta.dir, '..'),
174
+ env: { ...process.env, ...(model ? { ELANOUS_LLM_MODEL: model } : {}) },
175
+ stdio: ['ignore', 'pipe', 'ignore'],
176
+ });
177
+ let out = '';
178
+ let tooLong = false;
179
+ let timedOut = false;
180
+ const timer = setTimeout(() => { timedOut = true; child.kill(); reject(new Error('timeout')); }, 90_000);
181
+ child.stdout.on('data', (chunk: Buffer) => {
182
+ out += chunk.toString();
183
+ if (out.length > 1024 * 1024) { tooLong = true; child.kill(); }
184
+ });
185
+ child.on('error', (error) => { clearTimeout(timer); reject(error); });
186
+ child.on('close', (code) => {
187
+ clearTimeout(timer);
188
+ if (timedOut) return reject(new Error('timeout'));
189
+ if (tooLong) return reject(new Error('bot-output-too-large'));
190
+ if (code !== 0) return reject(new Error('bot-error'));
191
+ try {
192
+ const result = JSON.parse(out) as { reply?: unknown; error?: unknown };
193
+ if (typeof result.reply !== 'string') throw new Error('bot-no-reply');
194
+ resolve(result.reply);
195
+ } catch { reject(new Error('bot-no-reply')); }
196
+ });
197
+ });
198
+ }
199
+
200
+ function isPublished(version: string, releaseRoot: string): boolean {
201
+ try {
202
+ const record = JSON.parse(readFileSync(join(releaseRoot, 'release', version, 'release.json'), 'utf8')) as { publishedAt?: unknown; version?: unknown };
203
+ return record.version === version && typeof record.publishedAt === 'string';
204
+ } catch (error) {
205
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;
206
+ throw error;
207
+ }
208
+ }
209
+
210
+ function ledgerOpen(): number { return new DecisionLedger().list({ status: 'open' }).length; }
211
+ function memoryUpdatedAt(): string | null { return listMemories().find((entry) => entry.name === 'ops-now')?.updatedAt ?? null; }
212
+ function probeModel(): string | undefined {
213
+ const config = getUserConfig().raw.opsNowProbe;
214
+ if (!config || typeof config !== 'object' || Array.isArray(config)) return undefined;
215
+ const model = (config as Record<string, unknown>).model;
216
+ return typeof model === 'string' && model.trim() ? model.trim() : undefined;
217
+ }
218
+
219
+ export async function runOpsNowProbe(options: ProbeOptions = {}, deps: ProbeDeps = {}): Promise<{ rows: ProbeRow[]; exitCode: number; alert: string | null }> {
220
+ const now = (deps.now ?? (() => new Date()))();
221
+ const root = deps.root ?? effectiveInstanceRoot();
222
+ const releaseRoot = releaseLedgerRoot();
223
+ let version = options.version;
224
+ if (!version) {
225
+ try {
226
+ if (!deps.schedules && !existsSync(join(releaseRoot, 'release', 'features.sqlite'))) throw new Error('ledger-unreadable');
227
+ const schedules = await (deps.schedules ?? (() => listSchedules(releaseRoot)))();
228
+ const ordered = schedules.filter((row) => Number.isFinite(Date.parse(row.cutAt)))
229
+ .sort((a, b) => Date.parse(a.cutAt) - Date.parse(b.cutAt));
230
+ for (const row of ordered) {
231
+ if (!await (deps.published ?? ((v) => isPublished(v, releaseRoot)))(row.version)) {
232
+ version = row.version;
233
+ break;
234
+ }
235
+ }
236
+ } catch { /* A missing version makes the two release questions unmeasured. */ }
237
+ }
238
+ const updatedAt = (() => { try { return (deps.memoryUpdatedAt ?? memoryUpdatedAt)(); } catch { return null; } })();
239
+ let model: string | undefined;
240
+ try { model = deps.model ? deps.model() : probeModel(); } catch { /* Use the ask path's configured model. */ }
241
+ const rows: ProbeRow[] = [];
242
+ for (const item of STANDARD_QUESTIONS) {
243
+ const question = item.ask(version ?? '(판 미상)');
244
+ let ledgerValue: string | number | null = null;
245
+ let reason: string | null = null;
246
+ try {
247
+ if (item.kind !== 'open' && !version) throw new Error('ledger-unreadable');
248
+ if (item.kind === 'green' && !deps.green && !existsSync(join(releaseRoot, 'release', 'features.sqlite')) && !existsSync(join(releaseRoot, 'release', version!, 'checklist.json'))) throw new Error('ledger-unreadable');
249
+ if (item.kind === 'open' && !deps.open && !existsSync(new DecisionLedger().path)) throw new Error('ledger-unreadable');
250
+ const value = item.kind === 'cut' ? await (deps.cut ?? ((v) => getSchedule(v, releaseRoot)?.cutAt ?? null))(version!)
251
+ : item.kind === 'green' ? await (deps.green ?? ((v) => summarizeChecklist(listChecklist(v)).green))(version!) : await (deps.open ?? ledgerOpen)();
252
+ if (item.kind === 'cut') ledgerValue = typeof value === 'string' ? ledgerCutValue(value) : null;
253
+ else ledgerValue = typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null;
254
+ if (ledgerValue === null) reason = 'ledger-unreadable';
255
+ } catch { reason = 'ledger-unreadable'; }
256
+ let reply: string | null = null;
257
+ let botValue: string | number | null = null;
258
+ try { reply = await (deps.ask ?? askBot)(question, model); }
259
+ catch (error) { if (!reason) reason = (error as Error).message === 'timeout' ? 'timeout' : 'bot-unresponsive'; }
260
+ let verdict: ProbeVerdict = 'unmeasured';
261
+ if (!reason) {
262
+ if (!reply?.trim()) reason = 'bot-unresponsive';
263
+ else if (/확인\s*(?:중|해\s*보겠|해\s*볼게|해\s*보도록|이\s*필요)|조회\s*중|살펴\s*보겠/.test(reply)) { verdict = 'pending'; reason = 'bot-pending'; }
264
+ else {
265
+ const parsed = replyValue(item.kind, reply, ledgerValue!);
266
+ botValue = parsed.value;
267
+ if (botValue === null) reason = parsed.ambiguous ? 'value-ambiguous' : 'value-unparseable';
268
+ else verdict = botValue === ledgerValue ? 'match' : 'mismatch';
269
+ }
270
+ }
271
+ const row: ProbeRow = { ts: now.toISOString(), question, verdict, botValue, ledgerValue, opsNowUpdatedAt: updatedAt,
272
+ reason, botReply: reply === null ? null : redactSecrets({ reply }).reply.slice(0, 200) };
273
+ rows.push(row);
274
+ debug.log('ops-now.probe', 'verdict', { question, verdict, reason });
275
+ deps.observe?.(question, verdict, reason);
276
+ }
277
+ const path = join(root, 'ops-now-probe', `${kstDate(now)}.jsonl`);
278
+ mkdirSync(dirname(path), { recursive: true });
279
+ appendFileSync(path, rows.map((row) => JSON.stringify(row)).join('\n') + '\n', { mode: 0o600 });
280
+ const mismatches = rows.filter((row) => row.verdict === 'mismatch');
281
+ const alert = mismatches.length ? `🚨 ops-now 봇 답 불일치 — ${mismatches.map((row) => `${row.question} 봇 ${row.botValue} / 원장 ${row.ledgerValue}`).join(' · ')} · ops-now updatedAt ${updatedAt ?? '미상'}` : null;
282
+ let alertDelivery: 'sent' | 'failed' | 'dry-run' | null = alert ? (options.dryRun ? 'dry-run' : 'failed') : null;
283
+ if (alert && !options.dryRun) {
284
+ try {
285
+ if (await (deps.send ?? sendOutbound)(alert, 'ops-alert')) alertDelivery = 'sent';
286
+ } catch {
287
+ // A throwing sender has the same undelivered outcome as a false return.
288
+ }
289
+ if (alertDelivery === 'failed') debug.log('ops-now.probe', 'alert-failed', { kind: 'ops-alert' });
290
+ }
291
+ const print = deps.print ?? console.log;
292
+ const warning = [
293
+ ...(rows.some((row) => row.verdict === 'unmeasured') ? ['⚠ 측정하지 못한 질문이 있습니다.'] : []),
294
+ ...(alertDelivery === 'failed' ? ['⚠ ops-alert 전송 실패'] : []),
295
+ ].join(' ') || null;
296
+ if (options.json) print(JSON.stringify({ version: version ?? null, rows, alert, alertDelivery, warning, wouldSend: Boolean(alert && options.dryRun), exitCode: mismatches.length ? 1 : 0 }));
297
+ else {
298
+ for (const row of rows) print(`${row.verdict} · ${row.question} · 봇 ${row.botValue ?? '-'} · 원장 ${row.ledgerValue ?? '-'}${row.reason ? ` · ${row.reason}` : ''}`);
299
+ if (warning) print(warning);
300
+ if (alert) {
301
+ if (alertDelivery === 'dry-run') print(`보냈을 것: ${alert}`);
302
+ else if (alertDelivery === 'sent') print(alert);
303
+ }
304
+ }
305
+ return { rows, exitCode: mismatches.length ? 1 : 0, alert };
306
+ }
307
+
308
+ export async function main(args: string[] = process.argv.slice(2)): Promise<number> {
309
+ let version: string | undefined;
310
+ let dryRun = false, json = false, once = false;
311
+ for (let i = 0; i < args.length; i++) {
312
+ const arg = args[i];
313
+ if (arg === '--once') once = true;
314
+ else if (arg === '--dry-run') dryRun = true;
315
+ else if (arg === '--json') json = true;
316
+ else if (arg === '--version' && args[i + 1] && !args[i + 1]!.startsWith('--')) version = args[++i];
317
+ else throw new Error(`알 수 없는 옵션: ${arg}`);
318
+ }
319
+ if (!once) throw new Error('--once 필요');
320
+ await registerStandaloneLogSink('ops-now-probe');
321
+ return (await runOpsNowProbe({ version, dryRun, json })).exitCode;
322
+ }
323
+
324
+ if (import.meta.main) {
325
+ try { process.exitCode = await main(); }
326
+ catch (error) { console.error(`ops-now-probe: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 2; }
327
+ }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import { createHash } from 'node:crypto';
3
3
  import { spawnSync } from 'node:child_process';
4
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
4
+ import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
5
5
  import { join, resolve } from 'node:path';
6
6
  import { spawnSyncText } from '../src/util/spawn-sync-output.js';
7
7
 
@@ -74,11 +74,21 @@ export function publishInternalDist(checkout: string, out: string, keep = 3): {
74
74
  } else {
75
75
  renameSync(staging, target);
76
76
  }
77
+ const alias = join(download, `v${pkg.version}`);
78
+ try {
79
+ if (!lstatSync(alias).isSymbolicLink()) throw new Error(`version alias is not a symlink: ${alias}`);
80
+ } catch (error) {
81
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
82
+ }
77
83
  mkdirSync(join(out, 'latest'), { recursive: true });
78
84
  link = join(out, 'latest', `.download-${process.pid}-${Date.now()}`);
79
85
  symlinkSync(`../download/${name}`, link, 'dir');
80
86
  renameSync(link, join(out, 'latest', 'download'));
81
87
  link = undefined;
88
+ link = join(download, `.alias-${process.pid}-${Date.now()}`);
89
+ symlinkSync(name, link, 'dir');
90
+ renameSync(link, alias);
91
+ link = undefined;
82
92
  const versions = readdirSync(download, { withFileTypes: true })
83
93
  .filter((entry) => entry.isDirectory() && /^v[0-9A-Za-z][0-9A-Za-z._-]*-[0-9a-f]{12}$/.test(entry.name))
84
94
  .map((entry) => ({ name: entry.name, mtime: statSync(join(download, entry.name)).mtimeMs }))
@@ -4,15 +4,26 @@ import { dirname, isAbsolute, join, resolve } from 'node:path';
4
4
  import { debug } from '../../src/debug/log.js';
5
5
  import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
6
6
  import { emitNodeResult, readGraphContext, type GraphContext } from './node-verdict.js';
7
+ import { regressWarning, validatedTuiRegress } from './tui-node-checks.js';
7
8
 
8
9
  export type MetricVerdict = 'pass' | 'fail' | 'unmeasured';
9
- export interface ApprovalMetric { name: string; value: string; verdict: MetricVerdict }
10
+ export interface ApprovalMetric { name: string; value: string; verdict: MetricVerdict; reason?: string }
10
11
 
11
12
  const outcomeMetric = (name: string, node: Record<string, unknown> | undefined): ApprovalMetric => ({
12
13
  name, value: node?.outcome === undefined ? 'missing' : String(node.outcome),
13
14
  verdict: node?.outcome === undefined ? 'unmeasured' : node.outcome === 'ok' ? 'pass' : 'fail',
14
15
  });
15
16
 
17
+ /** Rows shown in auto-approval.md but never counted toward the 8 blocking metrics. */
18
+ const WARNING_ONLY = new Set(['tui-regress', 'mac-smoke']);
19
+
20
+ /** `ok` · `warn` (a failure) · `unmeasured` (error or no output) — the macOS smoke never blocks publishing. */
21
+ function macSmokeLevel(node: Record<string, unknown> | undefined): 'ok' | 'warn' | 'unmeasured' {
22
+ if (node?.outcome === 'ok') return 'ok';
23
+ if (node?.outcome === 'fail') return 'warn';
24
+ return 'unmeasured';
25
+ }
26
+
16
27
  export function runAutoApprove(context: GraphContext = readGraphContext(), deps: { instanceRoot?: string; repo?: string; bunVersion?: string } = {}) {
17
28
  const { version } = context.input;
18
29
  const root = deps.instanceRoot ?? effectiveInstanceRoot();
@@ -30,6 +41,8 @@ export function runAutoApprove(context: GraphContext = readGraphContext(), deps:
30
41
  catch { distCount = undefined; }
31
42
  }
32
43
  const gateErrorAbsent = gate && !Object.hasOwn(gate, 'error');
44
+ const regressStatus = regressWarning(validatedTuiRegress(context.outputs.tui?.regress));
45
+ const macSmoke = context.outputs['mac-smoke'];
33
46
  const metrics: ApprovalMetric[] = [
34
47
  { name: 'gate regressions and measurement', value: JSON.stringify({ outcome: gate?.outcome ?? null, introduced: gate?.introduced ?? null, error: gate?.error ?? null }),
35
48
  verdict: !gate || gate.outcome === undefined || !Array.isArray(gate.introduced) ? 'unmeasured'
@@ -47,16 +60,20 @@ export function runAutoApprove(context: GraphContext = readGraphContext(), deps:
47
60
  { name: 'installation files', value: `dist files=${distCount ?? 'missing'}; prepare.out=${String(out ?? 'missing')}`,
48
61
  verdict: prepare?.outcome !== 'ok' ? prepare?.outcome === undefined ? 'unmeasured' : 'fail'
49
62
  : distCount === undefined ? 'unmeasured' : distCount === 5 ? 'pass' : 'fail' },
63
+ // Warning-only and last, so the numbered rows 1–8 keep their places in auto-approval.md (V1g follow-up).
64
+ { name: 'tui-regress', value: regressStatus.level, reason: regressStatus.line, verdict: 'pass' },
65
+ // MAC1: the macOS smoke is warning-only too (ship with known issues) — shown, never counted.
66
+ { name: 'mac-smoke', value: macSmokeLevel(macSmoke), reason: typeof macSmoke?.summary === 'string' ? macSmoke.summary : undefined, verdict: 'pass' },
50
67
  ];
51
- const outcome = metrics.every((metric) => metric.verdict === 'pass') ? 'ok' as const : 'fail' as const;
68
+ const outcome = metrics.filter((metric) => !WARNING_ONLY.has(metric.name)).every((metric) => metric.verdict === 'pass') ? 'ok' as const : 'fail' as const;
52
69
  const report = join(root, 'release', version, 'auto-approval.md');
53
70
  const lines = [`# v${version} auto-approval`, '', `Outcome: ${outcome}`, '', '| # | Metric | Value | Verdict |', '|---|---|---|---|',
54
- ...metrics.map((metric, i) => `| ${i + 1} | ${metric.name} | ${metric.value.replaceAll('|', '\\|').replace(/[\r\n]/g, ' ')} | ${metric.verdict} |`),
71
+ ...metrics.map((metric, i) => `| ${i + 1} | ${metric.name} | ${[metric.value, metric.reason].filter(Boolean).join(' — ').replaceAll('|', '\\|').replace(/[\r\n]/g, ' ')} | ${metric.verdict} |`),
55
72
  '', '## 되돌리는 법', `gh release edit v${version} --draft`, `git tag -d v${version} && git push origin :refs/tags/v${version}`, '해당 docs PR revert', ''];
56
73
  mkdirSync(dirname(report), { recursive: true });
57
74
  writeFileSync(report, lines.join('\n'));
58
75
  debug.log('release-loop.approve', 'auto-decision', { version, outcome, metrics });
59
- return { outcome, verdict: outcome === 'ok' ? 'pass' as const : 'fail' as const, summary: `auto approval ${outcome}: ${metrics.filter((metric) => metric.verdict === 'pass').length}/8`,
76
+ return { outcome, verdict: outcome === 'ok' ? 'pass' as const : 'fail' as const, summary: `auto approval ${outcome}: ${metrics.filter((metric) => !WARNING_ONLY.has(metric.name) && metric.verdict === 'pass').length}/8`,
60
77
  ...(outcome === 'ok' ? { decidedBy: 'release-loop metrics' as const } : {}), metrics, report };
61
78
  }
62
79
 
@@ -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
+ }
@@ -62,20 +62,30 @@ function landingAt(sha: string, title: string): ReleaseLanding {
62
62
  };
63
63
  }
64
64
 
65
- /** next.md lines at the cutoff, each tied to the last landing in range whose diff added that exact line. */
66
- function nextMdNotes(cutoff: string, landings: ReleaseLanding[]): NextMdNote[] {
65
+ /**
66
+ * next.md lines added between the baseline and the cutoff, each tied to the last landing in range whose diff added that
67
+ * exact line. Lines already in the file at the baseline shipped with an earlier release and are left out (REL7b).
68
+ */
69
+ function nextMdNotes(baseline: string, cutoff: string, landings: ReleaseLanding[]): { notes: NextMdNote[]; carried: number } {
67
70
  const text = git(['show', `${cutoff}:${NEXT_MD}`], true);
68
- if (!text) return [];
71
+ if (!text) return { notes: [], carried: 0 };
72
+ const inRange = new Set(addedLines(requiredGit(['diff', '-U0', baseline, cutoff, '--', NEXT_MD])));
69
73
  const addedBy = new Map<string, string>();
70
74
  for (const landing of landings) {
71
75
  if (!landing.changedFiles.includes(NEXT_MD)) continue;
72
76
  const diff = requiredGit(['show', '-m', '--first-parent', '--format=', '-U0', landing.sha, '--', NEXT_MD]);
73
- for (const line of diff.split('\n')) if (line.startsWith('+') && !line.startsWith('+++')) addedBy.set(line.slice(1).trim(), landing.sha);
77
+ for (const line of addedLines(diff)) addedBy.set(line, landing.sha);
74
78
  }
75
- return parseNextMdNotes(text).map((note) => {
76
- const sha = note.raw ? addedBy.get(note.raw) : undefined;
79
+ const all = parseNextMdNotes(text);
80
+ const notes = all.filter((note) => note.raw !== undefined && inRange.has(note.raw)).map((note) => {
81
+ const sha = addedBy.get(note.raw!);
77
82
  return { kind: note.kind, line: note.line, ...(sha ? { sha } : {}) };
78
83
  });
84
+ return { notes, carried: all.length - notes.length };
85
+ }
86
+
87
+ function addedLines(diff: string): string[] {
88
+ return diff.split('\n').filter((line) => line.startsWith('+') && !line.startsWith('+++')).map((line) => line.slice(1).trim());
79
89
  }
80
90
 
81
91
  function runningGoalPaths(): string[] {
@@ -135,12 +145,13 @@ export function main(args: string[] = process.argv.slice(2)): void {
135
145
  const instanceRoot = effectiveInstanceRoot();
136
146
  const notes = readReleaseNotes(releaseNotesDir(instanceRoot));
137
147
  debug.log('release.notes', 'read', { fragments: notes.size, problems: notes.problems });
148
+ const nextMd = nextMdNotes(baselineSha, cutoff, landings);
138
149
  const manifest = buildReleaseManifest({
139
- version, baseline: { ref: baseline.ref, sha: baselineSha }, cutoff: { sha: cutoff }, landings, notes, nextMd: nextMdNotes(cutoff, landings),
150
+ version, baseline: { ref: baseline.ref, sha: baselineSha }, cutoff: { sha: cutoff }, landings, notes, nextMd: nextMd.notes,
140
151
  runningGoalPaths: runningGoalPaths(), publicCommandsBefore: commandsAt(baselineSha), publicCommandsAfter: commandsAt(cutoff),
141
152
  });
142
153
  const output = { ...manifest, baselineSource: baseline.source };
143
- debug.log('release-loop.notes', 'fragments', { version, ...manifest.fragments });
154
+ debug.log('release-loop.notes', 'fragments', { version, ...manifest.fragments, carriedFromEarlier: nextMd.carried });
144
155
  const directory = join(instanceRoot, 'release', version);
145
156
  mkdirSync(directory, { recursive: true });
146
157
  writeFileSync(join(directory, 'manifest.json'), JSON.stringify(output, null, 2) + '\n');
@@ -125,13 +125,14 @@ export const POD_MEMORY_SOURCE = 'docs/measurements/td1-whole-gate-mechanical-20
125
125
  export const POD_SHARD_FILE_CAP = 27;
126
126
 
127
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. */
128
+ /** Nightly-only whole-repository cases; gate runs the fixture cases in these same files. */
129
129
  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.
130
+ // Replaces F12's real-repo bucket B apps/pwa scope check and its whole-repo export partition check.
131
+ 'test/f12-sweep.test.ts',
132
+ // Replaces unwired-exports' real src/oauth caller check and its src/ad-pipeline CLI scan.
133
+ 'scripts/unwired-exports.test.ts',
134
+ // Replaces pwa-build-typecheck's full root tsc and PWA tsc sweeps (PWA build also runs in the release loop).
135
+ 'test/pwa-build-typecheck.test.ts',
135
136
  ];
136
137
  const tail40 = (output: string) => output.trimEnd().split(/\r?\n/).slice(-40).join('\n');
137
138
  const lastStartedTestFile = (output: string, paths: string[]): string | undefined => {
@@ -219,15 +220,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
219
220
  // CDP 시험은 `test:deterministic` 이 스스로 뺀다 — 조각에 그것만 남으면 bun «시험 없음» exit 1 을 «불완전»으로 읽었다(09-30 G1d 실측 둘).
220
221
  // bun 의 탐색은 숨은 디렉터리(`.x/`)를 안 연다 — 사람의 `bun test` 가 한 번도 안 돌리는 빈 픽스처가 조각에 혼자 남아 «Ran 0 tests» 를 «불완전»으로 읽었다(09-30 G1e 5번 조각).
221
222
  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('.')));
223
+ && !file.split('/').some((part) => part.startsWith('.')));
223
224
  const integrationOnly = files.filter((file) => POD_SWEEP_INTEGRATION_ONLY.includes(file));
224
225
  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
226
  if (!assignable.length) throw new Error('sweep incomplete: no tests ran');
228
227
  const durations = pod.durationSource ? readFileDurations(pod.durationSource) : new Map<string, number>();
229
228
  const memory = readFileMemory(join(tree, POD_MEMORY_SOURCE));
230
- const heavy = new Set(assignable.filter((file) => (memory.get(file) ?? 0) >= POD_HEAVY_FILE_MB));
229
+ // The TD1 measurements predate the fixture-only gate; do not isolate those five files at their old 2–13 GB peaks.
230
+ const fixtureOnly = new Set([...GATE_NIGHTLY_AUDITS, 'test/guardian/dispatch-surface-contract.test.ts', 'test/user-config-mcp.test.ts']);
231
+ const heavy = new Set(assignable.filter((file) => !fixtureOnly.has(file) && (memory.get(file) ?? 0) >= POD_HEAVY_FILE_MB));
231
232
  const light = assignable.filter((file) => !heavy.has(file));
232
233
  const shards = [
233
234
  ...(light.length ? planShards(light, durations, shardCount) : []),
@@ -437,9 +438,9 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
437
438
  const outputs: string[] = [];
438
439
  let total = { pass: 0, fail: 0, errors: 0, ran: 0, files: 0 };
439
440
  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;
441
+ if (!group.paths.length || !files.some((f) => group.paths.some((p) => f === p || f.startsWith(`${p}/`)))) continue;
441
442
  const start = Date.now();
442
- const groupIgnores = [...new Set([...cdpPatterns, ...GATE_NIGHTLY_AUDITS])]
443
+ const groupIgnores = [...new Set(cdpPatterns)]
443
444
  .filter((pattern) => files.includes(pattern) && group.paths.some((p) => pattern === p || pattern.startsWith(`${p}/`)))
444
445
  .flatMap((pattern) => ['--path-ignore-patterns', pattern]);
445
446
  const run = await command('bun', ['run', 'test:deterministic', ...groupIgnores, ...group.paths.map(asPath)], tree);
@@ -508,7 +509,7 @@ function readBaseline(root: string, version: string): { commit: string; failures
508
509
  return record;
509
510
  }
510
511
 
511
- function baselineCommit(root: string, version: string): string {
512
+ export function baselineCommit(root: string, version: string): string {
512
513
  const path = join(root, 'release', version, 'release.json');
513
514
  const manifest: unknown = JSON.parse(readFileSync(path, 'utf8'));
514
515
  const commit = manifest && typeof manifest === 'object' && 'sourceCommit' in manifest ? manifest.sourceCommit : undefined;