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,309 @@
1
+ #!/usr/bin/env bun
2
+ /** On node-b, from a clean main checkout: bun scripts/measure-gate-shards.ts --shards 4 --measurements docs/measurements/td1-whole-gate-mechanical-2026-10-01.tsv
3
+ * Runs the same tracked gate test files once together and once in GT2 memory-budgeted bundles.
4
+ * Missing TSV planning rows are measured individually on this machine before either comparison run;
5
+ * allow time for that calibration when the historical TSV is stale. No guessed RSS is used.
6
+ * Each mode uses the same machine, Bun executable and deterministic test environment. stdout is one JSON line;
7
+ * stderr contains diagnostics. RSS is the maximum sampled sum of process-group RSS (50 ms resolution).
8
+ * Peak RSS is sampling-dependent and excludes memory after a process leaves its group.
9
+ */
10
+ import { spawnSync } from 'node:child_process';
11
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, rmdirSync, writeFileSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { join, resolve } from 'node:path';
14
+ import { planGateTestShards } from '../src/self-dev/shard-plan.js';
15
+ import { prepareIsolatedTestEnv, deriveCdpTestPatterns } from './test-deterministic.js';
16
+
17
+ export interface GateMeasurement {
18
+ mode: 'unsharded' | 'sharded';
19
+ durationMs: number;
20
+ peakRssMb: number;
21
+ // Confirmed OOMs only; an unknown termination is counted separately.
22
+ oomCount: number;
23
+ unknownTerminations: number;
24
+ oomCountStatus: 'confirmed' | 'partial';
25
+ verdict: 'passed' | 'failed' | 'unmeasured';
26
+ cases: Record<string, 'passed' | 'failed'>;
27
+ runs: number;
28
+ }
29
+
30
+ export interface GateComparison {
31
+ commit: string;
32
+ machine: string;
33
+ files: number;
34
+ shards: number;
35
+ unsharded: GateMeasurement;
36
+ sharded: GateMeasurement;
37
+ verdictAgrees: boolean;
38
+ }
39
+
40
+ export function readGateMeasurements(path: string): { rss: Map<string, number>; seconds: Map<string, number> } {
41
+ const lines = readFileSync(path, 'utf8').trimEnd().split(/\r?\n/);
42
+ const header = lines.shift()?.split('\t') ?? [];
43
+ const fileAt = header.indexOf('file'), rssAt = header.indexOf('rss_mb'), secondsAt = header.indexOf('secs');
44
+ if (fileAt < 0 || rssAt < 0 || secondsAt < 0) throw new Error('measurement TSV needs file, rss_mb and secs columns');
45
+ const rss = new Map<string, number>(), seconds = new Map<string, number>();
46
+ for (const line of lines) {
47
+ const cells = line.split('\t');
48
+ const file = cells[fileAt], mb = Number(cells[rssAt]), sec = Number(cells[secondsAt]);
49
+ if (!file || rss.has(file) || !cells[rssAt] || !cells[secondsAt] || !Number.isFinite(mb) || mb <= 0 || !Number.isFinite(sec) || sec < 0) {
50
+ throw new Error(`invalid measurement row: ${line}`);
51
+ }
52
+ rss.set(file, mb);
53
+ seconds.set(file, sec);
54
+ }
55
+ return { rss, seconds };
56
+ }
57
+
58
+ function git(repo: string, args: string[]): string {
59
+ const result = spawnSync('git', args, { cwd: repo, encoding: 'utf8' });
60
+ if (result.status !== 0) throw new Error(`git ${args[0]} failed: ${result.stderr.trim()}`);
61
+ return result.stdout.trim();
62
+ }
63
+
64
+ export function trackedGateFiles(repo: string): { commit: string; files: string[] } {
65
+ if (git(repo, ['rev-parse', '--show-toplevel']) !== resolve(repo)) throw new Error('run from the repository root');
66
+ if (git(repo, ['symbolic-ref', '--short', 'HEAD']) !== 'main') throw new Error('measurement requires the main checkout');
67
+ if (git(repo, ['status', '--porcelain'])) throw new Error('measurement requires a clean main checkout');
68
+ const commit = git(repo, ['rev-parse', 'HEAD']);
69
+ const files = git(repo, ['ls-files', '*.test.*']).split('\n').filter((file) => /\.test\.(?:tsx?|jsx?|mts|cts)$/.test(file))
70
+ .filter((file) => !file.split('/').some((part) => part.startsWith('.'))).sort();
71
+ if (!files.length) throw new Error('no gate tests found');
72
+ return { commit, files };
73
+ }
74
+
75
+ /** Fill missing in-memory planning rows from actual single-file runs, never an assumed RSS. */
76
+ export async function calibrateMissingGateMeasurements(options: {
77
+ repo: string; files: readonly string[]; rss: Map<string, number>; seconds: Map<string, number>;
78
+ }): Promise<void> {
79
+ const { repo, files, rss, seconds } = options;
80
+ const missing = files.filter((file) => !rss.has(file) || !seconds.has(file));
81
+ if (!missing.length) return;
82
+ console.error(`calibrating ${missing.length} gate files missing from the historical TSV on this machine`);
83
+ const root = mkdtempSync(join(tmpdir(), 'gate-shards-calibrate-'));
84
+ try {
85
+ for (const [index, file] of missing.entries()) {
86
+ const env = prepareIsolatedTestEnv(process.env, join(root, `env-${index}`));
87
+ const report = join(root, `case-${index}.xml`);
88
+ const started = performance.now();
89
+ const child = Bun.spawn(['bun', 'test', '--reporter=junit', `--reporter-outfile=${report}`, `./${file}`], {
90
+ cwd: repo, env, stdin: 'ignore', stdout: 'ignore', stderr: 'pipe', detached: true,
91
+ });
92
+ let peakKb = 0;
93
+ const sample = () => {
94
+ const ps = spawnSync('ps', ['-e', '-o', 'pgid=', '-o', 'rss='], { encoding: 'utf8' });
95
+ if (ps.status !== 0) throw new Error(`RSS calibration sampling failed: ${file}`);
96
+ const kb = ps.stdout.split('\n').reduce((sum, line) => {
97
+ const [group, value] = line.trim().split(/\s+/).map(Number);
98
+ return group === child.pid && Number.isFinite(value) ? sum + value! : sum;
99
+ }, 0);
100
+ peakKb = Math.max(peakKb, kb);
101
+ };
102
+ const interval = setInterval(sample, 50);
103
+ let stderr: string, code: number;
104
+ try {
105
+ sample();
106
+ stderr = await new Response(child.stderr).text();
107
+ code = await child.exited;
108
+ sample();
109
+ } finally { clearInterval(interval); }
110
+ let cases: Record<string, 'passed' | 'failed'>;
111
+ try { cases = readCases(readFileSync(report, 'utf8'), [file]); }
112
+ catch (error) { throw new Error(`calibration JUnit incomplete for ${file}: ${error}`); }
113
+ const failed = Object.values(cases).includes('failed');
114
+ if (child.signalCode || peakKb === 0 || (code !== 0 && code !== 1) || (code === 0 && failed) || (code === 1 && !failed)) {
115
+ throw new Error(`calibration incomplete for ${file}: code=${code} signal=${child.signalCode ?? 'none'} ${stderr.slice(-500)}`);
116
+ }
117
+ rss.set(file, Math.ceil(peakKb / 1024));
118
+ seconds.set(file, (performance.now() - started) / 1000);
119
+ }
120
+ } finally { rmSync(root, { recursive: true, force: true }); }
121
+ }
122
+
123
+ // Bun JUnit writes one testsuite per file. Require every expected file and every declared case,
124
+ // including failures/errors; missing or truncated output is unmeasured, never a passing verdict.
125
+ export function readCases(xml: string, files: readonly string[]): Record<string, 'passed' | 'failed'> {
126
+ const expected = new Set(files), seen = new Set<string>();
127
+ const cases: Record<string, 'passed' | 'failed'> = Object.create(null);
128
+ const suites = [...xml.matchAll(/<testsuite\b([^>]*)>([\s\S]*?)<\/testsuite>/g)];
129
+ if (!/<testsuites\b/.test(xml) || !/<\/testsuites>\s*$/.test(xml)) throw new Error('incomplete JUnit document');
130
+ const attr = (text: string, key: string) => new RegExp(`\\b${key}="([^"]*)"`).exec(text)?.[1];
131
+ for (const [, attrs, body] of suites) {
132
+ const file = attr(attrs!, 'file') ?? attr(attrs!, 'name');
133
+ if (!file || !expected.has(file) || seen.has(file)) throw new Error(`unexpected or repeated JUnit suite: ${file}`);
134
+ seen.add(file);
135
+ const tests = Number(attr(attrs!, 'tests'));
136
+ const entries = [...body!.matchAll(/<testcase\b([^>]*?)(?:\/>|>([\s\S]*?)<\/testcase>)/g)];
137
+ if (!Number.isSafeInteger(tests) || tests < 1 || entries.length !== tests) throw new Error(`incomplete JUnit suite: ${file}`);
138
+ for (const [, properties, contents] of entries) {
139
+ const name = attr(properties!, 'name'), caseFile: string = attr(properties!, 'file') ?? file;
140
+ const className = attr(properties!, 'classname');
141
+ if (!name || caseFile !== file || /<skipped\b/.test(contents ?? '')) throw new Error(`incomplete JUnit case: ${file}`);
142
+ const id = `${file} > ${className && className !== file ? `${className} > ` : ''}${name}`;
143
+ if (id in cases) throw new Error(`duplicate JUnit case: ${id}`);
144
+ cases[id] = /<(?:failure|error)\b/.test(contents ?? '') ? 'failed' : 'passed';
145
+ }
146
+ }
147
+ if (seen.size !== expected.size) throw new Error(`missing JUnit suites: ${[...expected].filter((file) => !seen.has(file)).join(', ')}`);
148
+ return cases;
149
+ }
150
+
151
+ // A private cgroup records kernel-attributed OOM kills for exactly one test bundle.
152
+ // A host without delegated cgroup v2 write access cannot classify abnormal exits as OOM.
153
+ function oomKills(path: string): number {
154
+ const line = readFileSync(join(path, 'memory.events'), 'utf8').split('\n').find((entry) => entry.startsWith('oom_kill '));
155
+ const value = Number(line?.slice('oom_kill '.length));
156
+ if (!line || !Number.isSafeInteger(value) || value < 0) throw new Error(`invalid cgroup oom_kill counter: ${path}`);
157
+ return value;
158
+ }
159
+
160
+ interface Run { code: number | null; signal: string | null; xml: string; stderr: string; oomKills: number | null }
161
+
162
+ export async function measureGateComparison(options: {
163
+ repo: string; files: string[]; commit: string; shards: number; rss: ReadonlyMap<string, number>;
164
+ seconds: ReadonlyMap<string, number>; budgetGiB?: number;
165
+ /** Fixture-only cgroup filesystem; production always uses the calling process's cgroup v2. */
166
+ cgroupRoot?: string;
167
+ /** Test-only creation hook for a synthetic cgroup v2 fixture. */
168
+ onCgroupCreated?: (path: string) => void;
169
+ }): Promise<GateComparison> {
170
+ const { repo, files, commit, shards, rss, seconds } = options;
171
+ if (!Number.isSafeInteger(shards) || shards < 1 || files.length === 0 || new Set(files).size !== files.length) throw new Error('invalid shard count or files');
172
+ const bundles = planGateTestShards(files, rss, seconds, options.budgetGiB ?? 8, shards);
173
+ const root = mkdtempSync(join(tmpdir(), 'gate-shards-measure-'));
174
+ const cgroup = options.cgroupRoot ?? (() => {
175
+ try {
176
+ const entry = readFileSync('/proc/self/cgroup', 'utf8').split('\n').find((line) => line.startsWith('0::'));
177
+ if (!entry) return null;
178
+ const path = resolve('/sys/fs/cgroup', `.${entry.slice(3)}`);
179
+ return path.startsWith('/sys/fs/cgroup/') || path === '/sys/fs/cgroup' ? path : null;
180
+ } catch { return null; } // macOS and hosts without cgroup v2 report partial OOM counts.
181
+ })();
182
+ const measure = async (mode: GateMeasurement['mode'], groups: string[][]): Promise<GateMeasurement> => {
183
+ const started = performance.now();
184
+ const testRoot = join(root, mode);
185
+ mkdirSync(testRoot);
186
+ const env = prepareIsolatedTestEnv(process.env, testRoot);
187
+ const reports = groups.map((_, index) => join(root, `${mode}-${index}.xml`));
188
+ // Record total RSS of the concurrently running test process groups, not the wrapper's RSS.
189
+ const running = new Set<number>();
190
+ let peakKb = 0;
191
+ const sample = () => {
192
+ if (!running.size) return;
193
+ const ps = spawnSync('ps', ['-e', '-o', 'pgid=', '-o', 'rss='], { encoding: 'utf8' });
194
+ if (ps.status !== 0) throw new Error('RSS sampling failed');
195
+ const kb = ps.stdout.split('\n').reduce((sum, line) => {
196
+ const [group, rssKb] = line.trim().split(/\s+/).map(Number);
197
+ return running.has(group!) && Number.isFinite(rssKb) ? sum + rssKb! : sum;
198
+ }, 0);
199
+ peakKb = Math.max(peakKb, kb);
200
+ };
201
+ const runs: Run[] = [];
202
+ let interval: ReturnType<typeof setInterval> | undefined;
203
+ try {
204
+ await Promise.all(groups.map(async (group, index) => {
205
+ // Bundles share the mode's isolated environment but have separate Bun process groups.
206
+ const cmd = ['bun', 'test', '--reporter=junit', `--reporter-outfile=${reports[index]}`, ...group.map((file) => `./${file}`)];
207
+ let groupPath: string | null = null;
208
+ if (cgroup) {
209
+ try {
210
+ groupPath = join(cgroup, `gate-shards-${process.pid}-${index}-${mode}-${root.split('/').at(-1)}`);
211
+ mkdirSync(groupPath);
212
+ options.onCgroupCreated?.(groupPath);
213
+ oomKills(groupPath);
214
+ } catch {
215
+ if (groupPath) { try { rmdirSync(groupPath); } catch { /* No delegated cleanup access. */ } }
216
+ groupPath = null;
217
+ }
218
+ }
219
+ // The shell blocks before exec: assign its PID to the private cgroup first.
220
+ // exec retains the PID; descendants inherit the same group and memory.events.
221
+ const child = Bun.spawn(groupPath ? ['bash', '-c', 'read -r _ || exit 125; exec "$@"', 'gate-shards', ...cmd] : cmd, {
222
+ cwd: repo, env: options.cgroupRoot && groupPath ? { ...env, ELANOUS_GATE_MEASURE_CGROUP_DIR: groupPath } : env,
223
+ stdin: groupPath ? 'pipe' : 'ignore', stdout: 'ignore', stderr: 'pipe', detached: true,
224
+ });
225
+ let attached = false;
226
+ if (groupPath) {
227
+ try {
228
+ writeFileSync(join(groupPath, 'cgroup.procs'), String(child.pid));
229
+ attached = true;
230
+ } catch { /* Without attachment a cgroup OOM counter is not attributable. */ }
231
+ if (attached) child.stdin!.write('\n');
232
+ else child.kill(); // Fail closed rather than run an untracked wrapper.
233
+ child.stdin!.end();
234
+ }
235
+ running.add(child.pid);
236
+ if (!interval) interval = setInterval(sample, 50);
237
+ sample();
238
+ const stderr = await new Response(child.stderr).text();
239
+ const code = await child.exited;
240
+ sample();
241
+ running.delete(child.pid);
242
+ let count: number | null = null;
243
+ if (groupPath) {
244
+ try {
245
+ if (attached) count = oomKills(groupPath);
246
+ } catch { /* Lost attribution: do not report a definitive zero. */ }
247
+ try { rmdirSync(groupPath); } catch { /* Another live process may still occupy it. */ }
248
+ }
249
+ let xml = '';
250
+ try { xml = readFileSync(reports[index]!, 'utf8'); } catch { /* An absent JUnit is unmeasured. */ }
251
+ runs[index] = { code, signal: child.signalCode, xml, stderr, oomKills: count };
252
+ }));
253
+ } finally { if (interval) clearInterval(interval); }
254
+ const cases: Record<string, 'passed' | 'failed'> = Object.create(null);
255
+ // Only kernel OOM kills attributed to the bundle's private cgroup count.
256
+ // Neither test stderr nor SIGKILL/137 establishes an OOM cause.
257
+ let oomCount = 0;
258
+ let unknownTerminations = 0, complete = true;
259
+ for (const [index, run] of runs.entries()) {
260
+ if (run.oomKills !== null) oomCount += run.oomKills;
261
+ if ((run.signal || (run.code !== 0 && run.code !== 1)) && !run.oomKills) unknownTerminations++;
262
+ if (run.oomKills) complete = false;
263
+ try {
264
+ const batch = readCases(run.xml, groups[index]!);
265
+ const hasFailure = Object.values(batch).includes('failed');
266
+ if (![0, 1].includes(run.code ?? -1) || run.signal || (run.code === 0 && hasFailure) || (run.code === 1 && !hasFailure)) complete = false;
267
+ Object.assign(cases, batch);
268
+ } catch { complete = false; }
269
+ if (run.signal || (run.code !== 0 && run.code !== 1)) console.error(`${mode} bundle ${index}: signal=${run.signal ?? 'none'} code=${run.code ?? 'null'} ${run.stderr.slice(-500)}`);
270
+ }
271
+ if (peakKb === 0) complete = false;
272
+ return { mode, durationMs: Math.round(performance.now() - started), peakRssMb: Math.ceil(peakKb / 1024), oomCount, unknownTerminations, oomCountStatus: runs.some((run) => run.oomKills === null) ? 'partial' : 'confirmed',
273
+ verdict: !complete ? 'unmeasured' : Object.values(cases).includes('failed') ? 'failed' : 'passed', cases, runs: groups.length };
274
+ };
275
+ try {
276
+ const unsharded = await measure('unsharded', [files]);
277
+ const sharded = await measure('sharded', bundles.map((bundle) => bundle.files));
278
+ const verdictAgrees = unsharded.verdict !== 'unmeasured' && sharded.verdict !== 'unmeasured'
279
+ && unsharded.verdict === sharded.verdict
280
+ && JSON.stringify(Object.entries(unsharded.cases).sort()) === JSON.stringify(Object.entries(sharded.cases).sort());
281
+ return { commit, machine: (await import('node:os')).hostname(), files: files.length, shards: bundles.length, unsharded, sharded, verdictAgrees };
282
+ } finally { rmSync(root, { recursive: true, force: true }); }
283
+ }
284
+
285
+ export async function main(argv: string[] = process.argv.slice(2), repo = process.cwd()): Promise<number> {
286
+ const take = (flag: string): string | undefined => { const index = argv.indexOf(flag); return index < 0 ? undefined : argv[index + 1]; };
287
+ if (argv.includes('--help')) {
288
+ console.error('bun scripts/measure-gate-shards.ts --shards N --measurements <TSV> [--budget-gib 8] (clean main checkout on node-b)');
289
+ return 0;
290
+ }
291
+ const count = Number(take('--shards'));
292
+ const source = take('--measurements');
293
+ if (!source || !Number.isSafeInteger(count) || count < 1) throw new Error('--shards N and --measurements TSV are required');
294
+ const budgetGiB = take('--budget-gib') === undefined ? 8 : Number(take('--budget-gib'));
295
+ const { commit, files: tracked } = trackedGateFiles(repo);
296
+ const cdp = new Set(deriveCdpTestPatterns({ cwd: repo }));
297
+ // Match the deterministic whole-gate CDP exclusion; keep every other tracked test, including install.
298
+ const files = tracked.filter((file) => !cdp.has(file));
299
+ const { rss, seconds } = readGateMeasurements(resolve(repo, source));
300
+ await calibrateMissingGateMeasurements({ repo, files, rss, seconds });
301
+ const result = await measureGateComparison({ repo, files, commit, shards: count, rss, seconds, budgetGiB });
302
+ process.stdout.write(JSON.stringify(result) + '\n');
303
+ return result.verdictAgrees ? 0 : 1;
304
+ }
305
+
306
+ if (import.meta.main) {
307
+ try { process.exitCode = await main(); }
308
+ catch (error) { console.error(error); process.exitCode = 2; }
309
+ }
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bun
2
+ /** Seven-day read-only measurement of self-implement Pod memory by goal kind. */
3
+ import { existsSync } from 'node:fs';
4
+ import { LogStore, logsDbPath, type LogStoreRow } from '../src/mss/logging/log-store.js';
5
+
6
+ export const GOAL_TYPES = ['test', 'code', 'pwa-build', 'docs'] as const;
7
+ export type GoalType = typeof GOAL_TYPES[number];
8
+ const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
9
+ const MIB = 1024 * 1024;
10
+
11
+ type Observation = Pick<LogStoreRow, 'ts_ms' | 'event' | 'data' | 'category'>;
12
+ type Run = { type: GoalType | null; limit: string | null; peakMiB: number | null; samples: number; terminated: boolean; oomKilled: boolean };
13
+ type MemorySample = { cgroupBytes?: unknown };
14
+ export type MemoryMeasurement = {
15
+ window: { since: string; until: string };
16
+ sources: { logs: string; observations: number; samples: number; unclassifiedRuns: number; classification: 'goal-fields-or-space-id'; peakCoverage: 'recorded-samples-only' };
17
+ byGoalType: Array<{ goalType: GoalType; runs: number; measured: number; missingPeak: number; samples: number; memoryLimits: Record<string, number>; terminations: number; oomKilled: number; peakMiB: { p50: number | null; p95: number | null; max: number | null } }>;
18
+ };
19
+
20
+ function payload(raw: string | null): Record<string, unknown> {
21
+ try {
22
+ const parsed: unknown = JSON.parse(raw ?? 'null');
23
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : {};
24
+ } catch { return {}; }
25
+ }
26
+
27
+ /** Infer only unambiguous kinds from free text; never turn an unknown title into code. */
28
+ export function goalTypeOf(description: string): GoalType | null {
29
+ const kinds: GoalType[] = [];
30
+ if (/\b(?:pwa|next\.js|frontend|front-end|web app)[-\s]+(?:build|compile|typecheck|bundle)\b/i.test(description)) kinds.push('pwa-build');
31
+ if (/\b(?:test|tests|testing|spec|coverage|gate)\b/i.test(description) || /시험|테스트|검증/.test(description)) kinds.push('test');
32
+ if (/\b(?:docs?|documentation|readme|manual|report)\b/i.test(description) || /문서|보고서/.test(description)) kinds.push('docs');
33
+ if (/\b(?:implement|implementation|coding|code|cli)\b/i.test(description) || /구현|코드/.test(description)) kinds.push('code');
34
+ return kinds.length === 1 ? kinds[0]! : null;
35
+ }
36
+
37
+ function recordedGoalType(data: Record<string, unknown>, spaceId: string): GoalType | null {
38
+ if ('goalType' in data) return GOAL_TYPES.find((type) => type === data.goalType) ?? null;
39
+ if ('goalKind' in data) return GOAL_TYPES.find((type) => type === data.goalKind) ?? null;
40
+ const descriptions = [data.goalTitle, data.goalDescription, data.feature].filter((value): value is string => typeof value === 'string' && value.trim().length > 0);
41
+ return descriptions.length ? goalTypeOf(descriptions.join(' ')) : goalTypeOf(spaceId);
42
+ }
43
+
44
+ function percentile(sorted: readonly number[], fraction: number): number | null {
45
+ if (!sorted.length) return null;
46
+ const index = (sorted.length - 1) * fraction;
47
+ const low = Math.floor(index);
48
+ return Math.round((sorted[low]! + (sorted[Math.ceil(index)]! - sorted[low]!) * (index - low)) * 100) / 100;
49
+ }
50
+
51
+ /** All rows are read before aggregation: log query's default 100-row limit is not a seven-day census. */
52
+ export function measurePodMemoryByGoal(rows: readonly Observation[], nowMs: number = Date.now(), logs = logsDbPath()): MemoryMeasurement {
53
+ const sinceMs = nowMs - WEEK_MS;
54
+ const windowRows = rows.filter((row) => row.ts_ms >= sinceMs && row.ts_ms <= nowMs && row.category === 'self-implement.pod');
55
+ const runs = new Map<string, Run>();
56
+ const jobToSpace = new Map<string, string>();
57
+ let samples = 0;
58
+ const ordered = [...windowRows].sort((a, b) => a.ts_ms - b.ts_ms);
59
+ for (const row of ordered) {
60
+ if (row.event !== 'memory-limit') continue;
61
+ const data = payload(row.data);
62
+ const id = typeof data.spaceId === 'string' ? data.spaceId : '';
63
+ if (!id) continue;
64
+ runs.set(id, { type: recordedGoalType(data, id), limit: typeof data.memoryLimit === 'string' ? data.memoryLimit : null,
65
+ peakMiB: null, samples: 0, terminated: false, oomKilled: false });
66
+ }
67
+ for (const row of ordered) {
68
+ const data = payload(row.data);
69
+ const job = typeof data.job === 'string' ? data.job : '';
70
+ const directId = typeof data.spaceId === 'string' ? data.spaceId : '';
71
+ if (row.event === 'job-applied' && job && runs.has(directId)) jobToSpace.set(job, directId);
72
+ const run = runs.get(directId || jobToSpace.get(job) || '');
73
+ if (!run) continue;
74
+ if (row.event === 'job-finished') {
75
+ run.terminated = true;
76
+ run.oomKilled ||= data.containerReason === 'OOMKilled';
77
+ }
78
+ if (row.event === 'oom-evidence') { run.terminated = true; run.oomKilled = true; }
79
+ if (data.reason === 'OOMKilled') { run.terminated = true; run.oomKilled = true; }
80
+ if (row.event !== 'oom-evidence' && row.event !== 'memory-last') continue;
81
+ const rawSamples: unknown[] = row.event === 'oom-evidence' && Array.isArray(data.samples) ? data.samples : [data.sample];
82
+ for (const raw of rawSamples) {
83
+ const record = raw && typeof raw === 'object' ? raw as MemorySample : {};
84
+ const bytes = record.cgroupBytes;
85
+ if (typeof bytes !== 'number' || !Number.isSafeInteger(bytes) || bytes < 0) continue;
86
+ const reading = bytes / MIB;
87
+ run.peakMiB = Math.max(run.peakMiB ?? 0, reading);
88
+ run.samples++;
89
+ samples++;
90
+ }
91
+ }
92
+ return {
93
+ window: { since: new Date(sinceMs).toISOString(), until: new Date(nowMs).toISOString() },
94
+ sources: { logs, observations: windowRows.length, samples, unclassifiedRuns: [...runs.values()].filter((run) => run.type === null).length,
95
+ classification: 'goal-fields-or-space-id', peakCoverage: 'recorded-samples-only' },
96
+ byGoalType: GOAL_TYPES.map((goalType) => {
97
+ const group = [...runs.values()].filter((run) => run.type === goalType);
98
+ const peaks = group.flatMap((run) => run.peakMiB === null ? [] : [run.peakMiB]).sort((a, b) => a - b);
99
+ const memoryLimits: Record<string, number> = {};
100
+ for (const run of group) if (run.limit) memoryLimits[run.limit] = (memoryLimits[run.limit] ?? 0) + 1;
101
+ return { goalType, runs: group.length, measured: peaks.length, missingPeak: group.length - peaks.length,
102
+ samples: group.reduce((count, run) => count + run.samples, 0), memoryLimits,
103
+ terminations: group.filter((run) => run.terminated).length, oomKilled: group.filter((run) => run.oomKilled).length,
104
+ peakMiB: { p50: percentile(peaks, 0.5), p95: percentile(peaks, 0.95), max: peaks.at(-1) ?? null } };
105
+ }),
106
+ };
107
+ }
108
+
109
+ export function readPodMemoryMeasurement(path: string = logsDbPath(), nowMs: number = Date.now()): MemoryMeasurement {
110
+ if (!existsSync(path)) throw new Error(`log store not found: ${path}`);
111
+ const store = LogStore.openReadOnly(path);
112
+ try {
113
+ return measurePodMemoryByGoal(store.queryAll({ exactCategories: ['self-implement.pod'], sinceMs: nowMs - WEEK_MS, untilMs: nowMs }), nowMs, path);
114
+ } finally { store.close(); }
115
+ }
116
+
117
+ if (import.meta.main) {
118
+ const args = process.argv.slice(2);
119
+ const usage = 'Usage: bun scripts/measure-pod-memory-by-goal.ts [--json] [--logs-db <existing-logs.db>] [--help]';
120
+ const dbArg = args.indexOf('--logs-db');
121
+ const db = dbArg === -1 ? logsDbPath() : args[dbArg + 1];
122
+ if (!db || (dbArg !== -1 && (db.startsWith('--') || args.lastIndexOf('--logs-db') !== dbArg))
123
+ || args.some((arg, index) => !['--json', '--help', '--logs-db'].includes(arg) && index !== dbArg + 1)) throw new Error(usage);
124
+ if (args.includes('--help')) console.log(usage);
125
+ else {
126
+ const result = readPodMemoryMeasurement(db);
127
+ if (args.includes('--json')) console.log(JSON.stringify(result, null, 2));
128
+ else for (const group of result.byGoalType) console.log(`${group.goalType}: runs=${group.runs} measured=${group.measured} peak p50=${group.peakMiB.p50 ?? 'n/a'} MiB p95=${group.peakMiB.p95 ?? 'n/a'} MiB OOMKilled=${group.oomKilled}`);
129
+ }
130
+ }
@@ -10,9 +10,14 @@ import { judgeMissionRequests } from '../src/mission-loop/judge.js';
10
10
  import { unknownCronFlag } from '../src/domains/cron-flag-contract.js';
