elanous 0.2.17 → 0.2.18

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 (309) 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/P6YTVgzuZz5oTZhY4Din_/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/{1307-aac7332576c4d6fc.js → 1307-30dff22c9e1f3073.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/3857-4f936cdb30322aa6.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/4554-5761612531d0146b.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6158.9c0449a9a8d0064b.js → 6158.af2e93b7adff709b.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/8401-8615a660c84cdb03.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/app/approvals/{page-3143b07a817d1da9.js → page-d92f7ee3994e84c7.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-17ba086ef82d339b.js → page-4733c967b56a4277.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/board/{page-7eb661ff23af7da2.js → page-d22fd849cc22f104.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/botlab/page-bb742f995c6769e7.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/app/bots/{page-6e5c3a867557298b.js → page-02b073a2ac793b83.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/app/chat/page-8a9b3594bc23289b.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/app/consult/{page-5e77cd1802567c89.js → page-a0eb02638b1e6f31.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/app/control/page-308111abadf35670.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-4187666132fc98c4.js → page-5d97b2901e0d1ea6.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/app/editor/{page-09328d499162bae4.js → page-c39554c321576982.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/exec/{page-29ff3a8f84f03b6a.js → page-8c3d8e63ae2e1c98.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/field/{page-80ec7401bc83f511.js → page-9b72a07d424701c6.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/app/intake/{page-fc7d86467291ae38.js → page-a572f58cd3ca5864.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/app/live/page-be5ea965a07fbc41.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/loops/{page-0e2d6985fb42cd2f.js → page-c130b63862437814.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/app/market/{page-13e4108999f58d13.js → page-fa244bd146a00ae8.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-e8296ee284aa1293.js → page-44d56d6391965a6a.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/app/morning/{page-043a9111e74f6b24.js → page-83a700d4c754d802.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/app/{not-found-23a4601ceb7f452e.js → not-found-7b3170f374f77b9d.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-10d958605a77b3bd.js → page-a3c58f5c72a5f3f9.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-7a1d85e121065cc8.js → page-e8e1ecaea7cd71d2.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-12916918988ac97e.js → page-1467047104141297.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-d8a3347a9d0c3f4a.js → page-2da6f9b8a38c6978.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/sessions/page-102310930791197a.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/settings/page-6ed0b73bae8351d8.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-1d824510df025d18.js → page-44d5f767491692bf.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/app/setup/page-43336055451f6e37.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/share/{page-7f49fe645d5132f7.js → page-3cc47dca0922ab9a.js} +1 -1
  55. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a77ee355a2304ff0.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/tasks/{page-27d71f131acd9320.js → page-b17cd46cf0e9b8cf.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/app/term/page-61553851aa606146.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/today/page-a1f585e154e61c59.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/trace/{page-424659bacfb8cdd7.js → page-7bf54c9bb9274af8.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/app/vault/page-5150ef17b5383a57.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-5d4fef9ccd7d406b.js → page-134da468538baf48.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/{webpack-539cde99554be20f.js → webpack-c2782b330447ffb6.js} +1 -1
  66. package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +1 -0
  67. package/apps/pwa/out/approvals/index.html +1 -1
  68. package/apps/pwa/out/approvals/index.txt +14 -14
  69. package/apps/pwa/out/autopilot/index.html +1 -1
  70. package/apps/pwa/out/autopilot/index.txt +14 -14
  71. package/apps/pwa/out/board/index.html +1 -1
  72. package/apps/pwa/out/board/index.txt +14 -14
  73. package/apps/pwa/out/botlab/index.html +1 -1
  74. package/apps/pwa/out/botlab/index.txt +14 -14
  75. package/apps/pwa/out/bots/index.html +1 -1
  76. package/apps/pwa/out/bots/index.txt +14 -14
  77. package/apps/pwa/out/ceo/index.html +1 -1
  78. package/apps/pwa/out/ceo/index.txt +14 -14
  79. package/apps/pwa/out/chat/index.html +1 -1
  80. package/apps/pwa/out/chat/index.txt +14 -14
  81. package/apps/pwa/out/consult/index.html +1 -1
  82. package/apps/pwa/out/consult/index.txt +14 -14
  83. package/apps/pwa/out/control/index.html +1 -1
  84. package/apps/pwa/out/control/index.txt +14 -14
  85. package/apps/pwa/out/decisions/index.html +1 -0
  86. package/apps/pwa/out/decisions/index.txt +30 -0
  87. package/apps/pwa/out/design-check/index.html +1 -1
  88. package/apps/pwa/out/design-check/index.txt +14 -14
  89. package/apps/pwa/out/editor/index.html +1 -1
  90. package/apps/pwa/out/editor/index.txt +14 -14
  91. package/apps/pwa/out/exec/index.html +1 -1
  92. package/apps/pwa/out/exec/index.txt +14 -14
  93. package/apps/pwa/out/field/index.html +1 -1
  94. package/apps/pwa/out/field/index.txt +14 -14
  95. package/apps/pwa/out/healthz +1 -1
  96. package/apps/pwa/out/index.html +1 -1
  97. package/apps/pwa/out/index.txt +14 -14
  98. package/apps/pwa/out/inside/index.html +1 -1
  99. package/apps/pwa/out/inside/index.txt +14 -14
  100. package/apps/pwa/out/intake/index.html +1 -1
  101. package/apps/pwa/out/intake/index.txt +14 -14
  102. package/apps/pwa/out/live/index.html +1 -1
  103. package/apps/pwa/out/live/index.txt +14 -14
  104. package/apps/pwa/out/loops/index.html +1 -1
  105. package/apps/pwa/out/loops/index.txt +14 -14
  106. package/apps/pwa/out/market/index.html +1 -1
  107. package/apps/pwa/out/market/index.txt +14 -14
  108. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  109. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  110. package/apps/pwa/out/morning/index.html +1 -1
  111. package/apps/pwa/out/morning/index.txt +14 -14
  112. package/apps/pwa/out/observatory/index.html +1 -1
  113. package/apps/pwa/out/observatory/index.txt +14 -14
  114. package/apps/pwa/out/ops/checklist/index.html +1 -1
  115. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  116. package/apps/pwa/out/ops/release/index.html +1 -1
  117. package/apps/pwa/out/ops/release/index.txt +14 -14
  118. package/apps/pwa/out/ops/seats/index.html +1 -1
  119. package/apps/pwa/out/ops/seats/index.txt +14 -14
  120. package/apps/pwa/out/outputs/index.html +1 -1
  121. package/apps/pwa/out/outputs/index.txt +14 -14
  122. package/apps/pwa/out/reflection/index.html +1 -1
  123. package/apps/pwa/out/reflection/index.txt +15 -15
  124. package/apps/pwa/out/scheduler/index.html +1 -1
  125. package/apps/pwa/out/scheduler/index.txt +14 -14
  126. package/apps/pwa/out/sessions/index.html +1 -1
  127. package/apps/pwa/out/sessions/index.txt +14 -14
  128. package/apps/pwa/out/settings/devices/index.html +1 -1
  129. package/apps/pwa/out/settings/devices/index.txt +14 -14
  130. package/apps/pwa/out/settings/index.html +1 -1
  131. package/apps/pwa/out/settings/index.txt +14 -14
  132. package/apps/pwa/out/setup/done/index.html +1 -1
  133. package/apps/pwa/out/setup/done/index.txt +14 -14
  134. package/apps/pwa/out/setup/index.html +1 -1
  135. package/apps/pwa/out/setup/index.txt +14 -14
  136. package/apps/pwa/out/share/index.html +1 -1
  137. package/apps/pwa/out/share/index.txt +14 -14
  138. package/apps/pwa/out/showroom/index.html +1 -1
  139. package/apps/pwa/out/showroom/index.txt +14 -14
  140. package/apps/pwa/out/tasks/index.html +1 -1
  141. package/apps/pwa/out/tasks/index.txt +14 -14
  142. package/apps/pwa/out/term/index.html +1 -1
  143. package/apps/pwa/out/term/index.txt +14 -14
  144. package/apps/pwa/out/today/index.html +1 -1
  145. package/apps/pwa/out/today/index.txt +14 -14
  146. package/apps/pwa/out/trace/index.html +1 -1
  147. package/apps/pwa/out/trace/index.txt +14 -14
  148. package/apps/pwa/out/vault/index.html +1 -1
  149. package/apps/pwa/out/vault/index.txt +14 -14
  150. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  151. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  152. package/apps/pwa/out/workflows/index.html +1 -1
  153. package/apps/pwa/out/workflows/index.txt +14 -14
  154. package/apps/pwa/out/workspace/index.html +1 -1
  155. package/apps/pwa/out/workspace/index.txt +14 -14
  156. package/apps/pwa/out/worktrees/index.html +1 -1
  157. package/apps/pwa/out/worktrees/index.txt +14 -14
  158. package/package.json +2 -1
  159. package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
  160. package/samples/workflows/templates/chat-driven-research.yaml +35 -0
  161. package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
  162. package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
  163. package/samples/workflows/templates/manual-quickstart.yaml +21 -0
  164. package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
  165. package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
  166. package/scripts/ci-public-export-import-gate.ts +7 -2
  167. package/scripts/ci-typecheck-changed.ts +21 -6
  168. package/scripts/discord-seat-probe.ts +3 -2
  169. package/scripts/docs/generate-cli-anatomy.ts +162 -0
  170. package/scripts/goals/authoring-metrics.ts +73 -0
  171. package/scripts/landing-heal/must-fix-match.ts +7 -7
  172. package/scripts/landing-heal/run-mission.ts +3 -2
  173. package/scripts/public-export-test-run.ts +37 -2
  174. package/scripts/release-loop/checklist-gate-node.ts +13 -11
  175. package/scripts/release-loop/cut-branch.ts +2 -1
  176. package/scripts/release-loop/cutoff.ts +4 -2
  177. package/scripts/release-loop/docs-land-node.ts +8 -1
  178. package/scripts/release-loop/docs-node.ts +1 -1
  179. package/scripts/release-loop/gate-node.ts +99 -14
  180. package/scripts/release-loop/node-verdict.ts +2 -1
  181. package/scripts/release-loop/npm-publish-node.ts +11 -7
  182. package/scripts/release-loop/ops-upgrade-node.ts +8 -1
  183. package/scripts/release-loop/preflight.ts +246 -0
  184. package/scripts/release-loop/publish-node.ts +8 -1
  185. package/scripts/release-loop/release-readiness.ts +11 -6
  186. package/scripts/release-loop/release-version.ts +48 -0
  187. package/scripts/release-loop/resume-release.ts +115 -0
  188. package/scripts/release-loop/unattended-release.ts +43 -7
  189. package/scripts/release-loop/version-node.ts +145 -40
  190. package/scripts/rhythm/daily.ts +25 -4
  191. package/scripts/skills/public-check.ts +62 -12
  192. package/scripts/test-deterministic.ts +51 -33
  193. package/scripts/test-diet/effectiveness.ts +62 -1
  194. package/scripts/test-diet/lib.ts +1 -1
  195. package/scripts/test-diet/node.ts +8 -1
  196. package/src/agent-mission/review-loop.ts +4 -3
  197. package/src/agent-substrate/pr-comment-meta.ts +20 -0
  198. package/src/autopilot/build/llm-conflict-merge.ts +28 -8
  199. package/src/briefing/brief-items.ts +86 -17
  200. package/src/cli/autopilot-cli.ts +30 -11
  201. package/src/cli/brief-cli.ts +36 -2
  202. package/src/cli/freeze-cli.ts +3 -2
  203. package/src/cli/intake-cli.ts +73 -1
  204. package/src/cli/notify-cli.ts +75 -0
  205. package/src/cli/provider-cli.ts +12 -2
  206. package/src/cli/release-cli.ts +101 -17
  207. package/src/cli/tasks-cli.ts +309 -3
  208. package/src/context-bus/condense.ts +19 -3
  209. package/src/context-bus/context-day.ts +77 -24
  210. package/src/context-bus/context-first.ts +33 -0
  211. package/src/discord-self-message.ts +20 -2
  212. package/src/discord-slash-wire.ts +1 -0
  213. package/src/domains/outbound-alert.ts +200 -27
  214. package/src/domains/outbound-log-probe.ts +16 -1
  215. package/src/domains/release-tool.ts +2 -2
  216. package/src/execution-loop/gates.ts +11 -2
  217. package/src/flow-loop/split.ts +8 -4
  218. package/src/git-fs/worktree.ts +23 -3
  219. package/src/harness/harness-cli-command.ts +10 -2
  220. package/src/harness/harness-queue.ts +388 -33
  221. package/src/harness/helper-scan.ts +10 -3
  222. package/src/hq/seats.ts +369 -0
  223. package/src/index.ts +133 -15
  224. package/src/intake-plane/adopt-gate.ts +49 -0
  225. package/src/intake-plane/check.ts +3 -0
  226. package/src/intake-plane/collect-github.ts +57 -25
  227. package/src/intake-plane/discord-seat-work.ts +8 -2
  228. package/src/intake-plane/requirement-funnel.ts +316 -0
  229. package/src/knowledge/know-find.ts +10 -1
  230. package/src/loops/budget.ts +36 -0
  231. package/src/loops/orchestrator/finish-rate.ts +73 -1
  232. package/src/loops/orchestrator/grid-place.ts +11 -0
  233. package/src/loops/orchestrator/tick.ts +295 -20
  234. package/src/maturity/feature-maturity.ts +3 -2
  235. package/src/nexus/api/decisions-route.ts +11 -1
  236. package/src/nexus/api/loop-edges.ts +69 -13
  237. package/src/nexus/api/ops-seats-sources.ts +2 -2
  238. package/src/nexus/api/workflow-templates.ts +3 -0
  239. package/src/oauth/codex.ts +38 -0
  240. package/src/onboarding/first-chat-gate.ts +29 -0
  241. package/src/release-loop/checklist.ts +104 -6
  242. package/src/release-loop/feature-store.ts +10 -9
  243. package/src/release-loop/landing-freeze.ts +6 -4
  244. package/src/release-loop/placement.ts +13 -3
  245. package/src/release-loop/rubric.ts +80 -0
  246. package/src/seat-dispatch/seat-ask.ts +79 -16
  247. package/src/seat-loop/seat-loop.ts +12 -6
  248. package/src/self-dev/ask-launch-flow.ts +24 -3
  249. package/src/self-dev/ask-path-candidates.ts +68 -0
  250. package/src/self-dev/dev-pipeline.ts +4 -0
  251. package/src/self-dev/draft-triage-rules.ts +1 -1
  252. package/src/self-dev/orchestrate-cli.ts +22 -0
  253. package/src/self-dev/round-pr-supersede.ts +244 -0
  254. package/src/self-dev/run-supervisor.ts +14 -0
  255. package/src/self-implement/follow-up-goals.ts +2 -2
  256. package/src/self-implement/gate-remote.ts +427 -0
  257. package/src/self-implement/goal-author.ts +8 -3
  258. package/src/self-implement/l8-merge-queue.ts +29 -5
  259. package/src/self-implement/orchestrator.ts +59 -12
  260. package/src/self-implement/prior-draft-findings.ts +4 -3
  261. package/src/skills/skill-feedback.ts +76 -0
  262. package/src/task-agent/actions.ts +39 -6
  263. package/src/task-agent/judge.ts +31 -5
  264. package/src/task-agent/mission.ts +423 -0
  265. package/src/task-agent/shadow.ts +90 -0
  266. package/src/task-agent/task-hand.ts +235 -0
  267. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +10 -0
  268. package/src/task-orchestrator/surfaces/self-implement-pod.ts +86 -18
  269. package/src/telegram-loops-command.ts +1 -1
  270. package/src/telegram.ts +5 -20
  271. package/src/user-config.ts +63 -3
  272. package/src/version/packed-revision.json +1 -1
  273. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
  274. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
  275. package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
  276. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
  277. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
  278. package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
  279. package/apps/pwa/out/_next/static/chunks/6877-fe94e76a5841ee9b.js +0 -1
  280. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
  281. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
  282. package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +0 -1
  283. package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
  284. package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +0 -1
  285. package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +0 -1
  286. package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +0 -1
  287. package/apps/pwa/out/_next/static/chunks/app/chat/page-9a41d65355fc25b9.js +0 -1
  288. package/apps/pwa/out/_next/static/chunks/app/control/page-41afec0b255ed2bb.js +0 -1
  289. package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +0 -1
  290. package/apps/pwa/out/_next/static/chunks/app/layout-de43a186e5ba5683.js +0 -1
  291. package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +0 -1
  292. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +0 -1
  293. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +0 -1
  294. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a04260b8ccc968d4.js +0 -1
  295. package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +0 -1
  296. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +0 -1
  297. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-5a64cb5208c6a8fd.js +0 -1
  298. package/apps/pwa/out/_next/static/chunks/app/settings/page-1407ec83ea64c1f9.js +0 -1
  299. package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +0 -1
  300. package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +0 -1
  301. package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +0 -1
  302. package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +0 -1
  303. package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +0 -1
  304. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-fc2df261f8a2c7df.js +0 -1
  305. package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +0 -1
  306. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +0 -1
  307. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
  308. package/apps/pwa/out/_next/static/yRA5ur6DcPl0YHSRheH2O/_buildManifest.js +0 -1
  309. /package/apps/pwa/out/_next/static/{yRA5ur6DcPl0YHSRheH2O → P6YTVgzuZz5oTZhY4Din_}/_ssgManifest.js +0 -0
@@ -0,0 +1,30 @@
1
+ name: scheduled-daily-digest
2
+ description: |
3
+ Daily 9am Seoul-time digest workflow.
4
+ Triggers: schedule cron 0 9 * * * Asia/Seoul.
5
+ Does: crawls a fixed search term → omni-digest summary → saves to Obsidian.
6
+ Edit this template to swap the search term / Obsidian target.
7
+
8
+ _meta:
9
+ template:
10
+ title: Daily digest
11
+ description: Cron 9am → crawl → summarize → save
12
+ tags: [schedule, daily, digest]
13
+
14
+ nodes:
15
+ - id: tick
16
+ scheduleTrigger:
17
+ type: cron
18
+ cron: 0 9 * * *
19
+ timezone: Asia/Seoul
20
+ enabled: true
21
+
22
+ - id: crawl
23
+ skill: omni-crawl
24
+ arguments: "latest AI agent news"
25
+ depends_on: [tick]
26
+
27
+ - id: save
28
+ skill: omni-digest
29
+ arguments: $crawl.output
30
+ depends_on: [crawl]
@@ -0,0 +1,27 @@
1
+ name: webhook-deploy-hook
2
+ description: |
3
+ Production deploy webhook receiver. CI posts to /hooks/deploy with
4
+ the build artifact id; the workflow builds, runs tests, and notifies
5
+ on Slack/Discord depending on result.
6
+
7
+ _meta:
8
+ template:
9
+ title: Webhook deploy hook
10
+ description: POST /hooks/deploy → build → notify
11
+ tags: [webhook, deploy, ci]
12
+
13
+ nodes:
14
+ - id: receive
15
+ webhookTrigger:
16
+ method: POST
17
+ path: /hooks/deploy
18
+
19
+ - id: build
20
+ bash: |
21
+ echo "building $ARGUMENTS" && sleep 1 && echo ok
22
+ depends_on: [receive]
23
+
24
+ - id: notify
25
+ bash: |
26
+ echo "deploy result: $build.output"
27
+ depends_on: [build]
@@ -88,9 +88,14 @@ export async function exportImportCheck(changedFiles: readonly string[], root: s
88
88
  const tracked = trackedFiles(root);
89
89
  if (!tracked) return { measured: false, hits: [], unseen: 0, detail: 'git ls-files 실패' };
90
90
  let included: Set<string>;
91
+ let present: Set<string>;
91
92
  try {
92
93
  const { loadExportConfig, selectExportFiles } = await exportSelectors();
93
- included = new Set(selectExportFiles(tracked, loadExportConfig(root)));
94
+ const config = loadExportConfig(root);
95
+ included = new Set(selectExportFiles(tracked, config));
96
+ // An import target also exists in the export when `replace` writes a public file at that path. Only targets use
97
+ // this — a replaced private original is not shipped, so it is not scanned as an importer.
98
+ present = new Set([...included, ...Object.keys(config.replace ?? {})]);
94
99
  } catch (error) {
95
100
  return { measured: false, hits: [], unseen: 0, detail: error instanceof Error ? error.message : '매니페스트를 못 읽었다' };
96
101
  }
@@ -108,7 +113,7 @@ export async function exportImportCheck(changedFiles: readonly string[], root: s
108
113
  const resolvedSpec = resolveSpecifier(file, specifier);
109
114
  if (!resolvedSpec) return;
110
115
  const target = candidatePaths(resolvedSpec).find((candidate) => trackedSet.has(candidate));
111
- if (!target || included.has(target)) return;
116
+ if (!target || present.has(target)) return;
112
117
  const key = `${index}\0${target}`;
113
118
  if (seen.has(key)) return;
114
119
  seen.add(key);
@@ -1032,14 +1032,29 @@ export function runGate(io: Partial<GateIo> = {}): void {
1032
1032
  // ⭐ 그래서 막는 자리는 «여기»뿐이다 — 인-프로세스 호출자(`pr-cli.ts`·`seams.ts`)는
1033
1033
  // argv 를 안 넘기고, 만약 여기서 `process.argv` 를 «읽으면» 형제 게이트가 경고한 그 사고가 난다
1034
1034
  // (`elanous pr land` 의 인자를 자기 인자로 읽는다 — `src/cli/pr-cli.ts` 의 `args: []` 주석).
1035
- if (import.meta.main) {
1036
- const cliArgs = process.argv.slice(2);
1037
- if (cliArgs.length > 0) {
1038
- console.error(`[tsc-gate] ⛔ 이 게이트는 인자를 받지 않는다 — 준 인자 ${cliArgs.length}개를 «조용히 삼키지 않고» 막는다: ${cliArgs.join(' ')}`);
1035
+ if (import.meta.main) void (async () => {
1036
+ // GATE-REMOTE (10-06): the only accepted arguments are the dispatch flags `--remote [host]` / `--local` — they choose
1037
+ // «where» the same commit is measured, never «what» (the base stays merge-base(origin/main) on both sides).
1038
+ const { extractGateRemoteFlags, dispatchHeavyCheck } = await import('../src/self-implement/gate-remote.js');
1039
+ const flags = extractGateRemoteFlags(process.argv.slice(2));
1040
+ const cliArgs = flags.rest;
1041
+ if (cliArgs.length > 0 || flags.error) {
1042
+ if (flags.error) console.error(`[tsc-gate] ⛔ ${flags.error}`);
1043
+ if (cliArgs.length > 0) console.error(`[tsc-gate] ⛔ 이 게이트는 인자를 받지 않는다(--remote/--local 제외) — 준 인자 ${cliArgs.length}개를 «조용히 삼키지 않고» 막는다: ${cliArgs.join(' ')}`);
1039
1044
  console.error('[tsc-gate] 기준은 언제나 merge-base(origin/main) 다. 다른 기준으로 재려면 «그 트리에 서서» 돌려라:');
1040
1045
  console.error('[tsc-gate] git worktree add --detach <경로> <커밋> && cd <경로> && bun run scripts/ci-typecheck-changed.ts');
1041
1046
  console.error('[tsc-gate] ⇒ 그러면 merge-base 가 그때와 «같아진다». 이것이 재현의 유일한 길이다.');
1042
1047
  process.exit(2);
1043
1048
  }
1044
- runGate();
1045
- }
1049
+ const repo = sh('git rev-parse --show-toplevel').trim();
1050
+ const baseRef = process.env.TSC_BASE_REF;
1051
+ const passEnv = (sha: (ref: string) => string) => (['NODE_OPTIONS', 'TSC_BASE_REF', 'TSC_HEAP_MB'] as const).filter((key) => process.env[key])
1052
+ .map((key) => `${key}=${key === 'TSC_BASE_REF' && baseRef !== 'origin/main' ? sha(baseRef!) : process.env[key]}`);
1053
+ // exitCode, not exit(): piped stdout/stderr drain before the process ends.
1054
+ process.exitCode = await dispatchHeavyCheck({
1055
+ tool: 'ci-typecheck-changed', repo, flags,
1056
+ remoteArgv: (sha) => { const vars = passEnv(sha); return [...(vars.length ? ['env', ...vars] : []), 'bun', 'run', 'scripts/ci-typecheck-changed.ts', '--local']; },
1057
+ refs: baseRef ? [baseRef] : [],
1058
+ runLocal: () => { runGate(); return 0; },
1059
+ });
1060
+ })();
@@ -56,7 +56,8 @@ export async function probeDiscordSeatWork(text: string, options: ProbeOptions =
56
56
  open: () => { const db = new Database(':memory:'); return { db, close: () => db.close() } as unknown as MsgStore; },
57
57
  dispatch: async (seatId, forwarded) => {
58
58
  capture('ask', seatId, forwarded);
59
- return { channel: 'unknown', reply: '마른 실행 — 질문을 맡기지 않았습니다.' };
59
+ // Since #24523 a seat *task* also travels this ask path (so the answer can come back) — the wording covers both.
60
+ return { channel: 'unknown', reply: `마른 실행 — ${seatId}에 맡길 예정 (실제 맡김 없음).` };
60
61
  },
61
62
  send: async () => { throw new Error('dry Discord delivery unavailable'); },
62
63
  },
@@ -76,7 +77,7 @@ export async function probeDiscordSeatWork(text: string, options: ProbeOptions =
76
77
  ...options.liveDeps?.askDeps,
77
78
  dispatch: async (seatId, forwarded, deps, extra) => {
78
79
  capture('ask', seatId, forwarded);
79
- return (options.liveDeps?.askDeps?.dispatch ?? dispatchCeoTask)(seatId, forwarded, deps, extra);
80
+ return (options.liveDeps?.askDeps?.dispatch ?? options.liveDeps?.dispatch ?? dispatchCeoTask)(seatId, forwarded, deps, extra);
80
81
  },
81
82
  // This CLI has no Discord transport: even live mode must not post to Discord.
82
83
  send: async () => { throw new Error('probe does not send Discord messages'); },
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bun
2
+ /** DOC-GEN — src/cli/ 의 정적 Commander 명령을 실행 없이 TypeScript AST 로 읽는다. */
3
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join, relative } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import ts from 'typescript';
7
+ import { readCommit } from './generate-graph-anatomy.js';
8
+
9
+ export interface RenderCliAnatomyInput {
10
+ readonly cliRoot: string;
11
+ readonly repoRoot: string;
12
+ readonly commit: string;
13
+ readonly generatedAt: string;
14
+ }
15
+
16
+ interface CommandRow {
17
+ readonly name: string;
18
+ readonly description: string;
19
+ readonly file: string;
20
+ }
21
+
22
+ function propertyCall(expression: ts.Expression, method: string): expression is ts.CallExpression & { expression: ts.PropertyAccessExpression } {
23
+ return ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression)
24
+ && expression.expression.name.text === method;
25
+ }
26
+
27
+ function literal(expression: ts.Expression | undefined): string | undefined {
28
+ return expression && (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression))
29
+ ? expression.text : undefined;
30
+ }
31
+
32
+ function descriptionOf(command: ts.CallExpression): string {
33
+ let current: ts.Expression = command;
34
+ while (ts.isPropertyAccessExpression(current.parent) && current.parent.expression === current
35
+ && ts.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
36
+ const property = current.parent;
37
+ const call = current.parent.parent;
38
+ if (property.name.text === 'description') return literal(call.arguments[0]) ?? '';
39
+ if (property.name.text === 'command') break;
40
+ current = call;
41
+ }
42
+ return '';
43
+ }
44
+
45
+ function rowsInFile(source: string, file: string): CommandRow[] {
46
+ const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
47
+ interface Scope {
48
+ readonly owner: ts.Node;
49
+ readonly parent?: Scope;
50
+ readonly bindings: Map<string, ts.VariableDeclaration | null>;
51
+ }
52
+ const scopes = new Map<ts.Node, Scope>();
53
+ const gather = (node: ts.Node, outer?: Scope): void => {
54
+ const createsScope = ts.isSourceFile(node) || ts.isBlock(node) || ts.isModuleBlock(node)
55
+ || ts.isCaseBlock(node) || ts.isCatchClause(node) || ts.isFunctionLike(node)
56
+ || ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node);
57
+ const scope: Scope = createsScope ? { owner: node, parent: outer, bindings: new Map() } : outer!;
58
+ scopes.set(node, scope);
59
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
60
+ const list = node.parent;
61
+ const isVar = ts.isVariableDeclarationList(list) && (list.flags & ts.NodeFlags.BlockScoped) === 0;
62
+ let target = scope;
63
+ if (isVar) {
64
+ while (target.parent && !ts.isSourceFile(target.owner) && !ts.isFunctionLike(target.owner)) {
65
+ target = target.parent;
66
+ }
67
+ }
68
+ target.bindings.set(node.name.text, node);
69
+ }
70
+ if (ts.isFunctionLike(node)) {
71
+ for (const parameter of node.parameters) {
72
+ if (ts.isIdentifier(parameter.name)) scope.bindings.set(parameter.name.text, null);
73
+ }
74
+ }
75
+ if (ts.isCatchClause(node) && node.variableDeclaration && ts.isIdentifier(node.variableDeclaration.name)) {
76
+ scope.bindings.set(node.variableDeclaration.name.text, null);
77
+ }
78
+ ts.forEachChild(node, (child) => gather(child, scope));
79
+ };
80
+ gather(ast);
81
+
82
+ const commandName = (expression: ts.Expression, seen: ReadonlySet<ts.VariableDeclaration> = new Set()): string => {
83
+ if (ts.isParenthesizedExpression(expression)) return commandName(expression.expression, seen);
84
+ if (ts.isIdentifier(expression)) {
85
+ let scope = scopes.get(expression);
86
+ while (scope && !scope.bindings.has(expression.text)) scope = scope.parent;
87
+ const declaration = scope?.bindings.get(expression.text);
88
+ if (!declaration || !declaration.initializer || seen.has(declaration)) return '';
89
+ return commandName(declaration.initializer, new Set([...seen, declaration]));
90
+ }
91
+ if (propertyCall(expression, 'command')) {
92
+ const name = literal(expression.arguments[0]);
93
+ if (name === undefined) return '';
94
+ const parent = commandName(expression.expression.expression, seen);
95
+ return parent ? `${parent} ${name}` : name;
96
+ }
97
+ if (ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression)) {
98
+ return commandName(expression.expression.expression, seen);
99
+ }
100
+ return '';
101
+ };
102
+
103
+ const rows: CommandRow[] = [];
104
+ const visit = (node: ts.Node): void => {
105
+ if (ts.isCallExpression(node) && propertyCall(node, 'command')) {
106
+ const name = literal(node.arguments[0]);
107
+ if (name !== undefined) rows.push({ name: commandName(node), description: descriptionOf(node), file });
108
+ }
109
+ ts.forEachChild(node, visit);
110
+ };
111
+ visit(ast);
112
+ return rows;
113
+ }
114
+
115
+ function cell(value: string): string {
116
+ return value.replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
117
+ }
118
+
119
+ /** 지정된 src/cli/ 바로 아래 .ts 만 읽으며 import/명령을 실행하지 않는다. */
120
+ export function renderCliAnatomy(input: RenderCliAnatomyInput): string {
121
+ const rows = readdirSync(input.cliRoot, { withFileTypes: true })
122
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.ts')
123
+ && !entry.name.endsWith('.test.ts') && !entry.name.endsWith('.spec.ts'))
124
+ .flatMap((entry) => {
125
+ const abs = join(input.cliRoot, entry.name);
126
+ return rowsInFile(readFileSync(abs, 'utf8'), relative(input.repoRoot, abs).replace(/\\/g, '/'));
127
+ })
128
+ .sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.file < b.file ? -1 : a.file > b.file ? 1 : 0);
129
+ return [
130
+ '# CLI anatomy',
131
+ '',
132
+ '> 이 문서는 생성물이다 — 손으로 고치지 마라',
133
+ '',
134
+ `- generatedAt: ${input.generatedAt}`,
135
+ `- commit: ${input.commit}`,
136
+ '',
137
+ '| 명령 | 설명 | 정의 파일 |',
138
+ '| --- | --- | --- |',
139
+ ...rows.map((row) => `| ${cell(row.name)} | ${cell(row.description)} | ${cell(row.file)} |`),
140
+ '',
141
+ ].join('\n');
142
+ }
143
+
144
+ export function defaultOutputPath(repoRoot: string): string {
145
+ return join(repoRoot, 'docs', 'generated', 'cli-anatomy.md');
146
+ }
147
+
148
+ function main(): void {
149
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
150
+ const argv = process.argv.slice(2);
151
+ const index = argv.indexOf('--out');
152
+ const outArg = index < 0 ? undefined : argv[index + 1];
153
+ if (index >= 0 && (!outArg || outArg.startsWith('--'))) throw new Error('--out 에는 경로가 필요하다');
154
+ const out = outArg ?? defaultOutputPath(repoRoot);
155
+ const markdown = renderCliAnatomy({ cliRoot: join(repoRoot, 'src', 'cli'), repoRoot,
156
+ commit: readCommit(repoRoot), generatedAt: new Date().toISOString() });
157
+ mkdirSync(dirname(out), { recursive: true });
158
+ writeFileSync(out, markdown);
159
+ process.stdout.write(`${out}\n`);
160
+ }
161
+
162
+ if (import.meta.main) main();
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bun
2
+ import { readFileSync } from 'node:fs';
3
+ import { inspectAskMarkers } from '../ask-marker-check.js';
4
+
5
+ export interface AuthoringMeasurement {
6
+ readonly path: string;
7
+ readonly chars: number;
8
+ readonly bytes: number;
9
+ readonly sections: number;
10
+ readonly markerAxes: number;
11
+ readonly markerFailed: number;
12
+ }
13
+
14
+ type UnreadableMeasurement = { readonly path: string; readonly error: 'unreadable' };
15
+ type AuthoringRow = AuthoringMeasurement | UnreadableMeasurement;
16
+
17
+ export function measureAuthoring(path: string, text: string): AuthoringMeasurement {
18
+ const axes = inspectAskMarkers(text);
19
+ return {
20
+ path,
21
+ chars: text.length,
22
+ bytes: Buffer.byteLength(text, 'utf8'),
23
+ sections: text.split(/\r?\n/).filter((line) => /^#{1,6}\s/u.test(line)).length,
24
+ markerAxes: axes.length,
25
+ markerFailed: axes.filter((axis) => !(axis.marker && axis.extracted)).length,
26
+ };
27
+ }
28
+
29
+ export function median(numbers: readonly number[]): number | null {
30
+ if (numbers.length === 0) return null;
31
+ const sorted = [...numbers].sort((a, b) => a - b);
32
+ const middle = Math.floor(sorted.length / 2);
33
+ return sorted.length % 2 === 1
34
+ ? sorted[middle]!
35
+ : (sorted[middle - 1]! + sorted[middle]!) / 2;
36
+ }
37
+
38
+ function main(argv: readonly string[]): number {
39
+ const json = argv.includes('--json');
40
+ const paths = argv.filter((argument) => argument !== '--json');
41
+ const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
42
+ const rows: AuthoringRow[] = paths.map((path) => {
43
+ let text: string;
44
+ try {
45
+ text = decoder.decode(readFileSync(path));
46
+ } catch {
47
+ return { path, error: 'unreadable' };
48
+ }
49
+ return measureAuthoring(path, text);
50
+ });
51
+ const measured = rows.filter((row): row is AuthoringMeasurement => !('error' in row));
52
+ const summary = {
53
+ files: measured.length,
54
+ medianChars: median(measured.map((row) => row.chars)),
55
+ medianBytes: median(measured.map((row) => row.bytes)),
56
+ };
57
+
58
+ if (json) {
59
+ for (const row of rows) console.log(JSON.stringify(row));
60
+ console.log(JSON.stringify(summary));
61
+ } else {
62
+ console.log('path\tchars\tbytes\tsections\tmarkerAxes\tmarkerFailed\terror');
63
+ for (const row of rows) {
64
+ console.log('error' in row
65
+ ? `${row.path}\t\t\t\t\t\t${row.error}`
66
+ : `${row.path}\t${row.chars}\t${row.bytes}\t${row.sections}\t${row.markerAxes}\t${row.markerFailed}\t`);
67
+ }
68
+ console.log(`files\t${summary.files}\tmedianChars\t${summary.medianChars ?? '—'}\tmedianBytes\t${summary.medianBytes ?? '—'}`);
69
+ }
70
+ return rows.some((row) => 'error' in row) ? 1 : 0;
71
+ }
72
+
73
+ if (import.meta.main) process.exitCode = main(process.argv.slice(2));
@@ -1,4 +1,4 @@
1
- import { parse } from '../../src/agent-substrate/pr-comment-meta.js';
1
+ import { expandRecords, parse } from '../../src/agent-substrate/pr-comment-meta.js';
2
2
 
3
3
  export type MustFixVerdict = 'resolved' | 'unresolved' | 'unknown';
4
4
  export interface ReviewRoundMatch {
@@ -12,12 +12,12 @@ export interface ReviewRoundMatch {
12
12
  const MUST_FIX_ROUND = /^Round \d+: reviewer requested \d+ must-fix change\(s\)\.$/m;
13
13
 
14
14
  export function classifyReviewRounds(comments: Array<{ body?: string }>): ReviewRoundMatch[] {
15
- const reviews = comments.flatMap(({ body }) => {
16
- if (!body) return [];
17
- const meta = parse(body);
18
- return meta?.role === 'reviewer' && meta.run && meta.round !== undefined
19
- ? [{ body, run: meta.run, round: meta.round }] : [];
20
- });
15
+ const reviews = comments.flatMap(({ body }) =>
16
+ body ? expandRecords(body).flatMap((record) => {
17
+ const meta = parse(record);
18
+ return meta?.role === 'reviewer' && meta.run && meta.round !== undefined
19
+ ? [{ body: record, run: meta.run, round: meta.round }] : [];
20
+ }) : []);
21
21
  // 항목은 «must-fix 요청» 라운드에서만 센다 — «review completed (warn)» 의 요약 본문에도 «- » 글머리가 들어 있다(#21983 실물).
22
22
  return reviews.flatMap(({ body, run, round }) => !MUST_FIX_ROUND.test(body) ? [] :
23
23
  [...body.matchAll(/^- (.+)$/gm)].map((item) => ({
@@ -5,7 +5,7 @@ import { dirname, join, resolve } from 'node:path';
5
5
  import { githubAutomationToken } from '../../src/auth/github-app-token.js';
6
6
  import { debug } from '../../src/debug/log.js';
7
7
  import { emitDecision } from '../../src/live/detail-switch.js';
8
- import { parse } from '../../src/agent-substrate/pr-comment-meta.js';
8
+ import { expandRecords, parse } from '../../src/agent-substrate/pr-comment-meta.js';
9
9
  import { classifyReviewRounds, matchMustFix, type MustFixVerdict } from './must-fix-match.js';
10
10
  import { verifyCleanCheckout, type CheckoutResult } from './clean-checkout.js';
11
11
 
@@ -116,7 +116,8 @@ export function runMission(mission: string, ctx: GraphContext, run: RunCommand =
116
116
  const pages = JSON.parse(run(['api', `repos/{owner}/{repo}/pulls/${pr.number}/comments`, '--paginate', '--slurp'])) as Array<Array<{ body?: string }>>;
117
117
  if (!Array.isArray(pages) || !pages.every(Array.isArray)) throw new Error(`invalid review comments for PR #${pr.number}`);
118
118
  const inline = pages.flat();
119
- const comments = [...(details.reviews ?? []), ...(details.comments ?? []), ...inline];
119
+ const comments = [...(details.reviews ?? []), ...(details.comments ?? []), ...inline]
120
+ .flatMap((comment) => comment.body ? expandRecords(comment.body).map((body) => ({ ...comment, body })) : [comment]);
120
121
  const reviewRounds = comments.filter(({ body }) => {
121
122
  const meta = body ? parse(body) : null;
122
123
  return meta?.role === 'reviewer' && !!meta.run && meta.round !== undefined;
@@ -4,7 +4,7 @@ import { spawnSync } from 'node:child_process';
4
4
  import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { isAbsolute, join, relative, resolve, sep } from 'node:path';
7
- import { run as exportRun } from './public-export.js';
7
+ import { privateRedactionsPath, run as exportRun } from './public-export.js';
8
8
 
9
9
  export interface Comparison {
10
10
  exportOnly: string[];
@@ -118,4 +118,39 @@ export function run(argv: readonly string[], root = resolve(import.meta.dir, '..
118
118
  }
119
119
  }
120
120
 
121
- if (import.meta.main) process.exit(run(process.argv.slice(2)));
121
+ // GATE-REMOTE (10-06): `--remote [host]` runs the same commit on that host and prints its result (JSON gains host · remote:true);
122
+ // `--local` forces this machine. Without either, a busy machine (1-min load > gateRemote.loadThreshold) dispatches on its own.
123
+ if (import.meta.main) void (async () => {
124
+ const { extractGateRemoteFlags, dispatchHeavyCheck, unreproducibleArgs, relativizeArgs } = await import('../src/self-implement/gate-remote.js');
125
+ const flags = extractGateRemoteFlags(process.argv.slice(2));
126
+ if (flags.error) { console.error(flags.error); process.exit(2); }
127
+ const repo = resolve(import.meta.dir, '..');
128
+ // The private redaction table changes exported file contents — the remote export must use the same one or the comparison differs.
129
+ const table = privateRedactionsPath();
130
+ const payloadFiles = existsSync(table) ? [{ env: 'ELANOUS_EXPORT_REDACTIONS', content: readFileSync(table, 'utf8') }] : [];
131
+ // File arguments, the --files list and its entries resolve against the repository root (as run() does).
132
+ const paths = flags.rest.filter((arg) => !arg.startsWith('--'));
133
+ const listIndex = flags.rest.indexOf('--files');
134
+ const list = listIndex >= 0 ? flags.rest[listIndex + 1] : undefined;
135
+ // List entries reach the host verbatim (only positional arguments are rewritten), so an absolute entry is not portable.
136
+ const absoluteEntries: string[] = [];
137
+ if (list) {
138
+ try {
139
+ const entries = readFileSync(resolve(repo, list), 'utf8').split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
140
+ absoluteEntries.push(...entries.filter((entry) => isAbsolute(entry)));
141
+ paths.push(...entries);
142
+ } catch { /* run() reports it */ }
143
+ }
144
+ process.exitCode = await dispatchHeavyCheck({
145
+ payloadFiles,
146
+ localOnlyReason: (() => {
147
+ // Each must be a tracked file inside the repository, or the remote checkout would measure something else.
148
+ const bad = [...new Set([...absoluteEntries, ...unreproducibleArgs(paths, repo)])];
149
+ return bad.length ? `file argument not reproducible on the host (outside the repository or not tracked at HEAD): ${bad.join(' ')}` : undefined;
150
+ })(),
151
+ tool: 'public-export-test-run', repo, flags, json: flags.rest.includes('--json'),
152
+ installPwa: paths.some((arg) => arg.includes('apps/pwa')),
153
+ remoteArgv: ['bun', 'scripts/public-export-test-run.ts', '--local', ...relativizeArgs(flags.rest, repo)],
154
+ runLocal: () => run(flags.rest),
155
+ });
156
+ })();
@@ -1,24 +1,25 @@
1
1
  #!/usr/bin/env bun
2
- import { checklistGate, listChecklist, summarizeChecklist } from '../../src/release-loop/checklist.js';
2
+ import { cutChecklistGate, listChecklist, summarizeChecklist } from '../../src/release-loop/checklist.js';
3
3
  import * as store from '../../src/release-loop/feature-store.js';
4
4
  import { getSchedule } from '../../src/release-loop/release-schedule.js';
5
5
  import { debug } from '../../src/debug/log.js';
6
+ import { prereleaseKind } from './release-version.js';
6
7
  import { emitNodeResult, errorResult, readGraphContext, type GraphContext } from './node-verdict.js';
7
8
 
9
+ /** RELEASE-REHEARSAL-RC: a prerelease rehearses the pipeline; it must not judge or carry the stable version's cells. */
10
+ export function prereleaseChecklistSkip(context: GraphContext) {
11
+ const version = context.input.version;
12
+ if (prereleaseKind(version) === null) return null;
13
+ debug.log('release-loop.checklist-gate', 'skipped', { version, reason: 'prerelease' });
14
+ return { outcome: 'ok' as const, verdict: 'pass' as const, summary: `checklist gate skipped — ${version} is a prerelease rehearsal`, skipped: 'prerelease' };
15
+ }
16
+
8
17
  export function runChecklistGate(context: GraphContext = readGraphContext(), now: Date = new Date()) {
9
18
  const version = context.input.version;
10
19
  const data = listChecklist(version);
11
20
  const schedule = getSchedule(version);
12
21
  const deadline = schedule?.landBy;
13
- const overdue = deadline !== null && deadline !== undefined && now.getTime() > Date.parse(deadline);
14
- const autoMoved = overdue ? data.items.filter((item) => item.status === 'yellow' && item.priority !== 'P0' && item.disposition === undefined).map((item) => item.id) : [];
15
- const gate = checklistGate(version);
16
- const p0 = data.items.filter((item) => item.status === 'yellow' && item.priority === 'P0').map((item) => item.id);
17
- gate.undecided = gate.undecided.filter((id) => !autoMoved.includes(id) && !p0.includes(id));
18
- gate.moved = gate.moved.filter((id) => !p0.includes(id)).concat(autoMoved);
19
- gate.knownIssues = gate.knownIssues.filter((item) => !p0.includes(item.id));
20
- gate.blocked.push(...p0.filter((id) => !gate.blocked.includes(id)));
21
- gate.ok = gate.red.length === 0 && gate.undecided.length === 0 && gate.blocked.length === 0;
22
+ const { autoMoved, ...gate } = cutChecklistGate(version, deadline, now);
22
23
  const [major, minor, patch] = version.split('.').map(Number);
23
24
  const next = `${major}.${minor}.${patch! + 1}`;
24
25
  const carried: string[] = [];
@@ -65,7 +66,8 @@ export function runChecklistGate(context: GraphContext = readGraphContext(), now
65
66
 
66
67
  if (import.meta.main) {
67
68
  try {
68
- const result = runChecklistGate();
69
+ const context = readGraphContext();
70
+ const result = prereleaseChecklistSkip(context) ?? runChecklistGate(context);
69
71
  emitNodeResult(result);
70
72
  process.exitCode = result.outcome === 'ok' ? 0 : 1;
71
73
  } catch (error) {
@@ -3,6 +3,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join, resolve } from 'node:path';
5
5
  import { debug } from '../../src/debug/log.js';
6
+ import { isReleaseVersion } from './release-version.js';
6
7
 
7
8
  export interface CutBranchOptions { version: string; base: string; pick: string[]; append?: boolean; dryRun?: boolean; repoRoot?: string; log?: (line: string) => void }
8
9
 
@@ -26,7 +27,7 @@ export function cutReleaseBranch(opts: CutBranchOptions): { branch: string; comm
26
27
  const report = (event: 'created' | 'refused' | 'conflict' | 'appended', reason?: string, commit?: string, extra?: Record<string, string | string[]>) =>
27
28
  debug.log('release-loop.cut-branch', event, { version: opts.version, branch, ...(commit ? { commit } : {}), ...(reason ? { reason } : {}), ...extra });
28
29
  try {
29
- if (!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(opts.version)) throw new Error(`invalid release version: ${opts.version}`);
30
+ if (!isReleaseVersion(opts.version)) throw new Error(`invalid release version: ${opts.version}`);
30
31
  if (!opts.pick.length) throw new Error('at least one --pick commit is required');
31
32
  for (const sha of [opts.base, ...opts.pick]) if (!/^[0-9a-f]{7,40}$/i.test(sha)) throw new Error(`invalid commit SHA: ${sha}`);
32
33
  git(repo, ['fetch', 'origin', 'main']);
@@ -25,8 +25,10 @@ function requiredGit(args: string[]): string {
25
25
  }
26
26
 
27
27
  function versionParts(value: string): number[] | null {
28
- if (!/^\d+\.\d+\.\d+$/.test(value)) return null;
29
- return value.split('.').map(Number);
28
+ // A prerelease (0.2.18-rc.0) is placed by its base version — earlier stable tags are its baseline.
29
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-(?:rc|alpha|beta)\.\d+)?$/.exec(value);
30
+ if (!match) return null;
31
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
30
32
  }
31
33
 
32
34
  function compareVersions(a: number[], b: number[]): number {
@@ -7,6 +7,7 @@ import { recordDocsFollow, type DocsFollowItem } from './release-docs.js';
7
7
  import { dirname, join } from 'node:path';
8
8
  import { tmpdir } from 'node:os';
9
9
  import { errorResult, finishNode, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
10
+ import { prereleaseKind } from './release-version.js';
10
11
 
11
12
  export function runDocsLand(run: CommandRunner = runCommand, stateRoot = effectiveInstanceRoot(), ledgerRoot = releaseLedgerRoot()) {
12
13
  const context = readGraphContext();
@@ -119,6 +120,12 @@ export function runDocsLand(run: CommandRunner = runCommand, stateRoot = effecti
119
120
 
120
121
  if (import.meta.main) {
121
122
  let version = '';
122
- try { version = readGraphContext().input.version; process.exitCode = finishNode('docs-land', version, runDocsLand()); }
123
+ try {
124
+ version = readGraphContext().input.version;
125
+ // RELEASE-REHEARSAL-RC: a prerelease never lands docs on main or upgrades the operating hosts.
126
+ process.exitCode = finishNode('docs-land', version, prereleaseKind(version) !== null
127
+ ? { outcome: 'ok', verdict: 'pass', summary: `docs-land skipped — ${version} is a prerelease`, skipped: 'prerelease' }
128
+ : runDocsLand());
129
+ }
123
130
  catch (error) { process.exitCode = finishNode('docs-land', version, errorResult(error)); }
124
131
  }
@@ -72,7 +72,7 @@ export function runDocs(
72
72
  }
73
73
  throw new Error(`unknown argument: ${arg}`);
74
74
  }
75
- if (!version || !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/.test(version)) {
75
+ if (!version || !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:rc|alpha|beta)\.(?:0|[1-9]\d*))?$/.test(version)) {
76
76
  throw new Error('version required (--version or ELANOUS_GRAPH_CONTEXT.input.version): x.y.z');
77
77
  }
78
78
  root = resolve(root);