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
@@ -6,7 +6,7 @@ import { promisify } from 'node:util';
6
6
  import { debug } from '../debug/log.js';
7
7
  import { effectiveInstanceRoot } from '../instance/resolve.js';
8
8
  import { getUserConfig, type SeatLoopConfig } from '../user-config.js';
9
- import { seatDay, seatLedgerPath, type SeatEntry } from './seat-loop.js';
9
+ import { seatDay, seatLedgerPath, type OpCandidate, type SeatEntry } from './seat-loop.js';
10
10
 
11
11
  export type SeatReportDeps = {
12
12
  root?: string;
@@ -21,6 +21,21 @@ export type SeatReportResult = { seat: string; date: string; body: string; poste
21
21
  const repoRoot = resolve(import.meta.dir, '../..');
22
22
  const exec = promisify(execFile);
23
23
 
24
+ function opJudgment(candidate: OpCandidate): { kind: 'card' | 'todo'; text: string } | null {
25
+ if (candidate.kind === 'release-readiness') {
26
+ if (candidate.verdict === 'no-open-release') return null;
27
+ return { kind: 'todo', text: `판올림 준비 ${candidate.version} · ${candidate.verdict} · 빨강 ${candidate.red.join(', ') || '없음'} · 미결 ${candidate.undecided.join(', ') || '없음'} · 차단 ${candidate.blocked.join(', ') || '없음'}` };
28
+ }
29
+ if (candidate.kind === 'unassigned-cell') {
30
+ if (candidate.verdict === 'none' || !candidate.id) return null;
31
+ return { kind: 'todo', text: `빈 칸 분배 ${candidate.version} ${candidate.id} ${candidate.title ?? ''}`.trim() };
32
+ }
33
+ if (candidate.verdict === 'none' || !candidate.id) return null;
34
+ const text = `결정 대리 ${candidate.id} ${candidate.title ?? ''}`.trim();
35
+ return { kind: candidate.category && ['irreversible', 'money', 'security', 'secret', 'publish'].includes(candidate.category) ? 'card' : 'todo',
36
+ text: `${text} (${candidate.category ?? '범주 없음'})` };
37
+ }
38
+
24
39
  async function defaultSend(body: string, seat: string, pr: number, repo: string): Promise<void> {
25
40
  const dir = mkdtempSync(join(tmpdir(), 'seat-report-'));
26
41
  try {
@@ -42,7 +57,25 @@ export async function seatReport(seat: string, deps: SeatReportDeps = {}): Promi
42
57
  const entries = raw.split('\n').filter(Boolean).map((line) => JSON.parse(line) as SeatEntry);
43
58
  // One line per item, its last state wins: an `attempting` row followed by `launched` is not «unconfirmed».
44
59
  const latest = new Map<string, SeatEntry>();
60
+ const judgments = new Map<string, OpCandidate>();
45
61
  for (const entry of entries) {
62
+ if (seat === 'OP' && entry.candidate) {
63
+ if (entry.candidate.verdict === 'none') {
64
+ if (entry.candidate.id) {
65
+ const key = entry.candidate.kind === 'unassigned-cell'
66
+ ? `unassigned-cell:${JSON.stringify([entry.candidate.version, entry.candidate.id])}`
67
+ : `decision-delegation:${entry.candidate.id}`;
68
+ judgments.delete(key);
69
+ } else for (const key of judgments.keys()) if (key.startsWith(`${entry.candidate.kind}:`)) judgments.delete(key);
70
+ continue;
71
+ }
72
+ const key = entry.candidate.kind === 'unassigned-cell'
73
+ ? `unassigned-cell:${JSON.stringify([entry.candidate.version, entry.candidate.id])}`
74
+ : entry.candidate.kind === 'decision-delegation' && entry.candidate.id
75
+ ? `${entry.candidate.kind}:${entry.candidate.id}` : entry.candidate.kind;
76
+ judgments.set(key, entry.candidate);
77
+ continue;
78
+ }
46
79
  const key = entry.item ? `${entry.item.source}:${entry.item.version ?? ''}:${entry.item.id}` : `none:${entry.status}`;
47
80
  latest.delete(key);
48
81
  latest.set(key, entry);
@@ -55,7 +88,9 @@ export async function seatReport(seat: string, deps: SeatReportDeps = {}): Promi
55
88
  if (entry.status === 'attempting' || entry.status === 'outcome-unknown') return `결과 확인 필요 ${entry.status} ${label}`;
56
89
  return `건너뜀 ${entry.status} ${label}`;
57
90
  });
58
- const body = `**[${seat}]** {{TS}} → 보고 ${date}: ${detail.join(' · ') || '원장 기록 없음'}`;
91
+ const classified = [...judgments.values()].map(opJudgment).filter((row): row is NonNullable<typeof row> => row !== null);
92
+ const opDetail = classified.length ? ` · 결정 카드 후보: ${classified.filter((row) => row.kind === 'card').map((row) => row.text).join(' / ') || '없음'} · OP 가 할 일: ${classified.filter((row) => row.kind === 'todo').map((row) => row.text).join(' / ') || '없음'}` : '';
93
+ const body = `**[${seat}]** {{TS}} → 보고 ${date}: ${detail.join(' · ') || (classified.length ? 'OP 그림자 판단' : '원장 기록 없음')}${opDetail}`;
59
94
  const pr = (deps.config ?? getUserConfig().loops?.seat)?.reportPr;
60
95
  const posted = deps.post === true && pr !== undefined;
61
96
  if (posted) await (deps.send ?? ((text, id, number) => defaultSend(text, id, number, deps.repo ?? repoRoot)))(body, seat, pr);
@@ -97,6 +97,8 @@ export interface DevCliOpts {
97
97
  pollMs?: string;
98
98
  model?: string;
99
99
  attach?: string;
100
+ /** drive: DRIVE-JAIL boundary directory. */
101
+ jailHome?: string;
100
102
  observeOnly?: boolean;
101
103
  cols?: string;
102
104
  rows?: string;
@@ -1748,7 +1750,7 @@ export function assertDevCliPathOptions(
1748
1750
  if (foreign.length > 0) throw new DevPipelineError(formatForeignDevOptions(path, foreign));
1749
1751
  }
1750
1752
 
1751
- const DRIVE_ALIAS_OPTIONS = new Set(['goal', 'maxSteps', 'pollMs', 'model', 'cwd', 'worktree', 'json', 'attach']);
1753
+ const DRIVE_ALIAS_OPTIONS = new Set(['goal', 'maxSteps', 'pollMs', 'model', 'cwd', 'worktree', 'json', 'attach', 'jailHome']);
1752
1754
  const DRIVE_ALIAS_ALLOWED_FLAGS = [...DRIVE_ALIAS_OPTIONS].map(toCliFlag).join(' · ');
1753
1755
 
1754
1756
  export function assertDriveAliasOptions(explicitOptionNames: readonly string[]): void {
@@ -1947,6 +1949,7 @@ export function buildDevCliSpec(
1947
1949
  ...(opts.pollMs !== undefined ? { pollMs: parseNonNegativeInt(opts.pollMs, '--poll-ms') } : {}),
1948
1950
  ...(opts.model ? { model: opts.model } : {}),
1949
1951
  ...(opts.cwd ? { cwd: opts.cwd } : {}),
1952
+ ...(opts.jailHome ? { jailHome: opts.jailHome } : {}),
1950
1953
  },
1951
1954
  };
1952
1955
  }
@@ -25,6 +25,7 @@ import { createRepositoryReferencedFileReader, type ReferencedFileReader } from
25
25
  import { parseGoalDocumentClarifications } from '../self-implement/goal-author-clarification.js';
26
26
  import { requiredEvidenceFromGoal } from '../self-implement/off-diff-evidence.js';
27
27
  import { debug } from '../debug/log.js';
28
+ import { releasePathHold, releasePathHoldComment, RELEASE_PATH_LABEL } from './release-path-guard.js';
28
29
  import { runGitCommand } from '../git-fs/runner.js';
29
30
  import type { GitRunResult } from '../git-fs/retry.js';
30
31
  import { DEFAULT_BRANCH_WORKTREE_BASE, observeGitResidue, type GitResidueObservation } from '../git-fs/worktree.js';
@@ -135,6 +136,8 @@ export interface DevShellDriveOpts {
135
136
  pollMs?: number;
136
137
  model?: string;
137
138
  cwd?: string;
139
+ /** DRIVE-JAIL boundary — inputs naming paths outside it are not sent to the PTY. */
140
+ jailHome?: string;
138
141
  }
139
142
 
140
143
  /** staged harness(plan-staged) 실행 옵션 — `harness run` front door의 무손실 재라우팅용.
@@ -1852,6 +1855,24 @@ async function observeDevTaskDispatch(spec: DevPipelineSpec, plan: ResolvedDevPl
1852
1855
  }
1853
1856
  }
1854
1857
 
1858
+ async function inspectReleasePathBeforeMerge(seams: SelfImplementSeams, number: number, cwd: string): Promise<string | undefined> {
1859
+ if (!seams.readPrFiles) throw new Error('release-path inspection unavailable — automatic merge refused');
1860
+ const files = await seams.readPrFiles({ number, cwd });
1861
+ if (!Array.isArray(files) || !files.every((path) => typeof path === 'string')) throw new Error('invalid PR file list — automatic merge refused');
1862
+ const path = releasePathHold(files);
1863
+ if (!path) return undefined;
1864
+ debug.log('self-dev.merge', 'release-path-hold', { number, path, label: RELEASE_PATH_LABEL });
1865
+ try {
1866
+ if (!seams.addPrLabel) throw new Error('addPrLabel seam unavailable');
1867
+ await seams.addPrLabel({ number, label: RELEASE_PATH_LABEL, cwd });
1868
+ } catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number, path, action: 'label', error: String(error) }); }
1869
+ try {
1870
+ if (!seams.postPrComment) throw new Error('postPrComment seam unavailable');
1871
+ await seams.postPrComment({ number, body: releasePathHoldComment(path), cwd });
1872
+ } catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number, path, action: 'comment', error: String(error) }); }
1873
+ return path;
1874
+ }
1875
+
1855
1876
  async function runDevPipelineDispatch(
1856
1877
  spec: DevPipelineSpec,
1857
1878
  deps: DevPipelineDeps,
@@ -2071,7 +2092,22 @@ async function runDevPipelineDispatch(
2071
2092
  const defaultSeams = deps.buildSelfImplementSeams
2072
2093
  ? await deps.buildSelfImplementSeams(plan)
2073
2094
  : await buildDefaultSelfImplementSeams(plan, { progress: deps.progress });
2074
- const seams = deps.approver ? { ...defaultSeams, approvePr: deps.approver } : defaultSeams;
2095
+ const assembledSeams = deps.approver ? { ...defaultSeams, approvePr: deps.approver } : defaultSeams;
2096
+ // Guard even injected runSelfImplement implementations: do not trust a dispatched merge to
2097
+ // have used orchestrator's own PR-path check before requesting mergePr.
2098
+ const seams: SelfImplementSeams = {
2099
+ ...assembledSeams,
2100
+ ...(assembledSeams.mergePr ? { mergePr: async (input) => {
2101
+ let path: string | undefined;
2102
+ try { path = await inspectReleasePathBeforeMerge(assembledSeams, input.number, input.cwd); }
2103
+ catch (error) {
2104
+ debug.log('self-dev.merge', 'release-path-inspection-failed', { number: input.number, error: String(error) });
2105
+ return { merged: false, detail: `automatic merge refused: ${String(error)}` };
2106
+ }
2107
+ if (path) return { merged: false, detail: `OP approval required: ${path}` };
2108
+ return assembledSeams.mergePr!(input);
2109
+ } } : {}),
2110
+ };
2075
2111
  // ⭐ 대표 지시(2026-09-08) — ***걸음을 「위」로 흘린다.***
2076
2112
  // 🩸 그 전까지 런 슈퍼바이저가 받는 것은 «시도의 요약 판정»뿐이었고(stage·stopReason·분류 …)
2077
2113
  // 「어느 노드를 몇 번 밟았나」는 ***런 안에서 끝났다***(`onNodeEntry` 는 있는데 호출부 0).
@@ -1,11 +1,12 @@
1
- import { CLAIM_IDLE_HOURS, PR_LABELS } from '../github/pr-labels.js';
1
+ import { CLAIM_IDLE_HOURS, PR_LABELS, STALLED_DRAFT_HOURS } from '../github/pr-labels.js';
2
+ import { debug } from '../debug/log.js';
2
3
  import { decideDraft, type DraftTriagePr } from './draft-triage-rules.js';
3
4
 
4
5
  export interface SweepDraft extends DraftTriagePr {
5
6
  readonly title: string;
6
7
  readonly labels: readonly string[];
7
8
  readonly createdAt: string;
8
- /** Last PR update (push, label, comment). Missing ⇒ running claim stays untouched; other drafts use legacy triage. */
9
+ /** Last PR update (push, label, comment). Missing ⇒ no idle-based close; merged twins can still close. */
9
10
  readonly updatedAt?: string;
10
11
  readonly runId?: string | null;
11
12
  }
@@ -18,7 +19,7 @@ export interface DraftSweepAdapters {
18
19
  /** Each call returns one complete page; a rejection must not be mistaken for an empty page. */
19
20
  listDrafts(page: number, perPage: number, repository: string): Promise<readonly SweepDraft[]>;
20
21
  listMerged(page: number, perPage: number, repository: string): Promise<readonly SweepMergedPr[]>;
21
- /** Undefined means no run assessment; it does not authorize a close. */
22
+ /** Undefined means no run assessment; a merged twin or 24h idle draft can still authorize a close. */
22
23
  getRunStatus(draft: SweepDraft, repository: string): Promise<string | undefined>;
23
24
  /** Undefined means liveness could not be established. */
24
25
  listLiveBranches(repository: string): Promise<ReadonlySet<string> | undefined>;
@@ -26,6 +27,10 @@ export interface DraftSweepAdapters {
26
27
  closeDraft(repository: string, number: number, comment: string): Promise<void>;
27
28
  /** Resolve the latest claim comment owner; a failed lookup must not authorize a close. */
28
29
  getClaimOwner?(repository: string, number: number): Promise<string | undefined>;
30
+ /** Whether the current owned run has a self-implement.result final observation, even if its worktree remains. */
31
+ hasFinalRunResult?(draft: SweepDraft, repository: string): Promise<boolean | undefined>;
32
+ /** Per-file last change on the draft branch; undefined means file coverage is unverified. */
33
+ getLatestFileChanges?(draft: SweepDraft, repository: string): Promise<Readonly<Record<string, string>> | undefined>;
29
34
  }
30
35
 
31
36
  export interface DraftSweepOptions {
@@ -51,6 +56,7 @@ export interface DraftSweepResult {
51
56
  apply: boolean;
52
57
  complete: boolean;
53
58
  entries: DraftSweepEntry[];
59
+ counts: Record<string, number>;
54
60
  /** Drafts whose run could not be observed from here (kept, or closed by the idle rule). */
55
61
  unobserved?: number;
56
62
  /** Closes decided this tick (at most DRAFT_SWEEP_CLOSE_CAP). */
@@ -73,11 +79,8 @@ const stalledLabel = label('close', 'stalled');
73
79
  const supersededLabel = label('close', 'superseded');
74
80
  const approvalLabel = PR_LABELS.find((entry) => entry.axis === 'state' && entry.sweep.action === 'none')?.name;
75
81
  const keepLabel = PR_LABELS.find((entry) => entry.sweep.action === 'exclude')?.name;
82
+ const releaseHoldLabel = PR_LABELS.find((entry) => entry.axis === 'addon' && entry.sweep.action === 'none')?.name;
76
83
  const PAGE_SIZE = 100;
77
- /** 🅢 2026-09-28 (lead decision, channel #20798 04:1x): a run the sweeper cannot see is closed as stalled only when its branch
78
- * is not in a host worktree and the draft has been idle this long. A Pod lives at most POD_JOB_DEADLINE_SECONDS (3h), so a
79
- * draft idle for 48h cannot belong to a running Pod — the «not in a running Pod» condition follows from the idle time. */
80
- export const UNOBSERVED_IDLE_CLOSE_HOURS = 48;
81
84
  /** At most this many closes per tick, so a wrong rule cannot close everything at once. */
82
85
  export const DRAFT_SWEEP_CLOSE_CAP = 10;
83
86
 
@@ -94,7 +97,16 @@ async function collectPages<T>(fetch: (page: number, perPage: number) => Promise
94
97
 
95
98
  /** A failed inventory or liveness lookup is never treated as proof that a draft can be closed. */
96
99
  export async function runDraftSweep({ repository, adapters, apply = false, now = new Date() }: DraftSweepOptions): Promise<DraftSweepResult> {
97
- const result: DraftSweepResult = { repository, apply, complete: false, entries: [] };
100
+ const result: DraftSweepResult = { repository, apply, complete: false, entries: [], counts: {} };
101
+ const record = (entry: DraftSweepEntry): void => {
102
+ result.entries.push(entry);
103
+ result.counts[entry.reason] = (result.counts[entry.reason] ?? 0) + 1;
104
+ debug.log('drafts.cleanup', 'decided', { number: entry.number, action: entry.action, reason: entry.reason });
105
+ };
106
+ const finish = (): DraftSweepResult => {
107
+ debug.log('drafts.cleanup', 'summary', result.counts);
108
+ return result;
109
+ };
98
110
  let drafts: SweepDraft[];
99
111
  let merged: SweepMergedPr[];
100
112
  let liveBranches: ReadonlySet<string> | undefined;
@@ -109,58 +121,90 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
109
121
  || merged.some((pr) => !Number.isInteger(pr.number) || !pr.branch)) throw new Error('Invalid PR inventory');
110
122
  } catch (error) {
111
123
  result.error = String(error);
112
- return result;
124
+ return finish();
113
125
  }
114
126
  let statuses: Map<number, string | undefined>;
127
+ let finality: Map<number, boolean | undefined>;
128
+ let latestFileChanges: Map<number, Readonly<Record<string, string>> | undefined>;
115
129
  try {
116
130
  statuses = new Map<number, string | undefined>();
117
- for (const draft of drafts) statuses.set(draft.number, await adapters.getRunStatus(draft, repository));
131
+ finality = new Map<number, boolean | undefined>();
132
+ latestFileChanges = new Map<number, Readonly<Record<string, string>> | undefined>();
133
+ for (const draft of drafts) {
134
+ const status = await adapters.getRunStatus(draft, repository);
135
+ // A prior final cannot terminate a new active run on the same draft.
136
+ const active = status === 'running' || status === 'probable-running';
137
+ const final = active ? false : await adapters.hasFinalRunResult?.(draft, repository);
138
+ finality.set(draft.number, final);
139
+ statuses.set(draft.number, final ? 'self-implement.result final' : status);
140
+ if (draft.changedFiles?.length && adapters.getLatestFileChanges) {
141
+ latestFileChanges.set(draft.number, await adapters.getLatestFileChanges(draft, repository));
142
+ }
143
+ }
118
144
  } catch (error) {
119
145
  result.error = String(error);
120
- return result;
146
+ return finish();
121
147
  }
122
148
  result.complete = true;
123
149
  let closes = 0;
124
150
  let unobserved = 0;
125
151
  let claimed = 0;
126
152
  let claimExpired = 0;
127
- for (const draft of drafts) {
153
+ for (const listedDraft of drafts) {
154
+ const draft = { ...listedDraft, latestFileChanges: latestFileChanges.get(listedDraft.number) };
128
155
  const runStatus = statuses.get(draft.number);
156
+ const finalRunResult = finality.get(draft.number);
129
157
  const states = stateLabels.filter((state) => draft.labels.includes(state.name));
130
158
  const contradiction = states.length > 1 || draft.labels.includes(approvalLabel ?? '');
131
- if (!contradiction && draft.labels.includes(keepLabel ?? '')) {
132
- result.entries.push({ number: draft.number, action: 'keep', reason: `label:${keepLabel}`, applied: false });
159
+ if (draft.labels.includes(releaseHoldLabel ?? '') || (!contradiction && draft.labels.includes(keepLabel ?? ''))) {
160
+ const held = draft.labels.includes(keepLabel ?? '') ? keepLabel : releaseHoldLabel;
161
+ record({ number: draft.number, action: 'keep', reason: `label:${held}`, applied: false });
133
162
  continue;
134
163
  }
135
164
  const isClaimed = !contradiction && draft.labels.includes(runningLabel);
136
165
  const ageHours = (now.getTime() - Date.parse(draft.createdAt)) / 3_600_000;
166
+ const idleHours = typeof draft.updatedAt === 'string' && Number.isFinite(Date.parse(draft.updatedAt))
167
+ ? (now.getTime() - Date.parse(draft.updatedAt)) / 3_600_000 : NaN;
137
168
  // An unobserved claim may still have a merged twin: liveness/holds retain their priority,
138
169
  // but a superseded draft must not be hidden by the six-hour claim window.
139
- const mergedDecision = isClaimed ? decideDraft({ draft, runStatus: runStatus ?? 'ended-unclosed', mergedTwins: merged, liveBranches, ageHours }) : undefined;
140
- const supersededClaim = mergedDecision?.reason.startsWith('superseded-by #') === true;
170
+ const mergedDecision = isClaimed ? decideDraft({ draft, runStatus, mergedTwins: merged, openDrafts: drafts, liveBranches,
171
+ finalRunResult, ageHours: idleHours }) : undefined;
172
+ const supersededClaim = mergedDecision?.reason.startsWith('superseded-by #') === true
173
+ || mergedDecision?.reason.startsWith('duplicate-of-open #') === true;
174
+ if (!contradiction && mergedDecision?.reason === 'branch-finality-unobserved') {
175
+ record({ number: draft.number, action: 'keep', reason: mergedDecision.reason, applied: false });
176
+ continue;
177
+ }
141
178
  // Without an observed update time, neither expiration nor a fallback to creation time can authorize mutation —
142
179
  // but a merged twin does not need the update time, so superseded keeps its priority over the unobserved claim.
143
180
  if (isClaimed && !supersededClaim && (typeof draft.updatedAt !== 'string' || !Number.isFinite(Date.parse(draft.updatedAt)))) {
144
- result.entries.push({ number: draft.number, action: 'keep', reason: 'claim-update-unobserved', applied: false });
181
+ record({ number: draft.number, action: 'keep', reason: 'claim-update-unobserved', applied: false });
145
182
  continue;
146
183
  }
147
- const claimIdleHours = draft.updatedAt === undefined ? NaN : (now.getTime() - Date.parse(draft.updatedAt)) / 3_600_000;
148
- if (isClaimed && !supersededClaim && Number.isFinite(claimIdleHours) && claimIdleHours < CLAIM_IDLE_HOURS) {
184
+ if (isClaimed && !supersededClaim && Number.isFinite(idleHours) && idleHours < CLAIM_IDLE_HOURS) {
149
185
  claimed += 1;
150
- result.entries.push({ number: draft.number, action: 'keep', reason: `label:running(<${CLAIM_IDLE_HOURS}h)`, applied: false });
186
+ record({ number: draft.number, action: 'keep', reason: `label:running(<${CLAIM_IDLE_HOURS}h)`, applied: false });
151
187
  continue;
152
188
  }
153
- if (isClaimed && !supersededClaim && Number.isFinite(claimIdleHours) && claimIdleHours >= CLAIM_IDLE_HOURS) {
189
+ if (isClaimed && !supersededClaim && Number.isFinite(idleHours) && idleHours >= CLAIM_IDLE_HOURS) {
154
190
  claimExpired += 1;
155
- if (runStatus === 'running' || runStatus === 'probable-running' || liveBranches.has(draft.branch)) {
156
- result.entries.push({ number: draft.number, action: 'keep', reason: 'claim-expired-but-live', applied: false });
191
+ if (liveBranches.has(draft.branch) && finalRunResult === undefined
192
+ && runStatus !== 'running' && runStatus !== 'probable-running') {
193
+ record({ number: draft.number, action: 'keep', reason: 'branch-finality-unobserved', applied: false });
194
+ continue;
195
+ }
196
+ if (runStatus === 'running' || runStatus === 'probable-running' ||
197
+ (runStatus !== 'self-implement.result final' && liveBranches.has(draft.branch))) {
198
+ record({ number: draft.number, action: 'keep', reason: 'claim-expired-but-live', applied: false });
157
199
  continue;
158
200
  }
159
201
  const action = closes >= DRAFT_SWEEP_CLOSE_CAP ? 'keep' : 'close';
160
202
  if (action === 'close') closes += 1;
161
- const entry: DraftSweepEntry = { number: draft.number, action, reason: action === 'close' ? 'claim-expired' : 'close-cap',
203
+ const entry: DraftSweepEntry = { number: draft.number, action,
204
+ reason: action === 'close' ? runStatus === 'self-implement.result final'
205
+ ? 'claim-expired (self-implement.result final; worktree is not live)' : 'claim-expired' : 'close-cap',
162
206
  ...(action === 'close' ? { statusLabel: stalledLabel } : {}), applied: false };
163
- result.entries.push(entry);
207
+ record(entry);
164
208
  if (!apply || action !== 'close') continue;
165
209
  let labelsChanged = false;
166
210
  try {
@@ -168,7 +212,7 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
168
212
  await adapters.setLabels(repository, draft.number, { add: stalledLabel, remove: [runningLabel] });
169
213
  labelsChanged = true;
170
214
  await adapters.closeDraft(repository, draft.number,
171
- `Draft sweep: 처리 중 표식이 ${CLAIM_IDLE_HOURS}시간 갱신 없음 — 런·워크트리 없음 · 주인 ${owner}. Closed as stalled. Branch preserved; reopen to restore.`);
215
+ `Draft sweep: 처리 중 표식이 ${CLAIM_IDLE_HOURS}시간 갱신 없음 — ${runStatus === 'self-implement.result final' ? 'self-implement.result final · 남은 워크트리는 live 아님' : '런·워크트리 없음'} · 주인 ${owner}. Closed as stalled. Branch preserved; reopen to restore.`);
172
216
  entry.applied = true;
173
217
  } catch (error) {
174
218
  if (labelsChanged) entry.partialApplied = true;
@@ -178,17 +222,12 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
178
222
  }
179
223
  // Unlabelled non-harness drafts are outside the sweeper's jurisdiction.
180
224
  if (!contradiction && !states.length && !draft.branch.startsWith('self-impl/')) {
181
- result.entries.push({ number: draft.number, action: 'keep', reason: 'outside-harness', applied: false });
225
+ record({ number: draft.number, action: 'keep', reason: 'outside-harness', applied: false });
182
226
  continue;
183
227
  }
184
- let decision = supersededClaim ? mergedDecision! : decideDraft({ draft, runStatus, mergedTwins: merged, liveBranches, ageHours });
185
- if (decision.reason === 'unobserved') {
186
- unobserved += 1;
187
- const idleHours = (now.getTime() - Date.parse(draft.updatedAt ?? draft.createdAt)) / 3_600_000;
188
- if (!liveBranches.has(draft.branch) && Number.isFinite(idleHours) && idleHours >= UNOBSERVED_IDLE_CLOSE_HOURS) {
189
- decision = { action: 'close', reason: 'unobserved-idle' };
190
- }
191
- }
228
+ let decision = supersededClaim ? mergedDecision! : decideDraft({ draft, runStatus, mergedTwins: merged, openDrafts: drafts, liveBranches,
229
+ finalRunResult, ageHours: runStatus ? ageHours : idleHours });
230
+ if (!runStatus && (decision.reason === 'unobserved' || decision.reason === 'stale-unobserved')) unobserved += 1;
192
231
  if (!contradiction && decision.action === 'close') {
193
232
  if (closes >= DRAFT_SWEEP_CLOSE_CAP) decision = { action: 'keep', reason: 'close-cap' };
194
233
  else closes += 1;
@@ -199,10 +238,10 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
199
238
  : decision.reason;
200
239
  const isLive = decision.reason === 'live';
201
240
  const target = action === 'report' ? undefined : action === 'close'
202
- ? decision.reason.startsWith('superseded-by #') ? supersededLabel : stalledLabel
241
+ ? decision.reason.startsWith('superseded-by #') || decision.reason.startsWith('duplicate-of-open #') ? supersededLabel : stalledLabel
203
242
  : isLive ? (states.length ? runningLabel : undefined) : runStatus && (states[0]?.name === runningLabel || states.length === 0) ? stalledLabel : undefined;
204
243
  const entry: DraftSweepEntry = { number: draft.number, action, reason, ...(target ? { statusLabel: target } : {}), applied: false };
205
- result.entries.push(entry);
244
+ record(entry);
206
245
  if (!apply || action === 'report') continue;
207
246
  let labelsChanged = false;
208
247
  try {
@@ -213,8 +252,8 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
213
252
  labelsChanged = true;
214
253
  }
215
254
  if (action === 'close') {
216
- await adapters.closeDraft(repository, draft.number, decision.reason === 'unobserved-idle'
217
- ? `Draft sweep: run unobserved — no run record reachable here, no host worktree for this branch, idle ≥${UNOBSERVED_IDLE_CLOSE_HOURS}h. Closed as stalled. Branch preserved; reopen to restore.`
255
+ await adapters.closeDraft(repository, draft.number, decision.reason === 'stale-unobserved'
256
+ ? `Draft sweep: run unobserved — no run record reachable here, no host worktree for this branch, idle ≥${STALLED_DRAFT_HOURS}h. Closed as stalled. Branch preserved; reopen to restore.`
218
257
  : `Draft sweep: ${decision.reason}. Branch preserved.`);
219
258
  }
220
259
  entry.applied = labelsChanged || action === 'close';
@@ -227,5 +266,5 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
227
266
  result.closed = closes;
228
267
  result.claimed = claimed;
229
268
  result.claimExpired = claimExpired;
230
- return result;
269
+ return finish();
231
270
  }
@@ -1,42 +1,97 @@
1
1
  import { PR_LABELS, STALLED_DRAFT_HOURS } from '../github/pr-labels.js';
2
+ import { RELEASE_PATH_LABEL } from './release-path-guard.js';
2
3
 
3
4
  export interface DraftTriagePr {
4
5
  number: number;
5
6
  title?: string;
6
7
  branch: string;
7
8
  labels?: readonly string[];
9
+ body?: string;
10
+ mergeCommitMessage?: string;
11
+ landingVerifiedComments?: readonly string[];
12
+ createdAt?: string;
13
+ mergedAt?: string;
14
+ changedFiles?: readonly string[];
15
+ /** Latest change to each draft file, from the draft branch's commit history. Missing is not creation time. */
16
+ latestFileChanges?: Readonly<Record<string, string>>;
8
17
  }
9
18
 
10
19
  export interface DraftTriageInput {
11
20
  draft: DraftTriagePr;
12
21
  runStatus: string | undefined;
13
22
  mergedTwins: readonly DraftTriagePr[];
23
+ openDrafts?: readonly DraftTriagePr[];
14
24
  ageHours: number;
15
25
  liveBranches: ReadonlySet<string>;
26
+ /** false only when the current run's final result has actually been checked and ruled out. */
27
+ finalRunResult?: boolean;
16
28
  }
17
29
 
18
30
  export type DraftDecision = { action: 'close' | 'keep'; reason: string };
19
31
 
20
32
  // Labels the sweeper must never close: an approval-waiting state and the human «keep» / release holds (R-PRK3).
21
- const PROTECTED_LABELS: ReadonlySet<string> = new Set<string>(PR_LABELS
22
- .filter((label) => label.sweep.action === 'exclude' || (label.axis === 'state' && label.sweep.action === 'none'))
23
- .map((label) => label.name));
33
+ // RELGUARD's release-path hold waits for OP approval — a long wait is not «stale» (TC review #23217).
34
+ const PROTECTED_LABELS: ReadonlySet<string> = new Set<string>([...PR_LABELS
35
+ .filter((label) => label.sweep.action === 'exclude' || (label.sweep.action === 'none' && (label.axis === 'state' || label.axis === 'addon')))
36
+ .map((label) => label.name), RELEASE_PATH_LABEL]);
24
37
 
25
38
  const goalId = (branch: string): string | undefined => /(?:^|[-/])goalid-([a-f0-9]+)(?=-|\/|$)/i.exec(branch)?.[1]?.toLowerCase();
39
+ export const branchStem = (branch: string): string | undefined => /^self-impl\/(.+)-[a-f0-9]{8}-r[a-f0-9]+$/i.exec(branch)?.[1];
40
+ const slot = (body?: string): string | undefined => /^칸:\s*(.+?)\s*$/m.exec(body ?? '')?.[1];
41
+ const referencesDraft = (text: string, number: number): boolean =>
42
+ new RegExp(`(?:\\(수확\\s*#${number}\\s*\\)|\\bsuperseded\\s*#${number}(?!\\d))`, 'i').test(text);
43
+ const landingCommentReferencesDraft = (text: string, number: number): boolean =>
44
+ new RegExp(`\\blanding-verified\\s*:\\s*(?:draft|superseded|수확)\\s*#${number}(?!\\d)\\b`, 'i').test(text);
26
45
 
27
- export function decideDraft({ draft, runStatus, mergedTwins, ageHours, liveBranches }: DraftTriageInput): DraftDecision {
46
+ export function decideDraft({ draft, runStatus, mergedTwins, openDrafts, ageHours, liveBranches, finalRunResult }: DraftTriageInput): DraftDecision {
28
47
  const held = draft.labels?.find((label) => PROTECTED_LABELS.has(label));
29
48
  if (held) return { action: 'keep', reason: `label:${held}` };
30
- if (runStatus === 'running' || runStatus === 'probable-running' || (draft.branch && liveBranches.has(draft.branch))) {
49
+ if (runStatus !== 'self-implement.result final' && draft.branch && liveBranches.has(draft.branch)
50
+ && finalRunResult === undefined && runStatus !== 'running' && runStatus !== 'probable-running') {
51
+ return { action: 'keep', reason: 'branch-finality-unobserved' };
52
+ }
53
+ if (runStatus === 'running' || runStatus === 'probable-running' ||
54
+ (runStatus !== 'self-implement.result final' && draft.branch && liveBranches.has(draft.branch))) {
31
55
  return { action: 'keep', reason: 'live' };
32
56
  }
33
- // A missing assessment never authorizes a close; unknown is the running-run query's non-running classification.
34
- if (!runStatus) return { action: 'keep', reason: 'unobserved' }; // run status unknown — kept, and said so
35
57
  const lineage = goalId(draft.branch);
36
58
  const twin = mergedTwins.find((pr) => pr.number !== draft.number && (
37
59
  (draft.title && pr.title === draft.title) || (lineage && goalId(pr.branch) === lineage)
38
60
  ));
39
61
  if (twin) return { action: 'close', reason: `superseded-by #${twin.number}` };
62
+ const stem = branchStem(draft.branch);
63
+ const createdAt = Date.parse(draft.createdAt ?? '');
64
+ const newer = stem && draft.title && Number.isFinite(createdAt) ? openDrafts
65
+ ?.filter((pr) => pr.number !== draft.number && pr.title === draft.title && branchStem(pr.branch) === stem
66
+ && Number.isFinite(Date.parse(pr.createdAt ?? '')) && Date.parse(pr.createdAt!) > createdAt)
67
+ .sort((a, b) => Date.parse(b.createdAt!) - Date.parse(a.createdAt!) || b.number - a.number)[0] : undefined;
68
+ if (newer) return { action: 'close', reason: `duplicate-of-open #${newer.number}` };
69
+ const harvest = mergedTwins.find((pr) => pr.number !== draft.number && (
70
+ [pr.mergeCommitMessage, pr.body].some((text) => text && referencesDraft(text, draft.number))
71
+ || pr.landingVerifiedComments?.some((text) => landingCommentReferencesDraft(text, draft.number))
72
+ ));
73
+ if (harvest) return { action: 'close', reason: `superseded-by #${harvest.number} (harvest #${draft.number})` };
74
+ const created = Date.parse(draft.createdAt ?? '');
75
+ const files = draft.changedFiles;
76
+ const draftSlot = slot(draft.body);
77
+ const later = mergedTwins.filter((pr) => pr.number !== draft.number && Number.isFinite(created)
78
+ && Number.isFinite(Date.parse(pr.mergedAt ?? '')) && Date.parse(pr.mergedAt!) > created
79
+ && ((lineage && goalId(pr.branch) === lineage) || (draftSlot && slot(pr.body) === draftSlot)));
80
+ if (files?.length && files.every((file) => {
81
+ const changed = Date.parse(draft.latestFileChanges?.[file] ?? '');
82
+ return Number.isFinite(changed) && changed >= created && later.some((pr) =>
83
+ pr.changedFiles?.includes(file) && Date.parse(pr.mergedAt!) > changed);
84
+ })) {
85
+ const covering = later.filter((pr) => pr.changedFiles?.some((file) => files.includes(file)
86
+ && Date.parse(pr.mergedAt!) > Date.parse(draft.latestFileChanges![file]!)));
87
+ return { action: 'close', reason: `superseded-by #${covering.map((pr) => pr.number).join(', #')} (all-files-landed)` };
88
+ }
89
+ if (!runStatus) return Number.isFinite(ageHours) && ageHours >= STALLED_DRAFT_HOURS
90
+ ? { action: 'close', reason: 'stale-unobserved' }
91
+ : { action: 'keep', reason: 'unobserved' };
92
+ if (runStatus === 'self-implement.result final') return Number.isFinite(ageHours) && ageHours >= STALLED_DRAFT_HOURS
93
+ ? { action: 'close', reason: 'stale-ended-run (self-implement.result final; worktree is not live)' }
94
+ : { action: 'keep', reason: 'recent (self-implement.result final; worktree is not live)' };
40
95
  if (Number.isFinite(ageHours) && ageHours >= STALLED_DRAFT_HOURS) return { action: 'close', reason: 'stale-ended-run' };
41
96
  return { action: 'keep', reason: 'recent' };
42
97
  }