elanous 0.2.6 → 0.2.7

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 (450) 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-2eba6079f31b88d4.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/7647.2fcd30d894d5ee30.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{91ff6dda-3b33d42d20657429.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8519-f6b5d8a5833a7603.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8894-e92491a164192cc1.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/9454-a3e0953307216c58.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9740-67051141115ce775.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.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-d5ebde04844689e6.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-10ed24f413ed66e9.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/board/page-211810b6c93ab66a.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/page-624f7a2f89b60c8f.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-5a5fb385a4df0ffe.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-80497e93a878ddc5.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/consult/page-7457f52683562161.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/control/page-cee86394de407aa6.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/design-check/page-4ff8edab44196b8c.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/editor/page-92e4f44428d5e290.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/exec/page-b7dcf5d48a854b76.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/field/page-51480757e7d68b92.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-2a05dfe80c8bdf16.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/layout-d9979633aa82f8e6.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/live/page-30533117beb53625.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/market/page-f7857826c2f97ad7.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-07267f1391b96aba.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/morning/page-55d50e9b0006a91d.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/not-found-9699b1786be6171d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/observatory/page-43dd772aee8af75f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/page-a7e37af7d0399cb8.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/reflection/page-973ab7af59c718b7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a9f8d3865b91e436.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/sessions/page-15e5a15db84c56aa.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a2e572e4511f2a16.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/settings/page-dd107bf1c7d52a90.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d42b99cdfb9f27c6.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-2764ff40dad5a995.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/share/page-c5f1152db116ff96.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/showroom/page-f933bca81ea38a6f.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/tasks/page-c1c95739c0bff3b8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/term/page-a7aaffcf771662d8.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/trace/page-71d18eec33b9c667.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/vault/page-56adbe1a1f1379bd.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-2c4e59079ee357ac.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a81f113f3ef89d72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d422f38c052967e.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fc27b00e20733146.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/f537bdb19c69306a.css +1 -0
  96. package/apps/pwa/out/_next/static/keajW7DDyghEs1y8oJe6T/_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/package.json +5 -5
  178. package/plugins/card-followup/README.md +13 -4
  179. package/plugins/card-followup/graphs/card-followup.yaml +3 -1
  180. package/plugins/card-followup/graphs/recipes.yaml +5 -1
  181. package/plugins/card-followup/graphs/run-step.ts +122 -18
  182. package/plugins/card-followup/graphs/sales-strategy.ts +173 -0
  183. package/plugins/card-followup/plugin.json +1 -1
  184. package/plugins/doc-draft/README.md +13 -0
  185. package/plugins/doc-draft/examples/brief-sample.json +8 -0
  186. package/plugins/doc-draft/graphs/doc-draft.yaml +14 -0
  187. package/plugins/doc-draft/graphs/recipes.yaml +9 -0
  188. package/plugins/doc-draft/graphs/run-step.ts +113 -0
  189. package/plugins/doc-draft/plugin.json +24 -0
  190. package/plugins/geo-check/README.md +3 -1
  191. package/plugins/geo-check/graphs/run-step.ts +24 -3
  192. package/plugins/geo-check/plugin.json +1 -1
  193. package/plugins/job-coach/.codex-plugin/plugin.json +1 -1
  194. package/plugins/job-coach/README.md +1 -1
  195. package/plugins/job-coach/graphs/run-step.ts +2 -2
  196. package/plugins/job-coach/plugin.json +1 -1
  197. package/plugins/job-coach/plugin.ts +1 -1
  198. package/scripts/affinity/endcard.sh +3 -2
  199. package/scripts/affinity/reframe.sh +3 -1
  200. package/scripts/ci-public-export-leak-gate.ts +48 -0
  201. package/scripts/codex-quota-alert.ts +122 -258
  202. package/scripts/coord-tracks.json +4 -4
  203. package/scripts/field-feed/deliver-node.ts +52 -0
  204. package/scripts/field-feed/feed-node.ts +67 -0
  205. package/scripts/field-feed/lib.ts +162 -0
  206. package/scripts/field-feed/reel-node.ts +24 -0
  207. package/scripts/field-feed/start.ts +62 -0
  208. package/scripts/fixtures/vflow-sample.ndjson +6 -0
  209. package/scripts/install.sh +92 -13
  210. package/scripts/landing-heal/clean-checkout.ts +114 -0
  211. package/scripts/landing-heal/run-mission.ts +38 -3
  212. package/scripts/lib/pwa-scenarios/scenarios.ts +2 -1
  213. package/scripts/public-export.ts +8 -4
  214. package/scripts/release-loop/baseline-from-logs.ts +92 -0
  215. package/scripts/release-loop/env-known-failures.ts +31 -0
  216. package/scripts/release-loop/gate-node.ts +81 -19
  217. package/scripts/release-loop/known-issues-node.ts +159 -0
  218. package/scripts/release-loop/npm-publish-node.ts +118 -0
  219. package/scripts/release-loop/ops-upgrade-node.ts +87 -0
  220. package/scripts/release-loop/release-readiness.ts +58 -0
  221. package/scripts/release-loop/unattended-release.ts +93 -0
  222. package/scripts/ux/measure-first-text.ts +102 -0
  223. package/scripts/vflow-collect.ts +20 -7
  224. package/scripts/vflow-search.ts +73 -0
  225. package/scripts/video-free-line-test-walker.ts +36 -0
  226. package/scripts/video-pipeline.ts +2 -2
  227. package/skills/explainer-video/SKILL.md +12 -9
  228. package/skills/explainer-video/engine/build.mjs +1 -1
  229. package/skills/explainer-video/engine/reel.mjs +138 -31
  230. package/skills/explainer-video/engine/reel.sh +2 -1
  231. package/skills/explainer-video/examples/elanous-0.2.5/script.json +1 -1
  232. package/skills/grill-me/SKILL.md +1 -1
  233. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +1 -1
  234. package/src/a2a/server.ts +2 -0
  235. package/src/acp/elanous-aware-peers.ts +30 -0
  236. package/src/acp/server.ts +91 -15
  237. package/src/agent/monad-agent-turn.ts +25 -6
  238. package/src/agent/shared-app-tools.ts +5 -3
  239. package/src/agent-substrate/review-intent.ts +6 -2
  240. package/src/agent-substrate/shard-boundary-intent.ts +70 -0
  241. package/src/auth/github-app-token.ts +4 -1
  242. package/src/autopilot/track-agent-shadow.ts +151 -0
  243. package/src/autopilot/track-agent.ts +23 -3
  244. package/src/boot/acp-server-help.ts +16 -0
  245. package/src/boot/daemon-prompt-turn.ts +31 -10
  246. package/src/boot/daemon-tools/index.ts +7 -1
  247. package/src/budget/codex-credit-pace.ts +84 -0
  248. package/src/budget/codex-credit-plan.ts +154 -0
  249. package/src/budget/codex-reset-credit-state.ts +2 -0
  250. package/src/chat/chat-cli.ts +4 -1
  251. package/src/chat/short-question.ts +40 -0
  252. package/src/cli/agent-cli.ts +24 -15
  253. package/src/cli/ask-bare.ts +42 -0
  254. package/src/cli/cli-user-error.ts +25 -0
  255. package/src/cli/codex-credit-plan-view.ts +25 -0
  256. package/src/cli/dependence-gauge.ts +237 -0
  257. package/src/cli/doctor-cli.ts +5 -0
  258. package/src/cli/doctor-modes.ts +48 -0
  259. package/src/cli/intake-cli.ts +12 -2
  260. package/src/cli/intake-source-cli.ts +58 -0
  261. package/src/cli/machine-cli.ts +23 -0
  262. package/src/cli/msg-cli.ts +137 -0
  263. package/src/cli/plugin-cli.ts +25 -0
  264. package/src/cli/pr-cli.ts +36 -0
  265. package/src/cli/provider-cli.ts +5 -0
  266. package/src/cli/release-cli.ts +42 -1
  267. package/src/cli/release-run-if-ready.ts +48 -0
  268. package/src/cli/setup-cli.ts +27 -6
  269. package/src/cli/setup-recommend.ts +8 -0
  270. package/src/cli/usage-cli.ts +11 -1
  271. package/src/codex/setup.ts +27 -8
  272. package/src/dashboard/index.ts +1 -1
  273. package/src/discord.ts +56 -6
  274. package/src/domains/core-tools.ts +37 -14
  275. package/src/domains/outbound-alert.ts +50 -11
  276. package/src/exec-requests/planner.ts +140 -0
  277. package/src/exec-requests/runner.ts +338 -0
  278. package/src/exec-requests/store.ts +76 -0
  279. package/src/field/field-media.ts +8 -3
  280. package/src/field/field-reel.ts +196 -0
  281. package/src/grok/credential.ts +7 -5
  282. package/src/harness/aside-run-status.ts +33 -0
  283. package/src/harness/browser-verify.ts +48 -17
  284. package/src/harness/harness-cli-command.ts +25 -3
  285. package/src/harness/image-load-state.ts +21 -0
  286. package/src/harness/process-garbage.ts +45 -0
  287. package/src/index.ts +86 -14
  288. package/src/instance/leader.ts +13 -1
  289. package/src/intake-plane/collect-github.ts +5 -3
  290. package/src/intake-plane/collect-telegram-saved.ts +15 -3
  291. package/src/intake-plane/discord-seat-work.ts +56 -0
  292. package/src/intake-plane/intake-sources.ts +202 -0
  293. package/src/intake-plane/items.ts +28 -12
  294. package/src/intake-plane/seat-doc-route.ts +207 -0
  295. package/src/intake-plane/submit-intake-work.ts +9 -1
  296. package/src/intake-plane/telegram-seat-work.ts +72 -0
  297. package/src/llm/model-defaults.ts +24 -1
  298. package/src/llm.ts +5 -4
  299. package/src/machines/machine-ledger.ts +127 -0
  300. package/src/market/pack-internal-refs.ts +28 -0
  301. package/src/market/publish.ts +31 -4
  302. package/src/maturity/feature-maturity.ts +65 -0
  303. package/src/model-tier/turn-tier.ts +24 -0
  304. package/src/msg/msg-store.ts +149 -0
  305. package/src/native-tool-catalog.ts +2 -1
  306. package/src/nexus/api/chat-fast-path-config.ts +28 -0
  307. package/src/nexus/api/consult-requests.ts +117 -0
  308. package/src/nexus/api/discord-trigger-bot.ts +3 -0
  309. package/src/nexus/api/exec-requests.ts +51 -0
  310. package/src/nexus/api/field-uploads.ts +40 -3
  311. package/src/nexus/api/graph-approvals-feed.ts +140 -0
  312. package/src/nexus/api/graph-approvals.ts +71 -4
  313. package/src/nexus/api/http-server.ts +61 -7
  314. package/src/nexus/api/seat-requests.ts +254 -0
  315. package/src/nexus/api/trace-run-scan.ts +37 -0
  316. package/src/nexus/api/trace.ts +19 -3
  317. package/src/nexus/index.ts +3 -0
  318. package/src/nexus/setup-status.ts +4 -5
  319. package/src/notify/llm-budget-alert.ts +16 -10
  320. package/src/oauth/codex-account-rotation.ts +26 -4
  321. package/src/oauth/codex-account-store.ts +20 -2
  322. package/src/oauth/codex-browser-login.ts +173 -0
  323. package/src/oauth/codex.ts +4 -1
  324. package/src/oauth/fallback-chain.ts +5 -5
  325. package/src/oauth/store.ts +42 -5
  326. package/src/onboarding/continue-here.ts +29 -0
  327. package/src/onboarding/entry-hints.ts +8 -0
  328. package/src/onboarding/full-screen-io.ts +35 -3
  329. package/src/onboarding/help/skills.md +1 -1
  330. package/src/onboarding/non-interactive.ts +1 -0
  331. package/src/onboarding/subscription-hint.ts +27 -0
  332. package/src/onboarding/web-first.ts +83 -0
  333. package/src/onboarding.ts +230 -23
  334. package/src/plugins/maker/node-install.ts +92 -0
  335. package/src/plugins/maker/node-maker.ts +139 -0
  336. package/src/plugins/maker/plugin-maker.ts +19 -7
  337. package/src/policy/llm-policy.ts +268 -0
  338. package/src/prompt-library/session-guidance.ts +7 -1
  339. package/src/prompt-library/universal-preamble.ts +2 -2
  340. package/src/relay/relay-cli.ts +20 -0
  341. package/src/relay/relay-server.ts +220 -0
  342. package/src/release-loop/checklist.ts +9 -8
  343. package/src/self-dev/decompose.ts +1 -0
  344. package/src/self-dev/dev-pipeline.ts +6 -3
  345. package/src/self-dev/run-record-mirror.ts +44 -0
  346. package/src/self-dev/run-store.ts +12 -3
  347. package/src/self-implement/harness-policy-gates.ts +4 -1
  348. package/src/self-implement/report-origin.ts +12 -1
  349. package/src/session/chat.ts +17 -5
  350. package/src/skills/shared-agent-skill-roots.ts +25 -0
  351. package/src/steward/failure-streak.ts +78 -0
  352. package/src/steward/steward-cards.ts +24 -0
  353. package/src/steward/triage-budget.ts +127 -0
  354. package/src/steward/triage-plan.ts +75 -0
  355. package/src/steward/triage.ts +244 -42
  356. package/src/task-cards/card-store.ts +1 -1
  357. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  358. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +68 -0
  359. package/src/task-orchestrator/surfaces/self-implement-pod.ts +78 -4
  360. package/src/telegram.ts +38 -2
  361. package/src/tool-runtime/elanous-skills-list-runtime.ts +3 -3
  362. package/src/tool-runtime/self-cognition-runtimes.ts +160 -2
  363. package/src/user-config.ts +80 -4
  364. package/src/version/packed-revision.json +1 -1
  365. package/src/video-pipeline/recipes/character.ts +42 -5
  366. package/src/video-pipeline/recipes/ffmpeg.ts +1 -1
  367. package/src/video-pipeline/recipes/free-line.ts +16 -3
  368. package/src/video-pipeline/recipes/remote.ts +7 -1
  369. package/src/video-pipeline/vflow-reference.ts +109 -0
  370. package/apps/pwa/out/_next/static/chunks/1169-696263ac7af8c4d4.js +0 -1
  371. package/apps/pwa/out/_next/static/chunks/1883.c91a2648af4842fd.js +0 -1
  372. package/apps/pwa/out/_next/static/chunks/1947-9d64872eeb9cfdec.js +0 -1
  373. package/apps/pwa/out/_next/static/chunks/2808-dc06482994b40f70.js +0 -1
  374. package/apps/pwa/out/_next/static/chunks/3165-95515ca5f299a120.js +0 -1
  375. package/apps/pwa/out/_next/static/chunks/3190-e9282753e7ebde85.js +0 -1
  376. package/apps/pwa/out/_next/static/chunks/4259-99614149577e77cb.js +0 -1
  377. package/apps/pwa/out/_next/static/chunks/4283-329eabeaf233e6cd.js +0 -1
  378. package/apps/pwa/out/_next/static/chunks/4328-cb5058b1acc2de5e.js +0 -25
  379. package/apps/pwa/out/_next/static/chunks/4801-ecee6ef62b349b18.js +0 -1
  380. package/apps/pwa/out/_next/static/chunks/5110-8058791dd25a2e14.js +0 -1
  381. package/apps/pwa/out/_next/static/chunks/5330-c41e9670f594c38f.js +0 -1
  382. package/apps/pwa/out/_next/static/chunks/5423-e95fd125d1794349.js +0 -1
  383. package/apps/pwa/out/_next/static/chunks/5478-b5eae07dc79ea619.js +0 -1
  384. package/apps/pwa/out/_next/static/chunks/5787-96ee6642b9a661e5.js +0 -1
  385. package/apps/pwa/out/_next/static/chunks/6448-79d72368589f98bc.js +0 -1
  386. package/apps/pwa/out/_next/static/chunks/6522-9866c002b5531836.js +0 -1
  387. package/apps/pwa/out/_next/static/chunks/6729-b4a558b7aa891e0c.js +0 -1
  388. package/apps/pwa/out/_next/static/chunks/6969-cb03f9410b7d2e03.js +0 -1
  389. package/apps/pwa/out/_next/static/chunks/7007-3b9861091bb8dd21.js +0 -1
  390. package/apps/pwa/out/_next/static/chunks/7930-8dc7e20fc6fc19ca.js +0 -1
  391. package/apps/pwa/out/_next/static/chunks/8071-187edbc22a86741f.js +0 -1
  392. package/apps/pwa/out/_next/static/chunks/8198-d4101ad70cb9a579.js +0 -1
  393. package/apps/pwa/out/_next/static/chunks/8250.4a2c5553a07cdf47.js +0 -1
  394. package/apps/pwa/out/_next/static/chunks/8293-123b91e7b0330dc0.js +0 -1
  395. package/apps/pwa/out/_next/static/chunks/8296-d6d5d87dfa911d41.js +0 -1
  396. package/apps/pwa/out/_next/static/chunks/8305-603963c33ee8eec3.js +0 -1
  397. package/apps/pwa/out/_next/static/chunks/8612-4a0066f20951b8fd.js +0 -1
  398. package/apps/pwa/out/_next/static/chunks/9181-cf4e1b61c4783f92.js +0 -1
  399. package/apps/pwa/out/_next/static/chunks/9262-26c2ecbd5a67e4a2.js +0 -1
  400. package/apps/pwa/out/_next/static/chunks/9328-45abdebce4fbecb7.js +0 -1
  401. package/apps/pwa/out/_next/static/chunks/9355-dbc67205adf8745f.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/9763.255b90dd69875689.js +0 -1
  403. package/apps/pwa/out/_next/static/chunks/9933-66d31ec25c0231af.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-bd06fb55f4da0381.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4e586142da455a25.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-889ad5cddcf45b0d.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/app/board/page-47ba401d56572c27.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/app/botlab/page-0b54f9c83458e038.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/app/bots/page-4fcc296ef6c8ed90.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/app/chat/page-fe9fda494a87f4e5.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/app/control/page-f9642e25ce129590.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e1063e8ba5f3e2e7.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/app/editor/page-9d0df30027d8aa9d.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/app/healthz/route-bd06fb55f4da0381.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/app/intake/page-d97adf2c9455b8d0.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/app/layout-236b80d202110362.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/app/live/page-21a30f35f1a276ad.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/app/market/page-b1a5be357c4fa25d.js +0 -1
  419. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1705a60303f7f573.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/app/morning/page-76b337c11ad0e237.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/app/not-found-7c0f85fbb56f64c6.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/app/observatory/page-65ca16b20617b44d.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/app/page-e7f9b8fc29411c1d.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/app/reflection/page-92ea6213d1aeec04.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a913a005aacb5476.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2d78804a40dfdef6.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-08a99148e780ac00.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/app/settings/page-deb674e7ed36f815.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-49f8de0534d192d7.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/app/setup/layout-bd06fb55f4da0381.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/app/setup/page-ba162a28d2176e18.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/app/share/page-1ff1a37b550ab41a.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/app/showroom/page-ccaa698f56c0fbdb.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/app/tasks/page-53b944082de1d7db.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/app/term/page-9b70adf1552789bf.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/app/trace/page-30d482aa63241fe8.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/app/vault/page-aecf786f54651d8a.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6ab9b62c7b6e08f2.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/app/workflows/page-08949735455e0c9a.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/app/workspace/page-a1479005234a46c2.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3890e90bd232732.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/beb5cf10-9adcc10b83930090.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/framework-d68d41c88e05c801.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/main-app-11c63971b7a9593b.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/main-d09452353bd0d9cc.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/pages/_app-184d727cebeca767.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/pages/_error-21bbbbac99b720b1.js +0 -1
  448. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +0 -1
  449. package/apps/pwa/out/_next/static/qMI0jnlZaBjjm4aIDYNGM/_buildManifest.js +0 -1
  450. /package/apps/pwa/out/_next/static/{qMI0jnlZaBjjm4aIDYNGM → keajW7DDyghEs1y8oJe6T}/_ssgManifest.js +0 -0
@@ -51,7 +51,9 @@ export interface OAuthTokens {
51
51
  tokenType?: string;
52
52
  }
53
53
 
54
- export type CodexMirrorResult = 'written' | 'not-created-missing-cli-fields' | 'write-failed';
54
+ export type CodexMirrorResult = 'written' | 'not-created-missing-cli-fields' | 'write-failed'
55
+ // AUTH1 — ~/.codex is the Codex CLI's file: never mix another account's tokens into it.
56
+ | 'skipped-different-account' | 'skipped-unknown-account';
55
57
 
56
58
  export interface ProviderAuthState {
57
59
  tokens: OAuthTokens;
@@ -245,6 +247,9 @@ export interface WriteTokensOpts {
245
247
  /** Default true for 'openai-codex'. Set false to skip the ~/.codex
246
248
  * mirror (e.g. in tests that shouldn't touch the user's home). */
247
249
  mirrorCodex?: boolean;
250
+ /** AUTH1 — when the Codex CLI file belongs to a different account, replace it wholly with this
251
+ * login (id_token · account_id · tokens) instead of leaving it. Only on explicit user consent. */
252
+ replaceDifferentCodexAccount?: boolean;
248
253
  /** Explicit ChatGPT claims override. Normally left undefined — for
249
254
  * 'openai-codex' with OAuth tokens, saveTokens auto-decodes the
250
255
  * access-token JWT so every refresh site picks up fresh claims
@@ -296,7 +301,10 @@ export function saveTokens(
296
301
  ?? (provider === 'openai-codex' ? defaultCodexHome(process.env) : undefined);
297
302
  if (home) {
298
303
  // loginWithCodex → saveTokens reaches the Codex CLI mirror on each token save.
299
- state.codexMirrorResult = mirrorCodexAuth(tokens, state.lastRefresh, join(home, 'auth.json'));
304
+ state.codexMirrorResult = mirrorCodexAuth(tokens, state.lastRefresh, join(home, 'auth.json'), {
305
+ knownAccountId: state.chatGPT?.accountId,
306
+ replaceDifferentAccount: opts.replaceDifferentCodexAccount === true,
307
+ });
300
308
  }
301
309
  // ⛔ 이름 계정인데 홈을 모르면 «미러하지 않는다» — 모르는 곳에 토큰을 쓰지 않는다
302
310
  }
@@ -377,7 +385,12 @@ export function assertMirrorTargetIsSafeUnderTest(mirrorPath: string): void {
377
385
  * under `oauth.codex-mirror`. ⛔ The 2026-08-05 incident had to be traced by
378
386
  * guessing from the file's `last_refresh` FORMAT, which is deduction, not
379
387
  * observation. Token values are never logged — path + error kind only. */
380
- function mirrorCodexAuth(tokens: OAuthTokens, lastRefresh: string, mirrorPath: string = codexAuthPath()): CodexMirrorResult {
388
+ function mirrorCodexAuth(
389
+ tokens: OAuthTokens,
390
+ lastRefresh: string,
391
+ mirrorPath: string = codexAuthPath(),
392
+ account: { knownAccountId?: string; replaceDifferentAccount?: boolean } = {},
393
+ ): CodexMirrorResult {
381
394
  assertMirrorTargetIsSafeUnderTest(mirrorPath);
382
395
  try {
383
396
  const path = mirrorPath;
@@ -400,21 +413,45 @@ function mirrorCodexAuth(tokens: OAuthTokens, lastRefresh: string, mirrorPath: s
400
413
  && tokens.idToken.length > 0
401
414
  && typeof accountId === 'string'
402
415
  && accountId.length > 0;
416
+ // AUTH1 — the file is the Codex CLI's. Same account: rotate tokens as before. Different account
417
+ // (or ours unknown): leave it untouched unless the user asked to replace it — the old «hasBase»
418
+ // path kept the file's id_token/account_id and wrote our tokens next to them (two accounts mixed).
419
+ // Our account: id_token claim → stored claim → the access token's own claim. Refresh responses
420
+ // carry no id_token, and named rotation accounts keep their CLI homes in sync through this path —
421
+ // so an unknown account keeps the old rotation behaviour; only «both known and different» is refused.
422
+ const ourAccount = (typeof accountId === 'string' && accountId) || account.knownAccountId
423
+ || extractChatGPTClaims(tokens.accessToken)?.accountId || undefined;
424
+ const baseTokens = (existing.tokens && typeof existing.tokens === 'object') ? existing.tokens as Record<string, unknown> : {};
425
+ const baseAccount = typeof baseTokens.account_id === 'string' && baseTokens.account_id ? baseTokens.account_id : undefined;
426
+ let replaceWholly = false;
427
+ if (hasBase && baseAccount && !ourAccount) debug.log('oauth.codex-mirror', 'account-unknown', { path });
428
+ if (hasBase && baseAccount && ourAccount) {
429
+ if (ourAccount !== baseAccount) {
430
+ if (!account.replaceDifferentAccount || !canCreateUsableMirror) {
431
+ debug.log('oauth.codex-mirror', 'skipped-different-account', { path, replaceRequested: account.replaceDifferentAccount === true });
432
+ return 'skipped-different-account';
433
+ }
434
+ replaceWholly = true;
435
+ }
436
+ }
437
+
403
438
  if (!hasBase && !canCreateUsableMirror) {
404
439
  debug.log('oauth.codex-mirror', 'not-created-missing-cli-fields', { path });
405
440
  return 'not-created-missing-cli-fields';
406
441
  }
407
442
 
408
443
  mkdirSync(dirname(path), { recursive: true });
444
+ if (replaceWholly) existing = {};
445
+ const fresh = !hasBase || replaceWholly;
409
446
  const priorTokens = (existing.tokens && typeof existing.tokens === 'object')
410
447
  ? existing.tokens as Record<string, unknown> : {};
411
448
  existing.tokens = {
412
449
  ...priorTokens,
413
- ...(hasBase ? {} : { id_token: tokens.idToken, account_id: accountId }),
450
+ ...(fresh ? { id_token: tokens.idToken, account_id: accountId } : {}),
414
451
  access_token: tokens.accessToken,
415
452
  refresh_token: tokens.refreshToken,
416
453
  };
417
- if (!hasBase) {
454
+ if (fresh) {
418
455
  existing.OPENAI_API_KEY = null;
419
456
  existing.auth_mode = 'chatgpt';
420
457
  }
@@ -0,0 +1,29 @@
1
+ export interface ContinueHereOptions {
2
+ daemonRunning: boolean;
3
+ /** Resolved PWA URL for the running daemon, if available. */
4
+ pwaUrl?: string;
5
+ /** Already-issued short-lived phone connection link; never pass its token separately. */
6
+ phoneLink?: string;
7
+ telegramEnabled: boolean;
8
+ /** Non-interactive output must not include links (or QR payloads). */
9
+ interactive: boolean;
10
+ }
11
+
12
+ /** Render post-setup directions without inspecting the daemon, issuing credentials, or performing IO. */
13
+ export function continueHereLines(opts: ContinueHereOptions): string[] {
14
+ const lines = [' Continue here:'];
15
+ if (!opts.daemonRunning) lines.push(' Start the daemon: `elanous nexus run`');
16
+ if (opts.interactive && opts.daemonRunning && opts.pwaUrl) {
17
+ lines.push(` Browser: ${opts.pwaUrl}`);
18
+ } else {
19
+ lines.push(' Browser: `elanous nexus show`');
20
+ }
21
+ if (opts.interactive && opts.daemonRunning && opts.phoneLink) {
22
+ lines.push(` Phone: ${opts.phoneLink}`);
23
+ lines.push(' ⚠ This link contains a connection token — do not share it or include it in a public screenshot.');
24
+ } else {
25
+ lines.push(' Phone: `elanous phone link --temp --ttl 24h`');
26
+ }
27
+ if (opts.telegramEnabled) lines.push(' Telegram: `elanous telegram`');
28
+ return lines;
29
+ }
@@ -0,0 +1,8 @@
1
+ export const UNATTENDED_SETUP_COMMAND = 'elanous onboarding --non-interactive --config <answers.json>';
2
+ export const SKILLS_STEP_COMMAND = 'elanous onboarding skills';
3
+
4
+ export function unattendedSetupHint(): string {
5
+ return `unattended: \`${UNATTENDED_SETUP_COMMAND}\``;
6
+ }
7
+
8
+ export const SKILLS_LIST_DESCRIPTION = 'List elanous skills from configured skill directories (skills.activeSet / skills.dirs and packaged skills): subdirectories and the first non-heading line of each SKILL.md. Read-only.';
@@ -147,6 +147,28 @@ export function fullScreenIO(opts: FullScreenIOOpts = {}): WizardIO {
147
147
  out.write(composeFullPaint(spec));
148
148
  };
149
149
 
150
+ // OB4(2026-10-01 · 0.2.6 실물): print() 는 «다음 질문 화면»에 묻어 그린다 — 그런데 기기 코드 로그인처럼
151
+ // 질문 없이 오래 기다리는 구간에선 다음 화면이 오지 않아 코드·URL 이 끝내 안 보이고, 원시 모드라 Ctrl-C 도
152
+ // 신호가 안 돼 «멈춤»이 됐다. 질문이 없을 때 print 는 곧바로 메시지 화면을 그리고 Ctrl-C 감시를 붙인다.
153
+ let questionDepth = 0;
154
+ let idleWatcher: ((chunk: string | Buffer) => void) | null = null;
155
+ const detachIdleWatcher = (): void => {
156
+ if (idleWatcher) { inp.off('data', idleWatcher); idleWatcher = null; }
157
+ };
158
+ const attachIdleWatcher = (): void => {
159
+ if (idleWatcher || !inp.isTTY) return;
160
+ idleWatcher = (chunk) => {
161
+ const s = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
162
+ if (s.includes('\x03')) handleSigInt();
163
+ };
164
+ inp.on('data', idleWatcher);
165
+ };
166
+ const inQuestion = async <R>(fn: () => Promise<R>): Promise<R> => {
167
+ detachIdleWatcher();
168
+ questionDepth++;
169
+ try { return await fn(); } finally { questionDepth--; }
170
+ };
171
+
150
172
  // ── Raw key reader ──────────────────────────────────────────────
151
173
  const readKey = (): Promise<MiniKey> =>
152
174
  new Promise((resolve) => {
@@ -159,7 +181,12 @@ export function fullScreenIO(opts: FullScreenIOOpts = {}): WizardIO {
159
181
  });
160
182
 
161
183
  // ── choose ─────────────────────────────────────────────────────
162
- const choose = async <T>(
184
+ const choose = <T>(
185
+ prompt: string,
186
+ options: ChoiceOption<T>[],
187
+ opts: ChooseOpts = {},
188
+ ): Promise<T> => inQuestion(() => chooseInner(prompt, options, opts));
189
+ const chooseInner = async <T>(
163
190
  prompt: string,
164
191
  options: ChoiceOption<T>[],
165
192
  opts: ChooseOpts = {},
@@ -343,11 +370,11 @@ export function fullScreenIO(opts: FullScreenIOOpts = {}): WizardIO {
343
370
 
344
371
  // ── ask ────────────────────────────────────────────────────────
345
372
  const ask = async (prompt: string): Promise<string> => {
346
- return askInternal(prompt, false);
373
+ return inQuestion(() => askInternal(prompt, false));
347
374
  };
348
375
 
349
376
  const askSecret = async (prompt: string): Promise<string> => {
350
- return askInternal(prompt, true);
377
+ return inQuestion(() => askInternal(prompt, true));
351
378
  };
352
379
 
353
380
  const askInternal = async (prompt: string, mask: boolean): Promise<string> => {
@@ -407,6 +434,10 @@ export function fullScreenIO(opts: FullScreenIOOpts = {}): WizardIO {
407
434
  // box — the wizard frame already contains the same info.
408
435
  if (isBannerLine(text)) return;
409
436
  messages.push({ text, kind: 'plain' });
437
+ if (questionDepth === 0) {
438
+ paint(buildScreenSpec({ kind: 'message', lines: [] }, 'Ctrl-C cancel'));
439
+ attachIdleWatcher();
440
+ }
410
441
  };
411
442
 
412
443
  return {
@@ -414,6 +445,7 @@ export function fullScreenIO(opts: FullScreenIOOpts = {}): WizardIO {
414
445
  askSecret,
415
446
  print,
416
447
  close: () => {
448
+ detachIdleWatcher();
417
449
  exitRaw();
418
450
  // Final clear so any leftover screen does not interfere with
419
451
  // the post-wizard CLI banner / dashboard.
@@ -16,4 +16,4 @@ per line, blank line to finish. Paths that don't exist yet are
16
16
  kept anyway so you can create them later.
17
17
 
18
18
  You can change the active preset any time via:
19
- elanous setup skills
19
+ elanous onboarding skills
@@ -128,6 +128,7 @@ export function nonInteractiveIO(opts: NonInteractiveOptions = {}): WizardIO {
128
128
  section = STEP_SECTIONS[spec.index];
129
129
  },
130
130
  print,
131
+ nonInteractive: true,
131
132
  complete: reportUnusedAnswers,
132
133
  close: () => { /* no resources to release */ },
133
134
  };
@@ -0,0 +1,27 @@
1
+ // Onboarding step 1 — turn detected subscription logins into «Found» lines and a default provider (OB1 · 10-01).
2
+ // A fresh user with a ChatGPT/Codex or Grok login was shown «Auto-detect (env vars)» preselected and nothing found.
3
+ import type { DetectedProvider } from '../llm/provider-detect.js';
4
+
5
+ export interface SubscriptionHint {
6
+ found: Array<{ provider: 'openai-codex' | 'grok'; line: string }>;
7
+ /** Provider to preselect when the user has not chosen one yet. */
8
+ preferred: 'openai-codex' | 'grok';
9
+ }
10
+
11
+ const SOURCE_LABEL: Record<string, string> = {
12
+ 'codex-auth': '~/.codex/auth.json',
13
+ 'elanous-auth': 'elanous login',
14
+ 'grok-auth': '~/.grok/auth.json',
15
+ };
16
+
17
+ /** Subscriptions first: codex, then grok. With none found, codex is still the default (most users have ChatGPT). */
18
+ export function subscriptionHint(detected: readonly DetectedProvider[]): SubscriptionHint {
19
+ const found: SubscriptionHint['found'] = [];
20
+ for (const provider of ['openai-codex', 'grok'] as const) {
21
+ const hit = detected.find(d => d.provider === provider && d.auth === 'oauth');
22
+ if (!hit) continue;
23
+ const name = provider === 'openai-codex' ? 'ChatGPT / Codex subscription' : 'Grok subscription';
24
+ found.push({ provider, line: ` Found ${name} (${SOURCE_LABEL[hit.source] ?? hit.source})` });
25
+ }
26
+ return { found, preferred: found[0]?.provider ?? 'openai-codex' };
27
+ }
@@ -0,0 +1,83 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { isHeadlessEnv } from '../acp/codex-auth.js';
3
+ import { runNexusShow, type NexusShowResult } from '../cli/nexus-show.js';
4
+ import { debug } from '../debug/log.js';
5
+ import type { UserConfig } from '../user-config.js';
6
+
7
+ export interface WebFirstSetupDeps {
8
+ config: Pick<UserConfig, 'onboarding'>;
9
+ isTty?: boolean;
10
+ terminal?: boolean;
11
+ showNexus?: () => Promise<NexusShowResult>;
12
+ issueSetupLinkToken?: () => Promise<string | { token: string }>;
13
+ renderQr?: (link: string) => string | undefined;
14
+ openBrowser?: (link: string) => boolean;
15
+ isHeadless?: () => boolean;
16
+ print?: (line: string) => void;
17
+ }
18
+
19
+ function setupUrl(pwa: string, token: string): string {
20
+ return `${pwa.replace(/\/app\/?$/, '').replace(/\/$/, '')}/setup#t=${encodeURIComponent(token)}`;
21
+ }
22
+
23
+ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-shown' | 'fallback'> {
24
+ const observe = (event: 'link-shown' | 'fallback', reason?: string, qr = false, browserOpened = false, remote: 'loopback' | 'tailnet' = 'loopback') => {
25
+ try { debug.log('onboarding.web-first', event, { ...(reason ? { reason } : {}), qr, browserOpened, remote }); }
26
+ catch { /* Observability must not block onboarding. */ }
27
+ };
28
+ if (deps.config.onboarding.webFirst !== true) { observe('fallback', 'disabled'); return 'fallback'; }
29
+ if ((deps.isTty ?? (process.stdin.isTTY === true)) !== true) { observe('fallback', 'non-tty'); return 'fallback'; }
30
+ if (deps.terminal) { observe('fallback', 'terminal'); return 'fallback'; }
31
+
32
+ let shown: NexusShowResult;
33
+ try {
34
+ shown = await (deps.showNexus ?? (() => runNexusShow({ format: 'json', out: { log: () => {}, error: () => {} } })))();
35
+ } catch { observe('fallback', 'daemon-unavailable'); return 'fallback'; }
36
+ const running = shown.status === 'unregistered' || (shown.status === 'registered' && shown.instance?.alive === true);
37
+ if (!running || !shown.urls?.pwa.loopback) { observe('fallback', 'daemon-unavailable'); return 'fallback'; }
38
+
39
+ let token: string;
40
+ try {
41
+ const issue = deps.issueSetupLinkToken ?? (async () => {
42
+ const modulePath = '../auth/setup-link-token.js';
43
+ const mod = await import(modulePath) as { issueSetupLinkToken?: (options: Record<string, never>) => Promise<string | { token: string }> };
44
+ if (typeof mod.issueSetupLinkToken !== 'function') throw new Error('issuer-missing');
45
+ return mod.issueSetupLinkToken({});
46
+ });
47
+ const issued = await issue();
48
+ token = typeof issued === 'string' ? issued : issued?.token;
49
+ if (!token) throw new Error('issuer-missing');
50
+ } catch { observe('fallback', 'issuer-missing'); return 'fallback'; }
51
+
52
+ const print = deps.print ?? console.log;
53
+ const link = setupUrl(shown.urls.pwa.loopback, token);
54
+ const phoneLink = shown.urls.pwa.tailnet ? setupUrl(shown.urls.pwa.tailnet, token) : undefined;
55
+ print('브라우저에서 셋업을 이어가세요');
56
+ print(link);
57
+ let qr = false;
58
+ if (phoneLink) {
59
+ try {
60
+ const rendered = (deps.renderQr ?? ((url: string) => {
61
+ const result = spawnSync('qrencode', ['-t', 'ANSIUTF8', url], { encoding: 'utf8' });
62
+ return result.status === 0 ? result.stdout : undefined;
63
+ }))(phoneLink);
64
+ if (rendered) {
65
+ print(rendered);
66
+ print('같은 와이파이·tailnet 의 폰 카메라로 스캔하세요');
67
+ qr = true;
68
+ }
69
+ } catch { /* QR is optional. */ }
70
+ }
71
+ print('터미널에서 하려면: `elanous setup --terminal`');
72
+ let browserOpened = false;
73
+ if (!(deps.isHeadless ?? (() => isHeadlessEnv(process.env)))()) {
74
+ try {
75
+ browserOpened = (deps.openBrowser ?? ((url: string) => {
76
+ const command = process.platform === 'darwin' ? 'open' : process.platform === 'linux' || process.platform === 'freebsd' || process.platform === 'openbsd' ? 'xdg-open' : undefined;
77
+ return command ? spawnSync(command, [url], { stdio: 'ignore' }).status === 0 : false;
78
+ }))(link);
79
+ } catch { /* The displayed link remains usable. */ }
80
+ }
81
+ observe('link-shown', undefined, qr, browserOpened, phoneLink ? 'tailnet' : 'loopback');
82
+ return 'link-shown';
83
+ }