elanous 0.2.5 → 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 (479) hide show
  1. package/.env.example +10 -7
  2. package/README.md +9 -4
  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/{5391-8793f88b03b30161.js → 2375-cb6debea56cce4fb.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/{1751.50b96ea9c37b49b6.js → 2415.ed6428ff334c7ce2.js} +1 -1
  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/{4daa2798-1363d725c79f3593.js → 2ea96958-e8c7e112de50b067.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
  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/{8617.465ca22a319c95b3.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/{8918-482b30ce2a8ebf4c.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/{5348-bbf838e119661eee.js → 5791-bb82743fa6299562.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/{9704-3221c102623c8d73.js → 6062-73e68343a9814f6a.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/{4440-18bb160d95819f4e.js → 6090-85a3f05f954e5697.js} +1 -1
  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/{f6f3850d-7f324c6566002113.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-f89e9a303515a033.js → page-10ed24f413ed66e9.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/app/board/{page-4f403cd060442c95.js → page-211810b6c93ab66a.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-0ac5d053f0444d21.js → page-624f7a2f89b60c8f.js} +1 -1
  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-bccce0babceae30f.js → page-55d50e9b0006a91d.js} +1 -1
  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-2bf59c720fe9542c.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/icons/elanous-16.png +0 -0
  123. package/apps/pwa/out/icons/elanous-180.png +0 -0
  124. package/apps/pwa/out/icons/elanous-192.png +0 -0
  125. package/apps/pwa/out/icons/elanous-32.png +0 -0
  126. package/apps/pwa/out/icons/elanous-512.png +0 -0
  127. package/apps/pwa/out/index.html +1 -1
  128. package/apps/pwa/out/index.txt +21 -21
  129. package/apps/pwa/out/intake/index.html +1 -1
  130. package/apps/pwa/out/intake/index.txt +22 -22
  131. package/apps/pwa/out/live/index.html +1 -1
  132. package/apps/pwa/out/live/index.txt +22 -22
  133. package/apps/pwa/out/market/index.html +1 -1
  134. package/apps/pwa/out/market/index.txt +21 -21
  135. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  136. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  137. package/apps/pwa/out/morning/index.html +1 -1
  138. package/apps/pwa/out/morning/index.txt +22 -22
  139. package/apps/pwa/out/observatory/index.html +1 -1
  140. package/apps/pwa/out/observatory/index.txt +22 -22
  141. package/apps/pwa/out/reflection/index.html +1 -1
  142. package/apps/pwa/out/reflection/index.txt +22 -22
  143. package/apps/pwa/out/scheduler/index.html +1 -1
  144. package/apps/pwa/out/scheduler/index.txt +22 -22
  145. package/apps/pwa/out/sessions/index.html +1 -1
  146. package/apps/pwa/out/sessions/index.txt +21 -21
  147. package/apps/pwa/out/settings/devices/index.html +1 -1
  148. package/apps/pwa/out/settings/devices/index.txt +22 -22
  149. package/apps/pwa/out/settings/index.html +1 -1
  150. package/apps/pwa/out/settings/index.txt +22 -22
  151. package/apps/pwa/out/setup/done/index.html +1 -1
  152. package/apps/pwa/out/setup/done/index.txt +22 -22
  153. package/apps/pwa/out/setup/index.html +1 -1
  154. package/apps/pwa/out/setup/index.txt +22 -22
  155. package/apps/pwa/out/share/index.html +1 -1
  156. package/apps/pwa/out/share/index.txt +22 -22
  157. package/apps/pwa/out/showroom/index.html +1 -1
  158. package/apps/pwa/out/showroom/index.txt +21 -21
  159. package/apps/pwa/out/tasks/index.html +1 -1
  160. package/apps/pwa/out/tasks/index.txt +22 -22
  161. package/apps/pwa/out/term/index.html +1 -1
  162. package/apps/pwa/out/term/index.txt +22 -22
  163. package/apps/pwa/out/trace/index.html +1 -1
  164. package/apps/pwa/out/trace/index.txt +22 -22
  165. package/apps/pwa/out/vault/index.html +1 -1
  166. package/apps/pwa/out/vault/index.txt +22 -22
  167. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  168. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  169. package/apps/pwa/out/workflows/index.html +1 -1
  170. package/apps/pwa/out/workflows/index.txt +22 -22
  171. package/apps/pwa/out/workspace/index.html +1 -1
  172. package/apps/pwa/out/workspace/index.txt +22 -22
  173. package/apps/pwa/out/worktrees/index.html +1 -1
  174. package/apps/pwa/out/worktrees/index.txt +22 -22
  175. package/bin/elanous.cjs +107 -0
  176. package/graphs/field/field-feed.yaml +24 -0
  177. package/graphs/field/recipes.yaml +12 -0
  178. package/graphs/landing/landing-heal.yaml +3 -1
  179. package/graphs/landing/recipes.yaml +3 -0
  180. package/graphs/release/recipes.yaml +13 -0
  181. package/graphs/release/release-loop.yaml +13 -4
  182. package/package.json +5 -5
  183. package/plugins/card-followup/README.md +42 -0
  184. package/plugins/card-followup/examples/card-sample.json +7 -0
  185. package/plugins/card-followup/graphs/card-followup.yaml +18 -0
  186. package/plugins/card-followup/graphs/recipes.yaml +16 -0
  187. package/plugins/card-followup/graphs/run-step.ts +276 -0
  188. package/plugins/card-followup/graphs/sales-strategy.ts +173 -0
  189. package/plugins/card-followup/plugin.json +25 -0
  190. package/plugins/doc-draft/README.md +13 -0
  191. package/plugins/doc-draft/examples/brief-sample.json +8 -0
  192. package/plugins/doc-draft/graphs/doc-draft.yaml +14 -0
  193. package/plugins/doc-draft/graphs/recipes.yaml +9 -0
  194. package/plugins/doc-draft/graphs/run-step.ts +113 -0
  195. package/plugins/doc-draft/plugin.json +24 -0
  196. package/plugins/geo-check/README.md +15 -0
  197. package/plugins/geo-check/examples/brand-sample.json +8 -0
  198. package/plugins/geo-check/graphs/geo-check.yaml +20 -0
  199. package/plugins/geo-check/graphs/recipes.yaml +18 -0
  200. package/plugins/geo-check/graphs/run-step.ts +198 -0
  201. package/plugins/geo-check/plugin.json +24 -0
  202. package/plugins/job-coach/.codex-plugin/plugin.json +1 -1
  203. package/plugins/job-coach/README.md +31 -1
  204. package/plugins/job-coach/graphs/run-step.ts +2 -2
  205. package/plugins/job-coach/plugin.json +1 -1
  206. package/plugins/job-coach/plugin.ts +1 -1
  207. package/scripts/affinity/endcard.sh +3 -2
  208. package/scripts/affinity/reframe.sh +3 -1
  209. package/scripts/ci-public-export-leak-gate.ts +48 -0
  210. package/scripts/codex-quota-alert.ts +122 -258
  211. package/scripts/coord-tracks.json +4 -4
  212. package/scripts/daemon-port-baseline.txt +1 -2
  213. package/scripts/field-feed/deliver-node.ts +52 -0
  214. package/scripts/field-feed/feed-node.ts +67 -0
  215. package/scripts/field-feed/lib.ts +162 -0
  216. package/scripts/field-feed/reel-node.ts +24 -0
  217. package/scripts/field-feed/start.ts +62 -0
  218. package/scripts/fixtures/vflow-sample.ndjson +6 -0
  219. package/scripts/install.sh +92 -13
  220. package/scripts/landing-heal/clean-checkout.ts +114 -0
  221. package/scripts/landing-heal/run-mission.ts +38 -3
  222. package/scripts/lib/android-test-device.ts +32 -0
  223. package/scripts/lib/pwa-scenarios/scenarios.ts +2 -1
  224. package/scripts/public-export.ts +8 -4
  225. package/scripts/release-loop/baseline-from-logs.ts +92 -0
  226. package/scripts/release-loop/checklist-gate-node.ts +35 -0
  227. package/scripts/release-loop/env-known-failures.ts +31 -0
  228. package/scripts/release-loop/gate-diff.ts +29 -0
  229. package/scripts/release-loop/gate-node.ts +124 -29
  230. package/scripts/release-loop/known-issues-node.ts +159 -0
  231. package/scripts/release-loop/npm-publish-node.ts +118 -0
  232. package/scripts/release-loop/ops-upgrade-node.ts +87 -0
  233. package/scripts/release-loop/release-readiness.ts +58 -0
  234. package/scripts/release-loop/shard-plan.ts +47 -0
  235. package/scripts/release-loop/unattended-release.ts +93 -0
  236. package/scripts/ux/measure-first-text.ts +102 -0
  237. package/scripts/ux/record-page.ts +4 -1
  238. package/scripts/vflow-collect.ts +20 -7
  239. package/scripts/vflow-search.ts +73 -0
  240. package/scripts/video-free-line-test-walker.ts +36 -0
  241. package/scripts/video-pipeline.ts +2 -2
  242. package/skills/explainer-video/SKILL.md +24 -3
  243. package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -1
  244. package/skills/explainer-video/engine/build.mjs +2 -2
  245. package/skills/explainer-video/engine/reel.mjs +235 -0
  246. package/skills/explainer-video/engine/reel.sh +9 -0
  247. package/skills/explainer-video/engine/vo.ts +58 -16
  248. package/skills/explainer-video/examples/elanous-0.2.5/script.json +1 -1
  249. package/skills/grill-me/SKILL.md +1 -1
  250. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +1 -1
  251. package/src/a2a/server.ts +2 -0
  252. package/src/acp/elanous-aware-peers.ts +30 -0
  253. package/src/acp/server.ts +91 -15
  254. package/src/agent/monad-agent-turn.ts +25 -6
  255. package/src/agent/shared-app-tools.ts +5 -3
  256. package/src/agent-substrate/review-intent.ts +6 -2
  257. package/src/agent-substrate/shard-boundary-intent.ts +70 -0
  258. package/src/auth/github-app-token.ts +4 -1
  259. package/src/autopilot/mission-origin.ts +20 -4
  260. package/src/autopilot/mission-phase-track.ts +11 -1
  261. package/src/autopilot/track-agent-shadow.ts +151 -0
  262. package/src/autopilot/track-agent.ts +26 -6
  263. package/src/autopilot/track-courier.ts +2 -2
  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/chat/chat-cli.ts +4 -1
  271. package/src/chat/short-question.ts +40 -0
  272. package/src/cli/agent-cli.ts +24 -15
  273. package/src/cli/ask-bare.ts +42 -0
  274. package/src/cli/cli-user-error.ts +25 -0
  275. package/src/cli/codex-credit-plan-view.ts +25 -0
  276. package/src/cli/dependence-gauge.ts +237 -0
  277. package/src/cli/doctor-cli.ts +5 -0
  278. package/src/cli/doctor-modes.ts +48 -0
  279. package/src/cli/intake-cli.ts +12 -2
  280. package/src/cli/intake-source-cli.ts +58 -0
  281. package/src/cli/machine-cli.ts +23 -0
  282. package/src/cli/msg-cli.ts +137 -0
  283. package/src/cli/nexus-ios-bind.ts +25 -8
  284. package/src/cli/phone-link.ts +117 -0
  285. package/src/cli/plugin-cli.ts +52 -0
  286. package/src/cli/pr-cli.ts +36 -0
  287. package/src/cli/private-ledger-commands.ts +31 -0
  288. package/src/cli/provider-cli.ts +5 -0
  289. package/src/cli/release-cli.ts +56 -12
  290. package/src/cli/release-run-if-ready.ts +48 -0
  291. package/src/cli/setup-cli.ts +27 -6
  292. package/src/cli/setup-recommend.ts +8 -0
  293. package/src/cli/usage-cli.ts +11 -1
  294. package/src/codex/setup.ts +27 -8
  295. package/src/dashboard/index.ts +1 -1
  296. package/src/discord.ts +56 -6
  297. package/src/domains/core-tools.ts +37 -14
  298. package/src/domains/outbound-alert.ts +55 -16
  299. package/src/exec-requests/planner.ts +140 -0
  300. package/src/exec-requests/runner.ts +338 -0
  301. package/src/exec-requests/store.ts +76 -0
  302. package/src/field/field-media.ts +250 -0
  303. package/src/field/field-reel.ts +196 -0
  304. package/src/grok/credential.ts +7 -5
  305. package/src/harness/aside-run-status.ts +33 -0
  306. package/src/harness/browser-verify.ts +48 -17
  307. package/src/harness/harness-cli-command.ts +25 -3
  308. package/src/harness/image-load-state.ts +21 -0
  309. package/src/harness/process-garbage.ts +45 -0
  310. package/src/index.ts +104 -38
  311. package/src/instance/leader.ts +13 -1
  312. package/src/intake-plane/collect-github.ts +5 -3
  313. package/src/intake-plane/collect-telegram-saved.ts +15 -3
  314. package/src/intake-plane/discord-seat-work.ts +56 -0
  315. package/src/intake-plane/intake-sources.ts +202 -0
  316. package/src/intake-plane/items.ts +28 -12
  317. package/src/intake-plane/seat-doc-route.ts +207 -0
  318. package/src/intake-plane/submit-intake-work.ts +9 -1
  319. package/src/intake-plane/telegram-seat-work.ts +72 -0
  320. package/src/llm/model-defaults.ts +24 -1
  321. package/src/llm.ts +5 -4
  322. package/src/machines/machine-ledger.ts +127 -0
  323. package/src/market/pack-internal-refs.ts +28 -0
  324. package/src/market/publish.ts +31 -4
  325. package/src/maturity/feature-maturity.ts +65 -0
  326. package/src/model-tier/turn-tier.ts +24 -0
  327. package/src/msg/msg-store.ts +149 -0
  328. package/src/native-tool-catalog.ts +2 -1
  329. package/src/nexus/api/chat-fast-path-config.ts +28 -0
  330. package/src/nexus/api/consult-requests.ts +117 -0
  331. package/src/nexus/api/discord-trigger-bot.ts +3 -0
  332. package/src/nexus/api/exec-requests.ts +51 -0
  333. package/src/nexus/api/field-uploads.ts +180 -0
  334. package/src/nexus/api/graph-approvals-feed.ts +140 -0
  335. package/src/nexus/api/graph-approvals.ts +120 -4
  336. package/src/nexus/api/harness-api.ts +219 -5
  337. package/src/nexus/api/http-server.ts +68 -5
  338. package/src/nexus/api/seat-requests.ts +254 -0
  339. package/src/nexus/api/trace-run-scan.ts +37 -0
  340. package/src/nexus/api/trace.ts +19 -3
  341. package/src/nexus/index.ts +3 -0
  342. package/src/nexus/setup-status.ts +4 -5
  343. package/src/notify/llm-budget-alert.ts +125 -0
  344. package/src/oauth/codex-account-rotation.ts +26 -4
  345. package/src/oauth/codex-account-store.ts +20 -2
  346. package/src/oauth/codex-browser-login.ts +173 -0
  347. package/src/oauth/codex.ts +4 -1
  348. package/src/oauth/fallback-chain.ts +5 -5
  349. package/src/oauth/store.ts +42 -5
  350. package/src/onboarding/continue-here.ts +29 -0
  351. package/src/onboarding/entry-hints.ts +8 -0
  352. package/src/onboarding/full-screen-io.ts +35 -3
  353. package/src/onboarding/help/skills.md +1 -1
  354. package/src/onboarding/non-interactive.ts +1 -0
  355. package/src/onboarding/subscription-hint.ts +27 -0
  356. package/src/onboarding/web-first.ts +83 -0
  357. package/src/onboarding.ts +230 -23
  358. package/src/plugins/maker/node-install.ts +92 -0
  359. package/src/plugins/maker/node-maker.ts +139 -0
  360. package/src/plugins/maker/plugin-maker.ts +220 -0
  361. package/src/policy/llm-policy.ts +268 -0
  362. package/src/prompt-library/session-guidance.ts +7 -1
  363. package/src/prompt-library/universal-preamble.ts +2 -2
  364. package/src/relay/channel.ts +184 -0
  365. package/src/relay/mux.ts +182 -0
  366. package/src/relay/relay-cli.ts +20 -0
  367. package/src/relay/relay-server.ts +220 -0
  368. package/src/relay/test-vectors.json +29 -0
  369. package/src/release-loop/checklist.ts +36 -9
  370. package/src/seat-address/seat-address.ts +34 -0
  371. package/src/self-dev/decompose.ts +1 -0
  372. package/src/self-dev/dev-pipeline.ts +6 -3
  373. package/src/self-dev/run-record-mirror.ts +44 -0
  374. package/src/self-dev/run-store.ts +12 -3
  375. package/src/self-implement/harness-policy-gates.ts +4 -1
  376. package/src/self-implement/report-origin.ts +12 -1
  377. package/src/self-implement/run-ledger-compact.ts +1 -1
  378. package/src/session/chat.ts +17 -5
  379. package/src/session/index.ts +23 -10
  380. package/src/skills/shared-agent-skill-roots.ts +25 -0
  381. package/src/steward/failure-streak.ts +78 -0
  382. package/src/steward/steward-cards.ts +24 -0
  383. package/src/steward/triage-budget.ts +127 -0
  384. package/src/steward/triage-plan.ts +75 -0
  385. package/src/steward/triage.ts +244 -42
  386. package/src/task-cards/card-store.ts +1 -1
  387. package/src/task-orchestrator/surfaces/pod-bun-cache.ts +18 -0
  388. package/src/task-orchestrator/surfaces/pod-command-job.ts +12 -3
  389. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  390. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +68 -0
  391. package/src/task-orchestrator/surfaces/self-implement-pod.ts +78 -4
  392. package/src/telegram.ts +145 -2
  393. package/src/tool-runtime/elanous-skills-list-runtime.ts +3 -3
  394. package/src/tool-runtime/self-cognition-runtimes.ts +160 -2
  395. package/src/user-config.ts +84 -4
  396. package/src/version/packed-revision.json +1 -1
  397. package/src/video-pipeline/recipes/character.ts +42 -5
  398. package/src/video-pipeline/recipes/explainer.ts +213 -0
  399. package/src/video-pipeline/recipes/ffmpeg.ts +1 -1
  400. package/src/video-pipeline/recipes/free-line.ts +16 -3
  401. package/src/video-pipeline/recipes/remote.ts +7 -1
  402. package/src/video-pipeline/vflow-reference.ts +109 -0
  403. package/src/video-pipeline/walk-line.ts +3 -2
  404. package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +0 -25
  411. package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +0 -5
  419. package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/7527.943753b6ed829f09.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/9238.2cd5f47f4bf7a2c3.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +0 -1
  477. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +0 -1
  478. package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +0 -1
  479. /package/apps/pwa/out/_next/static/{ktMqfrBbf8BMGac0jqLrb → keajW7DDyghEs1y8oJe6T}/_ssgManifest.js +0 -0
@@ -0,0 +1,173 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+
4
+ type Data = Record<string, unknown>;
5
+ const object = (value: unknown): Data => value && typeof value === 'object' && !Array.isArray(value) ? value as Data : {};
6
+ const text = (value: unknown): string => typeof value === 'string' ? value.trim() : '';
7
+
8
+ type Fit = {
9
+ score: number | null;
10
+ label: 'high' | 'medium' | 'low' | 'unknown';
11
+ reasons: { text: string; basis: string }[];
12
+ };
13
+ type Approach = { who: string; problem: string; proposal: string; channel: string; timing: string };
14
+ type NextAction = { what: string; due: string };
15
+ type Strategy = { fit: Fit; approach: Approach; nextAction: NextAction };
16
+ type CrmRow = Record<(typeof columns)[number], string>;
17
+ const columns = ['name', 'company', 'title', 'email', 'interest', 'met_context', 'fit_score', 'fit_label', 'next_action', 'due', 'updated_at'] as const;
18
+
19
+ function parseAnswer(raw: unknown): Data {
20
+ const response = object(raw);
21
+ if (typeof response.reply === 'string') {
22
+ const reply = response.reply;
23
+ const start = reply.indexOf('{'), end = reply.lastIndexOf('}');
24
+ if (start < 0 || end < start) throw new Error('strategy 응답 JSON 객체 없음');
25
+ return object(JSON.parse(reply.slice(start, end + 1)));
26
+ }
27
+ return response;
28
+ }
29
+
30
+ async function defaultAsk(payload: Data): Promise<unknown> {
31
+ const child = Bun.spawn(['elanous', 'ask', '--json', JSON.stringify(payload)], { stdout: 'pipe', stderr: 'pipe', env: process.env });
32
+ const [stdout, stderr, status] = await Promise.all([new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited]);
33
+ if (status !== 0) throw new Error(`ask 실패: ${(stderr || stdout).slice(0, 200)}`);
34
+ return JSON.parse(stdout);
35
+ }
36
+
37
+ export async function buildStrategy({ card, research, context = '', offer = '', ask = defaultAsk }: {
38
+ card: Data; research: Data; context?: string; offer?: string; ask?: (payload: Data) => Promise<unknown>;
39
+ }): Promise<Strategy> {
40
+ const sources = Array.isArray(research.sources) ? research.sources.map(object).filter(source => /^https?:\/\//.test(text(source.url))) : [];
41
+ const evidence = sources.map((source, i) => ({ id: `S${i + 1}`, title: text(source.title), snippet: text(source.snippet), url: text(source.url) }));
42
+ const hasOffer = !!text(offer);
43
+ const sourceBasis = (basis: string) => /^S[1-9]\d*$/.test(basis) && Number(basis.slice(1)) <= evidence.length
44
+ && !!(evidence[Number(basis.slice(1)) - 1]?.title || evidence[Number(basis.slice(1)) - 1]?.snippet);
45
+ const fitBasis = (basis: string) => basis === 'card' && Object.values(card).some(value => !!text(value))
46
+ || basis === 'context' && !!text(context) || basis === 'offer' && hasOffer || sourceBasis(basis);
47
+ const validBasis = (basis: string) => basis === 'assumption' || fitBasis(basis);
48
+ const citedEvidence = (basis: string) => /^S\d+$/.test(basis) ? evidence[Number(basis.slice(1)) - 1] : undefined;
49
+ const instruction = 'JSON 객체만 출력: {"fit":{"score":0~100,"label":"high|medium|low","reasons":[{"text":"이유","basis":"S1|card|context|offer"} 3개]},"approach":{"who":"누구에게","problem":"어떤 문제","proposal":"어떤 제안","channel":"어느 채널","timing":"언제"},"approachBasis":{"who":["card"],"problem":["S1"],"proposal":["offer"],"channel":["assumption"],"timing":["assumption"]},"nextAction":{"what":"할 일","due":"기한"},"nextActionBasis":{"what":["assumption"],"due":["assumption"]}}. approachBasis와 nextActionBasis에는 각 필드의 주장에 실제로 사용한 근거 번호/입력을 적을 것. S#는 제공된 evidence 번호만 사용. nextAction은 고객의 확정 약속이나 확정 일정을 주장하지 말고 우리가 제안할 내부 행동과 목표 기한으로만 작성할 것. 출처에 없는 사실을 꾸며내지 말 것. offer가 없으면 fit 평가는 하지 말고 명함과 만남 맥락만으로 접근 전략을 작성할 것. 메시지는 보내지 말 것. 전략은 구체적이어야 한다(일반론 «AI 로 효율화» 금지): who = 이름·직함 ⊕ 결정권 추정(추정이면 basis 에 assumption); problem = 그 회사가 지금 겪을 법한 문제 하나 — 근거는 출처 S# 또는 만남 맥락(context)이어야 하고 없으면 만남 맥락에서 나온 관심사로 좁힌다; proposal = 우리 제안 하나(수치 약속 없음 · 작은 시범·시연·파일럿처럼 바로 해 볼 수 있는 것); channel = 메일/LinkedIn/전화 중 하나 ⊕ 그 이유 한 구; timing = 날짜나 요일로(예: 행사 다음 날 오전 · 이번 주 금요일 전). fit 이유는 서로 다른 근거로 셋을 채워라(card·context·offer·S#).';
50
+ let answer: Data = {};
51
+ let reasons: Fit['reasons'] = [];
52
+ let feedback = '';
53
+ // Three tries: with company-site evidence the writer still over-cites about one run in three (10-01 dry runs 0.2.6–0.2.8);
54
+ // the third try gets the rejected fields by name. The verdict rule itself is unchanged.
55
+ const LAST = 2;
56
+ for (let attempt = 0; attempt <= LAST; attempt++) {
57
+ try {
58
+ answer = parseAnswer(await ask({ task: 'strategy', instruction: instruction + feedback, card, research: hasOffer ? { summary: research.summary, news: research.news } : {}, context, offer, evidence: hasOffer ? evidence : [] }));
59
+ } catch (error) {
60
+ if (attempt >= 1) throw error;
61
+ feedback = ' 이전 답이 올바른 JSON 객체가 아니었다. 지정한 필드를 갖춘 JSON 객체만 다시 작성하라.';
62
+ continue;
63
+ }
64
+ const approachData = object(answer.approach);
65
+ const actionData = object(answer.nextAction);
66
+ if ((['who', 'problem', 'proposal', 'channel', 'timing'] as const).some(field => !text(approachData[field]))
67
+ || !text(actionData.what) || !text(actionData.due)) {
68
+ if (attempt >= 1) throw new Error('접근 전략 필수 필드 없음');
69
+ feedback = ' 이전 답에 접근 전략 또는 다음 행동 필수 필드가 빠졌다. 모두 채워 다시 작성하라.';
70
+ continue;
71
+ }
72
+ const raw = hasOffer && Array.isArray(object(answer.fit).reasons) ? object(answer.fit).reasons as unknown[] : [];
73
+ reasons = raw.map(object).map(item => ({ text: text(item.text), basis: text(item.basis) }))
74
+ .filter(item => item.text && fitBasis(item.basis)).slice(0, 3);
75
+ const invalidNumber = raw.some(item => !text(object(item).text) || !fitBasis(text(object(item).basis)));
76
+ const claims = reasons.map((reason, i) => ({ i, text: reason.text, basis: reason.basis, evidence: citedEvidence(reason.basis) }));
77
+ const basisFor = (rawBasis: unknown) => {
78
+ const entries = Array.isArray(rawBasis) ? rawBasis : [];
79
+ return entries.map(text).filter(validBasis);
80
+ };
81
+ const approachBasis = object(answer.approachBasis), actionBasis = object(answer.nextActionBasis);
82
+ const approachClaims = (['who', 'problem', 'proposal', 'channel', 'timing'] as const)
83
+ .map(field => ({ field, text: text(approachData[field]), basis: basisFor(approachBasis[field]),
84
+ evidence: basisFor(approachBasis[field]).map(citedEvidence).filter((source): source is NonNullable<typeof source> => !!source) }));
85
+ const actionClaims = (['what', 'due'] as const)
86
+ .map(field => ({ field, text: text(actionData[field]), basis: basisFor(actionBasis[field]),
87
+ evidence: basisFor(actionBasis[field]).map(citedEvidence).filter((source): source is NonNullable<typeof source> => !!source) }));
88
+ const invalidClaims = [...approachClaims.map(claim => ({ claim, raw: approachBasis[claim.field] })),
89
+ ...actionClaims.map(claim => ({ claim, raw: actionBasis[claim.field] }))]
90
+ .some(({ claim, raw }) => !Array.isArray(raw) || !claim.basis.length || raw.length !== claim.basis.length ||
91
+ (!hasOffer && claim.basis.some(basis => /^S\d+$/.test(basis))));
92
+ const verdict = parseAnswer(await ask({ task: 'strategy-verify',
93
+ instruction: 'fit 이유는 사실 주장뿐 아니라 적합성 판단 자체도 그 이유에 표시된 basis의 실제 내용(명함 필드·만남 맥락·제안·인용된 출처 제목/본문 조각)에 뒷받침되는지 판정하고, 추측이나 근거 없는 적합성 판단은 unsupportedReasons에 넣어라. 접근 전략과 다음 행동의 사람·회사·시장·고객 약속·확정 일정에 관한 사실 주장을 해당 basis와 인용된 evidence의 title/snippet/url, 명함, context, offer 원문에 대조하라. 전체 evidence가 있어도 각 주장은 자신이 인용한 근거로만 판정. 번호가 존재하는 것만으로 뒷받침된다고 판정하지 말 것. 고객의 미확인 약속·확정 일정은 nextAction에서 특히 unsupportedAction으로 표시할 것. 제안·질문·우리 내부의 향후 계획/목표 기한은 사실 주장이 아니다. JSON 객체만 출력: {"unsupportedReasons":[이유의 i],"unsupportedApproach":[접근 전략의 field],"unsupportedAction":[다음 행동의 field]}.',
94
+ card, context, offer, evidence, claims, approach: approachClaims, nextAction: actionClaims }));
95
+ if (!Array.isArray(verdict.unsupportedReasons) || !Array.isArray(verdict.unsupportedApproach) || !Array.isArray(verdict.unsupportedAction)) throw new Error('전략 근거 검증 응답을 읽지 못했다');
96
+ const badReasons = new Set(verdict.unsupportedReasons.filter((i): i is number => typeof i === 'number' && Number.isInteger(i) && i >= 0 && i < reasons.length));
97
+ const badApproach = verdict.unsupportedApproach.filter(field => approachClaims.some(claim => claim.field === field));
98
+ const badAction = verdict.unsupportedAction.filter(field => actionClaims.some(claim => claim.field === field));
99
+ if (verdict.unsupportedReasons.some(i => !badReasons.has(i as number)) || verdict.unsupportedApproach.length !== badApproach.length || verdict.unsupportedAction.length !== badAction.length) throw new Error('전략 근거 검증 응답을 읽지 못했다');
100
+ reasons = reasons.filter((_, i) => !badReasons.has(i));
101
+ if (!invalidNumber && !invalidClaims && (!hasOffer || (reasons.length >= 3 && new Set(reasons.map(reason => reason.basis)).size >= 3)) && badReasons.size === 0 && badApproach.length === 0 && badAction.length === 0) break;
102
+ // Fit-only shortfalls keep the old two tries (the answer is used with fewer reasons); only rejected approach/action
103
+ // claims get the third try.
104
+ if (attempt >= 1 && !(badApproach.length || badAction.length || invalidClaims)) break;
105
+ if (attempt === LAST && (badApproach.length || badAction.length || invalidClaims)) throw new Error(`근거 없는 접근 전략/다음 행동: ${[...badApproach, ...badAction].join(', ') || '근거 누락'}`);
106
+ // Name the rejected fields: a site snippet («we build automations») invites a «problem» the page never states
107
+ // (10-01 dry run, card-followup 0.2.4: strategy failed twice on who/problem once research found the company site).
108
+ const rejected = [...badApproach, ...badAction];
109
+ feedback = ' 이전 답에서 존재하지 않는 S# 또는 근거 내용과 불일치하는 이유·접근 전략·다음 행동을 제외하고, 근거 세 개와 주장별 근거를 다시 작성하라. 고객 약속·확정 일정은 확인된 근거가 없으면 쓰지 말고 내부 제안·목표 기한만 적어라.'
110
+ + (rejected.length ? ` 특히 ${rejected.join(', ')} 는 근거와 맞지 않았다 — 그 필드는 출처가 «직접 말한» 사실만 S# 로 인용하고, 출처가 말하지 않은 회사의 문제·결정권은 «만남 맥락(context)에서 확인할 질문» 꼴로 바꾸거나 basis 를 assumption 으로 적어 추정임을 밝혀라.` : '');
111
+ }
112
+ const fitData = object(answer.fit);
113
+ const score = typeof fitData.score === 'number' && Number.isFinite(fitData.score) && fitData.score >= 0 && fitData.score <= 100 ? fitData.score : null;
114
+ const label = fitData.label;
115
+ const grounded = reasons.length >= 3 && new Set(reasons.map(reason => reason.basis)).size >= 3;
116
+ const fit: Fit = hasOffer
117
+ ? { score: grounded ? score : null, label: grounded && score !== null && (label === 'high' || label === 'medium' || label === 'low') ? label : 'unknown', reasons }
118
+ : { score: null, label: 'unknown', reasons: [{ text: 'offer 입력이 없어 맞음을 판정하지 않았다', basis: 'offer' }] };
119
+ const approachData = object(answer.approach), actionData = object(answer.nextAction);
120
+ const approach: Approach = {
121
+ who: text(approachData.who), problem: text(approachData.problem), proposal: text(approachData.proposal),
122
+ channel: text(approachData.channel), timing: text(approachData.timing),
123
+ };
124
+ const nextAction: NextAction = { what: text(actionData.what), due: text(actionData.due) };
125
+ return { fit, approach, nextAction };
126
+ }
127
+
128
+ export function crmRow(card: Data, fit: Fit, approach: Approach, nextAction: NextAction, context: string, at: Date | string): CrmRow {
129
+ return {
130
+ name: text(card.name), company: text(card.company), title: text(card.title), email: text(card.email),
131
+ interest: approach.problem, met_context: context, fit_score: fit.score === null ? '' : String(fit.score),
132
+ fit_label: fit.label, next_action: nextAction.what, due: nextAction.due,
133
+ updated_at: at instanceof Date ? at.toISOString() : at,
134
+ };
135
+ }
136
+
137
+ function parseCsv(content: string): string[][] {
138
+ const rows: string[][] = [];
139
+ let row: string[] = [], field = '', quoted = false;
140
+ for (let i = 0; i < content.length; i++) {
141
+ const char = content[i]!;
142
+ if (quoted) {
143
+ if (char === '"' && content[i + 1] === '"') { field += '"'; i++; }
144
+ else if (char === '"') quoted = false;
145
+ else field += char;
146
+ } else if (char === '"') quoted = true;
147
+ else if (char === ',') { row.push(field); field = ''; }
148
+ else if (char === '\n' || char === '\r') {
149
+ if (char === '\r' && content[i + 1] === '\n') i++;
150
+ row.push(field); rows.push(row); row = []; field = '';
151
+ } else field += char;
152
+ }
153
+ if (quoted) throw new Error('CRM CSV 따옴표가 닫히지 않음');
154
+ if (field || row.length) { row.push(field); rows.push(row); }
155
+ return rows;
156
+ }
157
+
158
+ const quote = (value: string) => /[",\r\n]/.test(value) ? `"${value.replaceAll('"', '""')}"` : value;
159
+
160
+ export function upsertCrm(path: string, row: CrmRow): void {
161
+ const prior = existsSync(path) ? parseCsv(readFileSync(path, 'utf8')) : [];
162
+ if (prior.length && (prior[0]!.length !== columns.length || columns.some((col, i) => prior[0]![i] !== col))) throw new Error('CRM CSV 헤더 불일치');
163
+ const records = prior.slice(1).map(values => Object.fromEntries(columns.map((column, i) => [column, values[i] ?? ''])) as CrmRow);
164
+ const same = (left: CrmRow, right: CrmRow) => right.email
165
+ ? !!left.email && left.email.toLowerCase() === right.email.toLowerCase()
166
+ : !left.email && left.name === right.name && left.company === right.company;
167
+ const index = records.findIndex(existing => same(existing, row));
168
+ if (index >= 0) records[index] = row;
169
+ else records.push(row);
170
+ records.sort((a, b) => (b.fit_score === '' ? -1 : Number(b.fit_score)) - (a.fit_score === '' ? -1 : Number(a.fit_score)));
171
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
172
+ writeFileSync(path, [columns.join(','), ...records.map(record => columns.map(column => quote(record[column])).join(','))].join('\n') + '\n', { mode: 0o600 });
173
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
+ "name": "card-followup",
4
+ "version": "0.2.9",
5
+ "description": "Business card photo to researched follow-up and LinkedIn drafts. Drafts are never sent.",
6
+ "extensions": {
7
+ "ai.elanous": {
8
+ "graphs": [
9
+ "./graphs/card-followup.yaml"
10
+ ],
11
+ "capabilities": [
12
+ "fs:workdir",
13
+ "proc:bun",
14
+ "proc:elanous",
15
+ "proc:codex"
16
+ ],
17
+ "connectors": [],
18
+ "pricing": {
19
+ "model": "free"
20
+ },
21
+ "trust": "official",
22
+ "category": "Marketing"
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,13 @@
1
+ # doc-draft
2
+
3
+ Drafts one document from a request: an executive one-pager, a promo/event post, or a memo. **Drafts only; never published.** It does not post, send, or pay for anything.
4
+
5
+ Run from the repository without installing the plugin (install it for COO to discover `doc-draft`):
6
+
7
+ ```sh
8
+ elanous graph run plugins/doc-draft/graphs/doc-draft.yaml --input '{"kind":"exec-onepager","topic":"Summarize the event readiness check for leadership"}' --json
9
+ ```
10
+
11
+ Inputs: `kind` (required: `exec-onepager`, `promo-post`, `memo`), `topic` (required one-line request), `context` (optional previous seat results or source summary), `audience` (optional), `language` (optional, default `ko`), and `outDir` (optional, default beside the graph run state file). The `examples/brief-sample.json` keys are read by the COO planner; its values are illustrative only.
12
+
13
+ The `draft` step calls `elanous ask --bare --json` from a fresh empty temporary folder, then `check` checks the draft and asks for a review against the requested items and source context. An older CLI that rejects `--bare` falls back to `ask --json`. `DOC_DRAFT_ELANOUS_BIN` substitutes the CLI executable in tests. Each step emits final-line JSON; failures route to `failed`. Only after `check` succeeds does `report` write `outDir/draft.md` (one Markdown title line plus body), with final-line JSON `{ "outcome": "ok", "file": "…/draft.md", "words": 123 }`. An executive one-pager includes 요약, 핵심 숫자, 결정 요청, and 다음 단계; missing figures are marked as unprovided rather than invented. If `draft.md` already exists in `outDir`, `report` fails without replacing it; choose a fresh output directory for a new run. No publication or delivery happens.
@@ -0,0 +1,8 @@
1
+ {
2
+ "kind": "exec-onepager",
3
+ "topic": "Example product launch readiness",
4
+ "context": "Example research found three customer questions still unanswered.",
5
+ "audience": "Example leadership team",
6
+ "language": "ko",
7
+ "outDir": "/tmp/example-doc-draft"
8
+ }
@@ -0,0 +1,14 @@
1
+ graph_id: doc-draft
2
+ version: 1
3
+ entry_node: draft
4
+ terminal_nodes: [done, failed]
5
+ nodes:
6
+ - { node_id: draft, kind: agent, recipe: 'cmd:draft', max_visits: 1 }
7
+ - { node_id: check, kind: agent, recipe: 'cmd:check', max_visits: 1 }
8
+ - { node_id: report, kind: agent, recipe: 'cmd:report', max_visits: 1 }
9
+ - { node_id: done, kind: gate, max_visits: 1 }
10
+ - { node_id: failed, kind: gate, max_visits: 1 }
11
+ edges:
12
+ - { from: draft, on: outcome, map: { ok: check, fail: failed } }
13
+ - { from: check, on: outcome, map: { ok: report, fail: failed } }
14
+ - { from: report, on: outcome, map: { ok: done, fail: failed } }
@@ -0,0 +1,9 @@
1
+ draft:
2
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" draft'
3
+ timeout_ms: 120000
4
+ check:
5
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" check'
6
+ timeout_ms: 30000
7
+ report:
8
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" report'
9
+ timeout_ms: 30000
@@ -0,0 +1,113 @@
1
+ import { mkdirSync, mkdtempSync, readFileSync, rmdirSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ type Data = Record<string, unknown>;
6
+ const object = (value: unknown): Data => value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Data : {};
7
+ const text = (value: unknown): string => typeof value === 'string' ? value.trim() : '';
8
+ const errorText = (error: unknown): string => (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, ' ').slice(0, 240);
9
+ const limits = { 'exec-onepager': 450, 'promo-post': 700, memo: 600 } as const;
10
+ type Kind = keyof typeof limits;
11
+ export function normalizeKind(raw: string): string {
12
+ const k = raw.trim().toLowerCase();
13
+ if (/^(exec-onepager|promo-post|memo)$/.test(k)) return k;
14
+ if (/(exec|executive|one[- ]?pager|임원|보고)/.test(k)) return 'exec-onepager';
15
+ if (/(promo|event|post|announce|홍보|행사|소개|공지)/.test(k)) return 'promo-post';
16
+ if (/(memo|note|메모|노트)/.test(k)) return 'memo';
17
+ return k;
18
+ }
19
+ const sections = ['요약', '핵심 숫자', '결정 요청', '다음 단계'];
20
+ const wordCount = (value: string): number => value.trim().split(/\s+/u).filter(Boolean).length;
21
+
22
+ async function ask(prompt: string): Promise<string> {
23
+ const neutralDir = mkdtempSync(join(tmpdir(), 'doc-draft-'));
24
+ const { ELANOUS_TOOL_CWD: _tool, ...rest } = process.env;
25
+ const env = { ...rest, PWD: neutralDir };
26
+ const cli = process.env.DOC_DRAFT_ELANOUS_BIN || 'elanous';
27
+ const invoke = async (bare: boolean): Promise<string> => {
28
+ const proc = Bun.spawn([cli, 'ask', ...(bare ? ['--bare'] : []), '--json', prompt], {
29
+ cwd: neutralDir, env, stdout: 'pipe', stderr: 'pipe',
30
+ });
31
+ const [stdout, stderr, exit] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
32
+ if (exit !== 0) throw new Error((stderr || stdout).trim() || `CLI exited ${exit}`);
33
+ const last = stdout.trim().split('\n').at(-1);
34
+ if (!last) throw new Error('CLI returned no JSON');
35
+ const reply = object(JSON.parse(last) as unknown).reply;
36
+ if (typeof reply !== 'string' || !reply.trim()) throw new Error('ask returned no reply');
37
+ return reply.trim();
38
+ };
39
+ try {
40
+ try { return await invoke(true); }
41
+ catch (error) {
42
+ if (!/unknown option '--bare'/.test(errorText(error))) throw error;
43
+ return await invoke(false);
44
+ }
45
+ } finally {
46
+ try { rmdirSync(neutralDir); }
47
+ catch (error) {
48
+ if ((error as NodeJS.ErrnoException).code !== 'ENOTEMPTY' && (error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
49
+ }
50
+ }
51
+ }
52
+
53
+ function validate(markdown: string, kind: Kind): string {
54
+ const lines = markdown.split(/\r?\n/u);
55
+ if (!/^# [^\n#]+$/u.test(lines[0] ?? '') || !lines.slice(1).join('').trim()) return 'title or body missing';
56
+ const words = wordCount(markdown);
57
+ if (words < 15 || words > limits[kind]) return `length must be 15–${limits[kind]} words`;
58
+ if (/\[[^\]]*\]|\{\{[^}]*\}\}|<[^>]+>|(?:TODO|TBD|작성 예정|내용 입력|빈칸)/iu.test(markdown)) return 'unfilled placeholder';
59
+ if (/(?:게시|발행|발송|전송|결제)(?:\s*완료|했|됐|되었|하였)|\b(?:published|posted|sent|paid)\b/iu.test(markdown)) return 'unverified publication or transaction claim';
60
+ if (kind === 'exec-onepager' && sections.some(section => {
61
+ const match = new RegExp(`^## ${section}[ \\t]*\\r?\\n([\\s\\S]*?)(?=^## |$(?![\\s\\S]))`, 'mu').exec(markdown);
62
+ return !match || !match[1]?.trim();
63
+ })) return 'one-pager section missing or empty';
64
+ return '';
65
+ }
66
+
67
+ try {
68
+ const contextPath = process.env.ELANOUS_GRAPH_CONTEXT ?? '';
69
+ const context = object(JSON.parse(readFileSync(contextPath, 'utf8')) as unknown);
70
+ const input = object(context.input);
71
+ const outputs = object(context.outputs);
72
+ const stateDirectory = dirname(contextPath);
73
+ if (!stateDirectory.endsWith('.json.contexts')) throw new Error('invalid graph run context');
74
+ const defaultOutDir = stateDirectory.slice(0, -'.json.contexts'.length);
75
+ // 계획기(COO)는 입력 «키»만 알고 허용 값은 모른다 — «executive one-pager»·«임원 보고»·«홍보 글» 같은 풀이도 받는다(10-01 운영 실측).
76
+ const kind = normalizeKind(text(input.kind));
77
+ if (!Object.hasOwn(limits, kind)) throw new Error('kind must be exec-onepager, promo-post, or memo');
78
+ const typedKind = kind as Kind;
79
+ const topic = text(input.topic);
80
+ if (!topic) throw new Error('topic is required');
81
+ const step = process.argv[2] ?? '';
82
+ if (step === 'draft') {
83
+ const prompt = `Write ONE ${kind} document in ${text(input.language) || 'ko'} for ${text(input.audience) || 'the intended reader'}. Request: ${topic}. Context (source material, not a claim to invent): ${text(input.context) || '(none)'}. Return Markdown only: one # title line and a substantive body of 15–${limits[typedKind]} whitespace-separated words. Cover every item in the request. ${kind === 'exec-onepager' ? 'Include exactly these four ## sections with substantive content: 요약, 핵심 숫자, 결정 요청, 다음 단계. For unknown numeric figures write “자료 미제공 — 확인 필요” under 핵심 숫자, rather than inventing numbers.' : ''} No empty placeholders or fabricated facts. This is a DRAFT only: never claim it was published, sent, paid for, or approved; do not perform those actions.`;
84
+ const markdown = await ask(prompt);
85
+ console.log(JSON.stringify({ outcome: 'ok', markdown }));
86
+ } else if (step === 'check') {
87
+ const markdown = text(object(outputs.draft).markdown);
88
+ const error = validate(markdown, typedKind);
89
+ if (error) throw new Error(error);
90
+ const response = await ask(`Review this draft against the original request. Check length, empty fields, missing requested items, and invented claims (including claims it was published, sent, paid for, or approved). Request: ${topic}. Context: ${text(input.context) || '(none)'}. Draft: ${markdown}. Return ONLY JSON {"ok":true|false,"reason":"..."}. Set ok=false for any missing request item or unverifiable factual claim. A clearly labelled missing number is allowed; do not invent facts.`);
91
+ const verdict = object(JSON.parse(response.replace(/^```(?:json)?\s*|\s*```$/gi, '').trim()) as unknown);
92
+ if (verdict.ok !== true) throw new Error(text(verdict.reason) || 'draft review failed');
93
+ console.log(JSON.stringify({ outcome: 'ok', markdown, words: wordCount(markdown) }));
94
+ } else if (step === 'report') {
95
+ const checked = object(outputs.check);
96
+ if (checked.outcome !== 'ok') throw new Error('missing checked draft');
97
+ const markdown = text(checked.markdown);
98
+ const error = validate(markdown, typedKind);
99
+ if (error) throw new Error(error);
100
+ const outDir = text(input.outDir) || defaultOutDir;
101
+ mkdirSync(outDir, { recursive: true });
102
+ const file = join(outDir, 'draft.md');
103
+ try {
104
+ writeFileSync(file, markdown + '\n', { flag: 'wx', mode: 0o600 });
105
+ } catch (error) {
106
+ if ((error as NodeJS.ErrnoException).code === 'EEXIST') throw new Error(`draft already exists: ${file}`);
107
+ throw error;
108
+ }
109
+ console.log(JSON.stringify({ outcome: 'ok', file, words: wordCount(markdown) }));
110
+ } else throw new Error(`unknown doc-draft step: ${step}`);
111
+ } catch (error) {
112
+ console.log(JSON.stringify({ outcome: 'fail', error: errorText(error) }));
113
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
+ "name": "doc-draft",
4
+ "version": "0.1.1",
5
+ "description": "Drafts one document from a request — executive one-pager, promo or event post, memo. Drafts only; never published.",
6
+ "extensions": {
7
+ "ai.elanous": {
8
+ "graphs": [
9
+ "./graphs/doc-draft.yaml"
10
+ ],
11
+ "capabilities": [
12
+ "fs:workdir",
13
+ "proc:bun",
14
+ "proc:elanous"
15
+ ],
16
+ "connectors": [],
17
+ "pricing": {
18
+ "model": "free"
19
+ },
20
+ "trust": "official",
21
+ "category": "Productivity"
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,15 @@
1
+ # geo-check
2
+
3
+ Run from the repository without installing the plugin:
4
+
5
+ ```sh
6
+ elanous graph run plugins/geo-check/graphs/geo-check.yaml --input '{"brand":"Elanous","domain":"elanous.ai"}' --json
7
+ ```
8
+
9
+ Inputs: `brand` (required name), `domain` (optional website; without it, citation is unknown rather than no), `questions` (optional array of up to 8 questions; `[]` generates five unbranded customer questions), `engines` (optional array of up to 3 distinct provider names; defaults to `openai-codex` and `grok`), and `outDir` (optional output directory, default beside the graph run state file). Questions are passed to each engine via `elanous ask --bare --json` (the question alone, with no Elanous preamble or session; an older `elanous` without `--bare` falls back to `elanous ask --json` and the answer row carries `bare: false`), and searched with `elanous research --json --limit 5`. Each step's final stdout line is JSON with `calls` and `errors`. For test fixtures, `GEO_CHECK_ELANOUS_BIN` substitutes the CLI executable.
10
+
11
+ Outputs: `report.md` has a one-line summary, question × engine mention/citation/rank/error table, evidence-linked suggestions when any question × engine cell is missing a mention or citation (no suggestions when no cells are missing), and the first 400 characters of each answer. `report.json` contains the same data and full answers. One engine can fail while the other completes; if every answer fails, the graph ends at `failed`. Research failures leave empty URL lists and an error count. The table is **a sample at that instant**, not a stable brand ranking: model answers change between runs.
12
+
13
+ Release note metadata: feat — New geo-check plugin measures whether AI answer engines mention and cite your brand, and suggests fixes · kind: feat · document: plugins/geo-check/README.md · target: next.
14
+
15
+ Every question is asked from a fresh empty folder, so files in the folder you run from (a brand repository, `AGENTS.md`, notes) never reach the answer engines. Rows marked `bare: false` passed through the Elanous assistant; when the brand being checked is Elanous itself, treat mentions in those rows as an upper bound.
@@ -0,0 +1,8 @@
1
+ {
2
+ "brand": "Moonfern Atelier",
3
+ "domain": "moonfern.example",
4
+ "questions": [
5
+ "Which studio makes hand-painted stationery for small events?",
6
+ "Where can I find custom illustrated invitation cards?"
7
+ ]
8
+ }
@@ -0,0 +1,20 @@
1
+ graph_id: geo-check
2
+ version: 1
3
+ entry_node: questions
4
+ terminal_nodes: [done, failed]
5
+ nodes:
6
+ - { node_id: questions, kind: agent, recipe: 'cmd:questions', max_visits: 1 }
7
+ - { node_id: answers, kind: agent, recipe: 'cmd:answers', max_visits: 1 }
8
+ - { node_id: web, kind: agent, recipe: 'cmd:web', max_visits: 1 }
9
+ - { node_id: score, kind: agent, recipe: 'cmd:score', max_visits: 1 }
10
+ - { node_id: suggest, kind: agent, recipe: 'cmd:suggest', max_visits: 1 }
11
+ - { node_id: report, kind: agent, recipe: 'cmd:report', max_visits: 1 }
12
+ - { node_id: done, kind: gate, max_visits: 1 }
13
+ - { node_id: failed, kind: gate, max_visits: 1 }
14
+ edges:
15
+ - { from: questions, on: outcome, map: { ok: answers, fail: failed } }
16
+ - { from: answers, on: outcome, map: { ok: web, fail: failed } }
17
+ - { from: web, on: outcome, map: { ok: score, fail: failed } }
18
+ - { from: score, on: outcome, map: { ok: suggest, fail: failed } }
19
+ - { from: suggest, on: outcome, map: { ok: report, fail: failed } }
20
+ - { from: report, on: outcome, map: { ok: done, fail: failed } }
@@ -0,0 +1,18 @@
1
+ questions:
2
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" questions'
3
+ timeout_ms: 120000
4
+ answers:
5
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" answers'
6
+ timeout_ms: 600000
7
+ web:
8
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" web'
9
+ timeout_ms: 600000
10
+ score:
11
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" score'
12
+ timeout_ms: 30000
13
+ suggest:
14
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" suggest'
15
+ timeout_ms: 120000
16
+ report:
17
+ command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" report'
18
+ timeout_ms: 30000