elanous 0.2.16 → 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 (354) 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-b46d45b705e8c9ae.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/9247-269e4464cc4b491c.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d92f7ee3994e84c7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-3cb52e5ea8fc2fa5.js → page-4733c967b56a4277.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/board/page-d22fd849cc22f104.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-c1e20d7d338713f1.js → page-bb742f995c6769e7.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/bots/{page-482c5dbde699947c.js → page-02b073a2ac793b83.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/app/chat/page-8a9b3594bc23289b.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/app/control/{page-a0e2a6d1bfb52fc5.js → page-308111abadf35670.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-c53598cfce6156f2.js → page-5d97b2901e0d1ea6.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/editor/{page-13a63953f53c6a23.js → page-c39554c321576982.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/exec/{page-5d3c8429d04f3831.js → page-8c3d8e63ae2e1c98.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/field/{page-3193bdc0bbab047a.js → page-9b72a07d424701c6.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/app/intake/{page-6107ca8ddd5e3bdd.js → page-a572f58cd3ca5864.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/live/page-be5ea965a07fbc41.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/app/market/page-fa244bd146a00ae8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-44d56d6391965a6a.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/app/morning/{page-4167348049166852.js → page-83a700d4c754d802.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/{not-found-de52e8fdf9095f7a.js → not-found-7b3170f374f77b9d.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-ca3952cd78a83ca2.js → page-a3c58f5c72a5f3f9.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-1ebfe049c640e171.js → page-1467047104141297.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/sessions/page-102310930791197a.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/settings/page-6ed0b73bae8351d8.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-abe8e3b74bea1ffc.js → page-44d5f767491692bf.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/app/setup/page-43336055451f6e37.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/share/{page-d28573d6792b4275.js → page-3cc47dca0922ab9a.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a77ee355a2304ff0.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/tasks/{page-d751de5f8062ff5e.js → page-b17cd46cf0e9b8cf.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/app/term/{page-fe1759f94003b32b.js → page-61553851aa606146.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/app/today/{page-d64c984e855c8c68.js → page-a1f585e154e61c59.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/app/trace/page-7bf54c9bb9274af8.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/vault/{page-9afdee66b820c76e.js → page-5150ef17b5383a57.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-3544f154c87b43ee.js → page-134da468538baf48.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{webpack-539cde99554be20f.js → webpack-c2782b330447ffb6.js} +1 -1
  67. package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +1 -0
  68. package/apps/pwa/out/approvals/index.html +1 -1
  69. package/apps/pwa/out/approvals/index.txt +14 -14
  70. package/apps/pwa/out/autopilot/index.html +1 -1
  71. package/apps/pwa/out/autopilot/index.txt +14 -14
  72. package/apps/pwa/out/board/index.html +1 -1
  73. package/apps/pwa/out/board/index.txt +14 -14
  74. package/apps/pwa/out/botlab/index.html +1 -1
  75. package/apps/pwa/out/botlab/index.txt +14 -14
  76. package/apps/pwa/out/bots/index.html +1 -1
  77. package/apps/pwa/out/bots/index.txt +14 -14
  78. package/apps/pwa/out/ceo/index.html +1 -1
  79. package/apps/pwa/out/ceo/index.txt +14 -14
  80. package/apps/pwa/out/chat/index.html +1 -1
  81. package/apps/pwa/out/chat/index.txt +14 -14
  82. package/apps/pwa/out/consult/index.html +1 -1
  83. package/apps/pwa/out/consult/index.txt +14 -14
  84. package/apps/pwa/out/control/index.html +1 -1
  85. package/apps/pwa/out/control/index.txt +14 -14
  86. package/apps/pwa/out/decisions/index.html +1 -0
  87. package/apps/pwa/out/decisions/index.txt +30 -0
  88. package/apps/pwa/out/design-check/index.html +1 -1
  89. package/apps/pwa/out/design-check/index.txt +14 -14
  90. package/apps/pwa/out/editor/index.html +1 -1
  91. package/apps/pwa/out/editor/index.txt +14 -14
  92. package/apps/pwa/out/exec/index.html +1 -1
  93. package/apps/pwa/out/exec/index.txt +14 -14
  94. package/apps/pwa/out/field/index.html +1 -1
  95. package/apps/pwa/out/field/index.txt +14 -14
  96. package/apps/pwa/out/healthz +1 -1
  97. package/apps/pwa/out/index.html +1 -1
  98. package/apps/pwa/out/index.txt +14 -14
  99. package/apps/pwa/out/inside/index.html +1 -1
  100. package/apps/pwa/out/inside/index.txt +14 -14
  101. package/apps/pwa/out/intake/index.html +1 -1
  102. package/apps/pwa/out/intake/index.txt +14 -14
  103. package/apps/pwa/out/live/index.html +1 -1
  104. package/apps/pwa/out/live/index.txt +14 -14
  105. package/apps/pwa/out/loops/index.html +1 -1
  106. package/apps/pwa/out/loops/index.txt +14 -14
  107. package/apps/pwa/out/market/index.html +1 -1
  108. package/apps/pwa/out/market/index.txt +14 -14
  109. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  110. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  111. package/apps/pwa/out/morning/index.html +1 -1
  112. package/apps/pwa/out/morning/index.txt +14 -14
  113. package/apps/pwa/out/observatory/index.html +1 -1
  114. package/apps/pwa/out/observatory/index.txt +14 -14
  115. package/apps/pwa/out/ops/checklist/index.html +1 -1
  116. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  117. package/apps/pwa/out/ops/release/index.html +1 -1
  118. package/apps/pwa/out/ops/release/index.txt +14 -14
  119. package/apps/pwa/out/ops/seats/index.html +1 -1
  120. package/apps/pwa/out/ops/seats/index.txt +14 -14
  121. package/apps/pwa/out/outputs/index.html +1 -1
  122. package/apps/pwa/out/outputs/index.txt +14 -14
  123. package/apps/pwa/out/reflection/index.html +1 -1
  124. package/apps/pwa/out/reflection/index.txt +15 -15
  125. package/apps/pwa/out/scheduler/index.html +1 -1
  126. package/apps/pwa/out/scheduler/index.txt +14 -14
  127. package/apps/pwa/out/sessions/index.html +1 -1
  128. package/apps/pwa/out/sessions/index.txt +14 -14
  129. package/apps/pwa/out/settings/devices/index.html +1 -1
  130. package/apps/pwa/out/settings/devices/index.txt +14 -14
  131. package/apps/pwa/out/settings/index.html +1 -1
  132. package/apps/pwa/out/settings/index.txt +14 -14
  133. package/apps/pwa/out/setup/done/index.html +1 -1
  134. package/apps/pwa/out/setup/done/index.txt +14 -14
  135. package/apps/pwa/out/setup/index.html +1 -1
  136. package/apps/pwa/out/setup/index.txt +14 -14
  137. package/apps/pwa/out/share/index.html +1 -1
  138. package/apps/pwa/out/share/index.txt +14 -14
  139. package/apps/pwa/out/showroom/index.html +1 -1
  140. package/apps/pwa/out/showroom/index.txt +14 -14
  141. package/apps/pwa/out/tasks/index.html +1 -1
  142. package/apps/pwa/out/tasks/index.txt +14 -14
  143. package/apps/pwa/out/term/index.html +1 -1
  144. package/apps/pwa/out/term/index.txt +14 -14
  145. package/apps/pwa/out/today/index.html +1 -1
  146. package/apps/pwa/out/today/index.txt +14 -14
  147. package/apps/pwa/out/trace/index.html +1 -1
  148. package/apps/pwa/out/trace/index.txt +14 -14
  149. package/apps/pwa/out/vault/index.html +1 -1
  150. package/apps/pwa/out/vault/index.txt +14 -14
  151. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  152. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  153. package/apps/pwa/out/workflows/index.html +1 -1
  154. package/apps/pwa/out/workflows/index.txt +14 -14
  155. package/apps/pwa/out/workspace/index.html +1 -1
  156. package/apps/pwa/out/workspace/index.txt +14 -14
  157. package/apps/pwa/out/worktrees/index.html +1 -1
  158. package/apps/pwa/out/worktrees/index.txt +14 -14
  159. package/graphs/intake/intake-daily.yaml +9 -2
  160. package/graphs/intake/news-sources.yaml +4 -0
  161. package/graphs/intake/recipes.yaml +6 -1
  162. package/package.json +2 -1
  163. package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
  164. package/samples/workflows/templates/chat-driven-research.yaml +35 -0
  165. package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
  166. package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
  167. package/samples/workflows/templates/manual-quickstart.yaml +21 -0
  168. package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
  169. package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
  170. package/scripts/__fixtures__/intake-news.xml +7 -0
  171. package/scripts/ci-public-export-import-gate.ts +7 -2
  172. package/scripts/ci-typecheck-changed.ts +21 -6
  173. package/scripts/discord-seat-probe.ts +3 -2
  174. package/scripts/docs/generate-cli-anatomy.ts +162 -0
  175. package/scripts/goals/authoring-metrics.ts +73 -0
  176. package/scripts/intake-news.ts +169 -0
  177. package/scripts/landing-heal/must-fix-match.ts +7 -7
  178. package/scripts/landing-heal/run-mission.ts +3 -2
  179. package/scripts/public-export-test-run.ts +37 -2
  180. package/scripts/release-loop/checklist-gate-node.ts +13 -11
  181. package/scripts/release-loop/cut-branch.ts +2 -1
  182. package/scripts/release-loop/cutoff.ts +4 -2
  183. package/scripts/release-loop/docs-land-node.ts +77 -11
  184. package/scripts/release-loop/docs-node.ts +1 -1
  185. package/scripts/release-loop/gate-node.ts +99 -14
  186. package/scripts/release-loop/node-verdict.ts +2 -1
  187. package/scripts/release-loop/npm-publish-node.ts +11 -7
  188. package/scripts/release-loop/ops-upgrade-node.ts +8 -1
  189. package/scripts/release-loop/preflight.ts +246 -0
  190. package/scripts/release-loop/publish-node.ts +10 -3
  191. package/scripts/release-loop/release-docs.ts +134 -0
  192. package/scripts/release-loop/release-readiness.ts +11 -6
  193. package/scripts/release-loop/release-version.ts +48 -0
  194. package/scripts/release-loop/resume-release.ts +115 -0
  195. package/scripts/release-loop/unattended-release.ts +43 -7
  196. package/scripts/release-loop/version-node.ts +149 -41
  197. package/scripts/release-story/draft.ts +42 -14
  198. package/scripts/rhythm/daily.ts +25 -4
  199. package/scripts/skills/public-check.ts +62 -12
  200. package/scripts/test-deterministic.ts +51 -33
  201. package/scripts/test-diet/effectiveness.ts +62 -1
  202. package/scripts/test-diet/lib.ts +1 -1
  203. package/scripts/test-diet/node.ts +8 -1
  204. package/src/agent-mission/driver.ts +53 -10
  205. package/src/agent-mission/review-loop.ts +4 -3
  206. package/src/agent-substrate/pr-comment-meta.ts +20 -0
  207. package/src/autopilot/build/llm-conflict-merge.ts +28 -8
  208. package/src/autopilot/track-agent.ts +5 -3
  209. package/src/briefing/brief-items.ts +86 -17
  210. package/src/cli/autopilot-cli.ts +86 -1
  211. package/src/cli/brief-cli.ts +36 -2
  212. package/src/cli/decisions-cli.ts +4 -1
  213. package/src/cli/freeze-cli.ts +3 -2
  214. package/src/cli/intake-cli.ts +74 -2
  215. package/src/cli/log-event-names.ts +1 -0
  216. package/src/cli/notify-cli.ts +75 -0
  217. package/src/cli/pr-cli.ts +12 -1
  218. package/src/cli/provider-cli.ts +24 -0
  219. package/src/cli/release-cli.ts +101 -17
  220. package/src/cli/self-update-canary.ts +46 -0
  221. package/src/cli/self-update.ts +200 -1
  222. package/src/cli/tasks-cli.ts +309 -3
  223. package/src/context-bus/condense.ts +19 -3
  224. package/src/context-bus/context-day.ts +77 -24
  225. package/src/context-bus/context-first.ts +33 -0
  226. package/src/context-card/index.ts +45 -0
  227. package/src/context-card/task.ts +76 -0
  228. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
  229. package/src/decisions/decision-ledger.ts +10 -1
  230. package/src/discord-self-message.ts +20 -2
  231. package/src/discord-slash-wire.ts +1 -0
  232. package/src/domains/outbound-alert.ts +200 -27
  233. package/src/domains/outbound-log-probe.ts +16 -1
  234. package/src/domains/release-tool.ts +2 -2
  235. package/src/execution-loop/gates.ts +11 -2
  236. package/src/flow-loop/split.ts +8 -4
  237. package/src/git-fs/worktree.ts +23 -3
  238. package/src/harness/harness-cli-command.ts +151 -11
  239. package/src/harness/harness-pod-dispatch.ts +11 -0
  240. package/src/harness/harness-queue.ts +466 -32
  241. package/src/harness/helper-scan.ts +10 -3
  242. package/src/harness/nested-elanous-policy.ts +23 -4
  243. package/src/hq/fence-wrapper.ts +123 -0
  244. package/src/hq/hq.ts +8 -0
  245. package/src/hq/seats.ts +369 -0
  246. package/src/index.ts +190 -23
  247. package/src/intake-plane/adopt-gate.ts +49 -0
  248. package/src/intake-plane/check.ts +3 -0
  249. package/src/intake-plane/collect-github.ts +57 -25
  250. package/src/intake-plane/digest.ts +39 -4
  251. package/src/intake-plane/discord-seat-work.ts +8 -2
  252. package/src/intake-plane/requirement-funnel.ts +316 -0
  253. package/src/knowledge/know-find.ts +10 -1
  254. package/src/loops/budget.ts +36 -0
  255. package/src/loops/orchestrator/finish-rate.ts +73 -1
  256. package/src/loops/orchestrator/grid-place.ts +11 -0
  257. package/src/loops/orchestrator/tick.ts +295 -20
  258. package/src/maturity/feature-maturity.ts +3 -2
  259. package/src/nexus/api/decisions-route.ts +11 -1
  260. package/src/nexus/api/grid.ts +61 -0
  261. package/src/nexus/api/http-server.ts +19 -1
  262. package/src/nexus/api/loop-edges.ts +69 -13
  263. package/src/nexus/api/ops-seats-sources.ts +2 -2
  264. package/src/nexus/api/task-cards-api.ts +19 -0
  265. package/src/nexus/api/workflow-templates.ts +3 -0
  266. package/src/oauth/codex.ts +120 -2
  267. package/src/onboarding/first-chat-gate.ts +29 -0
  268. package/src/release-loop/checklist.ts +104 -6
  269. package/src/release-loop/feature-store.ts +10 -9
  270. package/src/release-loop/landing-freeze.ts +24 -14
  271. package/src/release-loop/placement.ts +13 -3
  272. package/src/release-loop/rubric.ts +80 -0
  273. package/src/seat-dispatch/seat-ask.ts +79 -16
  274. package/src/seat-loop/seat-loop.ts +107 -37
  275. package/src/self-dev/ask-launch-flow.ts +50 -10
  276. package/src/self-dev/ask-path-candidates.ts +68 -0
  277. package/src/self-dev/dev-pipeline.ts +4 -0
  278. package/src/self-dev/draft-triage-rules.ts +1 -1
  279. package/src/self-dev/orchestrate-cli.ts +22 -0
  280. package/src/self-dev/round-pr-supersede.ts +244 -0
  281. package/src/self-dev/run-store.ts +5 -1
  282. package/src/self-dev/run-supervisor.ts +21 -1
  283. package/src/self-dev/supervisor-verdict-edges.ts +46 -0
  284. package/src/self-implement/follow-up-goals.ts +2 -2
  285. package/src/self-implement/frozen-merges.ts +25 -20
  286. package/src/self-implement/gate-remote.ts +427 -0
  287. package/src/self-implement/goal-author-clarification.ts +81 -0
  288. package/src/self-implement/goal-author-cli.ts +33 -5
  289. package/src/self-implement/goal-author.ts +93 -12
  290. package/src/self-implement/goal-clarification-escalation.ts +37 -1
  291. package/src/self-implement/goal-document-write.ts +28 -0
  292. package/src/self-implement/heal-intake.ts +4 -0
  293. package/src/self-implement/host-regate.ts +3 -1
  294. package/src/self-implement/l8-merge-queue.ts +29 -5
  295. package/src/self-implement/orchestrator.ts +78 -13
  296. package/src/self-implement/prior-draft-findings.ts +4 -3
  297. package/src/skills/skill-feedback.ts +76 -0
  298. package/src/task-agent/actions.ts +151 -0
  299. package/src/task-agent/judge.ts +122 -0
  300. package/src/task-agent/mission.ts +423 -0
  301. package/src/task-agent/shadow.ts +90 -0
  302. package/src/task-agent/task-hand.ts +235 -0
  303. package/src/task-cards/card-store.ts +4 -1
  304. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +43 -4
  305. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  306. package/src/task-orchestrator/surfaces/pod-pool.ts +81 -13
  307. package/src/task-orchestrator/surfaces/self-implement-pod.ts +225 -35
  308. package/src/telegram-commands.ts +1 -1
  309. package/src/telegram-loops-command.ts +22 -15
  310. package/src/telegram.ts +5 -20
  311. package/src/user-config.ts +86 -4
  312. package/src/version/packed-revision.json +1 -1
  313. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
  314. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
  315. package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
  316. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
  317. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
  318. package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
  319. package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +0 -1
  320. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
  321. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
  322. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +0 -1
  323. package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
  324. package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +0 -1
  325. package/apps/pwa/out/_next/static/chunks/9247-29d889b809288e65.js +0 -1
  326. package/apps/pwa/out/_next/static/chunks/app/approvals/page-79c3ed84baaedd03.js +0 -1
  327. package/apps/pwa/out/_next/static/chunks/app/board/page-a424ef80885d1743.js +0 -1
  328. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1e962b31d1f11081.js +0 -1
  329. package/apps/pwa/out/_next/static/chunks/app/chat/page-8c2d9526164f5d09.js +0 -1
  330. package/apps/pwa/out/_next/static/chunks/app/consult/page-ffff6d819fbc6e0f.js +0 -1
  331. package/apps/pwa/out/_next/static/chunks/app/inside/page-76270efaee638f17.js +0 -1
  332. package/apps/pwa/out/_next/static/chunks/app/layout-dce686e582c23937.js +0 -1
  333. package/apps/pwa/out/_next/static/chunks/app/live/page-d3d53b146416e422.js +0 -1
  334. package/apps/pwa/out/_next/static/chunks/app/loops/page-1a61c7ca1ceb3ae7.js +0 -1
  335. package/apps/pwa/out/_next/static/chunks/app/market/page-51f811fa119308b6.js +0 -1
  336. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-dacff46049e1557e.js +0 -1
  337. package/apps/pwa/out/_next/static/chunks/app/observatory/page-36a7d994f4ca0299.js +0 -1
  338. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-5b042736aa113756.js +0 -1
  339. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-acb749f1e432bcf3.js +0 -1
  340. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cd78862707999911.js +0 -1
  341. package/apps/pwa/out/_next/static/chunks/app/page-54b9ef8afe6278fd.js +0 -1
  342. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-57924393e3e4e539.js +0 -1
  343. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9e0ce6c8129fa641.js +0 -1
  344. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-31fa1ce4c4aff9ae.js +0 -1
  345. package/apps/pwa/out/_next/static/chunks/app/settings/page-0f5cd57ca928f42b.js +0 -1
  346. package/apps/pwa/out/_next/static/chunks/app/setup/page-4364ef9f4e7c7f0f.js +0 -1
  347. package/apps/pwa/out/_next/static/chunks/app/showroom/page-59f03fda76c03d22.js +0 -1
  348. package/apps/pwa/out/_next/static/chunks/app/trace/page-86914b0dee8ab7f8.js +0 -1
  349. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d4aef67abf264874.js +0 -1
  350. package/apps/pwa/out/_next/static/chunks/app/workflows/page-1ea64acadd704ace.js +0 -1
  351. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-30c2073bfc21c004.js +0 -1
  352. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
  353. package/apps/pwa/out/_next/static/rv9cierV0jSOvDBm1g0XB/_buildManifest.js +0 -1
  354. /package/apps/pwa/out/_next/static/{rv9cierV0jSOvDBm1g0XB → P6YTVgzuZz5oTZhY4Din_}/_ssgManifest.js +0 -0
@@ -0,0 +1,30 @@
1
+ name: http-poll-then-alert
2
+ description: |
3
+ Hourly HTTP poll of an upstream API. When the response diverges from
4
+ the last seen value, fires the notify step. Useful for status pages /
5
+ feature flag dashboards / blog feeds.
6
+
7
+ _meta:
8
+ template:
9
+ title: HTTP poll + alert
10
+ description: Cron hourly → HTTP fetch → diff → notify
11
+ tags: [schedule, http, monitor]
12
+
13
+ nodes:
14
+ - id: tick
15
+ scheduleTrigger:
16
+ type: interval
17
+ interval: 3600000
18
+ enabled: true
19
+
20
+ - id: probe
21
+ http:
22
+ method: GET
23
+ url: https://status.example.com/api/status
24
+ timeout: 15000
25
+ depends_on: [tick]
26
+
27
+ - id: alert
28
+ bash: |
29
+ echo "status: $probe.output"
30
+ depends_on: [probe]
@@ -0,0 +1,21 @@
1
+ name: manual-quickstart
2
+ description: |
3
+ Two-node smoke for the very first PWA user — click ▶ "Run now" and
4
+ see the graph light up. Echoes the arguments and exits. Modify to
5
+ taste once you've confirmed the editor works.
6
+
7
+ _meta:
8
+ template:
9
+ title: Manual quickstart
10
+ description: Manual ▶ → echo → done (first-touch smoke)
11
+ tags: [manual, starter]
12
+
13
+ nodes:
14
+ - id: start
15
+ manualTrigger:
16
+ description: Click ▶ Run now to fire this workflow
17
+
18
+ - id: echo
19
+ bash: |
20
+ echo "hello from monad-agent: $ARGUMENTS"
21
+ depends_on: [start]
@@ -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]
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rss version="2.0"><channel><title>AI타임스</title>
3
+ <item><title><![CDATA[구글 RRSI, 하니스만 고쳐 에이전트 성능 향상]]></title><link>https://www.aitimes.com/news/articleView.html?idxno=215802</link><description><![CDATA[구글은 모델 학습 없이 코딩 에이전트의 성능을 높였다.]]></description><pubDate>Tue, 06 Oct 2026 06:00:00 GMT</pubDate></item>
4
+ <item><title>프로야구 결승</title><link>https://www.aitimes.com/news/articleView.html?idxno=215803</link><description>올해 우승팀은 스포츠 팬들의 축하를 받았다.</description><pubDate>Tue, 06 Oct 2026 06:00:00 GMT</pubDate></item>
5
+ <item><title>인공지능 기술 소식</title><link>https://www.aitimes.com/news/articleView.html?idxno=215804</link><description>일반적인 기술 행사 안내.</description><pubDate>Tue, 06 Oct 2026 06:00:00 GMT</pubDate></item>
6
+ <item><title>로컬 LLM 연구</title><link>https://www.aitimes.com/news/articleView.html?idxno=215805</link><description>오래된 기사.</description><pubDate>Sun, 04 Oct 2026 06:00:00 GMT</pubDate></item>
7
+ </channel></rss>
@@ -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));
@@ -0,0 +1,169 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { parse as parseYaml } from 'yaml';
6
+ import { judge } from '../src/llm/judge-layer.js';
7
+ import { effectiveInstanceRoot } from '../src/instance/resolve.js';
8
+ import { canonicalUrl } from '../src/intake-plane/items.js';
9
+
10
+ export interface NewsSource { name: string; rss: string }
11
+ export interface NewsArticle { title: string; description: string; url: string; published: string }
12
+ export interface NewsCheck { items: { fact: string; line: string; verdict: string; current: string }[] }
13
+ export interface NewsDeps {
14
+ fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
15
+ now?: () => Date;
16
+ check?: (facts: readonly string[]) => Promise<NewsCheck>;
17
+ classify?: (article: NewsArticle) => Promise<boolean>;
18
+ log?: (message: string) => void;
19
+ }
20
+
21
+ const AXES = /하니스|harness|에이전트|agent|코딩\s*(?:에이전트|agent)|coding\s*agent|로컬\s*(?:llm|언어모델)|local\s*llm|기업.{0,12}ai\s*도입|enterprise\s*ai|ai\s*투자|인공지능\s*투자|ai\s*investment/i;
22
+ const AMBIGUOUS = /\bAI\b|인공지능|생성형|\bLLM\b/i;
23
+ const entity = (text: string): string => text.replace(/&#(x[\da-f]+|\d+);|&(amp|lt|gt|quot|apos|nbsp|lsquo|rsquo|ldquo|rdquo|middot|hellip|ndash|mdash);/gi, (match, numeric: string | undefined, named: string | undefined) => {
24
+ if (numeric) {
25
+ const code = numeric[0]?.toLowerCase() === 'x' ? parseInt(numeric.slice(1), 16) : parseInt(numeric, 10);
26
+ return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match;
27
+ }
28
+ return ({ amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ', lsquo: '‘', rsquo: '’', ldquo: '“', rdquo: '”', middot: '·', hellip: '…', ndash: '–', mdash: '—' } as Record<string, string>)[named?.toLowerCase() ?? ''] ?? match;
29
+ });
30
+ const plain = (text: string): string => entity(text.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, '$1').replace(/<[^>]+>/g, ' ')).replace(/\s+/g, ' ').trim();
31
+ const field = (xml: string, tag: string): string => plain(xml.match(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${tag}>`, 'i'))?.[1] ?? '');
32
+
33
+ /** RSS 2.0 items, including CDATA, escaped HTML and pubDate. */
34
+ export function parseNewsRss(xml: string): NewsArticle[] {
35
+ if (!/<rss\b|<rdf:RDF\b/i.test(xml)) throw new Error('RSS 응답이 아님');
36
+ return [...xml.matchAll(/<item(?:\s[^>]*)?>([\s\S]*?)<\/item>/gi)].flatMap((match) => {
37
+ const item = match[1] ?? '';
38
+ const url = field(item, 'link');
39
+ const published = field(item, 'pubDate');
40
+ return /^https?:\/\//i.test(url) && Number.isFinite(Date.parse(published))
41
+ ? [{ title: field(item, 'title'), description: field(item, 'description'), url, published }]
42
+ : [];
43
+ });
44
+ }
45
+
46
+ export function newsInterest(article: NewsArticle): 'yes' | 'no' | 'ambiguous' {
47
+ const text = `${article.title} ${article.description}`;
48
+ if (AXES.test(text)) return 'yes';
49
+ return AMBIGUOUS.test(text) ? 'ambiguous' : 'no';
50
+ }
51
+
52
+ async function classifyAmbiguous(article: NewsArticle): Promise<boolean> {
53
+ const decision = await judge({
54
+ site: 'intake.news.interest',
55
+ prompt: `제목·요약만 보고 하니스·에이전트·코딩 에이전트·로컬 LLM·기업 AI 도입·AI 투자 관련 기사인지 판정한다. JSON {"relevant":true|false} 만 답하라.\n제목: ${article.title}\n요약: ${article.description}`,
56
+ schema: (value) => value && typeof value === 'object' && typeof (value as { relevant?: unknown }).relevant === 'boolean'
57
+ ? (value as { relevant: boolean }).relevant : null,
58
+ });
59
+ if (!decision.ok) throw new Error('관심 축 판정 실패');
60
+ return decision.value;
61
+ }
62
+
63
+ /** The CLI, not a local imitation of the checker, is the implication authority. No --author or release mutation. */
64
+ async function checkWithCli(facts: readonly string[]): Promise<NewsCheck> {
65
+ const result = spawnSync('bun', ['bin/elanous.mjs', '--test', 'intake', 'check', ...facts.flatMap((fact) => ['--fact', fact]), '--json'], {
66
+ cwd: resolve(import.meta.dir, '..'), encoding: 'utf8', timeout: 120_000, maxBuffer: 4 * 1024 * 1024,
67
+ });
68
+ if (result.error || result.status !== 0) throw new Error(result.error?.message ?? result.stderr?.trim() ?? `intake check exited ${result.status}`);
69
+ // Standalone notifications may precede JSON on stdout.
70
+ const start = result.stdout.indexOf('{');
71
+ if (start < 0) throw new Error('intake check JSON 없음');
72
+ const parsed = JSON.parse(result.stdout.slice(start)) as NewsCheck;
73
+ if (!Array.isArray(parsed.items)) throw new Error('intake check items 없음');
74
+ return parsed;
75
+ }
76
+
77
+ function summarize(html: string): string[] {
78
+ const body = html.replace(/<script\b[^>]*>[\s\S]*?<\/script>|<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ');
79
+ const paragraphs = [...body.matchAll(/<(?:p|h[1-4])\b[^>]*>([\s\S]*?)<\/(?:p|h[1-4])>/gi)]
80
+ .map((match) => plain(match[1] ?? '')).filter((text) => text.length >= 25 && !/무단전재|저작권|기자\s*=/.test(text));
81
+ if (!paragraphs.length) throw new Error('본문을 읽지 못함');
82
+ const text = paragraphs.join(' ');
83
+ const sentences = text.split(/(?<=[.!?。])\s+/).map((s) => s.trim()).filter(Boolean);
84
+ // 앞 문장 요약(최대 다섯 줄) — 짧은 기사는 있는 문장만 남긴다. 낱말을 잘라 줄 수를 채우지 않는다(사실을 지어내지 않는다).
85
+ return sentences.slice(0, 5).map((sentence) => sentence.slice(0, 240));
86
+ }
87
+
88
+ export async function runIntakeNews(options: { root: string; sources: readonly NewsSource[]; deps?: NewsDeps }): Promise<{ written: number; failed: number }> {
89
+ const { root, sources, deps = {} } = options;
90
+ const request = deps.fetch ?? fetch;
91
+ const log = deps.log ?? ((message: string) => console.error(message));
92
+ const now = (deps.now ?? (() => new Date()))();
93
+ const day = new Date(now.getTime() + 9 * 3600_000).toISOString().slice(0, 10);
94
+ const state = join(root, 'intake', 'news-seen.jsonl');
95
+ const lens = join(root, 'intake', 'outbox', 'lens', `${day}.jsonl`);
96
+ const seen = new Set(existsSync(state) ? readFileSync(state, 'utf8').split('\n').filter(Boolean) : []);
97
+ // 렌즈에 이미 쓴 기사도 «본 것» — 렌즈 기록과 상태 기록 사이에서 죽어도 재실행이 같은 기사를 다시 쓰지 않는다(24h 창이라 어제·오늘 파일).
98
+ const yesterday = new Date(now.getTime() + 9 * 3600_000 - 86_400_000).toISOString().slice(0, 10);
99
+ for (const lensDay of [yesterday, day]) {
100
+ const file = join(root, 'intake', 'outbox', 'lens', `${lensDay}.jsonl`);
101
+ if (!existsSync(file)) continue;
102
+ for (const line of readFileSync(file, 'utf8').split('\n')) {
103
+ try { const id = (JSON.parse(line) as { id?: unknown }).id; if (typeof id === 'string') seen.add(id); } catch { /* 깨진 줄은 건너뛴다 */ }
104
+ }
105
+ }
106
+ let written = 0;
107
+ let failed = 0;
108
+ for (const source of sources) {
109
+ try {
110
+ const response = await request(source.rss, { signal: AbortSignal.timeout(30_000) });
111
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
112
+ for (const article of parseNewsRss(await response.text())) {
113
+ const published = Date.parse(article.published);
114
+ if (published > now.getTime() || published < now.getTime() - 86_400_000) continue;
115
+ const id = createHash('sha256').update(canonicalUrl(article.url) ?? article.url).digest('hex').slice(0, 16);
116
+ if (seen.has(id)) continue;
117
+ const interest = newsInterest(article);
118
+ if (interest === 'no') continue;
119
+ try {
120
+ if (interest === 'ambiguous' && !(await (deps.classify ?? classifyAmbiguous)(article))) continue;
121
+ const page = await request(article.url, { signal: AbortSignal.timeout(30_000) });
122
+ if (!page.ok) throw new Error(`본문 HTTP ${page.status}`);
123
+ const summary = summarize(await page.text());
124
+ const name = article.title.match(/\b[A-Z][A-Z0-9]{2,}\b/)?.[0] ?? article.title;
125
+ // 함의는 기사 하나에서 셋까지 — 제목 ⊕ 요약 앞 두 문장을 각각 «엘라누스가 이걸 하나»로 대조한다(판정선: 함의 3).
126
+ const facts = [
127
+ `elanous는 \`${name}\` 관련 ${article.title} 기능을 지원한다`,
128
+ ...summary.slice(0, 2).map((line) => `elanous는 다음 일을 한다: ${line.slice(0, 160)}`),
129
+ ];
130
+ const check = await (deps.check ?? checkWithCli)(facts);
131
+ if (!check.items.length) throw new Error('intake check 항목 없음');
132
+ // «판단 필요» is a review suggestion, not an asserted absence; keep the check verdict attached.
133
+ const suggestions = check.items.filter((item) => item.verdict === '없음' || item.verdict === '판단 필요')
134
+ .map((item) => ({ kind: '칸 제안', fact: item.fact, status: '제안', verdict: item.verdict }));
135
+ const verdict = suggestions.length ? '보강'
136
+ : check.items.every((item) => item.verdict === '있음') ? '참고' : '경쟁 대조';
137
+ const record = {
138
+ id, at: now.toISOString(), source: source.name, url: article.url, title: article.title,
139
+ summary, implication: check.items.map((item) => item.line), suggestions,
140
+ lensVerdict: verdict, why: `엘라누스 대조: ${check.items.map((item) => item.line).join(' · ')}`.slice(0, 500), target: name,
141
+ };
142
+ mkdirSync(dirname(lens), { recursive: true });
143
+ appendFileSync(lens, `${JSON.stringify(record)}\n`);
144
+ mkdirSync(dirname(state), { recursive: true });
145
+ appendFileSync(state, `${id}\n`);
146
+ seen.add(id);
147
+ written++;
148
+ } catch (error) {
149
+ failed++;
150
+ log(`못 모음: ${article.url} — ${error instanceof Error ? error.message : String(error)}`);
151
+ }
152
+ }
153
+ } catch (error) {
154
+ failed++;
155
+ log(`못 모음: ${source.name} — ${error instanceof Error ? error.message : String(error)}`);
156
+ }
157
+ }
158
+ return { written, failed };
159
+ }
160
+
161
+ if (import.meta.main) {
162
+ const config = parseYaml(readFileSync(resolve(import.meta.dir, '../graphs/intake/news-sources.yaml'), 'utf8')) as { sources?: NewsSource[] };
163
+ if (!Array.isArray(config.sources) || !config.sources.every((source) => source && typeof source.name === 'string' && source.name.trim() && typeof source.rss === 'string' && /^https?:\/\//.test(source.rss))) {
164
+ throw new Error('news-sources.yaml: sources 배열 필요');
165
+ }
166
+ const result = await runIntakeNews({ root: effectiveInstanceRoot(), sources: config.sources });
167
+ console.log(`intake-news: ${result.written}건 · 못 모음 ${result.failed}건`);
168
+ if (result.failed) process.exitCode = 1;
169
+ }
@@ -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) => ({