11
11
  import { ensureCronNodePath } from '../src/domains/cron-path.js';
12
12
  import { registerStandaloneLogSink } from '../src/domains/standalone-log-sink.js';
13
+ import { debug } from '../src/debug/log.js';
13
14
 
14
15
  export type CreateHarnessGoal = (goal: HarnessGoal) => Promise<void> | void;
15
16
 
17
+ function logJudge(event: string, data: Record<string, unknown>): void {
18
+ try { debug.log('mission-fabric.judge', event, data); } catch { /* observation must not change a judgment */ }
19
+ }
20
+
16
21
  /**
17
22
  * ⛔ 실패해도 «여기까지 본 것」을 잃지 않는다.
18
23
  * 📏 회귀(리뷰 2R must-fix): 카탈로그가 없을 때 옛 CLI 는 「📍 권위 트리 / 📍 요청 카탈로그」 두 줄을
@@ -73,8 +78,23 @@ export async function runMissionRequestJudge(argv: readonly string[], dependenci
73
78
  };
74
79
  const authorityRoot = resolve(flag('--root') ?? join(dirname(new URL(import.meta.url).pathname), '..'));
75
80
  const result = judgeMissionRequests(authorityRoot);
81
+ logJudge('requests-judged', {
82
+ authorityRoot: result.authorityRoot, requestCatalog: result.requestCatalog,
83
+ catalogStatus: result.catalogStatus, requestsScanned: result.requestsScanned,
84
+ candidateCount: result.judgments.filter(judgment => judgment.status === 'blueprint-candidate').length,
85
+ invalidCount: result.invalidCount,
86
+ });
87
+ for (const judgment of result.judgments) {
88
+ logJudge('request-decision', {
89
+ file: judgment.file, status: judgment.status,
90
+ ...(judgment.status === 'invalid-request' ? { reasons: judgment.reasons } : {}),
91
+ ...(judgment.status === 'missing-capability' ? { missingCapabilities: judgment.missingCapabilities.map(capability => capability.id) } : {}),
92
+ ...(judgment.status === 'missing-blueprint' ? { reason: 'missing-blueprint' } : {}),
93
+ });
94
+ }
76
95
  const lines = [`📍 권위 트리: ${result.authorityRoot}`, `📍 요청 카탈로그: ${result.requestCatalog}`];
77
96
  if (result.catalogStatus === 'missing') {
97
+ logJudge('skipped', { reason: 'request-catalog-missing', requestCatalog: result.requestCatalog });
78
98
  const message = '⛔ 요청 카탈로그가 «없다» — 「요청 0건」이 아니라 ***디렉토리 부재***다. root 를 확인하라.';
79
99
  throw new MissionRequestJudgeError(message, [...lines, message]);
80
100
  }
@@ -91,13 +111,23 @@ export async function runMissionRequestJudge(argv: readonly string[], dependenci
91
111
  else lines.push(`✅ ${judgment.file} ⇒ 스키마 통과 · 능력 ${judgment.capabilityCount}개`, ' 🟢 블루프린트 «후보» 있음 → 검증 ⑴~⑷');
92
112
  }
93
113
  lines.push(`📏 훑은 ${result.requestsScanned} · invalid ${result.invalidCount}`);
94
- if (!argv.includes('--tick')) return lines;
114
+ if (!argv.includes('--tick')) {
115
+ logJudge('skipped', { reason: 'tick-not-requested' });
116
+ return lines;
117
+ }
95
118
 
96
119
  const cycle = dependencies.runCompositeCycle
97
120
  ? await dependencies.runCompositeCycle(authorityRoot)
98
121
  : await runCompositeCycle(authorityRoot, { createHarnessGoal: dependencies.createHarnessGoal ?? createHarnessGoal });
99
122
  lines.push(`🔁 복합 회차 ${cycle.actions.length}건`);
123
+ if (cycle.actions.length === 0) logJudge('skipped', { reason: 'no-cycle-actions' });
100
124
  for (const action of cycle.actions) {
125
+ logJudge('cycle-decision', {
126
+ requestId: action.requestId, action: action.action,
127
+ ...(action.action === 'escalated' || action.action === 'ignored' ? { reason: action.reason } : {}),
128
+ ...(action.action === 'goal-created' ? { paths: action.goal.paths } : {}),
129
+ ...(action.action === 'executed' ? { fileDelivery: action.fileDelivery.status } : {}),
130
+ });
101
131
  if (action.action === 'executed') {
102
132
  const delivery = action.fileDelivery.status === 'persisted'
103
133
  ? `file-delivery persisted · ${action.fileDelivery.path} · ${action.fileDelivery.bytes} bytes`
@@ -31,7 +31,7 @@ const report = await composeMorningReport(new Date(), { narrate, heatmapImageUrl
31
31
  if (dry) {
32
32
  console.log(report);
33
33
  } else {
34
- const sent = await sendTelegramReport(cfg, report, { markdown: true });
34
+ const sent = await sendTelegramReport(cfg, report, { markdown: true, kind: 'report' });
35
35
  console.error(sent
36
36
  ? '[morning-report] sent to report channel ✓'
37
37
  : '[morning-report] no report channel configured — skipped');
@@ -39,7 +39,7 @@ if (dry) {
39
39
  // 히트맵 이미지 첨부(위에서 캡처한 URL 재사용). fail-soft.
40
40
  if (heatmapImageUrl) {
41
41
  try {
42
- const ok = await sendReportPhoto(cfg, heatmapImageUrl, { caption: '🗺️ S&P 500 히트맵 (finviz)' });
42
+ const ok = await sendReportPhoto(cfg, heatmapImageUrl, { caption: '🗺️ S&P 500 히트맵 (finviz)', kind: 'report' });
43
43
  console.error(ok ? '[morning-report] heatmap image sent ✓' : '[morning-report] heatmap: no report channel');
44
44
  } catch (e) { console.error(`[morning-report] heatmap image error: ${e instanceof Error ? e.message : String(e)}`); }
45
45
  }
@@ -54,7 +54,7 @@ const report = parts.join('\n');
54
54
  if (dry) {
55
55
  console.log(report);
56
56
  } else {
57
- const sent = await sendTelegramReport(cfg, report, { markdown: true });
57
+ const sent = await sendTelegramReport(cfg, report, { markdown: true, kind: 'report' });
58
58
  console.error(sent
59
59
  ? '[opportunity-scan] sent to report channel ✓'
60
60
  : '[opportunity-scan] no report channel — printing:\n' + report);
@@ -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
+ export 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
 
@@ -11,10 +11,11 @@ export function runChecklistGate(context: GraphContext = readGraphContext()) {
11
11
  if (gate.ok && gate.moved.length) {
12
12
  const [major, minor, patch] = version.split('.').map(Number);
13
13
  const next = `${major}.${minor}.${patch! + 1}`;
14
+ // 이월은 «같은 칸»을 다음 판으로 옮기는 것 — 다른 판 id 충돌 검사(CKID #23407)의 대상이 아니다.
14
15
  for (const id of gate.moved) {
15
16
  const item = data.items.find((candidate) => candidate.id === id)!;
16
17
  if (listChecklist(next).items.some((candidate) => candidate.id === id)) continue;
17
- try { addItem(next, { id, title: item.title, ...(item.owner !== undefined ? { owner: item.owner } : {}), ...(item.kind !== undefined ? { kind: item.kind } : {}) }); }
18
+ try { addItem(next, { id, title: item.title, ...(item.owner !== undefined ? { owner: item.owner } : {}), ...(item.kind !== undefined ? { kind: item.kind } : {}) }, { allowDuplicateId: true }); }
18
19
  catch (error) {
19
20
  if (!listChecklist(next).items.some((candidate) => candidate.id === id)) throw error;
20
21
  }