elanous 0.2.15 → 0.2.17

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/chunks/{1307-33ffcc49ab45123b.js → 1307-aac7332576c4d6fc.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{6877-7c6208705c284124.js → 6877-fe94e76a5841ee9b.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/{9103-7a3ae7f60af3b99f.js → 9103-60fbef33e66f0a46.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/app/approvals/{page-0e2c57fe6add4b2a.js → page-3143b07a817d1da9.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-e05a77df7e005b04.js → page-17ba086ef82d339b.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/app/bots/{page-b8c49f6b4fa2df91.js → page-6e5c3a867557298b.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/app/chat/{page-976813c91d7394ea.js → page-9a41d65355fc25b9.js} +1 -1
  16. package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/app/control/{page-1d4901eb7c2d8822.js → page-41afec0b255ed2bb.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-72d3e7ff35a8c954.js → page-4187666132fc98c4.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/editor/{page-60c7a8e1a4fe62ce.js → page-09328d499162bae4.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/exec/{page-2a52b316cb143d9c.js → page-29ff3a8f84f03b6a.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/field/{page-c3ce483c8d5db370.js → page-80ec7401bc83f511.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/app/intake/{page-96f074f6538e8a2c.js → page-fc7d86467291ae38.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/{layout-e97be5334d83a9f5.js → layout-de43a186e5ba5683.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/morning/{page-c1343f9499d86f3f.js → page-043a9111e74f6b24.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/{not-found-8739a2e0ae793130.js → not-found-23a4601ceb7f452e.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-d23b12bb92242558.js → page-10d958605a77b3bd.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-c7fea475488201a8.js → page-a04260b8ccc968d4.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-5efbf81124c474ae.js → page-12916918988ac97e.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-06ee266953d9c879.js → page-5a64cb5208c6a8fd.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/settings/{page-153c2b3bcc89e8de.js → page-1407ec83ea64c1f9.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/app/share/{page-0d6d23b40263a7ea.js → page-7f49fe645d5132f7.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/trace/{page-73735b64bfe1ae67.js → page-424659bacfb8cdd7.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-f7e631e9b4daf66e.js → page-fc2df261f8a2c7df.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-9817c7f9007466cc.js → page-5d4fef9ccd7d406b.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +1 -0
  55. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +1 -0
  56. package/apps/pwa/out/_next/static/css/{04dabcbcc4bfa6db.css → 085673d826b98b62.css} +1 -1
  57. package/apps/pwa/out/approvals/index.html +1 -1
  58. package/apps/pwa/out/approvals/index.txt +15 -15
  59. package/apps/pwa/out/autopilot/index.html +1 -1
  60. package/apps/pwa/out/autopilot/index.txt +15 -15
  61. package/apps/pwa/out/board/index.html +1 -1
  62. package/apps/pwa/out/board/index.txt +15 -15
  63. package/apps/pwa/out/botlab/index.html +1 -1
  64. package/apps/pwa/out/botlab/index.txt +15 -15
  65. package/apps/pwa/out/bots/index.html +1 -1
  66. package/apps/pwa/out/bots/index.txt +15 -15
  67. package/apps/pwa/out/ceo/index.html +1 -1
  68. package/apps/pwa/out/ceo/index.txt +15 -15
  69. package/apps/pwa/out/chat/index.html +1 -1
  70. package/apps/pwa/out/chat/index.txt +15 -15
  71. package/apps/pwa/out/consult/index.html +1 -1
  72. package/apps/pwa/out/consult/index.txt +15 -15
  73. package/apps/pwa/out/control/index.html +1 -1
  74. package/apps/pwa/out/control/index.txt +15 -15
  75. package/apps/pwa/out/design-check/index.html +1 -1
  76. package/apps/pwa/out/design-check/index.txt +15 -15
  77. package/apps/pwa/out/editor/index.html +1 -1
  78. package/apps/pwa/out/editor/index.txt +15 -15
  79. package/apps/pwa/out/exec/index.html +1 -1
  80. package/apps/pwa/out/exec/index.txt +15 -15
  81. package/apps/pwa/out/field/index.html +1 -1
  82. package/apps/pwa/out/field/index.txt +15 -15
  83. package/apps/pwa/out/healthz +1 -1
  84. package/apps/pwa/out/index.html +1 -1
  85. package/apps/pwa/out/index.txt +15 -15
  86. package/apps/pwa/out/inside/index.html +1 -1
  87. package/apps/pwa/out/inside/index.txt +15 -15
  88. package/apps/pwa/out/intake/index.html +1 -1
  89. package/apps/pwa/out/intake/index.txt +15 -15
  90. package/apps/pwa/out/live/index.html +1 -1
  91. package/apps/pwa/out/live/index.txt +15 -15
  92. package/apps/pwa/out/loops/index.html +1 -1
  93. package/apps/pwa/out/loops/index.txt +15 -15
  94. package/apps/pwa/out/market/index.html +1 -1
  95. package/apps/pwa/out/market/index.txt +15 -15
  96. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  97. package/apps/pwa/out/missions/placeholder/index.txt +15 -15
  98. package/apps/pwa/out/morning/index.html +1 -1
  99. package/apps/pwa/out/morning/index.txt +15 -15
  100. package/apps/pwa/out/observatory/index.html +1 -1
  101. package/apps/pwa/out/observatory/index.txt +15 -15
  102. package/apps/pwa/out/ops/checklist/index.html +1 -1
  103. package/apps/pwa/out/ops/checklist/index.txt +15 -15
  104. package/apps/pwa/out/ops/release/index.html +1 -1
  105. package/apps/pwa/out/ops/release/index.txt +15 -15
  106. package/apps/pwa/out/ops/seats/index.html +1 -1
  107. package/apps/pwa/out/ops/seats/index.txt +15 -15
  108. package/apps/pwa/out/outputs/index.html +1 -1
  109. package/apps/pwa/out/outputs/index.txt +15 -15
  110. package/apps/pwa/out/reflection/index.html +1 -1
  111. package/apps/pwa/out/reflection/index.txt +16 -16
  112. package/apps/pwa/out/scheduler/index.html +1 -1
  113. package/apps/pwa/out/scheduler/index.txt +15 -15
  114. package/apps/pwa/out/sessions/index.html +1 -1
  115. package/apps/pwa/out/sessions/index.txt +15 -15
  116. package/apps/pwa/out/settings/devices/index.html +1 -1
  117. package/apps/pwa/out/settings/devices/index.txt +15 -15
  118. package/apps/pwa/out/settings/index.html +1 -1
  119. package/apps/pwa/out/settings/index.txt +15 -15
  120. package/apps/pwa/out/setup/done/index.html +1 -1
  121. package/apps/pwa/out/setup/done/index.txt +15 -15
  122. package/apps/pwa/out/setup/index.html +1 -1
  123. package/apps/pwa/out/setup/index.txt +15 -15
  124. package/apps/pwa/out/share/index.html +1 -1
  125. package/apps/pwa/out/share/index.txt +15 -15
  126. package/apps/pwa/out/showroom/index.html +1 -1
  127. package/apps/pwa/out/showroom/index.txt +15 -15
  128. package/apps/pwa/out/tasks/index.html +1 -1
  129. package/apps/pwa/out/tasks/index.txt +15 -15
  130. package/apps/pwa/out/term/index.html +1 -1
  131. package/apps/pwa/out/term/index.txt +15 -15
  132. package/apps/pwa/out/today/index.html +1 -1
  133. package/apps/pwa/out/today/index.txt +15 -15
  134. package/apps/pwa/out/trace/index.html +1 -1
  135. package/apps/pwa/out/trace/index.txt +15 -15
  136. package/apps/pwa/out/vault/index.html +1 -1
  137. package/apps/pwa/out/vault/index.txt +15 -15
  138. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  139. package/apps/pwa/out/workflows/chat-ui/index.txt +15 -15
  140. package/apps/pwa/out/workflows/index.html +1 -1
  141. package/apps/pwa/out/workflows/index.txt +15 -15
  142. package/apps/pwa/out/workspace/index.html +1 -1
  143. package/apps/pwa/out/workspace/index.txt +15 -15
  144. package/apps/pwa/out/worktrees/index.html +1 -1
  145. package/apps/pwa/out/worktrees/index.txt +15 -15
  146. package/graphs/doc-gen/doc-gen.yaml +24 -0
  147. package/graphs/doc-gen/recipes.yaml +3 -0
  148. package/graphs/intake/intake-daily.yaml +9 -2
  149. package/graphs/intake/news-sources.yaml +4 -0
  150. package/graphs/intake/recipes.yaml +6 -1
  151. package/graphs/orchestrator/orchestrator.yaml +7 -0
  152. package/graphs/orchestrator/recipes.yaml +3 -0
  153. package/graphs/steward/recipes.yaml +2 -1
  154. package/package.json +1 -1
  155. package/scripts/__fixtures__/intake-news.xml +7 -0
  156. package/scripts/ci-public-export-import-gate.ts +154 -0
  157. package/scripts/ci-test-interference-gate.ts +5 -1
  158. package/scripts/ci-typecheck-changed.ts +34 -15
  159. package/scripts/docs/doc-rot.ts +164 -0
  160. package/scripts/docs/generate-graph-anatomy.ts +131 -9
  161. package/scripts/docs-cli-check.ts +4 -4
  162. package/scripts/goals/goal-census.ts +343 -0
  163. package/scripts/intake-news.ts +169 -0
  164. package/scripts/measure/author-section-contribution.ts +84 -0
  165. package/scripts/release-loop/cut-branch.ts +43 -13
  166. package/scripts/release-loop/docs-land-node.ts +69 -10
  167. package/scripts/release-loop/gate-node.ts +3 -1
  168. package/scripts/release-loop/publish-node.ts +2 -2
  169. package/scripts/release-loop/release-docs.ts +134 -0
  170. package/scripts/release-loop/vault-note-node.ts +19 -2
  171. package/scripts/release-loop/version-node.ts +7 -4
  172. package/scripts/release-story/draft.ts +42 -14
  173. package/scripts/rhythm/monthly.ts +97 -0
  174. package/src/acp/client.ts +17 -2
  175. package/src/agent-mission/driver.ts +104 -11
  176. package/src/agent-mission/supervisor-metrics-cli.ts +40 -0
  177. package/src/agent-mission/supervisor-metrics.ts +218 -0
  178. package/src/autopilot/track-agent-shadow.ts +2 -1
  179. package/src/autopilot/track-agent.ts +5 -3
  180. package/src/briefing/brief-items.ts +191 -36
  181. package/src/budget/usage-outcomes.ts +204 -0
  182. package/src/cli/autopilot-cli.ts +66 -0
  183. package/src/cli/brief-cli.ts +73 -0
  184. package/src/cli/decisions-cli.ts +4 -1
  185. package/src/cli/intake-cli.ts +1 -1
  186. package/src/cli/know-cli.ts +20 -0
  187. package/src/cli/log-event-names.ts +1 -0
  188. package/src/cli/logs-cli.ts +43 -1
  189. package/src/cli/pr-cli.ts +92 -13
  190. package/src/cli/provider-cli.ts +14 -0
  191. package/src/cli/release-cli.ts +11 -8
  192. package/src/cli/self-update-canary.ts +46 -0
  193. package/src/cli/self-update.ts +399 -1
  194. package/src/cli/usage-cli.ts +26 -0
  195. package/src/context-card/index.ts +45 -0
  196. package/src/context-card/task.ts +76 -0
  197. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
  198. package/src/decisions/decision-ledger.ts +10 -1
  199. package/src/discord-self-message.ts +9 -0
  200. package/src/flow-loop/split.ts +24 -0
  201. package/src/harness/harness-cli-command.ts +178 -12
  202. package/src/harness/harness-pod-dispatch.ts +36 -55
  203. package/src/harness/harness-queue.ts +86 -7
  204. package/src/harness/harness-seams.ts +13 -3
  205. package/src/harness/helper-repair.ts +139 -8
  206. package/src/harness/helper-scan.ts +13 -2
  207. package/src/harness/nested-elanous-policy.ts +133 -0
  208. package/src/hq/fence-wrapper.ts +123 -0
  209. package/src/hq/hq.ts +16 -2
  210. package/src/hq/lease.ts +5 -3
  211. package/src/hq/transfer.ts +185 -0
  212. package/src/index.ts +168 -13
  213. package/src/intake-plane/digest.ts +85 -28
  214. package/src/knowledge/know-find.ts +105 -0
  215. package/src/llm.ts +75 -19
  216. package/src/loops/orchestrator/finish-rate.ts +14 -3
  217. package/src/loops/orchestrator/tick.ts +96 -25
  218. package/src/maturity/bot-slash-catalog.ts +11 -2
  219. package/src/maturity/feature-maturity.ts +2 -2
  220. package/src/maturity/tui-slash-availability.ts +9 -0
  221. package/src/nexus/api/grid.ts +61 -0
  222. package/src/nexus/api/http-server.ts +19 -1
  223. package/src/nexus/api/task-cards-api.ts +19 -0
  224. package/src/oauth/codex.ts +82 -2
  225. package/src/oauth/overload-failover-launch.ts +75 -0
  226. package/src/oauth/overload-failover.ts +137 -0
  227. package/src/release-loop/checklist.ts +10 -5
  228. package/src/release-loop/feature-store.ts +10 -9
  229. package/src/release-loop/landing-freeze.ts +18 -10
  230. package/src/release-loop/placement.ts +17 -8
  231. package/src/seat-dispatch/seat-ask.ts +33 -6
  232. package/src/seat-loop/seat-loop.ts +172 -21
  233. package/src/self-dev/ask-launch-flow.ts +48 -8
  234. package/src/self-dev/authored-goal-trace.ts +64 -0
  235. package/src/self-dev/dev-cli.ts +19 -1
  236. package/src/self-dev/dev-pipeline.ts +6 -5
  237. package/src/self-dev/entrance-registry.ts +10 -6
  238. package/src/self-dev/old-door.ts +73 -0
  239. package/src/self-dev/run-store.ts +5 -1
  240. package/src/self-dev/run-supervisor.ts +7 -1
  241. package/src/self-dev/supervisor-verdict-edges.ts +46 -0
  242. package/src/self-implement/app-api-budget.ts +166 -0
  243. package/src/self-implement/budget-gate.ts +7 -5
  244. package/src/self-implement/follow-up-goals.ts +289 -0
  245. package/src/self-implement/frozen-merges.ts +25 -20
  246. package/src/self-implement/goal-author-clarification.ts +81 -0
  247. package/src/self-implement/goal-author-cli.ts +33 -5
  248. package/src/self-implement/goal-author.ts +107 -25
  249. package/src/self-implement/goal-clarification-escalation.ts +37 -1
  250. package/src/self-implement/goal-document-write.ts +28 -0
  251. package/src/self-implement/heal-intake.ts +4 -0
  252. package/src/self-implement/heal-triage.ts +44 -0
  253. package/src/self-implement/host-regate.ts +3 -1
  254. package/src/self-implement/orchestrator.ts +157 -8
  255. package/src/self-implement/run-ledger.ts +4 -0
  256. package/src/self-implement/seams.ts +44 -15
  257. package/src/session-runtime/index.ts +2 -0
  258. package/src/session-runtime/retry-api.ts +87 -0
  259. package/src/session-runtime/retry-policy.ts +107 -6
  260. package/src/steward/working-backwards.ts +16 -1
  261. package/src/task-agent/actions.ts +118 -0
  262. package/src/task-agent/judge.ts +96 -0
  263. package/src/task-cards/card-cli.ts +25 -0
  264. package/src/task-cards/card-store.ts +9 -4
  265. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +33 -4
  266. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  267. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +4 -3
  268. package/src/task-orchestrator/surfaces/pod-ledger-prod-sink.ts +75 -0
  269. package/src/task-orchestrator/surfaces/pod-pool.ts +95 -18
  270. package/src/task-orchestrator/surfaces/pod-source-receive.ts +37 -1
  271. package/src/task-orchestrator/surfaces/self-implement-pod.ts +168 -37
  272. package/src/task-orchestrator/surfaces/self-implement.ts +2 -0
  273. package/src/telegram-commands.ts +6 -1
  274. package/src/telegram-loops-command.ts +21 -14
  275. package/src/telegram.ts +47 -0
  276. package/src/user-config.ts +59 -4
  277. package/src/version/packed-revision.json +1 -1
  278. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +0 -1
  279. package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +0 -1
  280. package/apps/pwa/out/_next/static/chunks/9247-29d889b809288e65.js +0 -1
  281. package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +0 -1
  282. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +0 -1
  283. package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +0 -1
  284. package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +0 -1
  285. package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +0 -1
  286. package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +0 -1
  287. package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +0 -1
  288. package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +0 -1
  289. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +0 -1
  290. package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +0 -1
  291. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +0 -1
  292. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +0 -1
  293. package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +0 -1
  294. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +0 -1
  295. package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +0 -1
  296. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +0 -1
  297. package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +0 -1
  298. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +0 -1
  299. package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +0 -1
  300. package/apps/pwa/out/_next/static/chunks/app/term/page-f5597e894c02cd33.js +0 -1
  301. package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +0 -1
  302. package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +0 -1
  303. package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +0 -1
  304. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +0 -1
  305. package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +0 -1
  306. package/src/launch-head/seat-goal-queue-lock.fixture.ts +0 -15
  307. package/src/launch-head/seat-goal-queue.ts +0 -198
  308. /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_buildManifest.js +0 -0
  309. /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_ssgManifest.js +0 -0
package/src/index.ts CHANGED
@@ -27,10 +27,12 @@ import { installDevCompletionGuard } from './self-dev/dev-completion-guard.js';
27
27
  import { buildOrchestrateDecomposePrepareArgs, normalizeOrchestrateRequest, splitOrchestrateGoalTexts } from './self-dev/self-orchestrate-runtime.js';
28
28
  import { CLI_ENTRANCE_BASELINE, evaluateCommandEntranceBaseline } from './self-dev/entrance-baseline.js';
29
29
  import { CLI_HARNESS_DOGFOOD_ENTRANCE, CLI_HARNESS_ORCHESTRATE_ENTRANCE, describeEntranceCommand, listEntrancesWithModelExposure, renderLaunchEntrances, summarizeEntrances, type EntranceId } from './self-dev/entrance-registry.js';
30
+ import { isOldDoorInternalCall, refuseOldDoor } from './self-dev/old-door.js';
30
31
  import { collectCommandEntrances, renderCommandEntrances } from './self-dev/entrance-inventory.js';
31
32
  import { isGoalAuthorFileName } from './self-implement/goal-document.js';
32
33
  import { DEV_PIPELINE_SINK_SURFACE } from './self-implement/self-cli-sink-surface.js';
33
34
  import { registerPrivateLedgerCommands } from './cli/private-ledger-commands.js';
35
+ import { registerKnowCommand } from './cli/know-cli.js';
34
36
  import { registerSeatRequestsCommands } from './cli/seat-requests-cli.js';
35
37
  import { applyTestStateDirFlagFromArgv } from './cli/test-state-dir-flag.js';
36
38
  import { applyTestFlagFromArgv, observeTestFlagOwnership, uncoveredTestFlagPaths, staleTestFlagPaths } from './cli/test-flag.js';
@@ -53,6 +55,7 @@ export { runSchedule, scheduleCreatePlan } from './cli/schedule-cli.js';
53
55
  export type { ScheduleDispatch } from './cli/schedule-cli.js';
54
56
  import { registerReviewLoopOptions, buildReviewLoopOpts } from './agent-mission/review-loop-cli.js';
55
57
  import { registerCapabilitiesCommand } from './agent-mission/capabilities-cli.js';
58
+ import { registerSupervisorMetricsCommand } from './agent-mission/supervisor-metrics-cli.js';
56
59
  import { agentBackendNames } from './agent-mission/driver.js';
57
60
  import { registerWhereCommand } from './cli/where-cli.js';
58
61
  import { registerShadowCommand } from './cli/shadow-cli.js';
@@ -70,6 +73,7 @@ import { registerFlowCommands } from './cli/flow-cli.js';
70
73
  import { registerModelWatchCommand } from './cli/model-watch-cli.js';
71
74
  import { registerIntakeCommands } from './cli/intake-cli.js';
72
75
  import { registerTasksCommands } from './cli/tasks-cli.js';
76
+ import { registerBriefCommands } from './cli/brief-cli.js';
73
77
  import { registerLabelsCommands } from './cli/labels-cli.js';
74
78
  import { registerMsgCommands } from './cli/msg-cli.js';
75
79
  import { registerDoctorCommand } from './cli/doctor-cli.js';
@@ -255,7 +259,7 @@ interface RunDevAskFromGoalFileDeps {
255
259
  runSayLaunchFlow: (
256
260
  sayText: string,
257
261
  entrance?: import('./self-dev/entrance-registry.js').EntranceDeclaration,
258
- selection?: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string },
262
+ selection?: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string; readonly authorGrade?: import('./self-implement/goal-author.js').GoalAuthorGradeSelection },
259
263
  ) => Promise<RunDevAskFlowResult>;
260
264
  runAskFileLaunchFlow: (
261
265
  askPath: string,
@@ -290,7 +294,7 @@ export function assembleAskLaunchPolicy(selection: {
290
294
  async function runDefaultSayLaunchFlow(
291
295
  sayText: string,
292
296
  entrance?: import('./self-dev/entrance-registry.js').EntranceDeclaration,
293
- selection: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string } = {},
297
+ selection: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string; readonly authorGrade?: import('./self-implement/goal-author.js').GoalAuthorGradeSelection } = {},
294
298
  ): Promise<RunDevAskFlowResult> {
295
299
  const { readFileSync, writeFileSync } = await import('node:fs');
296
300
  const [flowMod, { runGoalAuthorCli }, { relative: relativeToCwdPath }, { CLI_HARNESS_SAY_ENTRANCE }] = await Promise.all([
@@ -315,6 +319,7 @@ async function runDefaultSayLaunchFlow(
315
319
  ...assembleAskLaunchPolicy(selection),
316
320
  ...(selection.goalType === undefined ? {} : { goalType: selection.goalType }),
317
321
  ...(selection.groundingCwd === undefined ? {} : { groundingCwd: selection.groundingCwd }),
322
+ ...(selection.authorGrade === undefined ? {} : { authorGrade: selection.authorGrade }),
318
323
  }, {
319
324
  print: (line) => console.error(line),
320
325
  log: (event, data, level) => debug.log('dev-pipeline', event, data, { level }),
@@ -324,6 +329,9 @@ async function runDefaultSayLaunchFlow(
324
329
  cwd: () => process.cwd(),
325
330
  now: () => Date.now(),
326
331
  isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
332
+ // POD-SELF-ANSWER: non-TTY (Pod) authoring self-answers clarifications with the author resolver.
333
+ selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
334
+ writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
327
335
  buildPreflightDeps: askIo.buildAskPreflightDeps,
328
336
  priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
329
337
  recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
@@ -372,6 +380,9 @@ async function runDefaultAskFileLaunchFlow(
372
380
  cwd: () => process.cwd(),
373
381
  now: () => Date.now(),
374
382
  isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
383
+ // POD-SELF-ANSWER: non-TTY (Pod) authoring self-answers clarifications with the author resolver.
384
+ selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
385
+ writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
375
386
  buildPreflightDeps: askIo.buildAskPreflightDeps,
376
387
  priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
377
388
  recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
@@ -814,6 +825,7 @@ async function runDevSayFromWords(
814
825
  authoringEntrance,
815
826
  {
816
827
  ...(opts.forcePreflight === undefined ? {} : { forcePreflight: opts.forcePreflight }),
828
+ ...(opts.authorGrade === undefined ? {} : { authorGrade: { grade: opts.authorGrade, source: opts.authorGradeSource ?? 'flag' } }),
817
829
  ...(grounding.groundingCwd === undefined ? {} : { groundingCwd: grounding.groundingCwd }),
818
830
  },
819
831
  );
@@ -875,6 +887,7 @@ registerUsageCommand(program);
875
887
  registerLiveCommands(program);
876
888
  registerResearchCommand(program);
877
889
  registerReleaseCommands(program);
890
+ registerKnowCommand(program);
878
891
  registerFreezeCommands(program);
879
892
  registerFlowCommands(program);
880
893
  // HQ-HB · HQ-FENCE (10-04): one writer across mbp · node-b · cloud-vm — lease on the arbiter, 2-of-3 quorum, generation fencing.
@@ -893,24 +906,42 @@ hqCmd.command('host').description('이 머신의 HQ 호스트 이름 설정')
893
906
  });
894
907
  hqCmd.command('lease').argument('<action>', 'acquire|renew|status|release')
895
908
  .option('--host <name>', '이 호스트 이름(기본 ~/.elanous-hq/host · hq.hostName · os.hostname)')
909
+ .option('--expected-holder <name>', 'release CAS: 해제할 임대의 예상 소유자')
910
+ .option('--expected-generation <number>', 'release CAS: 해제할 임대의 예상 세대')
896
911
  .option('--json', 'JSON 출력')
897
- .action(async (action: string, opts: { host?: string; json?: boolean }) => {
912
+ .action(async (action: string, opts: { host?: string; expectedHolder?: string; expectedGeneration?: string; json?: boolean }) => {
898
913
  try {
899
914
  if (!['acquire', 'renew', 'status', 'release'].includes(action)) throw new CliUserError(`hq lease: unknown action ${action}`, 'acquire|renew|status|release');
915
+ if ((opts.expectedHolder !== undefined || opts.expectedGeneration !== undefined) && action !== 'release')
916
+ throw new CliUserError('hq lease: expected holder/generation are only valid for release');
917
+ if ((opts.expectedHolder === undefined) !== (opts.expectedGeneration === undefined)
918
+ || (opts.expectedGeneration !== undefined && (!/^[1-9]\d*$/.test(opts.expectedGeneration) || !Number.isSafeInteger(Number(opts.expectedGeneration)))))
919
+ throw new CliUserError('hq lease release: supply both --expected-holder and --expected-generation (positive integer)');
900
920
  await hqSink();
901
921
  const { hqLease } = await import('./hq/hq.js');
902
- const result = hqLease(action as 'acquire', {}, opts.host ? { host: opts.host } : {});
922
+ const result = hqLease(action as 'acquire', {}, {
923
+ ...(opts.host ? { host: opts.host } : {}),
924
+ ...(opts.expectedHolder !== undefined ? { expectedHolder: opts.expectedHolder, expectedGeneration: Number(opts.expectedGeneration) } : {}),
925
+ });
903
926
  if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
904
927
  else console.log(result.ok ? `hq lease ${action}: ok${'record' in result && result.record ? ` · holder ${result.record.holder} · generation ${result.record.generation}` : ''}` : `hq lease ${action}: refused — ${'reason' in result ? result.reason : ''}`);
905
928
  if (!result.ok) process.exitCode = 2;
906
929
  } catch (error) { if (error instanceof CliUserError) throw error; console.error(`hq lease: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
907
930
  });
908
931
  hqCmd.command('promote').description('HQ 승격 런북 (기본 dry-run · --apply 일 때만 변경)')
909
- .requiredOption('--to <host>', '승격 대상 호스트')
910
- .option('--apply', '대기 사본을 승격 우주에 반영하고 넥서스·rescue 실행')
932
+ .option('--to <host>', '기존 임대 취득 후 승격 대상 호스트 (생략하면 mbp → node-b 전환 포함)')
933
+ .option('--apply', '임대 이전 및 승격 실행 · 터미널 확인 필수 (기존 --to 경로는 임대 보유 필요)')
911
934
  .option('--json', 'JSON 출력')
912
935
  .action(async (opts: { to: string; apply?: boolean; json?: boolean }) => {
913
936
  try {
937
+ if (!opts.to) {
938
+ const { transferHq, formatTransfer } = await import('./hq/transfer.js');
939
+ const result = transferHq('promote', opts.apply === true);
940
+ if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
941
+ else console.log(formatTransfer(result));
942
+ if (!result.ok) process.exitCode = 1;
943
+ return;
944
+ }
914
945
  const { promoteHq, formatPromote } = await import('./hq/promote.js');
915
946
  const result = promoteHq(opts.to, opts.apply === true);
916
947
  if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
@@ -918,6 +949,18 @@ hqCmd.command('promote').description('HQ 승격 런북 (기본 dry-run · --appl
918
949
  if (!result.ok) process.exitCode = 1;
919
950
  } catch (error) { console.error(`hq promote: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
920
951
  });
952
+ hqCmd.command('handback').description('node-b → mbp 임대·크론 울타리 복귀 (기본 읽기 전용)')
953
+ .option('--apply', '각 검사를 통과한 뒤 터미널 확인을 받고 이전 실행')
954
+ .option('--json', '단계별 결과·저널 경로 JSON 출력')
955
+ .action(async (opts: { apply?: boolean; json?: boolean }) => {
956
+ try {
957
+ const { transferHq, formatTransfer } = await import('./hq/transfer.js');
958
+ const result = transferHq('handback', opts.apply === true);
959
+ if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
960
+ else console.log(formatTransfer(result));
961
+ if (!result.ok) process.exitCode = 1;
962
+ } catch (error) { console.error(`hq handback: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
963
+ });
921
964
  hqCmd.command('heartbeat').description('보유자는 갱신 · 아니면 대기(보유자에 닿는지 중재자에 보고)').option('--json', 'JSON 출력')
922
965
  .action(async (opts: { json?: boolean }) => {
923
966
  try {
@@ -942,12 +985,47 @@ hqCmd.command('seen').description('이 호스트가 본 가장 높은 임대 세
942
985
  process.exitCode = result.seen ? 0 : 3;
943
986
  });
944
987
  registerHqMovePlanCommand(hqCmd);
988
+ const fenceWrapperCmd = hqCmd.command('fence-wrapper').description('설치본 HQ 울타리 크론 래퍼');
989
+ fenceWrapperCmd.command('install').description('래퍼 제안 또는 백업 후 원자적 설치')
990
+ .option('--dry-run', '변경 내용만 출력 (기본)')
991
+ .option('--yes', '기존 파일 백업 후 설치')
992
+ .action(async (opts: { dryRun?: boolean; yes?: boolean }) => {
993
+ try {
994
+ if (opts.dryRun && opts.yes) throw new Error('--dry-run and --yes cannot be used together');
995
+ const { getElanousConfigDir } = await import('./elanous-config-dir.js');
996
+ const { installedHqFenceEntry, installHqFenceWrapper, renderHqFenceWrapper, resolveHqFenceBun } = await import('./hq/fence-wrapper.js');
997
+ const configDir = getElanousConfigDir();
998
+ const bun = resolveHqFenceBun();
999
+ const body = renderHqFenceWrapper({ entry: installedHqFenceEntry(), configDir, bun });
1000
+ const result = installHqFenceWrapper(configDir, body, opts.yes === true);
1001
+ if (opts.yes) console.log(`hq-fence installed: ${result.path} · bun: ${bun}${result.backup ? ` · backup: ${result.backup}` : ''}`);
1002
+ else console.log(`hq-fence bun (absolute · cron has no PATH): ${bun}\n${result.preview}`);
1003
+ } catch (error) { console.error(`hq fence-wrapper install: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
1004
+ });
1005
+ fenceWrapperCmd.command('alert <reason>').description('HQ 울타리 실패를 기존 루프 소유자 요청 원장에 적재')
1006
+ .action(async (reason: string) => {
1007
+ try {
1008
+ const { notifyOwners } = await import('./loops/checker.js');
1009
+ const { getElanousConfigDir } = await import('./elanous-config-dir.js');
1010
+ notifyOwners([{ id: `hq-fence:${Date.now()}:${process.pid}`, owner: 'TC', enabled: true, registered: true,
1011
+ state: 'failing', reason }], { root: getElanousConfigDir() });
1012
+ } catch (error) { console.error(`hq fence-wrapper alert: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
1013
+ });
945
1014
  hqCmd.command('fence-audit').description('운영 crontab 의 HQ 울타리 밖 쓰기 잡 목록과 감싼 줄 제안(읽기 전용)')
946
1015
  .option('--json', 'JSON 출력')
947
1016
  .action(async (opts: { json?: boolean }) => {
948
1017
  try {
949
1018
  await hqSink();
950
1019
  const rows = (await import('./hq/fence-audit.js')).hqFenceAudit();
1020
+ const { getElanousConfigDir } = await import('./elanous-config-dir.js');
1021
+ const { repositoryWorktreeCdWarning } = await import('./hq/fence-wrapper.js');
1022
+ const wrapper = _joinPath(getElanousConfigDir(), 'bin', 'hq-fence');
1023
+ if (existsSync(wrapper)) {
1024
+ try {
1025
+ const warning = repositoryWorktreeCdWarning(readFileSync(wrapper, 'utf8'));
1026
+ if (warning) console.error(warning);
1027
+ } catch (error) { console.error(`hq fence-audit: wrapper inspection unavailable: ${error instanceof Error ? error.message : String(error)}`); }
1028
+ }
951
1029
  if (opts.json) await writeStdoutJson(`${JSON.stringify(rows)}\n`);
952
1030
  else if (!rows.length) console.log('hq fence-audit: unfenced 0');
953
1031
  else for (const row of rows) console.log(`${row.raw}\n role: ${row.recommendedRole}\n suggested: ${row.suggestedLine}`);
@@ -967,9 +1045,59 @@ registerSeatRequestsCommands(seatCmd);
967
1045
  seatCmd.command('answer <askId> <answer>').description('자리 질문에 답을 남기고 원래 표면으로 회신 예약')
968
1046
  .action(async (askId: string, answer: string) => {
969
1047
  try {
970
- const { answerSeatAsk } = await import('./seat-dispatch/seat-ask.js');
1048
+ try { await (await import('./domains/standalone-log-sink.js')).registerStandaloneLogSink('seat-answer'); } catch { /* file trail remains available */ }
1049
+ const { debug } = await import('./debug/log.js');
1050
+ const { answerSeatAsk, deliverSeatAnswers, seatAskDeliveryInProgress, seatAskReplyInfo } = await import('./seat-dispatch/seat-ask.js');
971
1051
  answerSeatAsk(askId, answer);
1052
+ const { origin, askedAt, answeredAt } = seatAskReplyInfo(askId);
972
1053
  console.log(`자리 답변 기록: ${askId}`);
1054
+ if (origin.channel !== 'telegram') {
1055
+ debug.log('seat.ask', 'reply-no-target', { id: askId, via: origin.channel });
1056
+ console.log(`전달 대상 없음: ${askId} (${origin.channel})`);
1057
+ return;
1058
+ }
1059
+ const token = process.env.TELEGRAM_BOT_TOKEN?.trim();
1060
+ const elapsedMs = askedAt === null ? null : Math.max(0, answeredAt - askedAt);
1061
+ if (!token) {
1062
+ debug.log('seat.ask', 'reply-failed', { id: askId, via: 'telegram', reason: 'token-missing', elapsedMs });
1063
+ console.log(`텔레그램 토큰 없음 (TELEGRAM_BOT_TOKEN): ${askId} · 회신 대기`);
1064
+ return;
1065
+ }
1066
+ const botId = token.split(':')[0];
1067
+ if (origin.botId && origin.botId !== botId) {
1068
+ debug.log('seat.ask', 'reply-no-target', { id: askId, via: 'telegram', reason: 'bot-mismatch' });
1069
+ console.log(`전달 대상 없음: ${askId} (수신 봇 불일치) · 회신 대기`);
1070
+ return;
1071
+ }
1072
+ try {
1073
+ let sent = false;
1074
+ await deliverSeatAnswers({ askId, channel: 'telegram', botId, send: async (target, text) => {
1075
+ if (target.channel !== 'telegram') throw new Error('seat ask belongs to another surface');
1076
+ const response = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
1077
+ method: 'POST', headers: { 'content-type': 'application/json' },
1078
+ body: JSON.stringify({ chat_id: target.chatId, text, reply_to_message_id: target.messageId,
1079
+ ...(target.threadId === undefined ? {} : { message_thread_id: target.threadId }) }),
1080
+ });
1081
+ const result = await response.json() as { ok?: boolean; description?: string };
1082
+ if (!response.ok || result.ok !== true) throw new Error(result.description ?? `Telegram HTTP ${response.status}`);
1083
+ sent = true;
1084
+ } });
1085
+ if (!sent) {
1086
+ if (seatAskDeliveryInProgress(askId)) {
1087
+ debug.log('seat.ask', 'reply-in-progress', { id: askId, via: 'telegram', reason: 'claimed-by-other-worker' });
1088
+ console.log(`다른 작업자가 전달 중: ${askId}`);
1089
+ } else {
1090
+ debug.log('seat.ask', 'reply-no-target', { id: askId, via: 'telegram', reason: 'not-claimed' });
1091
+ console.log(`전달 대상 없음: ${askId} (회신 대기)`);
1092
+ }
1093
+ return;
1094
+ }
1095
+ debug.log('seat.ask', 'reply-sent', { id: askId, via: 'telegram', elapsedMs });
1096
+ console.log(`텔레그램 회신 전달: ${askId} · 지연 ${elapsedMs === null ? '미상' : `${elapsedMs}ms`}`);
1097
+ } catch (error) {
1098
+ debug.log('seat.ask', 'reply-failed', { id: askId, via: 'telegram', reason: error instanceof Error ? error.message : String(error), elapsedMs });
1099
+ console.log(`텔레그램 회신 실패: ${askId} · 회신 대기`);
1100
+ }
973
1101
  } catch (error) { console.error(`seat answer: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
974
1102
  });
975
1103
  seatCmd.command('loop').requiredOption('--seat <SEAT>', 'MK|OP|TC|UX')
@@ -1170,7 +1298,7 @@ pythonCmd.command('setup').description('elanous venv(~/.local/share/elanous/pyth
1170
1298
 
1171
1299
  program.command('self-update')
1172
1300
  .alias('update')
1173
- .description('설치본은 릴리스로, 체크아웃은 깨끗한 체크아웃으로 갱신하고 승인 시 넥서스 재시작 · `elanous update` 와 같다 · `--auto on` 이면 매일 자동')
1301
+ .description('설치본은 릴리스로, 체크아웃은 깨끗한 체크아웃으로 갱신 · --auto 는 캐너리 자동 판단, --auto on|off|status 는 기존 자동 갱신 서비스 관리')
1174
1302
  .option('--from <checkout>', '설치할 체크아웃 (기본: 설치본은 릴리스, 체크아웃은 현재 체크아웃)')
1175
1303
  .option('--version <version>', '설치본에서 지정한 릴리스 버전 설치 (기본: latest)')
1176
1304
  .option('--restart', '넥서스 재시작 승인')
@@ -1178,9 +1306,15 @@ program.command('self-update')
1178
1306
  .option('--keep <n>', '설치 뒤 남길 최근 판 수(설치본은 current·직전 판, 체크아웃은 current·데몬 판 보호 · 0 이면 정리 안 함)', '3')
1179
1307
  .option('--alert', '실패(exit≠0)를 알림으로도 보냄 — 크론(무인) 실행용')
1180
1308
  .option('--skip-pwa-build', '체크아웃 설치 전 PWA 빌드를 명시적으로 건너뜀')
1181
- .option('--auto <on|off|status>', '자동 갱신 — macOS launchd · Linux systemd 타이머가 매일 04:17 에 `self-update --restart --alert` (크론이 이미 부르면 켜지 않는다)')
1182
- .action(async (opts: { from?: string; version?: string; restart?: boolean; json?: boolean; keep?: string; alert?: boolean; skipPwaBuild?: boolean; auto?: string }) => {
1183
- if (opts.auto !== undefined) {
1309
+ .option('--dev', '판 사이 dev 빌드 설치 — versions/<판>-dev.<sha12> · install.json channel=dev · 이전 versionDir 보존 (사람 승인 · 자동 아님)')
1310
+ .option('--rollback', 'install.json 의 이전 versionDir 로 current 를 되돌린다 (이전이 없으면 거부)')
1311
+ .option('--auto [on|off|status]', '인자 없이: 에지 레일 계획/실행 · on|off|status: 기존 자동 갱신 서비스 관리')
1312
+ .option('--dry-run', '에지 레일 계획만 출력; 설치·되돌림·상태 쓰기 없음')
1313
+ .option('--seat <seat>', '에지 레일 자리 (OP|TC|MK|UX)')
1314
+ .option('--quiet-window', '상주 프로세스 재시작이 가능한 조용한 창이라고 명시')
1315
+ .option('--canary-run-id <id>', '캐너리 성공 런의 고유 ID (독립 검증된 성공 런에서만 입력; 같은 ID 는 중복 적중하지 않음)')
1316
+ .action(async (opts: { from?: string; version?: string; restart?: boolean; json?: boolean; keep?: string; alert?: boolean; skipPwaBuild?: boolean; dev?: boolean; rollback?: boolean; auto?: string | boolean; dryRun?: boolean; seat?: string; quietWindow?: boolean; canaryRunId?: string }) => {
1317
+ if (typeof opts.auto === 'string') {
1184
1318
  if (!['on', 'off', 'status'].includes(opts.auto)) { console.error(`--auto 는 on · off · status 중 하나: ${opts.auto}`); process.exitCode = 2; return; }
1185
1319
  const { runAutoUpdate } = await import('./cli/update-auto.js');
1186
1320
  process.exitCode = (await runAutoUpdate(opts.auto as 'on' | 'off' | 'status')).exitCode;
@@ -1188,9 +1322,9 @@ program.command('self-update')
1188
1322
  }
1189
1323
  const { runUpdateForInstallation } = await import('./cli/self-update.js');
1190
1324
  // ⭐ 한 번 도는 CLI 는 logs.db 싱크를 스스로 붙여야 `debug.log('self-update', …)` 가 저장된다(없으면 조용히 사라진다 · 09-24 실측).
1191
- try { const { registerStandaloneLogSink } = await import('./domains/standalone-log-sink.js'); await registerStandaloneLogSink('self-update'); } catch { /* 관측 실패가 갱신을 막지 않는다 */ }
1325
+ if (!opts.dryRun) try { const { registerStandaloneLogSink } = await import('./domains/standalone-log-sink.js'); await registerStandaloneLogSink('self-update'); } catch { /* 관측 실패가 갱신을 막지 않는다 */ }
1192
1326
  const keep = Number.parseInt(opts.keep ?? '3', 10);
1193
- const result = await runUpdateForInstallation({ ...opts, skipPwaBuild: opts.skipPwaBuild, keep: Number.isFinite(keep) ? keep : 3 }, { cliRoot: REPOSITORY_ROOT });
1327
+ const result = await runUpdateForInstallation({ ...opts, auto: opts.auto === true, quietWindow: opts.quietWindow === true, skipPwaBuild: opts.skipPwaBuild, keep: Number.isFinite(keep) ? keep : 3 }, { cliRoot: REPOSITORY_ROOT });
1194
1328
  process.exitCode = result.exitCode;
1195
1329
  });
1196
1330
 
@@ -4259,6 +4393,12 @@ selfCmd
4259
4393
  .option('--supervise-rounds <n>', '슈퍼바이저 재개 라운드 상한 (기본 3 · 끄려면 --no-supervise)')
4260
4394
  .option('--json', '구조화 출력 {stage, ok, branch, worktree, prUrl?, merged?}')
4261
4395
  .action(async (parts: string[], opts: { featureFile?: string; base?: string; draft?: boolean; openPr?: boolean; autoMerge?: boolean; autoReview?: boolean; maxWait?: string; json?: boolean; plan?: boolean; enhance?: boolean; ground?: boolean; observeOnly?: boolean }) => {
4396
+ if (!isOldDoorInternalCall('self-implement')) {
4397
+ const refused = refuseOldDoor('self-implement');
4398
+ debug.log('harness.entrance', 'old-door-refused', { door: refused.door, caller: refused.caller });
4399
+ ui.error(refused.message);
4400
+ process.exit(refused.exitCode);
4401
+ }
4262
4402
  if (opts.featureFile && parts.length > 0) { ui.error('--feature-file 과 위치 인자 feature 는 함께 줄 수 없다'); process.exit(2); }
4263
4403
  let feature: string;
4264
4404
  try { feature = (opts.featureFile ? readFileSync(opts.featureFile, 'utf8') : parts.join(' ')).trim(); }
@@ -4418,6 +4558,12 @@ const selfOrchestrateCmd = selfCmd
4418
4558
  .option('--help-all', '모든 orchestrate 옵션 표시')
4419
4559
  .action(function (this: Command, parts: string[], opts: { goalFile?: string[]; concurrency?: string; autoMerge?: boolean; autoReview?: boolean; openPr?: boolean; base?: string; teardown?: boolean; resume?: string; board?: boolean; decompose?: boolean; fabricDecompose?: boolean; maxTasks?: string; supervise?: boolean; superviseRounds?: string; json?: boolean }) {
4420
4560
  return (async () => {
4561
+ if (!isOldDoorInternalCall('self-orchestrate')) {
4562
+ const refused = refuseOldDoor('self-orchestrate');
4563
+ debug.log('harness.entrance', 'old-door-refused', { door: refused.door, caller: refused.caller });
4564
+ ui.error(refused.message);
4565
+ process.exit(refused.exitCode);
4566
+ }
4421
4567
  // 위치 인자는 종전처럼 분리하고 파일 입력은 파일당 한 골이다.
4422
4568
  let inputGoals: ReturnType<typeof readSelfOrchestrateGoals>;
4423
4569
  try { inputGoals = readSelfOrchestrateGoals(parts, opts.goalFile); }
@@ -5943,6 +6089,7 @@ agentCmd.hook('preAction', async (_thisCommand, actionCommand) => {
5943
6089
  });
5944
6090
 
5945
6091
  registerCapabilitiesCommand(agentCmd);
6092
+ registerSupervisorMetricsCommand(agentCmd);
5946
6093
 
5947
6094
  agentCmd.command('install-from-docs <tool>')
5948
6095
  .description('공식 설치 문서를 읽고 안전한 설치 줄을 선택한다 — sudo는 사람에게 넘긴다')
@@ -6814,6 +6961,11 @@ const selfDevCmd = program
6814
6961
  // ⭐ `--ask`/`--say` — 발사 절차 넷을 «한 로직»으로. 저작 → 전제 검사 → 발사.
6815
6962
  // ⛔ 여기서 저작한 골 파일을 아래 `--file` 자리에 그대로 넘긴다(새 실행 경로를 만들지 않는다).
6816
6963
  let askAuthoredFile: string | undefined;
6964
+ if (opts.ask !== undefined && !isOldDoorInternalCall('dev-ask')) {
6965
+ const refused = refuseOldDoor('dev-ask');
6966
+ debug.log('harness.entrance', 'old-door-refused', { door: refused.door, caller: refused.caller });
6967
+ throw new DevPipelineError(refused.message);
6968
+ }
6817
6969
  const retirementInput = opts.ask !== undefined
6818
6970
  ? { kind: 'ask' as const, value: opts.ask }
6819
6971
  : opts.say !== undefined
@@ -6896,6 +7048,8 @@ const selfDevCmd = program
6896
7048
  now: () => Date.now(),
6897
7049
  // ⛔ 「대화형인가」는 «두 쪽»을 본다 — 파이프로 몰면 물어도 답이 안 온다.
6898
7050
  isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
7051
+ selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
7052
+ writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
6899
7053
  buildPreflightDeps: buildAskPreflightDeps,
6900
7054
  priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
6901
7055
  recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
@@ -7538,6 +7692,7 @@ missionCmd
7538
7692
  });
7539
7693
 
7540
7694
  registerTasksCommands(program);
7695
+ registerBriefCommands(program);
7541
7696
  registerLabelsCommands(program);
7542
7697
  registerMsgCommands(program);
7543
7698
 
@@ -6,8 +6,9 @@ import { loadIntakeLedger, type IntakeItem } from './items.js';
6
6
  import { readSavedCursorAt } from './collect-telegram-saved.js';
7
7
  import { intakeOutboxDir, kstDay } from './route.js';
8
8
 
9
- export interface DigestEntry { id: string; sources: string[]; url?: string; note?: string; noteName?: string; oneLiner?: string; axis: string; impact?: { fact: string; current: string; action: string } }
10
- export interface IntakeDigest { day: string; absorbed: DigestEntry[]; goals: { fact: string; url?: string }[]; review?: { fact: string; note?: string }[]; grounding: number; release: number; manual: number; savedSilence?: { days: number; lastNewAt: string } }
9
+ export type DigestLensVerdict = '대체 후보' | '보강' | '경쟁 대조';
10
+ export interface DigestEntry { id: string; sources: string[]; url?: string; note?: string; noteName?: string; oneLiner?: string; axis: string; impact?: { verdict: DigestLensVerdict; why: string; target: string } }
11
+ export interface IntakeDigest { day: string; absorbed: DigestEntry[]; goals: { fact: string; url?: string }[]; news?: { title: string; url: string; summary: string[]; implication: string[] }[]; shadowSuggestions?: { fact: string; url?: string; verdict: string }[]; review?: { fact: string; note?: string }[]; grounding: number; release: number; manual: number; savedSilence?: { days: number; lastNewAt: string } }
11
12
 
12
13
  const AXIS_LABEL: Record<string, string> = {
13
14
  video_automation: '영상 자동화', agent_basics: '에이전트 기본', agent_applied: '에이전트 응용', unrelated: '그 밖',
@@ -40,27 +41,32 @@ function readJsonl(file: string): Record<string, unknown>[] {
40
41
  /** Saved Messages silent for more than two days → the digest says so (a quiet 0 must not look like «nothing to do»). */
41
42
  const SAVED_SILENCE_MS = 48 * 3600_000;
42
43
 
44
+ /** A «why» that only names paths (optionally behind a label like «경로:») is evidence, not a reason for us. */
45
+ export function pathOnly(why: string): boolean {
46
+ const rest = why
47
+ .replace(/`?(?:[\w.-]+\/)*[\w.-]+\.[A-Za-z0-9]{1,6}(?::\d+)?`?/g, ' ')
48
+ .replace(/`?(?:[\w.-]+\/)+[\w.-]*`?/g, ' ')
49
+ .replace(/(?:경로|파일|근거|path|file|evidence)\s*[::]?/gi, ' ')
50
+ .replace(/[\s,·:;()[\]\-–—]+/g, '');
51
+ return rest.length < 4;
52
+ }
53
+
43
54
  export function buildIntakeDigest(root: string, day: string, readFile: (p: string) => string | undefined = (p) => (existsSync(p) ? readFileSync(p, 'utf8') : undefined), now: Date = new Date()): IntakeDigest {
44
55
  const items = [...loadIntakeLedger(root).items.values()]
45
56
  .filter((i) => (i.status === 'absorbed' || i.status === 'routed') && kstDay(i.lastSeenAt) === day && i.outputs.some((o) => o.kind === 'note'));
46
57
  const out = intakeOutboxDir(root);
47
58
  const relevant = new Map<string, NonNullable<DigestEntry['impact']>>();
48
- for (const [folder, action] of [
49
- ['goals', '없는 기능의 골 후보를 세운다'],
50
- ['manual', '문서·약속을 현재 동작에 맞게 보강한다'],
51
- ['review', '대조 근거를 추가로 확인한다'],
52
- ['release', '이미 착지한 기능의 바깥 맥락을 릴리스 노트에 반영한다'],
53
- ] as const) {
59
+ // The lens (src/intake-plane/lens.ts) writes its verdicts to outbox/lens/<day>.jsonl; route folders carry none.
60
+ for (const folder of ['lens'] as const) {
54
61
  for (const row of readJsonl(join(out, folder, `${day}.jsonl`))) {
55
62
  if (typeof row.id !== 'string' || relevant.has(row.id)) continue;
56
- const fact = folder === 'release' ? row.title : row.fact;
57
- if (typeof fact !== 'string' || !fact.trim()) continue;
58
- relevant.set(row.id, {
59
- fact,
60
- current: typeof (folder === 'release' ? row.summary : row.current) === 'string'
61
- ? String(folder === 'release' ? row.summary : row.current) : '대조 근거 없음',
62
- action,
63
- });
63
+ const verdict = row.lensVerdict;
64
+ if (verdict !== '대체 후보' && verdict !== '보강' && verdict !== '경쟁 대조') continue;
65
+ const why = typeof row.why === 'string' ? row.why.trim() : '';
66
+ const target = typeof row.target === 'string' ? row.target.trim() : '';
67
+ // A check's fact/current or repo path is evidence, not a lens judgement or a reason for us.
68
+ if (!why || !target || pathOnly(why)) continue;
69
+ relevant.set(row.id, { verdict, why, target });
64
70
  }
65
71
  }
66
72
  const absorbed = items.map((i: IntakeItem): DigestEntry => {
@@ -76,12 +82,24 @@ export function buildIntakeDigest(root: string, day: string, readFile: (p: strin
76
82
  };
77
83
  });
78
84
  const goals = readJsonl(join(out, 'goals', `${day}.jsonl`)).map((g) => ({ fact: String(g.fact ?? ''), ...(g.url ? { url: String(g.url) } : {}) }));
85
+ const lensRows = readJsonl(join(out, 'lens', `${day}.jsonl`));
86
+ const news = lensRows.flatMap((row) =>
87
+ typeof row.title === 'string' && typeof row.url === 'string' && Array.isArray(row.summary) && Array.isArray(row.implication)
88
+ ? [{ title: row.title, url: row.url, summary: row.summary.filter((s): s is string => typeof s === 'string'), implication: row.implication.filter((s): s is string => typeof s === 'string') }]
89
+ : []);
90
+ const shadowSuggestions = lensRows.flatMap((row) =>
91
+ Array.isArray(row.suggestions) ? row.suggestions.flatMap((raw: unknown) => {
92
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return [];
93
+ const suggestion = raw as Record<string, unknown>;
94
+ if (suggestion.status !== '제안' || typeof suggestion.fact !== 'string' || !suggestion.fact.trim()) return [];
95
+ return [{ fact: suggestion.fact, ...(typeof row.url === 'string' ? { url: row.url } : {}), verdict: typeof suggestion.verdict === 'string' ? suggestion.verdict : '판단 필요' }];
96
+ }) : []);
79
97
  const review = readJsonl(join(out, 'review', `${day}.jsonl`)).map((r) => ({ fact: String(r.fact ?? ''), ...(r.note ? { note: String(r.note) } : {}) }));
80
98
  const grounding = readJsonl(join(out, 'grounding.jsonl')).filter((g) => typeof g.at === 'string' && kstDay(g.at) === day).length;
81
99
  const lastNewAt = readSavedCursorAt(root);
82
100
  const silentMs = lastNewAt ? now.getTime() - Date.parse(lastNewAt) : NaN;
83
101
  return {
84
- day, absorbed, goals, review, grounding,
102
+ day, absorbed, goals, ...(news.length ? { news } : {}), ...(shadowSuggestions.length ? { shadowSuggestions } : {}), review, grounding,
85
103
  release: readJsonl(join(out, 'release', `${day}.jsonl`)).length,
86
104
  manual: readJsonl(join(out, 'manual', `${day}.jsonl`)).length,
87
105
  ...(lastNewAt && silentMs > SAVED_SILENCE_MS ? { savedSilence: { days: Math.floor(silentMs / 86_400_000), lastNewAt } } : {}),
@@ -92,7 +110,8 @@ export function buildIntakeDigest(root: string, day: string, readFile: (p: strin
92
110
  export function renderDigestMarkdown(d: IntakeDigest): string {
93
111
  const L: string[] = [`## 📰 오늘의 흡수 요약 (${d.absorbed.length})`, ''];
94
112
  if (d.savedSilence) L.push(`> ⚠️ 텔레그램 «저장된 메시지»에서 새 글을 ${d.savedSilence.days}일째 못 받았다(마지막 새 글 수집 ${kstDay(d.savedSilence.lastNewAt)}) — 저장했는데 안 들어왔다면 저장한 곳(본인 «저장된 메시지»인지)을 확인한다.`, '');
95
- if (!d.absorbed.length) { L.push('오늘 흡수한 것이 없다.', ''); return L.join('\n'); }
113
+ if (!d.absorbed.length) L.push('오늘 흡수한 것이 없다.', '');
114
+ if (!d.absorbed.length && !d.news?.length) return L.join('\n');
96
115
  const byAxis = new Map<string, DigestEntry[]>();
97
116
  for (const e of d.absorbed) (byAxis.get(e.axis) ?? byAxis.set(e.axis, []).get(e.axis)!).push(e);
98
117
  for (const [axis, rows] of byAxis) {
@@ -100,34 +119,72 @@ export function renderDigestMarkdown(d: IntakeDigest): string {
100
119
  for (const e of rows) L.push(`- ${e.noteName ? `[[${e.noteName}]]` : e.url ?? e.id} — ${e.oneLiner ?? '(요약 줄 없음)'}`);
101
120
  L.push('');
102
121
  }
122
+ if (d.news?.length) {
123
+ L.push(`### 📰 관심 뉴스 (${d.news.length})`, '');
124
+ for (const article of d.news.slice(0, 10)) {
125
+ L.push(`- [${article.title}](${article.url})`);
126
+ for (const line of article.summary) L.push(` - ${line}`);
127
+ for (const line of article.implication) L.push(` - 엘라누스 함의: ${line}`);
128
+ }
129
+ L.push('');
130
+ }
103
131
  if (d.goals.length) {
104
132
  L.push(`### 🔴 엘라누스에 없는 것 — 골 후보 (${d.goals.length})`, '');
105
133
  for (const g of d.goals.slice(0, 10)) L.push(`- ${g.fact}${g.url ? ` · [원본](${g.url})` : ''}`);
106
134
  L.push('');
107
135
  }
108
- if (d.review?.length) {
109
- L.push(`### 🟡 사람이 가를 것 — 판단 필요 (${d.review.length})`, '', '> 근거가 실행 코드에 닿지만 «같은 것인가»는 결정론으로 못 가른다 — 노트의 🧭 절에서 판단한다.', '');
110
- for (const r of d.review.slice(0, 10)) L.push(`- ${r.fact}${r.note ? ` · [[${basename(r.note, '.md')}]]` : ''}`);
111
- if (d.review.length > 10) L.push(`- … 외 ${d.review.length - 10}건`);
136
+ if (d.shadowSuggestions?.length) {
137
+ L.push(`### 📰 뉴스 칸 제안 — 그림자, 판 미등록 (${d.shadowSuggestions.length})`, '');
138
+ for (const s of d.shadowSuggestions.slice(0, 10)) L.push(`- [${s.verdict}] ${s.fact}${s.url ? ` · [원본](${s.url})` : ''}`);
112
139
  L.push('');
113
140
  }
141
+ const undecided = d.absorbed.filter((e) => !e.impact).length;
142
+ if (undecided) L.push(`렌즈 판정 못 함 ${undecided} — 원장 \`elanous intake items\``, '');
114
143
  L.push(`> 매뉴얼 후보 ${d.manual} · 릴리스 노트 맥락 ${d.release} · 그라운딩 후보 ${d.grounding} — 흡수 원장 \`elanous intake items\` · 큐 \`<인스턴스>/intake/outbox/\``, '');
115
144
  return L.join('\n');
116
145
  }
117
146
 
118
147
  /** 텔레그램 — 흡수 렌즈가 대조한 항목만 SCQA 짧은 판으로 낸다. */
119
148
  export function renderDigestTelegram(d: IntakeDigest, _opts: { vaultRoot?: string; notePath?: string } = {}): string {
149
+ // «Touching» is decided by the lens verdict alone; a missing note summary only changes how S reads (ACP must-fix).
120
150
  const touching = d.absorbed.filter((e) => e.impact);
121
151
  const L = [`흡수 ${d.absorbed.length} → 우리에게 닿는 것 ${touching.length}`];
122
- if (!touching.length) return L[0];
123
- for (const e of touching.slice(0, 3)) {
152
+ // 관심 뉴스는 최대 셋 — 기사마다 S(요약 첫 줄) · A(엘라누스 함의 첫 줄) · 링크를 한 덩어리로(NEWS-INTAKE).
153
+ for (const article of (d.news ?? []).slice(0, 3)) {
154
+ L.push(`📰 ${article.title}`);
155
+ if (article.summary[0]) L.push(`S: ${article.summary[0]}`);
156
+ if (article.implication[0]) L.push(`A: ${article.implication[0]}`);
157
+ L.push(article.url);
158
+ }
159
+ if (d.shadowSuggestions?.length) L.push(`뉴스 칸 제안 ${d.shadowSuggestions.length}건 (그림자·판 미등록): ${d.shadowSuggestions.slice(0, 3).map((s) => `[${s.verdict}] ${s.fact}${s.url ? ` ${s.url}` : ''}`).join(' · ')}`);
160
+ if (!touching.length) return L.join('\n');
161
+ // At most three items are shown, each as its own S·C·A·link block so context and source stay paired;
162
+ // a later item sharing (verdict, target) says «위와 같은 행동» instead of repeating the A sentence (ACP must-fix).
163
+ // S must be the note's own summary: items without one still count as touching but are not shown (ACP must-fix).
164
+ const shownItems = touching.filter((e) => e.oneLiner?.trim()).slice(0, 3);
165
+ const actionSeen = new Set<string>();
166
+ const actionsUsed = new Set<string>();
167
+ for (const e of shownItems) {
168
+ const impact = e.impact!;
169
+ const key = `${impact.verdict}\u0000${impact.target}`;
170
+ const base = impact.verdict === '대체 후보' ? `${impact.target} lite Pod 실증 제안`
171
+ : impact.verdict === '보강' ? `칸 ${impact.target} 에 근거 추가`
172
+ : `${impact.target} 비교표 갱신`;
173
+ // Every item keeps its own concrete action; a repeat of (verdict, target) names which item it is, so no two A lines match.
174
+ const label = (e.oneLiner?.trim() || impact.why).slice(0, 24);
175
+ let action = actionSeen.has(key) ? `${base} — «${label}» 근거로` : base;
176
+ // Two identical labels still differ by their position in the list.
177
+ if (actionsUsed.has(action)) action = `${action} (${shownItems.indexOf(e) + 1})`;
178
+ actionsUsed.add(action);
179
+ actionSeen.add(key);
124
180
  L.push('',
125
- `S 무엇: ${e.impact!.fact}`,
126
- `C 우리에게 왜: ${e.impact!.current}`,
127
- `A 그래서 무엇을 하나: ${e.impact!.action}`,
181
+ `S 무엇: ${e.oneLiner?.trim() || '노트 한 줄 요약 없음'}`,
182
+ `C 우리에게 왜: ${impact.why}`,
183
+ `A 그래서 무엇을 하나: ${action}`,
128
184
  `🔗 원문 링크: ${e.url?.trim() || '링크 없음'}`,
129
185
  );
130
186
  }
131
- if (d.absorbed.length > touching.length) L.push('', `그 밖 ${d.absorbed.length - touching.length}건 · 닿지 않음`);
187
+ if (touching.length > shownItems.length) L.push('', `닿는 것 ${touching.length - shownItems.length}건 더(요약 없는 것 포함) · 원장 \`elanous intake items\``);
188
+ if (d.absorbed.length > touching.length) L.push('', `그 밖 ${d.absorbed.length - touching.length}건 · 참고`);
132
189
  return L.join('\n');
133
190
  }