elanous 0.2.6 → 0.2.8

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 (517) hide show
  1. package/.env.example +10 -7
  2. package/README.md +4 -0
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{3995-bee512a7063036ce.js → 2375-cb6debea56cce4fb.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +25 -0
  16. package/apps/pwa/out/_next/static/chunks/{8d0d9faf-97887ff99713b84e.js → 2ea96958-e8c7e112de50b067.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/{5329.8b7e4bca684b6eec.js → 3403.4bc97b4066945a94.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{7633.0654fe6ea259c1ee.js → 4323.c5dfb6f503304775.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/4836-3084c58c1725a40b.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{2984-977cfa339fcd65a5.js → 5080-1613752891fcadb4.js} +3 -3
  24. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{763-7d0e1913b5074e98.js → 5791-bb82743fa6299562.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/{4240-7153881b0b377306.js → 6062-73e68343a9814f6a.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/{91ff6dda-3b33d42d20657429.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8894-7317998f6cb97d8c.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9454-a3e0953307216c58.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/approvals/page-9aa47b0bc6d570ff.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f4d2ecbbae6088d6.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/board/page-2053e49930c82748.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/page-d4b6df905f185055.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-a70ba27c33003dd0.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-186fc6952f027acc.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/consult/page-18166f885d831d3e.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/control/page-1c9d6cfe68b121c2.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/design-check/page-cbbe03c0da7b081a.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/editor/page-c108ff1fdb665c97.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/exec/page-147a328753d983e2.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/field/page-799395a9df7d95aa.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/intake/page-6a8158b71d1fe9d7.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/layout-9567560270857531.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/live/page-e7ed3d010153d818.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/market/page-c0c0d19d51342d3e.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2e002ad8faa43291.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/morning/page-b672e02e4bec8deb.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/not-found-1ba4a5d857276334.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/observatory/page-9db2226f38c542fb.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/page-70ee65f5f7a151dc.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0bb8e43203efb23b.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-092e1bcf27d751cc.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/sessions/page-eb52580c4b75b905.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7464c1987dd76e6d.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/settings/page-e573437b0a1c728f.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-294300625e49e4d3.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/setup/page-085847b088675978.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/share/page-9fe9d38c36999eb4.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/showroom/page-d8ab4d1489223459.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6141f67f531d8b6a.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/term/page-295a02b1026b8255.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/trace/page-1eb9a0e1e054209d.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/vault/page-82efa177a30f3741.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d0be51cec4f62606.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/workflows/page-2e367075ffdbc062.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/workspace/page-647ed2b66c1d49f1.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ba058c56e38f2792.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{webpack-37b8bf78a3c6eec5.js → webpack-e5bea36f183b25e6.js} +1 -1
  95. package/apps/pwa/out/_next/static/css/5ef72a618a8994f3.css +1 -0
  96. package/apps/pwa/out/_next/static/lywc8m_HDzH9MKSDQhyEj/_buildManifest.js +1 -0
  97. package/apps/pwa/out/approvals/index.html +1 -1
  98. package/apps/pwa/out/approvals/index.txt +22 -22
  99. package/apps/pwa/out/autopilot/index.html +1 -1
  100. package/apps/pwa/out/autopilot/index.txt +22 -22
  101. package/apps/pwa/out/board/index.html +1 -1
  102. package/apps/pwa/out/board/index.txt +22 -22
  103. package/apps/pwa/out/botlab/index.html +1 -1
  104. package/apps/pwa/out/botlab/index.txt +21 -21
  105. package/apps/pwa/out/bots/index.html +1 -1
  106. package/apps/pwa/out/bots/index.txt +21 -21
  107. package/apps/pwa/out/chat/index.html +1 -1
  108. package/apps/pwa/out/chat/index.txt +21 -21
  109. package/apps/pwa/out/consult/index.html +1 -0
  110. package/apps/pwa/out/consult/index.txt +32 -0
  111. package/apps/pwa/out/control/index.html +1 -1
  112. package/apps/pwa/out/control/index.txt +22 -22
  113. package/apps/pwa/out/design-check/index.html +1 -1
  114. package/apps/pwa/out/design-check/index.txt +22 -22
  115. package/apps/pwa/out/editor/index.html +1 -1
  116. package/apps/pwa/out/editor/index.txt +22 -22
  117. package/apps/pwa/out/exec/index.html +1 -0
  118. package/apps/pwa/out/exec/index.txt +32 -0
  119. package/apps/pwa/out/field/index.html +1 -0
  120. package/apps/pwa/out/field/index.txt +32 -0
  121. package/apps/pwa/out/healthz +1 -1
  122. package/apps/pwa/out/index.html +1 -1
  123. package/apps/pwa/out/index.txt +21 -21
  124. package/apps/pwa/out/intake/index.html +1 -1
  125. package/apps/pwa/out/intake/index.txt +22 -22
  126. package/apps/pwa/out/live/index.html +1 -1
  127. package/apps/pwa/out/live/index.txt +22 -22
  128. package/apps/pwa/out/market/index.html +1 -1
  129. package/apps/pwa/out/market/index.txt +21 -21
  130. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  131. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  132. package/apps/pwa/out/morning/index.html +1 -1
  133. package/apps/pwa/out/morning/index.txt +22 -22
  134. package/apps/pwa/out/observatory/index.html +1 -1
  135. package/apps/pwa/out/observatory/index.txt +22 -22
  136. package/apps/pwa/out/reflection/index.html +1 -1
  137. package/apps/pwa/out/reflection/index.txt +22 -22
  138. package/apps/pwa/out/scheduler/index.html +1 -1
  139. package/apps/pwa/out/scheduler/index.txt +22 -22
  140. package/apps/pwa/out/sessions/index.html +1 -1
  141. package/apps/pwa/out/sessions/index.txt +21 -21
  142. package/apps/pwa/out/settings/devices/index.html +1 -1
  143. package/apps/pwa/out/settings/devices/index.txt +22 -22
  144. package/apps/pwa/out/settings/index.html +1 -1
  145. package/apps/pwa/out/settings/index.txt +22 -22
  146. package/apps/pwa/out/setup/done/index.html +1 -1
  147. package/apps/pwa/out/setup/done/index.txt +22 -22
  148. package/apps/pwa/out/setup/index.html +1 -1
  149. package/apps/pwa/out/setup/index.txt +22 -22
  150. package/apps/pwa/out/share/index.html +1 -1
  151. package/apps/pwa/out/share/index.txt +22 -22
  152. package/apps/pwa/out/showroom/index.html +1 -1
  153. package/apps/pwa/out/showroom/index.txt +21 -21
  154. package/apps/pwa/out/tasks/index.html +1 -1
  155. package/apps/pwa/out/tasks/index.txt +22 -22
  156. package/apps/pwa/out/term/index.html +1 -1
  157. package/apps/pwa/out/term/index.txt +22 -22
  158. package/apps/pwa/out/trace/index.html +1 -1
  159. package/apps/pwa/out/trace/index.txt +22 -22
  160. package/apps/pwa/out/vault/index.html +1 -1
  161. package/apps/pwa/out/vault/index.txt +22 -22
  162. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  163. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  164. package/apps/pwa/out/workflows/index.html +1 -1
  165. package/apps/pwa/out/workflows/index.txt +22 -22
  166. package/apps/pwa/out/workspace/index.html +1 -1
  167. package/apps/pwa/out/workspace/index.txt +22 -22
  168. package/apps/pwa/out/worktrees/index.html +1 -1
  169. package/apps/pwa/out/worktrees/index.txt +22 -22
  170. package/bin/elanous.cjs +107 -0
  171. package/graphs/field/field-feed.yaml +24 -0
  172. package/graphs/field/recipes.yaml +12 -0
  173. package/graphs/landing/landing-heal.yaml +3 -1
  174. package/graphs/landing/recipes.yaml +3 -0
  175. package/graphs/release/recipes.yaml +10 -0
  176. package/graphs/release/release-loop.yaml +10 -3
  177. package/graphs/test-diet/recipes.yaml +9 -0
  178. package/graphs/test-diet/test-diet.yaml +22 -0
  179. package/package.json +6 -5
  180. package/persona-presets/_index.yaml +10 -0
  181. package/persona-presets/_schema.json +146 -0
  182. package/persona-presets/dana.yaml +26 -0
  183. package/persona-presets/haru.yaml +27 -0
  184. package/persona-presets/kai.yaml +27 -0
  185. package/persona-presets/leo.yaml +27 -0
  186. package/persona-presets/mira.yaml +30 -0
  187. package/persona-presets/nari.yaml +27 -0
  188. package/persona-presets/sora.yaml +27 -0
  189. package/persona-presets/yuna.yaml +27 -0
  190. package/plugins/card-followup/README.md +13 -4
  191. package/plugins/card-followup/graphs/card-followup.yaml +3 -1
  192. package/plugins/card-followup/graphs/recipes.yaml +5 -1
  193. package/plugins/card-followup/graphs/run-step.ts +122 -18
  194. package/plugins/card-followup/graphs/sales-strategy.ts +173 -0
  195. package/plugins/card-followup/plugin.json +1 -1
  196. package/plugins/doc-draft/README.md +13 -0
  197. package/plugins/doc-draft/examples/brief-sample.json +8 -0
  198. package/plugins/doc-draft/graphs/doc-draft.yaml +14 -0
  199. package/plugins/doc-draft/graphs/recipes.yaml +9 -0
  200. package/plugins/doc-draft/graphs/run-step.ts +113 -0
  201. package/plugins/doc-draft/plugin.json +24 -0
  202. package/plugins/geo-check/README.md +3 -1
  203. package/plugins/geo-check/graphs/run-step.ts +58 -13
  204. package/plugins/geo-check/plugin.json +1 -1
  205. package/plugins/job-coach/.codex-plugin/plugin.json +1 -1
  206. package/plugins/job-coach/README.md +1 -1
  207. package/plugins/job-coach/graphs/run-step.ts +2 -2
  208. package/plugins/job-coach/plugin.json +1 -1
  209. package/plugins/job-coach/plugin.ts +1 -1
  210. package/scripts/affinity/endcard.sh +3 -2
  211. package/scripts/affinity/reframe.sh +3 -1
  212. package/scripts/ci-public-export-leak-gate.ts +48 -0
  213. package/scripts/codex-quota-alert.ts +122 -258
  214. package/scripts/coord-tracks.json +4 -4
  215. package/scripts/field-feed/deliver-node.ts +57 -0
  216. package/scripts/field-feed/feed-node.ts +67 -0
  217. package/scripts/field-feed/lib.ts +164 -0
  218. package/scripts/field-feed/reel-node.ts +24 -0
  219. package/scripts/field-feed/start.ts +62 -0
  220. package/scripts/fixtures/vflow-sample.ndjson +6 -0
  221. package/scripts/install.sh +109 -21
  222. package/scripts/landing-heal/clean-checkout.ts +114 -0
  223. package/scripts/landing-heal/run-mission.ts +38 -3
  224. package/scripts/lib/pwa-scenarios/scenarios.ts +2 -1
  225. package/scripts/persona-presets/lint.ts +79 -0
  226. package/scripts/public-export.ts +8 -4
  227. package/scripts/release-loop/baseline-from-logs.ts +92 -0
  228. package/scripts/release-loop/checklist-gate-node.ts +2 -2
  229. package/scripts/release-loop/env-known-failures.ts +31 -0
  230. package/scripts/release-loop/gate-node.ts +108 -22
  231. package/scripts/release-loop/known-issues-node.ts +159 -0
  232. package/scripts/release-loop/npm-publish-node.ts +124 -0
  233. package/scripts/release-loop/ops-upgrade-node.ts +95 -0
  234. package/scripts/release-loop/publish-node.ts +23 -1
  235. package/scripts/release-loop/release-readiness.ts +58 -0
  236. package/scripts/release-loop/shard-plan.ts +17 -0
  237. package/scripts/release-loop/unattended-release.ts +93 -0
  238. package/scripts/storyboard/storyboard.ts +167 -0
  239. package/scripts/test-diet/lib.ts +88 -0
  240. package/scripts/test-diet/node.ts +102 -0
  241. package/scripts/ux/measure-first-text.ts +102 -0
  242. package/scripts/vflow-collect.ts +20 -7
  243. package/scripts/vflow-search.ts +73 -0
  244. package/scripts/video-free-line-test-walker.ts +36 -0
  245. package/scripts/video-pipeline.ts +2 -2
  246. package/skills/explainer-video/SKILL.md +12 -9
  247. package/skills/explainer-video/engine/build.mjs +1 -1
  248. package/skills/explainer-video/engine/reel.mjs +138 -31
  249. package/skills/explainer-video/engine/reel.sh +2 -1
  250. package/skills/explainer-video/examples/elanous-0.2.5/script.json +1 -1
  251. package/skills/grill-me/SKILL.md +1 -1
  252. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +1 -1
  253. package/src/a2a/server.ts +2 -0
  254. package/src/acp/auth-methods.ts +30 -0
  255. package/src/acp/elanous-aware-peers.ts +30 -0
  256. package/src/acp/server.ts +96 -20
  257. package/src/agent/monad-agent-turn.ts +25 -6
  258. package/src/agent/shared-app-tools.ts +5 -3
  259. package/src/agent-substrate/review-intent.ts +6 -2
  260. package/src/agent-substrate/shard-boundary-intent.ts +70 -0
  261. package/src/auth/github-app-token.ts +4 -1
  262. package/src/autopilot/track-agent-shadow.ts +151 -0
  263. package/src/autopilot/track-agent.ts +23 -3
  264. package/src/boot/acp-server-help.ts +16 -0
  265. package/src/boot/daemon-prompt-turn.ts +31 -10
  266. package/src/boot/daemon-tools/index.ts +7 -1
  267. package/src/budget/codex-credit-pace.ts +84 -0
  268. package/src/budget/codex-credit-plan.ts +154 -0
  269. package/src/budget/codex-reset-credit-state.ts +2 -0
  270. package/src/channel-import/detect.ts +191 -0
  271. package/src/channel-import/run.ts +111 -0
  272. package/src/chat/chat-cli.ts +4 -1
  273. package/src/chat/short-question.ts +40 -0
  274. package/src/cli/agent-cli.ts +24 -15
  275. package/src/cli/ask-bare.ts +42 -0
  276. package/src/cli/cli-user-error.ts +25 -0
  277. package/src/cli/codex-credit-plan-view.ts +25 -0
  278. package/src/cli/config-test-sync.ts +4 -0
  279. package/src/cli/decisions-cli.ts +13 -3
  280. package/src/cli/dependence-gauge.ts +237 -0
  281. package/src/cli/doctor-bundle.ts +128 -0
  282. package/src/cli/doctor-cli.ts +41 -1
  283. package/src/cli/doctor-local-llm.ts +95 -0
  284. package/src/cli/doctor-modes.ts +48 -0
  285. package/src/cli/import-cli.ts +60 -0
  286. package/src/cli/intake-cli.ts +12 -2
  287. package/src/cli/intake-source-cli.ts +58 -0
  288. package/src/cli/machine-cli.ts +23 -0
  289. package/src/cli/mcp-login.ts +13 -4
  290. package/src/cli/msg-cli.ts +137 -0
  291. package/src/cli/persona-cli.ts +116 -0
  292. package/src/cli/plugin-cli.ts +25 -0
  293. package/src/cli/pr-cli.ts +36 -0
  294. package/src/cli/provider-cli.ts +5 -0
  295. package/src/cli/release-cli.ts +50 -8
  296. package/src/cli/release-run-if-ready.ts +48 -0
  297. package/src/cli/setup-cli.ts +27 -6
  298. package/src/cli/setup-recommend.ts +8 -0
  299. package/src/cli/skills-cli.ts +173 -0
  300. package/src/cli/start-cli.ts +13 -4
  301. package/src/cli/usage-cli.ts +11 -1
  302. package/src/codex/setup.ts +37 -16
  303. package/src/dashboard/index.ts +18 -2
  304. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -2
  305. package/src/dashboard/slash-runtime/help-from-registry.ts +4 -2
  306. package/src/decisions/decision-cards.ts +291 -0
  307. package/src/decisions/decision-ledger.ts +5 -2
  308. package/src/decisions/discord-decision-cards.ts +133 -0
  309. package/src/decisions/telegram-decision-cards.ts +100 -0
  310. package/src/directives/version-at.ts +77 -0
  311. package/src/discord.ts +73 -6
  312. package/src/domains/core-tools.ts +37 -14
  313. package/src/domains/outbound-alert.ts +94 -12
  314. package/src/domains/repeated-failure.ts +1 -1
  315. package/src/error-report/report.ts +200 -0
  316. package/src/exec-requests/planner.ts +146 -0
  317. package/src/exec-requests/runner.ts +378 -0
  318. package/src/exec-requests/store.ts +78 -0
  319. package/src/field/field-feed-auto.ts +48 -0
  320. package/src/field/field-media.ts +8 -3
  321. package/src/field/field-reel.ts +203 -0
  322. package/src/grok/credential.ts +7 -5
  323. package/src/harness/aside-run-status.ts +33 -0
  324. package/src/harness/browser-verify.ts +48 -17
  325. package/src/harness/harness-cli-command.ts +25 -3
  326. package/src/harness/image-load-state.ts +21 -0
  327. package/src/harness/process-garbage.ts +45 -0
  328. package/src/hooks/error-report.ts +210 -0
  329. package/src/hooks/receiver.ts +41 -1
  330. package/src/import/apply.ts +128 -0
  331. package/src/import/plan.ts +197 -0
  332. package/src/index.ts +168 -21
  333. package/src/input-core/text-entry.ts +13 -5
  334. package/src/instance/leader.ts +13 -1
  335. package/src/intake-plane/collect-github.ts +5 -3
  336. package/src/intake-plane/collect-telegram-saved.ts +15 -3
  337. package/src/intake-plane/discord-seat-work.ts +56 -0
  338. package/src/intake-plane/intake-sources.ts +202 -0
  339. package/src/intake-plane/items.ts +28 -12
  340. package/src/intake-plane/seat-answer.ts +96 -0
  341. package/src/intake-plane/seat-doc-route.ts +221 -0
  342. package/src/intake-plane/submit-intake-work.ts +9 -1
  343. package/src/intake-plane/telegram-seat-work.ts +72 -0
  344. package/src/llm/model-defaults.ts +24 -1
  345. package/src/llm.ts +5 -4
  346. package/src/machines/machine-ledger.ts +127 -0
  347. package/src/market/pack-internal-refs.ts +28 -0
  348. package/src/market/publish.ts +31 -4
  349. package/src/maturity/feature-maturity.ts +65 -0
  350. package/src/model-tier/turn-tier.ts +24 -0
  351. package/src/msg/msg-store.ts +149 -0
  352. package/src/native-tool-catalog.ts +2 -1
  353. package/src/nexus/api/chat-fast-path-config.ts +28 -0
  354. package/src/nexus/api/consult-requests.ts +128 -0
  355. package/src/nexus/api/discord-trigger-bot.ts +3 -0
  356. package/src/nexus/api/error-reports.ts +108 -0
  357. package/src/nexus/api/exec-requests.ts +51 -0
  358. package/src/nexus/api/field-uploads.ts +40 -3
  359. package/src/nexus/api/graph-approvals-feed.ts +140 -0
  360. package/src/nexus/api/graph-approvals.ts +71 -4
  361. package/src/nexus/api/http-server.ts +82 -8
  362. package/src/nexus/api/outbound-report.ts +7 -0
  363. package/src/nexus/api/running-runs-background.ts +68 -0
  364. package/src/nexus/api/running-runs-child.ts +6 -0
  365. package/src/nexus/api/seat-requests.ts +254 -0
  366. package/src/nexus/api/share-captures.ts +91 -0
  367. package/src/nexus/api/skill-problems.ts +56 -0
  368. package/src/nexus/api/terminals.ts +24 -8
  369. package/src/nexus/api/trace-run-scan.ts +37 -0
  370. package/src/nexus/api/trace.ts +19 -3
  371. package/src/nexus/index.ts +28 -1
  372. package/src/nexus/setup-status.ts +11 -7
  373. package/src/notify/llm-budget-alert.ts +16 -10
  374. package/src/oauth/browser-availability.ts +14 -0
  375. package/src/oauth/codex-account-rotation.ts +26 -4
  376. package/src/oauth/codex-account-store.ts +20 -2
  377. package/src/oauth/codex-browser-login.ts +173 -0
  378. package/src/oauth/codex-quota-policy.ts +16 -0
  379. package/src/oauth/codex.ts +4 -1
  380. package/src/oauth/fallback-chain.ts +5 -5
  381. package/src/oauth/store.ts +42 -5
  382. package/src/onboarding/continue-here.ts +34 -0
  383. package/src/onboarding/entry-hints.ts +8 -0
  384. package/src/onboarding/full-screen-io.ts +35 -3
  385. package/src/onboarding/help/skills.md +1 -1
  386. package/src/onboarding/non-interactive.ts +1 -0
  387. package/src/onboarding/subscription-hint.ts +27 -0
  388. package/src/onboarding/web-first.ts +90 -0
  389. package/src/onboarding.ts +287 -26
  390. package/src/persona/presets.ts +105 -0
  391. package/src/plugins/maker/node-install.ts +92 -0
  392. package/src/plugins/maker/node-maker.ts +139 -0
  393. package/src/plugins/maker/plugin-maker.ts +19 -7
  394. package/src/policy/llm-policy.ts +268 -0
  395. package/src/prompt-library/session-guidance.ts +7 -1
  396. package/src/prompt-library/universal-preamble.ts +2 -2
  397. package/src/relay/relay-cli.ts +20 -0
  398. package/src/relay/relay-server.ts +220 -0
  399. package/src/release-loop/checklist.ts +37 -13
  400. package/src/self-dev/decompose.ts +1 -0
  401. package/src/self-dev/dev-pipeline.ts +6 -3
  402. package/src/self-dev/orchestrate.ts +18 -11
  403. package/src/self-dev/run-record-mirror.ts +44 -0
  404. package/src/self-dev/run-store.ts +12 -3
  405. package/src/self-implement/harness-policy-gates.ts +4 -1
  406. package/src/self-implement/report-origin.ts +12 -1
  407. package/src/session/chat.ts +17 -5
  408. package/src/shell-env-bootstrap.ts +44 -7
  409. package/src/skills/connect-claude-plugin.ts +142 -0
  410. package/src/skills/connect.ts +70 -0
  411. package/src/skills/index.ts +29 -1
  412. package/src/skills/repair.ts +124 -0
  413. package/src/skills/runner.ts +11 -2
  414. package/src/skills/shared-agent-skill-roots.ts +25 -0
  415. package/src/skills/trigger-extract.ts +1 -1
  416. package/src/steward/failure-streak.ts +78 -0
  417. package/src/steward/steward-cards.ts +24 -0
  418. package/src/steward/triage-budget.ts +127 -0
  419. package/src/steward/triage-plan.ts +75 -0
  420. package/src/steward/triage.ts +244 -42
  421. package/src/task-cards/card-store.ts +1 -1
  422. package/src/task-orchestrator/surfaces/pod-command-job.ts +16 -8
  423. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  424. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +68 -0
  425. package/src/task-orchestrator/surfaces/self-implement-pod.ts +78 -4
  426. package/src/telegram-commands.ts +13 -0
  427. package/src/telegram.ts +72 -2
  428. package/src/tool-runtime/elanous-skills-list-runtime.ts +3 -3
  429. package/src/tool-runtime/self-cognition-runtimes.ts +160 -2
  430. package/src/user-config.ts +189 -15
  431. package/src/version/packed-revision.json +1 -1
  432. package/src/video-pipeline/recipes/character.ts +42 -5
  433. package/src/video-pipeline/recipes/ffmpeg.ts +1 -1
  434. package/src/video-pipeline/recipes/free-line.ts +16 -3
  435. package/src/video-pipeline/recipes/remote.ts +7 -1
  436. package/src/video-pipeline/vflow-reference.ts +109 -0
  437. package/apps/pwa/out/_next/static/chunks/1169-696263ac7af8c4d4.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/1883.c91a2648af4842fd.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/1947-9d64872eeb9cfdec.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/2808-dc06482994b40f70.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/3165-95515ca5f299a120.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/3190-e9282753e7ebde85.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/4259-99614149577e77cb.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/4283-329eabeaf233e6cd.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/4328-cb5058b1acc2de5e.js +0 -25
  446. package/apps/pwa/out/_next/static/chunks/4801-ecee6ef62b349b18.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/5110-8058791dd25a2e14.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/5330-c41e9670f594c38f.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/5423-e95fd125d1794349.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/5478-b5eae07dc79ea619.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/5787-96ee6642b9a661e5.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/6448-79d72368589f98bc.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/6522-9866c002b5531836.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/6729-b4a558b7aa891e0c.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/6969-cb03f9410b7d2e03.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/7007-3b9861091bb8dd21.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/7930-8dc7e20fc6fc19ca.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/8071-187edbc22a86741f.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/8198-d4101ad70cb9a579.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/8250.4a2c5553a07cdf47.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/8293-123b91e7b0330dc0.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/8296-d6d5d87dfa911d41.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/8305-603963c33ee8eec3.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/8612-4a0066f20951b8fd.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/9181-cf4e1b61c4783f92.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/9262-26c2ecbd5a67e4a2.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/9328-45abdebce4fbecb7.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/9355-dbc67205adf8745f.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/9763.255b90dd69875689.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/9933-66d31ec25c0231af.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-bd06fb55f4da0381.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4e586142da455a25.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-889ad5cddcf45b0d.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/board/page-47ba401d56572c27.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/botlab/page-0b54f9c83458e038.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/bots/page-4fcc296ef6c8ed90.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/chat/page-fe9fda494a87f4e5.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/control/page-f9642e25ce129590.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e1063e8ba5f3e2e7.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/editor/page-9d0df30027d8aa9d.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/healthz/route-bd06fb55f4da0381.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/intake/page-d97adf2c9455b8d0.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/layout-236b80d202110362.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/live/page-21a30f35f1a276ad.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/market/page-b1a5be357c4fa25d.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1705a60303f7f573.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/morning/page-76b337c11ad0e237.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/not-found-7c0f85fbb56f64c6.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/observatory/page-65ca16b20617b44d.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/page-e7f9b8fc29411c1d.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/reflection/page-92ea6213d1aeec04.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a913a005aacb5476.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2d78804a40dfdef6.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-08a99148e780ac00.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/settings/page-deb674e7ed36f815.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-49f8de0534d192d7.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/setup/layout-bd06fb55f4da0381.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/setup/page-ba162a28d2176e18.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/share/page-1ff1a37b550ab41a.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/showroom/page-ccaa698f56c0fbdb.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/tasks/page-53b944082de1d7db.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/term/page-9b70adf1552789bf.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/trace/page-30d482aa63241fe8.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/vault/page-aecf786f54651d8a.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6ab9b62c7b6e08f2.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/workflows/page-08949735455e0c9a.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/workspace/page-a1479005234a46c2.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3890e90bd232732.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/beb5cf10-9adcc10b83930090.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/framework-d68d41c88e05c801.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/main-app-11c63971b7a9593b.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/main-d09452353bd0d9cc.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/pages/_app-184d727cebeca767.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/pages/_error-21bbbbac99b720b1.js +0 -1
  515. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +0 -1
  516. package/apps/pwa/out/_next/static/qMI0jnlZaBjjm4aIDYNGM/_buildManifest.js +0 -1
  517. /package/apps/pwa/out/_next/static/{qMI0jnlZaBjjm4aIDYNGM → lywc8m_HDzH9MKSDQhyEj}/_ssgManifest.js +0 -0
package/src/index.ts CHANGED
@@ -9,6 +9,9 @@ import { LOGS_SINCE_OPTION, registerLogsCommands } from './cli/logs-cli.js';
9
9
  import { registerDocsCommands } from './cli/docs-cli.js';
10
10
  import { registerA2ACommands } from './cli/a2a-cli.js';
11
11
  import { registerPluginCommands } from './cli/plugin-cli.js';
12
+ import { registerConnectCommand, registerSkillsCommands } from './cli/skills-cli.js';
13
+ import { registerImportCommand } from './cli/import-cli.js';
14
+ import { registerPersonaCommands } from './cli/persona-cli.js';
12
15
  import { registerFleetCommands } from './cli/fleet-cli.js';
13
16
  import { readPipedStdin } from './cli/piped-stdin.js';
14
17
  import { writeStdoutJson } from './cli/stdout-json.js';
@@ -62,6 +65,7 @@ import { registerModelWatchCommand } from './cli/model-watch-cli.js';
62
65
  import { registerIntakeCommands } from './cli/intake-cli.js';
63
66
  import { registerTasksCommands } from './cli/tasks-cli.js';
64
67
  import { registerLabelsCommands } from './cli/labels-cli.js';
68
+ import { registerMsgCommands } from './cli/msg-cli.js';
65
69
  import { registerDoctorCommand } from './cli/doctor-cli.js';
66
70
  import { registerProviderCommands } from './cli/provider-cli.js';
67
71
  export { buildCodexAccountImportGuidance, setCodexAccountLogSinkModuleForTesting } from './cli/provider-cli.js';
@@ -74,6 +78,7 @@ import { registerGraphCommands } from './graph-runner/graph-cli.js';
74
78
  import { registerLoopCommands } from './loops/loop-cli.js';
75
79
  import { registerCardCommand } from './task-cards/card-cli.js';
76
80
  import { registerLaunchHeadCommands } from './launch-head/launch-head-cli.js';
81
+ import { acpServerHelpText } from './boot/acp-server-help.js';
77
82
  // IMPORTANT: parse `--config-dir <dir>` + `--test-state-dir <dir>`
78
83
  // BEFORE Commander loads — the resolvers are read at module-init
79
84
  // time by several config-touching imports below, so the override
@@ -95,7 +100,8 @@ import type { AdPipelinePlan, AdPipelineResult } from './ad-pipeline/run.js';
95
100
  import type { AcpPermissionApprover } from './acp/client.js';
96
101
  import { runGitCommand } from './git-fs/runner.js';
97
102
  import { debug, redactSecretText, redactSecrets } from './debug/log.js';
98
- import { HarnessCliInputError, installHarnessCliCommand, type HarnessAskSayChildLlmOptions, type HarnessAskSayOptions, type HarnessPlanOptions } from './harness/harness-cli-command.js';
103
+ import { installHarnessCliCommand, type HarnessAskSayChildLlmOptions, type HarnessAskSayOptions, type HarnessPlanOptions } from './harness/harness-cli-command.js';
104
+ import { formatCliUserError, isCliUserError } from './cli/cli-user-error.js';
99
105
  import { dispatchSolveMission } from './skills/tools/solve-mission.js';
100
106
  import { performBrowserAction, type BrowserActionDeps, type BrowserActionResult } from './harness/browser-act.js';
101
107
  import { decideTypeAction, type TypeActionDecision, type TypeTarget } from './harness/browser-act-type.js';
@@ -152,7 +158,7 @@ async function readStdinLine(prompt: string = ''): Promise<string> {
152
158
  finally { rl.close(); }
153
159
  }
154
160
  import { loginWithCodex, CODEX_DEVICE_LOGIN_URL } from './oauth/codex.js';
155
- import { authStorePath, loadTokens, deleteTokens, listProviders as listAuthProviders } from './oauth/store.js';
161
+ import { authStorePath, loadTokens, deleteTokens, saveTokens, listProviders as listAuthProviders, type CodexMirrorResult } from './oauth/store.js';
156
162
  import { renderKeyHelp, CONTEXT_LABELS, type KeyContext } from './keybindings.js';
157
163
  import { auditKeybindings, renderKeymapAudit } from './keymap-audit.js';
158
164
  import { runCodexSetup } from './codex/setup.js';
@@ -164,6 +170,7 @@ import { initSessionWorkingDir } from './session/working-dir.js';
164
170
  import { rewriteBareNexusToStatus } from './cli/nexus-entry.js';
165
171
  import { registerIngestTokenCommands } from './cli/ingest-token-cli.js';
166
172
  import { registerMcpGatewayCommands } from './cli/mcp-gateway-cli.js';
173
+ import { registerRelayCommand } from './relay/relay-cli.js';
167
174
  import type { ReviewImage } from './agent-substrate/pr-reviewer.js';
168
175
  import {
169
176
  describeMissionRouting,
@@ -864,6 +871,14 @@ registerDoctorCommand(program);
864
871
  registerControlCommands(program);
865
872
  registerHooksCommands(program);
866
873
  registerSetupCommand(program);
874
+ program.commands.find(command => command.name() === 'setup')!
875
+ .option('--terminal', 'Run the terminal onboarding wizard')
876
+ .hook('preAction', async (_command, action) => {
877
+ if (action.name() === 'setup' && action.opts().terminal) {
878
+ const completed = await runOnboardingForCli();
879
+ process.exit(completed ? 0 : (process.exitCode || 2));
880
+ }
881
+ });
867
882
  registerStartCommand(program);
868
883
  registerGroundingSourcesCli(program);
869
884
  registerGraphCommands(program);
@@ -873,6 +888,10 @@ registerCardCommand(program);
873
888
  registerLaunchHeadCommands(program);
874
889
  registerA2ACommands(program);
875
890
  registerPluginCommands(program);
891
+ registerSkillsCommands(program);
892
+ registerConnectCommand(program);
893
+ registerImportCommand(program);
894
+ registerPersonaCommands(program);
876
895
 
877
896
  const marketCmd = program.command('market').description('Signed plugin marketplace');
878
897
  marketCmd.command('publish').description('Publish a local signed marketplace index and archives')
@@ -905,6 +924,10 @@ marketCmd.command('publish').description('Publish a local signed marketplace ind
905
924
  console.log(`Published ${result.published.length} plugins (sequence ${result.sequence}); skipped ${result.skipped.length}`);
906
925
  for (const warning of result.warnings) console.warn(`⚠ ${warning.dir}: ${warning.graph} uses recipes it does not ship (${warning.recipes.join(', ')}) — third-party graphs should use their own recipes.yaml or custom nodes`);
907
926
  }
927
+ for (const item of result.skipped) {
928
+ for (const hit of item.hits ?? []) console.error(`${item.dir}/${hit.file}:${hit.line}: ${hit.marker}`);
929
+ }
930
+ if (!result.ok) process.exitCode = 1;
908
931
  } catch (error) {
909
932
  console.error(`market publish: ${error instanceof Error ? error.message : 'failed'}`);
910
933
  process.exitCode = 1;
@@ -1002,7 +1025,7 @@ program.command('self-update')
1002
1025
 
1003
1026
  program
1004
1027
  .name('elanous')
1005
- .description('TUI skill runner — Yazi-style 3-pane + multi-LLM, with remote sync, smart diff, and SQLite logging')
1028
+ .description('말 한 줄로 시작: elanous harness say "…" — 끝까지 간다 · 다 보인다 · 스스로를 만들었다')
1006
1029
  .version(cliVersion())
1007
1030
  // Documentation-only entry — the flag is extracted from argv by
1008
1031
  // `applyConfigDirFlagFromArgv` at module init (above) so Commander
@@ -1028,6 +1051,7 @@ program
1028
1051
  '--test',
1029
1052
  '격리 테스트 인스턴스로 실행 — cwd 의 git 트리(worktree 포함)에서 `<트리>/.elanous-test` 를 루트로 잡고 state·config 두 축을 함께 격리한다. config 사본이 없으면 자동 물질화. `--test=<dir>` 로 루트 직접 지정 가능(값 문법은 `=` 형태 하나 — 모호함 없음). ELANOUS_STATE_DIR/--config-dir 을 손으로 줄 필요가 없다.',
1030
1053
  );
1054
+ program.addHelpText('after', acpServerHelpText());
1031
1055
 
1032
1056
  program
1033
1057
  .command('measure-fabric-arc-ab')
@@ -1076,6 +1100,8 @@ const mcpCmd = program
1076
1100
  .description('MCP (Model Context Protocol) server / client integration');
1077
1101
  registerMcpGatewayCommands(mcpCmd);
1078
1102
 
1103
+ registerRelayCommand(program);
1104
+
1079
1105
  mcpCmd
1080
1106
  .command('serve')
1081
1107
  .description('Run a stdio MCP server exposing the configured mcp.servers as proxy tools (used by `claude mcp add elanous -- elanous mcp serve`)')
@@ -2952,6 +2978,9 @@ const harnessOrchestrateCmd = registerHarnessOrchestrateCapabilityOptions(
2952
2978
 
2953
2979
  const selfCmd = program.command('self').description('Self-awareness memory — 외부 도구(Claude Code/Codex)가 구현/변경 이력을 elanous 기억에 주입·회상');
2954
2980
 
2981
+ // M12 Claude Code 의존도 계기판 — `elanous self dependence [--since] [--until] [--json]`(읽기만).
2982
+ { const { registerDependenceCommand } = await import('./cli/dependence-gauge.js'); registerDependenceCommand(selfCmd); }
2983
+
2955
2984
  function printExtendedOrchestrateHelp(command: Command, positional = '[goals...]'): void {
2956
2985
  const optionLines = command.options
2957
2986
  .filter((option) => option.long !== '--help-all')
@@ -4155,6 +4184,9 @@ const selfOrchestrateCmd = selfCmd
4155
4184
  });
4156
4185
  process.env[HARNESS_RUN_ID_ENV] = runId;
4157
4186
  reportRunId = runId;
4187
+ // HS1 — `harness stop <runId>` must find this process from the moment the run ID exists.
4188
+ try { (await import('./self-dev/orchestrate.js')).writeRunPidRecord(runId); }
4189
+ catch (error) { debug.log('self-dev.orchestrate', 'early-pid-failed', { runId, error: String(error) }, { level: 'warn' }); }
4158
4190
  const createdAt = prior?.createdAt ?? Date.now();
4159
4191
  const { bindOrchestrateRunLedger } = await import('./self-dev/self-orchestrate-runtime.js');
4160
4192
  const { checkpoint } = bindOrchestrateRunLedger({
@@ -4280,7 +4312,26 @@ const selfOrchestrateCmd = selfCmd
4280
4312
  grokApiKeyOptIn = getUserConfig().harness?.pod?.grokApiKeyOptIn === true;
4281
4313
  const credential = resolveGrokCredential();
4282
4314
  const { resolveCodexQuotaPolicy, codexPolicyAllowsCredits, codexPolicyAllowsFallback } = await import('./oauth/codex-quota-policy.js');
4283
- const quotaPolicy = resolveCodexQuotaPolicy(getUserConfig().llm).policy;
4315
+ const resolvedQuota = resolveCodexQuotaPolicy(getUserConfig().llm);
4316
+ const quotaPolicy = resolvedQuota.policy;
4317
+ // POL1 — say which policy this launch uses and where it came from; warn when a test universe disagrees with production.
4318
+ try {
4319
+ const { effectiveInstanceRoot, prodInstanceRoot } = await import('./instance/resolve.js');
4320
+ const { describeLaunchQuotaPolicy } = await import('./oauth/codex-quota-policy.js');
4321
+ const root = effectiveInstanceRoot();
4322
+ const kind = root === prodInstanceRoot() ? 'prod' as const : 'test' as const;
4323
+ let production: ReturnType<typeof resolveCodexQuotaPolicy> | undefined;
4324
+ if (kind === 'test') {
4325
+ try {
4326
+ const { readFileSync } = await import('node:fs');
4327
+ const prodLlm = (JSON.parse(readFileSync(`${prodInstanceRoot()}/config.json`, 'utf8')) as { llm?: Record<string, unknown> }).llm;
4328
+ production = resolveCodexQuotaPolicy(prodLlm);
4329
+ } catch { /* no production config on this machine */ }
4330
+ }
4331
+ const described = describeLaunchQuotaPolicy({ current: resolvedQuota, universe: { kind, root }, ...(production ? { production } : {}) });
4332
+ debug.log('self-implement.pod', 'quota-policy', { policy: resolvedQuota.policy, source: resolvedQuota.source, universe: kind, productionPolicy: production?.policy ?? null });
4333
+ if (!opts.json) { ui.info(described.line); if (described.warning) ui.warn(described.warning); }
4334
+ } catch { /* the line is advice; the launch goes on */ }
4284
4335
  const plan = planPodProvider({
4285
4336
  codexCandidates: inspectCodexRotation().candidates,
4286
4337
  // Per-account caps (대표 default:97) override the Pod default cap — without them default was dropped at 60%.
@@ -7019,6 +7070,7 @@ missionCmd
7019
7070
 
7020
7071
  registerTasksCommands(program);
7021
7072
  registerLabelsCommands(program);
7073
+ registerMsgCommands(program);
7022
7074
 
7023
7075
  // ── ask alias (script-friendly one-shot query) ──
7024
7076
  program
@@ -7027,7 +7079,28 @@ program
7027
7079
  .option('--reuse', 'Reuse the active CLI session instead of creating a new one')
7028
7080
  .option('--session <id>', 'Continue an explicit session (id or unique prefix). Overrides --reuse and active session.')
7029
7081
  .option('--json', 'Emit a single JSON line {sessionId, provider, model, reply, logPath, budget} instead of streaming text + ui.info trailer. Stable shape for LLM self-spawn.')
7030
- .action(async (parts: string[], opts: { reuse?: boolean; session?: string; json?: boolean }) => {
7082
+ .option('--bare', 'Send only this text to the model: no Elanous preamble, project tree, memory, tools or session')
7083
+ .action(async (parts: string[], opts: { reuse?: boolean; session?: string; json?: boolean; bare?: boolean }) => {
7084
+ if (opts.bare) {
7085
+ try {
7086
+ const { askBare } = await import('./cli/ask-bare.js');
7087
+ const llm = await import('./llm.js');
7088
+ const { getUserConfig } = await import('./user-config.js');
7089
+ const { trimToBudget } = await import('./tokens.js');
7090
+ const result = await askBare({ text: parts.join(' '), deps: {
7091
+ getUserConfig, decideProviderForConfig: llm.decideProviderForConfig, getProviderForConfig: llm.getProviderForConfig,
7092
+ streamLLM: llm.streamLLM, trimToBudget,
7093
+ } });
7094
+ if (opts.json) process.stdout.write(JSON.stringify({ sessionId: null, ...result, logPath: null, budget: null, bare: true }) + '\n');
7095
+ else process.stdout.write(result.reply.endsWith('\n') ? result.reply : `${result.reply}\n`);
7096
+ } catch (error) {
7097
+ const message = error instanceof Error ? error.message : String(error);
7098
+ if (opts.json) process.stdout.write(JSON.stringify({ error: message, bare: true }) + '\n');
7099
+ else console.error(`ask --bare failed: ${message}`);
7100
+ process.exitCode = 1;
7101
+ }
7102
+ return;
7103
+ }
7031
7104
  const cfg = reloadUserConfig();
7032
7105
  await runChatTurnCli({
7033
7106
  cfg,
@@ -7193,9 +7266,13 @@ program
7193
7266
  });
7194
7267
 
7195
7268
  // ── login (provider OAuth) ──
7196
- export function codexLoginSuccessMessage(mirrorResult?: 'written' | 'not-created-missing-cli-fields' | 'write-failed'): string {
7269
+ export function codexLoginSuccessMessage(mirrorResult?: CodexMirrorResult): string {
7197
7270
  const prefix = `Signed in. Tokens at ${authStorePath()}.`;
7198
7271
  if (mirrorResult === 'written') return `${prefix} Mirrored to ~/.codex/auth.json.`;
7272
+ if (mirrorResult === 'skipped-different-account') {
7273
+ return `${prefix} Your Codex CLI login (~/.codex/auth.json) belongs to a different account — left unchanged. To switch it, run \`elanous login openai-codex --replace-codex-cli-login\`.`;
7274
+ }
7275
+ if (mirrorResult === 'skipped-unknown-account') return `${prefix} Codex CLI login left unchanged.`;
7199
7276
  if (mirrorResult === 'not-created-missing-cli-fields') {
7200
7277
  return `${prefix} Codex CLI mirror was not created because this login response lacked its required fields; run \`codex login\` once to initialize ~/.codex/auth.json.`;
7201
7278
  }
@@ -7208,17 +7285,33 @@ const loginCmd = program.command('login').description('Authenticate to an LLM pr
7208
7285
  loginCmd
7209
7286
  .command('openai-codex')
7210
7287
  .description('Sign in to OpenAI Codex via the ChatGPT device-code flow')
7211
- .action(async () => {
7212
- ui.header('OpenAI Codex — device-code sign-in');
7288
+ .option('--replace-codex-cli-login', 'if the Codex CLI (~/.codex/auth.json) is signed in to a different account, replace it with this login')
7289
+ .action(async (opts: { replaceCodexCliLogin?: boolean }) => {
7290
+ // OB5d — say why there is no browser (ssh · no display) and what to do instead; otherwise try the browser first.
7291
+ const { browserUnavailableReason } = await import('./oauth/browser-availability.js');
7292
+ const noBrowser = browserUnavailableReason();
7293
+ let browserState: Awaited<ReturnType<typeof import('./oauth/codex-browser-login.js')['loginWithCodexBrowser']>> | null = null;
7294
+ if (!noBrowser) {
7295
+ ui.header('OpenAI Codex — 브라우저 로그인');
7296
+ console.log(' 브라우저에서 로그인을 마치세요 — 끝나면 자동으로 이어집니다.');
7297
+ try {
7298
+ const { loginWithCodexBrowser } = await import('./oauth/codex-browser-login.js');
7299
+ browserState = await loginWithCodexBrowser();
7300
+ } catch {
7301
+ console.log(' 브라우저 로그인이 안 됐습니다 — 코드로 이어갑니다.');
7302
+ }
7303
+ }
7304
+ if (!browserState) ui.header('OpenAI Codex — 코드로 로그인');
7305
+ if (noBrowser) console.log(` ${noBrowser}`);
7213
7306
  try {
7214
- const state = await loginWithCodex({
7307
+ const state = browserState ?? await loginWithCodex({
7215
7308
  onProgress: (p) => {
7216
7309
  if (p.type === 'user_code' && p.userCode) {
7217
7310
  console.log('');
7218
- console.log(` 1) Open in any browser: ${p.loginUrl}`);
7219
- console.log(` 2) Enter this code: ${p.userCode}`);
7311
+ console.log(` 1) 아무 브라우저에서 열기: ${p.loginUrl}`);
7312
+ console.log(` 2) 코드 입력: ${p.userCode}`);
7220
7313
  console.log('');
7221
- console.log(' Waiting for sign-in… (Ctrl+C to cancel)');
7314
+ console.log(' 로그인을 기다리는 중… (취소: Ctrl+C)');
7222
7315
  }
7223
7316
  if (p.type === 'polling' && p.pollAttempt === 1) {
7224
7317
  process.stdout.write(' .');
@@ -7233,7 +7326,21 @@ loginCmd
7233
7326
  }
7234
7327
  },
7235
7328
  });
7236
- ui.info(codexLoginSuccessMessage(state.codexMirrorResult));
7329
+ // AUTH1 — another account's Codex CLI login is left alone unless the user says to replace it.
7330
+ let mirrorResult = state.codexMirrorResult;
7331
+ if (mirrorResult === 'skipped-different-account') {
7332
+ let replace = opts.replaceCodexCliLogin === true;
7333
+ if (!replace && process.stdin.isTTY && process.stdout.isTTY) {
7334
+ const { createInterface } = await import('node:readline/promises');
7335
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
7336
+ try {
7337
+ const answer = await rl.question(' Your Codex CLI (~/.codex/auth.json) is signed in to a different account. Replace it with this login? [y/N] ');
7338
+ replace = /^y(es)?$/i.test(answer.trim());
7339
+ } finally { rl.close(); }
7340
+ }
7341
+ if (replace) mirrorResult = saveTokens('openai-codex', state.tokens, { replaceDifferentCodexAccount: true }).codexMirrorResult;
7342
+ }
7343
+ ui.info(codexLoginSuccessMessage(mirrorResult));
7237
7344
  ui.info(`Expires in ~${state.tokens.expiresAt ? Math.round((state.tokens.expiresAt - Date.now()) / 60000) : '?'}min; auto-refresh on next use.`);
7238
7345
  } catch (err: any) {
7239
7346
  ui.error(`login failed: ${err?.message ?? err}`);
@@ -7821,6 +7928,15 @@ sessionCmd
7821
7928
  console.log(res.formatted ?? '(no context)');
7822
7929
  });
7823
7930
 
7931
+ async function runFirstSetupForCli(cfg: ReturnType<typeof getUserConfig>, announceFallback = false): Promise<boolean> {
7932
+ if (cfg.onboarding.webFirst === true) {
7933
+ const { runWebFirstSetup } = await import('./onboarding/web-first.js');
7934
+ if (await runWebFirstSetup({ config: cfg }) === 'link-shown') return false;
7935
+ if (announceFallback) ui.info('No config yet — launching setup wizard first.');
7936
+ }
7937
+ return runOnboardingForCli();
7938
+ }
7939
+
7824
7940
  async function runOnboardingForCli(): Promise<boolean> {
7825
7941
  try {
7826
7942
  await runOnboarding();
@@ -7856,8 +7972,8 @@ program
7856
7972
  if (opts.tools) announceChatToolsCompatibility();
7857
7973
  const cfg = getUserConfig();
7858
7974
  if (needsOnboarding(cfg)) {
7859
- ui.info('No config yet — launching setup wizard first.');
7860
- if (!await runOnboardingForCli()) return;
7975
+ if (cfg.onboarding.webFirst !== true) ui.info('No config yet — launching setup wizard first.');
7976
+ if (!await runFirstSetupForCli(cfg, true)) return;
7861
7977
  }
7862
7978
  const refreshed = reloadUserConfig();
7863
7979
  // ★ 관측갭 수리(2026-07-21·제1원칙·트랙A) — self-implement 자식 goal-loop(`chat --goal-loop`)은 데몬과
@@ -7923,8 +8039,8 @@ program
7923
8039
  }
7924
8040
  const cfg = getUserConfig();
7925
8041
  if (needsOnboarding(cfg)) {
7926
- ui.info('No config yet — launching setup wizard first.');
7927
- if (!await runOnboardingForCli()) return;
8042
+ if (cfg.onboarding.webFirst !== true) ui.info('No config yet — launching setup wizard first.');
8043
+ if (!await runFirstSetupForCli(cfg, true)) return;
7928
8044
  }
7929
8045
  const refreshed = reloadUserConfig();
7930
8046
  const { runRepl } = await import('./repl/index.js');
@@ -9725,6 +9841,23 @@ nexusChannelBotCmd
9725
9841
  process.exit(result.exitCode);
9726
9842
  });
9727
9843
 
9844
+ // EN13 — bring an existing Telegram/Discord bot over from OpenClaw · Hermes · the previous elanous (~/.monad).
9845
+ nexusChannelBotCmd
9846
+ .command('import')
9847
+ .description('Find Telegram/Discord bot settings you already use (OpenClaw, Hermes, previous elanous), preview them with the token masked, and store them after you agree.')
9848
+ .option('--yes', 'Import without asking')
9849
+ .action(async (opts: { yes?: boolean }) => {
9850
+ const { runChannelImport } = await import('./channel-import/run.js');
9851
+ const { createInterface } = await import('node:readline/promises');
9852
+ const ask = process.stdin.isTTY ? async (question: string): Promise<boolean> => {
9853
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
9854
+ try { const answer = (await rl.question(question)).trim(); return answer === '' || /^(y|yes|예|네)$/i.test(answer); }
9855
+ finally { rl.close(); }
9856
+ } : undefined;
9857
+ const result = await runChannelImport({ yes: opts.yes, ...(ask ? { ask } : {}) });
9858
+ process.exit(result.exitCode);
9859
+ });
9860
+
9728
9861
  // FU A6-real P5 (2026-05-11) — interactive Firecrawl setup.
9729
9862
  // Walks the user through CLI detection + API key entry + persist to
9730
9863
  // `registry.discovery.firecrawl.apiKey`. `--api-key <value>` skips
@@ -10389,6 +10522,14 @@ async function main(): Promise<void> {
10389
10522
  // elanous --acp-server --transport=unix-socket --socket-path=/tmp/x.sock
10390
10523
  // elanous --acp-server --transport=websocket --port=31415
10391
10524
  // elanous --acp-server --transport=websocket --no-auth # skip token check
10525
+ if (rawArgs.includes('--acp-server') && rawArgs.includes('--login')) {
10526
+ // EN10a — an ACP client's terminal auth re-launches `elanous --acp-server --login`: run the sign-in in that terminal and exit with its status.
10527
+ const { ACP_LOGIN_SUBCOMMAND, currentLaunch } = await import('./acp/auth-methods.js');
10528
+ const launch = currentLaunch();
10529
+ const { spawnSync } = await import('node:child_process');
10530
+ const run = spawnSync(launch.command, [...launch.args, ...ACP_LOGIN_SUBCOMMAND], { stdio: 'inherit' });
10531
+ process.exit(run.status ?? 1);
10532
+ }
10392
10533
  if (rawArgs.includes('--acp-server')) {
10393
10534
  const { bootAcpServer, parseAcpBootArgs } = await import('./boot/acp-server.js');
10394
10535
  const { createDaemonRuntime } = await import('./boot/daemon-runtime.js');
@@ -10597,7 +10738,7 @@ async function main(): Promise<void> {
10597
10738
  // gates on config completeness — no entry-mode branch.)
10598
10739
  const cfg = getUserConfig();
10599
10740
  if (needsOnboarding(cfg)) {
10600
- if (!await runOnboardingForCli()) return;
10741
+ if (!await runFirstSetupForCli(cfg)) return;
10601
10742
  }
10602
10743
 
10603
10744
  // Active-provider banner so users know WHICH model/auth is about to
@@ -10679,12 +10820,18 @@ async function main(): Promise<void> {
10679
10820
  * 회귀 방어 = `src/cli-entry.test.ts`(실물 `bin/elanous.mjs` 를 spawn 한다).
10680
10821
  */
10681
10822
  export function runCli(): void {
10682
- main().catch((err) => {
10823
+ main().catch(async (err) => {
10683
10824
  closeTui();
10684
- if (err instanceof HarnessCliInputError) {
10685
- console.error(`❌ ${err.message}`);
10825
+ if (isCliUserError(err)) {
10826
+ console.error(formatCliUserError(err));
10686
10827
  process.exit(1);
10687
10828
  }
10829
+ // ER1 — a real crash is reported once (consented · scrubbed · never blocks more than the send timeout).
10830
+ try {
10831
+ const { reportError } = await import('./error-report/report.js');
10832
+ const outcome = await reportError({ code: 'cli-crash', message: err instanceof Error ? `${err.name}: ${err.message}` : String(err), ...(err instanceof Error && err.stack ? { stack: err.stack } : {}), surface: 'cli' });
10833
+ if (outcome.sent) console.error(`오류를 운영팀에 알렸습니다${outcome.reportId ? ` (보고 번호 ${outcome.reportId})` : ''}.`);
10834
+ } catch { /* the crash itself is what matters */ }
10688
10835
  throw err;
10689
10836
  });
10690
10837
  }
@@ -40,15 +40,23 @@ export function keyEventToTextInsertion(
40
40
  return preservePrintableText(ev, name);
41
41
  }
42
42
 
43
+ /** Hangul Compatibility Jamo (ㄱ…ㅣ · ㅋㅋ · ㅠㅠ). The key parser maps a lone jamo keystroke to the QWERTY key
44
+ * on the same position so hotkeys work under the Korean IME — but as TEXT it must stay the jamo the person typed
45
+ * (U1 · 2026-10-02: «ㅋㅋㅋ ㅠㅠ» came out as «zzz bb» in the chat input). */
46
+ const COMPAT_JAMO = /^[\u3131-\u318E]$/;
47
+
43
48
  function preservePrintableText(ev: KeyEvent, name: string): string {
49
+ // The chat composer passes the TUI key (original bytes on `raw`); other composers pass a KeyEvent (`sequence`).
50
+ const sequence = ev.sequence ?? (ev as { raw?: string }).raw;
51
+ if (sequence && name.length === 1 && COMPAT_JAMO.test(sequence)) return sequence;
44
52
  if (
45
- ev.sequence
46
- && ev.sequence.length === 1
53
+ sequence
54
+ && sequence.length === 1
47
55
  && name.length === 1
48
- && ev.sequence !== name
49
- && ev.sequence.toLowerCase() === name.toLowerCase()
56
+ && sequence !== name
57
+ && sequence.toLowerCase() === name.toLowerCase()
50
58
  ) {
51
- return ev.sequence;
59
+ return sequence;
52
60
  }
53
61
  if (name.length === 1) return ev.shift ? name.toUpperCase() : name;
54
62
  return name;
@@ -2,7 +2,7 @@
2
2
  import { INSTALLED_PACKAGE_MARKERS, isInstalledPackagePath } from './installed-package.js';
3
3
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
- import { dirname, join, resolve } from 'node:path';
5
+ import { dirname, join, resolve, basename } from 'node:path';
6
6
 
7
7
  export interface LeaderRefusalRecord {
8
8
  refusedAt: string;
@@ -53,10 +53,22 @@ export function normalizeTree(p: string): string {
53
53
  try { return realpathSync(abs); } catch { return abs; }
54
54
  }
55
55
 
56
+ /** npm/Homebrew/nvm `<prefix>/lib/node_modules` · bun `…/install/global/node_modules` · pnpm `…/global/<n>/node_modules`. */
57
+ export function isGlobalNodeModules(dir: string): boolean {
58
+ if (basename(dir) !== 'node_modules') return false;
59
+ const parent = basename(dirname(dir));
60
+ return parent === 'lib' || parent === 'global' || (/^\d+$/.test(parent) && basename(dirname(dirname(dir))) === 'global');
61
+ }
62
+
56
63
  export function treeFromScriptPath(scriptPath: string): string | null {
57
64
  let dir = dirname(normalizeTree(scriptPath));
58
65
  for (let i = 0; i < 30; i++) {
59
66
  if (existsSync(join(dir, '.git'))) return dir;
67
+ // A GLOBAL install stops at its node_modules: a git repo around the install prefix (Homebrew's /opt/homebrew
68
+ // is one; so is a dotfiles-managed home) is not this code's source tree. Without this stop `npm i -g` under
69
+ // Homebrew ran as a «source tree» test universe writing config to /opt/homebrew/.elanous-test (OB3 · 10-01).
70
+ // A project-local <checkout>/node_modules/elanous still resolves to the checkout (the existing design).
71
+ if (isGlobalNodeModules(dir)) return null;
60
72
  const parent = dirname(dir);
61
73
  if (parent === dir) return null;
62
74
  dir = parent;
@@ -131,7 +131,7 @@ export function signalsFromSnapshot(stars: number, prev: StarSnapshot | undefine
131
131
  return { stars, starsDelta, starsPerDay: starsDelta / span };
132
132
  }
133
133
 
134
- function appendSnapshots(root: string, rows: StarSnapshot[]): void {
134
+ export function appendGithubStarSnapshots(root: string, rows: StarSnapshot[]): void {
135
135
  if (!rows.length) return;
136
136
  mkdirSync(intakeLedgerDir(root), { recursive: true });
137
137
  appendFileSync(githubStarsFile(root), rows.map((r) => JSON.stringify(r)).join('\n') + '\n');
@@ -154,6 +154,8 @@ export interface CollectGithubOpts {
154
154
  /** 스냅숏·비교의 «오늘». 생략하면 UTC 날짜. */
155
155
  day?: string;
156
156
  now?: () => Date;
157
+ /** 등록 원천이 질의 하나만 수집할 때; 생략 시 기존 관심 질의 전부. */
158
+ queries?: readonly string[];
157
159
  }
158
160
 
159
161
  /**
@@ -173,7 +175,7 @@ export async function collectGithubStars(
173
175
  const found: GithubStarRepo[] = [];
174
176
  // «급상승»은 최근에 생긴 저장소 중 별 순이다 — 전체 기간 별 순이면 활발한 거대 저장소가 매일 같은 목록으로 나온다(2026-09-26 검토).
175
177
  const windowStart = new Date(Date.parse(`${day}T00:00:00.000Z`) - days * 86_400_000).toISOString().slice(0, 10);
176
- for (const query of GITHUB_STAR_QUERIES) {
178
+ for (const query of opts.queries ?? GITHUB_STAR_QUERIES) {
177
179
  const rows = await search(`${query} created:>=${windowStart}`, perQuery);
178
180
  const recent = rows.filter((r) => isRecentRepo(r, day, days));
179
181
  queries.push({ query, received: recent.length });
@@ -208,7 +210,7 @@ export async function collectGithubStars(
208
210
  day, days, perQuery, dryRun: !!opts.dryRun, queries, repos, raws: raws.length,
209
211
  };
210
212
  if (!opts.dryRun) {
211
- appendSnapshots(root, repos.map((row) => ({ day, repo: row.repo, stars: row.stars })));
213
+ appendGithubStarSnapshots(root, repos.map((row) => ({ day, repo: row.repo, stars: row.stars })));
212
214
  result.ingest = ingestIntakeItems(root, 'github', raws);
213
215
  }
214
216
  debug.log('intake.collect', 'github-stars', {
@@ -60,14 +60,26 @@ export async function collectTelegramSaved(root: string, fetch: FetchSavedMessag
60
60
  }
61
61
 
62
62
  /** GramJS 사용자 세션으로 `me` 대화를 읽는 실제 구현. 자격이 없으면 이유를 담아 던진다(값은 싣지 않는다). */
63
- export async function gramjsFetchSaved(env: NodeJS.ProcessEnv = process.env): Promise<{ fetch: FetchSavedMessages; close: () => Promise<void> }> {
63
+ type GramjsModules = { TelegramClient: typeof import('telegram').TelegramClient; StringSession: typeof import('telegram/sessions').StringSession };
64
+ const loadGramjs = async (): Promise<GramjsModules> => ({
65
+ TelegramClient: (await import('telegram')).TelegramClient,
66
+ StringSession: (await import('telegram/sessions')).StringSession,
67
+ });
68
+
69
+ export async function gramjsFetchSaved(
70
+ env: NodeJS.ProcessEnv = process.env,
71
+ load: () => Promise<GramjsModules> = loadGramjs,
72
+ ): Promise<{ fetch: FetchSavedMessages; close: () => Promise<void> }> {
64
73
  const apiId = Number(env.TELEGRAM_API_ID ?? 0);
65
74
  const apiHash = env.TELEGRAM_API_HASH ?? '';
66
75
  const session = env.TELEGRAM_USER_SESSION ?? '';
67
76
  const missing = [!apiId && 'TELEGRAM_API_ID', !apiHash && 'TELEGRAM_API_HASH', !session && 'TELEGRAM_USER_SESSION'].filter(Boolean);
68
77
  if (missing.length) throw new Error(`텔레그램 사용자 세션 자격이 없다: ${missing.join(' · ')} (docs/manual/MANUAL-telegram-unmanned-test-2026-07-21.md §1~§3)`);
69
- const { TelegramClient } = await import('telegram');
70
- const { StringSession } = await import('telegram/sessions');
78
+ // `telegram` is an optional dependency: its native websocket helpers have no Linux ARM64 build, so npm may leave it out.
79
+ let modules: GramjsModules;
80
+ try { modules = await load(); }
81
+ catch { throw new Error('텔레그램 사용자 세션 모듈(telegram)이 이 설치에 없다 — 선택 의존이라 Linux ARM64 등에서는 빠진다(npm i -g telegram 으로 따로 깔 수 있다)'); }
82
+ const { TelegramClient, StringSession } = modules;
71
83
  const client = new TelegramClient(new StringSession(session), apiId, apiHash, { connectionRetries: 3 });
72
84
  client.setLogLevel('error' as never); // 연결 로그가 표준출력을 채우지 않게
73
85
  await client.connect();
@@ -0,0 +1,56 @@
1
+ import { parseSeatAddress, resolveSeat } from '../seat-address/seat-address.js';
2
+ import {
3
+ submitIntakeWork,
4
+ type SubmitIntakeWorkDeps,
5
+ } from './submit-intake-work.js';
6
+
7
+ export interface DiscordSeatWorkMessage {
8
+ channelId: string;
9
+ messageId: string;
10
+ threadId?: string;
11
+ }
12
+
13
+ export interface DiscordSeatWorkDeps extends SubmitIntakeWorkDeps {
14
+ submit?: typeof submitIntakeWork;
15
+ }
16
+
17
+ /** Addressed Discord work goes through the graph intake door, not the chat turn. */
18
+ export async function handleDiscordSeatWork(
19
+ text: string,
20
+ msg: DiscordSeatWorkMessage,
21
+ deps: DiscordSeatWorkDeps = {},
22
+ ): Promise<string | null> {
23
+ const address = parseSeatAddress(text);
24
+ if (!address) return null;
25
+
26
+ const seats = address.seats.map((name) => ({ name, seat: resolveSeat(name) }));
27
+ const unknown = seats.filter(({ seat }) => !seat).map(({ name }) => `@${name}`);
28
+ if (unknown.length) return `어느 좌석을 말씀하시나요? ${unknown.join(', ')}은(는) 등록된 좌석이 아닙니다. 좌석을 확인해 다시 보내 주세요.`;
29
+ const body = address.body.trim();
30
+ if (!body) return '어떤 일을 맡길까요? 좌석 주소 뒤에 요청 내용을 적어 다시 보내 주세요.';
31
+
32
+ const reportTo = {
33
+ channel: 'discord' as const,
34
+ channelId: msg.channelId,
35
+ ...(msg.threadId ? { discordThreadId: msg.threadId } : {}),
36
+ };
37
+ const replies: string[] = [];
38
+ for (const { seat } of seats) {
39
+ if (!seat) continue;
40
+ const label = seat.title ?? seat.id;
41
+ const result = await (deps.submit ?? submitIntakeWork)({
42
+ text: `@${label} ${body}`,
43
+ track: 'graph',
44
+ origin: {
45
+ kind: 'external', ledgerSource: 'memo', provider: 'other',
46
+ ref: `discord:${msg.channelId}:${msg.messageId}`, reportTo,
47
+ },
48
+ }, deps);
49
+ if (result.ok && result.track === 'graph') {
50
+ replies.push(`@${label} 접수번호: ${result.acceptanceId}`);
51
+ } else {
52
+ replies.push(`@${label} 접수 실패 — ${result.ok ? '접수번호가 없습니다' : result.reason.split('\n')[0]!.slice(0, 200)}`);
53
+ }
54
+ }
55
+ return replies.join('\n');
56
+ }