elanous 0.2.23 → 0.2.24

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 (347) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{272-b23d2e92161d11fd.js → 272-0eed0fb0aab716b6.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{3961-fbef064c213b2b18.js → 3961-aaae04ed1d32622f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/app/approvals/{page-d5341ac96203a983.js → page-3b9fc39362473ae7.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/app/board/{page-55c631c032dcc47e.js → page-d7602d489edf5f37.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ad3bd8084048bee4.js → page-24282bf9f90031a5.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/app/ceo/{page-5c5d0e370f495ef6.js → page-4eb84d454f8c3415.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/app/chat/{page-c325e21543cd48a8.js → page-b2e494bdad57fcb5.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/app/consult/{page-6168a7c43e6ef8f5.js → page-c0ab229673a8b0eb.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/app/editor/{page-25bb425afdb27541.js → page-bf88c0f558d8ef54.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/app/exec/{page-32d72fdef1afe11a.js → page-52fec523e5b5d3ad.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/app/inside/{page-2bd9ce9c020d02d4.js → page-22725e2570f1126b.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/intake/{page-a34096245e63b9f2.js → page-1891335950d68b70.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/app/live/{page-4cc66d22ca4ec502.js → page-c314b75c11234998.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-83b14c729fcea837.js → page-9f9c85415f61782b.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-ccdb83ed40c8d724.js → page-8526c17ae38e6a50.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/app/morning/{page-7ad3de8fa06fdea9.js → page-f998637a8402115c.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-786111f30b6f0969.js → page-6f23159fedb41f67.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-48fb31810693c357.js → page-1d809a87139dd024.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-4e17cce5e2ed0fee.js → page-da9e570234d481fd.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-cb154acadb025414.js → page-b92caddb5c715f30.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-c2dd2b19c93f90ab.js → page-57ffeeb6019440fd.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/app/sessions/{page-d3c007c8a0ddd7ee.js → page-2c2b3f29cec1efa4.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-7837ce2aacb97b04.js → page-9369279f72fc7b51.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/app/showroom/{page-119be9a0444d2482.js → page-b5c0c996f329371e.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/app/tasks/{page-fa806c018833e332.js → page-89881ccbcf728978.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/today/{page-d431fbdea6ad93dd.js → page-58d4e5cb30ef4871.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-847c3de6ca8a4416.js → page-acf868c64d77f950.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-74e69ba2c8e970d4.js → page-bc79f0833533fa84.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/worktrees/{page-70038f41ae7cf931.js → page-d5c4398eea03d8f3.js} +1 -1
  53. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
  54. package/apps/pwa/out/approvals/index.html +1 -1
  55. package/apps/pwa/out/approvals/index.txt +14 -14
  56. package/apps/pwa/out/autopilot/index.html +1 -1
  57. package/apps/pwa/out/autopilot/index.txt +14 -14
  58. package/apps/pwa/out/board/index.html +1 -1
  59. package/apps/pwa/out/board/index.txt +14 -14
  60. package/apps/pwa/out/botlab/index.html +1 -1
  61. package/apps/pwa/out/botlab/index.txt +14 -14
  62. package/apps/pwa/out/bots/index.html +1 -1
  63. package/apps/pwa/out/bots/index.txt +14 -14
  64. package/apps/pwa/out/ceo/index.html +1 -1
  65. package/apps/pwa/out/ceo/index.txt +14 -14
  66. package/apps/pwa/out/chat/index.html +1 -1
  67. package/apps/pwa/out/chat/index.txt +14 -14
  68. package/apps/pwa/out/consult/index.html +1 -1
  69. package/apps/pwa/out/consult/index.txt +14 -14
  70. package/apps/pwa/out/control/index.html +1 -1
  71. package/apps/pwa/out/control/index.txt +14 -14
  72. package/apps/pwa/out/decisions/index.html +1 -1
  73. package/apps/pwa/out/decisions/index.txt +14 -14
  74. package/apps/pwa/out/design-check/index.html +1 -1
  75. package/apps/pwa/out/design-check/index.txt +14 -14
  76. package/apps/pwa/out/editor/index.html +1 -1
  77. package/apps/pwa/out/editor/index.txt +14 -14
  78. package/apps/pwa/out/exec/index.html +1 -1
  79. package/apps/pwa/out/exec/index.txt +14 -14
  80. package/apps/pwa/out/field/index.html +1 -1
  81. package/apps/pwa/out/field/index.txt +14 -14
  82. package/apps/pwa/out/healthz +1 -1
  83. package/apps/pwa/out/index.html +1 -1
  84. package/apps/pwa/out/index.txt +14 -14
  85. package/apps/pwa/out/inside/index.html +1 -1
  86. package/apps/pwa/out/inside/index.txt +14 -14
  87. package/apps/pwa/out/intake/index.html +1 -1
  88. package/apps/pwa/out/intake/index.txt +14 -14
  89. package/apps/pwa/out/live/index.html +1 -1
  90. package/apps/pwa/out/live/index.txt +14 -14
  91. package/apps/pwa/out/live-run/index.html +1 -1
  92. package/apps/pwa/out/live-run/index.txt +14 -14
  93. package/apps/pwa/out/loops/index.html +1 -1
  94. package/apps/pwa/out/loops/index.txt +14 -14
  95. package/apps/pwa/out/market/index.html +1 -1
  96. package/apps/pwa/out/market/index.txt +14 -14
  97. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  98. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  99. package/apps/pwa/out/morning/index.html +1 -1
  100. package/apps/pwa/out/morning/index.txt +14 -14
  101. package/apps/pwa/out/observatory/index.html +1 -1
  102. package/apps/pwa/out/observatory/index.txt +14 -14
  103. package/apps/pwa/out/ops/checklist/index.html +1 -1
  104. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  105. package/apps/pwa/out/ops/release/index.html +1 -1
  106. package/apps/pwa/out/ops/release/index.txt +14 -14
  107. package/apps/pwa/out/ops/seats/index.html +1 -1
  108. package/apps/pwa/out/ops/seats/index.txt +14 -14
  109. package/apps/pwa/out/outputs/index.html +1 -1
  110. package/apps/pwa/out/outputs/index.txt +14 -14
  111. package/apps/pwa/out/reflection/index.html +1 -1
  112. package/apps/pwa/out/reflection/index.txt +15 -15
  113. package/apps/pwa/out/scheduler/index.html +1 -1
  114. package/apps/pwa/out/scheduler/index.txt +14 -14
  115. package/apps/pwa/out/sessions/index.html +1 -1
  116. package/apps/pwa/out/sessions/index.txt +14 -14
  117. package/apps/pwa/out/settings/devices/index.html +1 -1
  118. package/apps/pwa/out/settings/devices/index.txt +14 -14
  119. package/apps/pwa/out/settings/index.html +1 -1
  120. package/apps/pwa/out/settings/index.txt +14 -14
  121. package/apps/pwa/out/setup/done/index.html +1 -1
  122. package/apps/pwa/out/setup/done/index.txt +14 -14
  123. package/apps/pwa/out/setup/index.html +1 -1
  124. package/apps/pwa/out/setup/index.txt +14 -14
  125. package/apps/pwa/out/share/index.html +1 -1
  126. package/apps/pwa/out/share/index.txt +14 -14
  127. package/apps/pwa/out/showroom/index.html +1 -1
  128. package/apps/pwa/out/showroom/index.txt +14 -14
  129. package/apps/pwa/out/tasks/index.html +1 -1
  130. package/apps/pwa/out/tasks/index.txt +14 -14
  131. package/apps/pwa/out/term/index.html +1 -1
  132. package/apps/pwa/out/term/index.txt +14 -14
  133. package/apps/pwa/out/today/index.html +1 -1
  134. package/apps/pwa/out/today/index.txt +14 -14
  135. package/apps/pwa/out/trace/index.html +1 -1
  136. package/apps/pwa/out/trace/index.txt +14 -14
  137. package/apps/pwa/out/vault/index.html +1 -1
  138. package/apps/pwa/out/vault/index.txt +14 -14
  139. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  140. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  141. package/apps/pwa/out/workflows/index.html +1 -1
  142. package/apps/pwa/out/workflows/index.txt +14 -14
  143. package/apps/pwa/out/workspace/index.html +1 -1
  144. package/apps/pwa/out/workspace/index.txt +14 -14
  145. package/apps/pwa/out/worktrees/index.html +1 -1
  146. package/apps/pwa/out/worktrees/index.txt +14 -14
  147. package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
  148. package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
  149. package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
  150. package/catalog/providers/openrouter.yaml +2 -0
  151. package/graphs/implement-loop.yaml +31 -0
  152. package/graphs/ops/harness-gc.yaml +17 -0
  153. package/graphs/ops/recipes.yaml +3 -0
  154. package/graphs/overlays/README.md +1 -1
  155. package/graphs/overlays/stop-heal-ladder.yaml +105 -0
  156. package/package.json +1 -1
  157. package/scripts/add-api-key.sh +1 -1
  158. package/scripts/ci-typecheck-changed.ts +71 -14
  159. package/scripts/fleet/bedrock-pod-secret.ts +122 -0
  160. package/scripts/fleet/node-setup-linux.sh +97 -0
  161. package/scripts/fleet/node-setup.sh +11 -0
  162. package/scripts/fleet/zai-pod-secret.ts +86 -0
  163. package/scripts/land-global-checks.ts +3 -0
  164. package/scripts/measure-log-diet-2.ts +213 -0
  165. package/scripts/measure-tsc-affected-roots.ts +289 -0
  166. package/scripts/release-loop/gate-executor.ts +28 -0
  167. package/scripts/release-loop/gate-node.ts +262 -26
  168. package/scripts/release-loop/resume-release.ts +9 -3
  169. package/scripts/release-loop/resume.ts +41 -0
  170. package/scripts/release-loop/unattended-release.ts +22 -7
  171. package/scripts/tsc-baseline-cache.ts +147 -0
  172. package/scripts/usage-rollup.ts +58 -6
  173. package/src/agent/run-context.ts +10 -0
  174. package/src/agent-mission/driver.ts +18 -3
  175. package/src/agent-mission/resource-ladder.ts +8 -3
  176. package/src/agent-mission/review-loop.ts +8 -2
  177. package/src/agent-substrate/acp-implementer.ts +139 -0
  178. package/src/agent-substrate/pr-reviewer.ts +31 -4
  179. package/src/agent-substrate/self-review-cli.ts +48 -9
  180. package/src/autopilot/mission-critique.ts +18 -5
  181. package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
  182. package/src/autopilot/mission-trace.ts +12 -1
  183. package/src/autopilot/system-lookback-run.ts +16 -10
  184. package/src/bench/bench.ts +183 -0
  185. package/src/budget/fetchers/grok.ts +15 -5
  186. package/src/budget/llm-cost.ts +37 -5
  187. package/src/budget/types.ts +8 -2
  188. package/src/budget/unified-usage.ts +88 -6
  189. package/src/cli/bench-cli.ts +34 -0
  190. package/src/cli/guardian-cli.ts +26 -1
  191. package/src/cli/image-cli.ts +101 -0
  192. package/src/cli/log-event-names.ts +4 -0
  193. package/src/cli/pr-cli.ts +62 -5
  194. package/src/cli/pr-land-overlap-evidence.ts +160 -12
  195. package/src/cli/release-cli.ts +18 -9
  196. package/src/cli/rfc-status.ts +52 -2
  197. package/src/cli/self-update.ts +104 -0
  198. package/src/cli/tasks-cli.ts +109 -4
  199. package/src/cli/usage-cli.ts +91 -8
  200. package/src/core-turn/run-goal-loop.ts +5 -4
  201. package/src/dashboard/ad-run-setup-bindings.ts +279 -0
  202. package/src/dashboard/index.ts +18 -276
  203. package/src/dashboard/stale-install-check.ts +11 -0
  204. package/src/debug/log-diet.ts +38 -7
  205. package/src/debug/log.ts +19 -1
  206. package/src/domains/release-tool.ts +39 -0
  207. package/src/error-report/report.ts +21 -4
  208. package/src/github/pr-labels.ts +1 -0
  209. package/src/graph-runner/graph-cli.ts +42 -1
  210. package/src/graph-runner/runner.ts +167 -6
  211. package/src/grok/usage.ts +23 -2
  212. package/src/grounding/ref-index.ts +253 -0
  213. package/src/harness/dispatch-backpressure.ts +10 -2
  214. package/src/harness/harness-clean.ts +199 -78
  215. package/src/harness/harness-cli-command.ts +122 -7
  216. package/src/harness/harness-gc.ts +331 -0
  217. package/src/harness/harness-stop.ts +4 -2
  218. package/src/harness/harness-substrate-default.ts +142 -7
  219. package/src/harness/launch-registry.ts +6 -0
  220. package/src/harness/worktree-branch-prefix.ts +9 -0
  221. package/src/hq/fence.ts +187 -0
  222. package/src/hq/seats.ts +38 -22
  223. package/src/images/image-ledger.ts +179 -0
  224. package/src/index.ts +93 -11
  225. package/src/instance/child-scope.ts +32 -1
  226. package/src/instance/dev-project.ts +133 -0
  227. package/src/instance/resolve.ts +24 -0
  228. package/src/instance/spawn-elanous.ts +45 -0
  229. package/src/intake-plane/ref-prefetch.ts +110 -0
  230. package/src/intelligence-map/model-catalog.ts +72 -0
  231. package/src/llm/bedrock-eventstream.ts +215 -0
  232. package/src/llm/bedrock-provider.ts +114 -41
  233. package/src/llm/bedrock.ts +174 -28
  234. package/src/llm/openrouter-byok-cost.ts +96 -0
  235. package/src/llm/openrouter-deepseek.ts +151 -0
  236. package/src/llm/openrouter-upstream-pins.config.ts +25 -0
  237. package/src/llm/zai-coding-plan.ts +700 -0
  238. package/src/llm.ts +87 -16
  239. package/src/loops/checker.ts +148 -9
  240. package/src/loops/orchestrator/resync-shadow.ts +34 -7
  241. package/src/maturity/feature-maturity.ts +2 -2
  242. package/src/model-tier/llm-tier-map.ts +9 -5
  243. package/src/models/prompts.ts +2 -1
  244. package/src/mss/logging/log-store.ts +58 -11
  245. package/src/nexus/api/missions.ts +73 -2
  246. package/src/nexus/api/ops-api.ts +18 -0
  247. package/src/nexus/index.ts +7 -75
  248. package/src/nexus/tools-kind.ts +78 -0
  249. package/src/oauth/codex-account-rotation.ts +39 -2
  250. package/src/oauth/codex-account-store.ts +323 -24
  251. package/src/oauth/fallback-chain.ts +53 -15
  252. package/src/onboarding/first-run.ts +37 -18
  253. package/src/onboarding/web-first.ts +20 -2
  254. package/src/ops/machine-heartbeat.ts +185 -0
  255. package/src/ops/overview-cache.ts +175 -0
  256. package/src/ops/overview.ts +8 -0
  257. package/src/prompt-cache/openai.ts +3 -0
  258. package/src/prompt-cache/types.ts +5 -0
  259. package/src/prompt-enhance/enhance.ts +23 -0
  260. package/src/release-loop/placement.ts +16 -1
  261. package/src/requirements/requirement-ledger.ts +536 -0
  262. package/src/retro/daily.ts +5 -5
  263. package/src/seat-loop/seat-loop.ts +32 -10
  264. package/src/self-dev/dev-cli.ts +44 -10
  265. package/src/self-dev/dev-pipeline.ts +7 -2
  266. package/src/self-dev/draft-residue.ts +14 -2
  267. package/src/self-dev/draft-sweep.ts +103 -0
  268. package/src/self-dev/graph-journey-route.ts +6 -0
  269. package/src/self-dev/orchestrate-cli.ts +25 -3
  270. package/src/self-dev/orchestrate.ts +41 -6
  271. package/src/self-dev/run-supervisor.ts +188 -15
  272. package/src/self-dev/run-types.ts +13 -0
  273. package/src/self-dev/supervisor-verdict-edges.ts +1 -0
  274. package/src/self-implement/budget-gate.ts +53 -13
  275. package/src/self-implement/child-context-composition.ts +139 -0
  276. package/src/self-implement/child-llm-preference.ts +13 -5
  277. package/src/self-implement/claude-acp-implement.ts +67 -0
  278. package/src/self-implement/flex-signals.ts +59 -0
  279. package/src/self-implement/frozen-merges.ts +8 -3
  280. package/src/self-implement/goal-author-decompose.ts +10 -2
  281. package/src/self-implement/goal-author.ts +24 -9
  282. package/src/self-implement/graph-overlay-condition.ts +28 -0
  283. package/src/self-implement/graph-overlay-yaml.ts +41 -7
  284. package/src/self-implement/graph-templates.ts +33 -1
  285. package/src/self-implement/graph-yaml.ts +56 -0
  286. package/src/self-implement/heal-intake.ts +5 -1
  287. package/src/self-implement/orchestrator.ts +144 -15
  288. package/src/self-implement/running-runs.ts +75 -5
  289. package/src/self-implement/seams.ts +47 -1
  290. package/src/self-implement/self-implement-cli.ts +9 -4
  291. package/src/self-implement/stop-autoheal.ts +69 -2
  292. package/src/session-runtime/retry-policy.ts +2 -1
  293. package/src/steward/launch.ts +5 -4
  294. package/src/steward/triage-budget.ts +62 -0
  295. package/src/steward/triage.ts +83 -22
  296. package/src/task-agent/actions.ts +62 -5
  297. package/src/task-agent/completion-evidence.ts +5 -0
  298. package/src/task-agent/cover.ts +101 -3
  299. package/src/task-agent/judge.ts +16 -0
  300. package/src/task-agent/land-order-ledger.ts +95 -0
  301. package/src/task-agent/live-move-history.ts +87 -1
  302. package/src/task-agent/live-moves.ts +350 -20
  303. package/src/task-agent/rejudge-on-head.ts +75 -20
  304. package/src/task-agent/review-prior-fix.ts +146 -0
  305. package/src/task-agent/run-adopt.ts +136 -0
  306. package/src/task-agent/shadow.ts +53 -9
  307. package/src/task-agent/task-hand.ts +54 -7
  308. package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
  309. package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
  310. package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
  311. package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
  312. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
  313. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
  314. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  315. package/src/task-orchestrator/surfaces/pod-pool.ts +20 -4
  316. package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
  317. package/src/task-orchestrator/surfaces/self-implement-pod.ts +213 -23
  318. package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
  319. package/src/typecheck-ratchet.ts +1 -0
  320. package/src/user-config.ts +51 -11
  321. package/src/version/packed-revision.json +1 -1
  322. package/src/workflow-runtime/triggers/registry.ts +59 -0
  323. package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
  324. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
  325. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
  326. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
  327. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
  328. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +0 -1
  329. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
  330. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
  331. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
  332. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
  333. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
  334. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
  335. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
  336. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
  337. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
  338. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
  339. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
  340. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
  341. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
  342. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
  343. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
  344. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
  345. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
  346. /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +0 -0
  347. /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
@@ -32,6 +32,9 @@
32
32
  # ⛔⭐ 그리고 ***「거른 뒤의 가장 이른 행」을 「원장의 바닥」으로 읽지 마라*** — 그 둘은 다른 값이다.
33
33
  # 바닥을 재려면 그 «필터를 빼고» 같은 이벤트의 가장 이른 행을 본다.
34
34
 
35
+ # L0 여정 단계 목록(journey_stage 닫힌 집합) — 노드별 선언 커버리지의 분모.
36
+ # 입구 · 저작 · 배치 · 실행 · 착지 · 실패 갈래 · 종료 (RFC ARG §L0).
37
+ journey_stages: [entry, author, dispatch, run, land, recover, end]
35
38
  # ⛔⭐ `graph_id` 는 «원장의 조인 키»다 — 바꾸면 옛 표본과 «비교 불가»가 된다.
36
39
  # 📏 2026-09-08 실측: 원장에 graphId="self-implement" 로 15건이 이미 쌓였다.
37
40
  # 📌 RFC §4.2 는 이 템플릿을 `implement-loop` 이라 불렀지만, ***코드·원장이 쓰는 이름이 canonical***이다.
@@ -72,6 +75,7 @@ runner_inputs: [ask_text, goal, worktree, branch, review-intent, head-sha, base-
72
75
  nodes:
73
76
  - node_id: author
74
77
  group: author
78
+ journey_stage: author
75
79
  kind: agent
76
80
  recipe: goal-author
77
81
  max_visits: 2
@@ -84,6 +88,7 @@ nodes:
84
88
 
85
89
  - node_id: plan
86
90
  group: author
91
+ journey_stage: author
87
92
  kind: agent
88
93
  recipe: harness-plan-rfc
89
94
  max_visits: 2
@@ -96,6 +101,7 @@ nodes:
96
101
 
97
102
  - node_id: decompose
98
103
  group: author
104
+ journey_stage: author
99
105
  kind: judge
100
106
  recipe: fabric-decompose-adapter
101
107
  max_visits: 12
@@ -108,6 +114,7 @@ nodes:
108
114
 
109
115
  - node_id: implement
110
116
  group: build
117
+ journey_stage: run
111
118
  kind: agent
112
119
  recipe: headless-goal-loop # seams.implement → 자식 PTY
113
120
  max_visits: 12
@@ -122,6 +129,7 @@ nodes:
122
129
 
123
130
  - node_id: gate
124
131
  group: verify
132
+ journey_stage: run
125
133
  kind: gate
126
134
  recipe: gate-baseline # 변경 파일 «범위» · 새 회귀만
127
135
  max_visits: 11
@@ -136,6 +144,7 @@ nodes:
136
144
 
137
145
  - node_id: review
138
146
  group: verify
147
+ journey_stage: run
139
148
  kind: judge
140
149
  recipe: pr-reviewer # agent-substrate/pr-reviewer
141
150
  max_visits: 11
@@ -150,6 +159,7 @@ nodes:
150
159
 
151
160
  - node_id: rework
152
161
  group: verify
162
+ journey_stage: run
153
163
  kind: agent
154
164
  recipe: headless-goal-loop # 같은 루프의 다음 라운드
155
165
  max_visits: 10
@@ -164,6 +174,7 @@ nodes:
164
174
 
165
175
  - node_id: main-sync
166
176
  group: land
177
+ journey_stage: land
167
178
  kind: git
168
179
  recipe: seams-git-merge-main # LLM 충돌해결 포함
169
180
  max_visits: 2
@@ -176,6 +187,7 @@ nodes:
176
187
 
177
188
  - node_id: regate
178
189
  group: land
190
+ journey_stage: land
179
191
  kind: gate
180
192
  recipe: gate-baseline # 충돌해결 «뒤» 재-gate
181
193
  max_visits: 2
@@ -188,6 +200,7 @@ nodes:
188
200
 
189
201
  - node_id: open-pr
190
202
  group: land
203
+ journey_stage: land
191
204
  kind: git
192
205
  recipe: seams-gh-open-pr
193
206
  # 📏 실측 2026-09-08 (원장 30일 · 전 우주 · 걸음 191개 소급 계산):
@@ -204,6 +217,7 @@ nodes:
204
217
 
205
218
  - node_id: merge
206
219
  group: land
220
+ journey_stage: land
207
221
  kind: git
208
222
  recipe: seams-gh-merge-squash
209
223
  # 📏 실측 2026-09-08 (원장 30일 · 전 우주 · 걸음 191개 소급 계산):
@@ -222,6 +236,7 @@ nodes:
222
236
  # ───────── 여정 앞단: 입구 → 대기열 → 발사 관문 → 배치 ─────────
223
237
  - node_id: intake
224
238
  group: entry
239
+ journey_stage: entry
225
240
  kind: observe
226
241
  recipe: harness-entrance # src/harness/harness-cli-command.ts (say · ask · TUI /harness)
227
242
  max_visits: 1
@@ -233,6 +248,7 @@ nodes:
233
248
 
234
249
  - node_id: queue
235
250
  group: entry
251
+ journey_stage: entry
236
252
  kind: gate
237
253
  recipe: harness-queue # src/harness/harness-queue.ts (directSay 플래그 · 기본 끔 → 건너뜀)
238
254
  max_visits: 1
@@ -244,6 +260,7 @@ nodes:
244
260
 
245
261
  - node_id: launch-gate
246
262
  group: entry
263
+ journey_stage: entry
247
264
  kind: gate
248
265
  recipe: pre-launch-gate # harness-cli-command.ts preLaunchGate (예산 · 같은 골 활성 런)
249
266
  max_visits: 1
@@ -255,6 +272,7 @@ nodes:
255
272
 
256
273
  - node_id: dispatch
257
274
  group: dispatch
275
+ journey_stage: dispatch
258
276
  kind: judge
259
277
  recipe: harness-substrate-select # resolveLaunchSubstrate → substrate = local | pod
260
278
  max_visits: 2
@@ -267,6 +285,7 @@ nodes:
267
285
  # ───────── Pod 배치 (substrate == pod 일 때만 — local 은 건너뛴다) ─────────
268
286
  - node_id: pool-admit
269
287
  group: dispatch-pod
288
+ journey_stage: dispatch
270
289
  kind: gate
271
290
  recipe: pod-pool-admission # src/task-orchestrator/surfaces/self-implement-pod.ts (입장 · 멤버 슬롯 · 메모리 등급)
272
291
  max_visits: 4
@@ -278,6 +297,7 @@ nodes:
278
297
 
279
298
  - node_id: image-sync
280
299
  group: dispatch-pod
300
+ journey_stage: dispatch
281
301
  kind: gate
282
302
  recipe: pod-pool-image-sync # src/task-orchestrator/surfaces/pod-pool.ts syncPoolImages (멤버별 · pack 한 번)
283
303
  max_visits: 4
@@ -289,6 +309,7 @@ nodes:
289
309
 
290
310
  - node_id: credential-refresh
291
311
  group: dispatch-pod
312
+ journey_stage: dispatch
292
313
  kind: gate
293
314
  recipe: pod-credential-prerefresh # self-implement-pod.ts podCodexCredentialWithPrerefresh
294
315
  max_visits: 4
@@ -301,6 +322,7 @@ nodes:
301
322
  # ───────── 착지: 동결 검사 → (보류) → 병합 → 회수 ─────────
302
323
  - node_id: freeze-check
303
324
  group: land
325
+ journey_stage: land
304
326
  kind: gate
305
327
  recipe: landing-freeze-admission # src/self-implement/frozen-merges.ts admitLandingMerge (병합 직전 한 곳)
306
328
  max_visits: 4
@@ -312,6 +334,7 @@ nodes:
312
334
 
313
335
  - node_id: hold
314
336
  group: land
337
+ journey_stage: land
315
338
  kind: hitl
316
339
  recipe: frozen-merge-queue # frozen-merges.ts queueFrozenMerge → sweepFrozenMerges 가 해제 뒤 재개
317
340
  max_visits: 4
@@ -323,6 +346,7 @@ nodes:
323
346
 
324
347
  - node_id: cleanup
325
348
  group: land
349
+ journey_stage: land
326
350
  kind: git
327
351
  recipe: post-merge-cleanup # src/self-implement/orchestrator.ts (워크트리 ⊕ 브랜치 회수)
328
352
  max_visits: 1
@@ -335,6 +359,7 @@ nodes:
335
359
  # ───────── 실패 쪽: 결과 해석 → 수확 → heal → 다음 한 수 ─────────
336
360
  - node_id: result-parse
337
361
  group: recover
362
+ journey_stage: recover
338
363
  kind: observe
339
364
  recipe: pod-failure-reason # src/task-orchestrator/surfaces/pod-failure-reason.ts
340
365
  max_visits: 4
@@ -346,6 +371,7 @@ nodes:
346
371
 
347
372
  - node_id: salvage
348
373
  group: recover
374
+ journey_stage: recover
349
375
  kind: git
350
376
  recipe: salvage-branch # salvage/si-task-<job>/… (Pod Job 이 push · salvage-branches.ts 가 읽는다)
351
377
  max_visits: 4
@@ -355,8 +381,11 @@ nodes:
355
381
  tools: git-write
356
382
  outputs: [salvage_ref]
357
383
 
384
+ # 🩹 멈춤 갈래(stop_class)별 처방 노드는 «여기 없다» — 런타임 오버레이 `graphs/overlays/stop-heal-ladder.yaml` 이
385
+ # `heal` 에서 `on: stop_class` 간선으로 갈라지는 노드(id = 처방 이름)를 얹는다. 읽는 쪽 = `stop-autoheal.ts`.
358
386
  - node_id: heal
359
387
  group: recover
388
+ journey_stage: recover
360
389
  kind: judge
361
390
  recipe: heal-intake # src/self-implement/heal-intake.ts (호스트에서만)
362
391
  max_visits: 4
@@ -368,6 +397,7 @@ nodes:
368
397
 
369
398
  - node_id: next-move
370
399
  group: recover
400
+ journey_stage: recover
371
401
  kind: judge
372
402
  recipe: task-agent-judge # src/task-agent/judge.ts (판단부 → 실행부)
373
403
  max_visits: 4
@@ -379,6 +409,7 @@ nodes:
379
409
 
380
410
  - node_id: stopped
381
411
  group: end
412
+ journey_stage: end
382
413
  kind: observe
383
414
  recipe: journey-stopped # 거절·포기 — 종결
384
415
  max_visits: 1
@@ -0,0 +1,17 @@
1
+ graph_id: harness-gc
2
+ loop:
3
+ title: Harness GC
4
+ description: Reclaim only ladder-safe harness worktrees and merged branch-only refs in bounded ticks
5
+ owner: OP
6
+ trigger:
7
+ cron: '*/10 * * * *'
8
+ events: [manual]
9
+ version: 1
10
+ entry_node: tick
11
+ terminal_nodes: [done, failed]
12
+ nodes:
13
+ - { node_id: tick, kind: agent, recipe: 'cmd:harness-gc-tick', max_visits: 1 }
14
+ - { node_id: done, kind: gate, max_visits: 1 }
15
+ - { node_id: failed, kind: gate, max_visits: 1 }
16
+ edges:
17
+ - { from: tick, on: outcome, map: { ok: done, skipped: done, fail: failed, error: failed } }
@@ -12,3 +12,6 @@ secret-exposure-scan:
12
12
  guardian-shadow:
13
13
  command: 'bun "$ELANOUS_GRAPH_DIR/../../bin/elanous.mjs" guardian tick'
14
14
  timeout_ms: 120000
15
+ harness-gc-tick:
16
+ command: 'bun "$ELANOUS_GRAPH_DIR/../../src/harness/harness-gc.ts" --json'
17
+ timeout_ms: 300000
@@ -18,7 +18,7 @@
18
18
  ```yaml
19
19
  overlay_id: patient-research
20
20
  target: default-loop
21
- stage: launch # launch | runtime
21
+ stage: launch # launch | runtime | heal(멈춤 갈래 사다리 전용 · stop-autoheal 만 읽는다)
22
22
  patch:
23
23
  - op: replace
24
24
  path: /nodes/2/max_visits
@@ -0,0 +1,105 @@
1
+ # 멈춤 갈래 사다리(STOP-AUTOHEAL)를 «선언»으로 — 0.2.24 GRAPH-HEAL-NODES 첫 조각.
2
+ #
3
+ # 한 문서(`---` 로 나눈다) = 멈춤 갈래 하나 = 처방 노드 하나. 조건은 실행기가 이미 주는 `stop_class` 다.
4
+ # stop_class == env-unrelated → clean-workspace-regate
5
+ # stop_class == main-sync → rebase-regate
6
+ # stop_class == pod-died → resume-from-salvage
7
+ # stop_class == evidence-uncovered → derive-evidence-rejudge
8
+ # ⛔ 이 넷 밖의 갈래(review-repeat · review-out-of-scope · fabric · launch-failed · unclassified)는 선언이 «없다» —
9
+ # 처방은 `needs-owner` 이고 그것은 코드 기본(`AUTOHEAL_ACTION_BY_CLASS`)이 말한다.
10
+ #
11
+ # 🔑 노드 id 가 곧 처방 이름이다. `src/self-implement/stop-autoheal.ts` 는 그 갈래에 얹힌 오버레이가 «더한 노드 id» 로
12
+ # 처방을 고르고, 선언이 없거나 못 읽으면 코드 표로 간다(원장·관측의 `source` = graph | code-default).
13
+ # ⇒ 이 파일과 코드 표가 «같은 답»을 내는지는 시험이 문다(stop-autoheal.test.ts).
14
+ # ⚠️ 이 조각은 표를 선언으로 «옮기기만» 한다 — 노드의 recipe 는 주입 seam 이름(`stopAutohealActions`)이다.
15
+ # 새 처방 노드(예: strategy-switch)는 다음 조각이다.
16
+ #
17
+ # 🚨 경로·값은 «파싱된 스펙» 키(camelCase)다 — `nodeId`·`maxVisits`.
18
+ # ⛔ stage 는 `heal` 이다 — `runtime` 이면 실행기가 라운드마다 원장의 stop 줄로 `stop_class` 를 채워 이 노드들을
19
+ # «실행 그래프»에 얹는다(버전 해시·원장 값이 바뀐다). `heal` 은 `stop-autoheal.ts` 만 고른다.
20
+ # 📌 한 번만 시도한다(원장 가드와 같은 규율) — 그래서 maxVisits 1 이다.
21
+ # 📌 들어오는 간선 = `heal` 이 stop_class 로 가른다 · 나가는 간선 = 처방 결과(healed → 재발사 · needs-owner → 종결).
22
+ ---
23
+ overlay_id: stop-heal-ladder-env-unrelated
24
+ target: self-implement
25
+ stage: heal
26
+ applies_when: stop_class == env-unrelated
27
+ patch:
28
+ - op: add
29
+ path: /nodes/-
30
+ value:
31
+ nodeId: clean-workspace-regate
32
+ kind: gate
33
+ recipe: stop-autoheal:clean-workspace-regate
34
+ maxVisits: 1
35
+ journeyStage: recover
36
+ contract: { inputs: [worktree], tools: read-and-run-tests, outputs: [passed, gate-log] }
37
+ - op: add
38
+ path: /edges/-
39
+ value: { from: heal, on: stop_class, map: { env-unrelated: clean-workspace-regate } }
40
+ - op: add
41
+ path: /edges/-
42
+ value: { from: clean-workspace-regate, on: outcome, map: { healed: dispatch, needs-owner: stopped } }
43
+ ---
44
+ overlay_id: stop-heal-ladder-main-sync
45
+ target: self-implement
46
+ stage: heal
47
+ applies_when: stop_class == main-sync
48
+ patch:
49
+ - op: add
50
+ path: /nodes/-
51
+ value:
52
+ nodeId: rebase-regate
53
+ kind: git
54
+ recipe: stop-autoheal:rebase-regate
55
+ maxVisits: 1
56
+ journeyStage: recover
57
+ contract: { inputs: [worktree, base-branch], tools: git-write, outputs: [synced, passed] }
58
+ - op: add
59
+ path: /edges/-
60
+ value: { from: heal, on: stop_class, map: { main-sync: rebase-regate } }
61
+ - op: add
62
+ path: /edges/-
63
+ value: { from: rebase-regate, on: outcome, map: { healed: dispatch, needs-owner: stopped } }
64
+ ---
65
+ overlay_id: stop-heal-ladder-pod-died
66
+ target: self-implement
67
+ stage: heal
68
+ applies_when: stop_class == pod-died
69
+ patch:
70
+ - op: add
71
+ path: /nodes/-
72
+ value:
73
+ nodeId: resume-from-salvage
74
+ kind: git
75
+ recipe: stop-autoheal:resume-from-salvage
76
+ maxVisits: 1
77
+ journeyStage: recover
78
+ contract: { inputs: [salvage_ref], tools: git-write, outputs: [resumed] }
79
+ - op: add
80
+ path: /edges/-
81
+ value: { from: heal, on: stop_class, map: { pod-died: resume-from-salvage } }
82
+ - op: add
83
+ path: /edges/-
84
+ value: { from: resume-from-salvage, on: outcome, map: { healed: dispatch, needs-owner: stopped } }
85
+ ---
86
+ overlay_id: stop-heal-ladder-evidence-uncovered
87
+ target: self-implement
88
+ stage: heal
89
+ applies_when: stop_class == evidence-uncovered
90
+ patch:
91
+ - op: add
92
+ path: /nodes/-
93
+ value:
94
+ nodeId: derive-evidence-rejudge
95
+ kind: judge
96
+ recipe: stop-autoheal:derive-evidence-rejudge
97
+ maxVisits: 1
98
+ journeyStage: recover
99
+ contract: { inputs: [diff, review-summary], tools: read-only, outputs: [verdict] }
100
+ - op: add
101
+ path: /edges/-
102
+ value: { from: heal, on: stop_class, map: { evidence-uncovered: derive-evidence-rejudge } }
103
+ - op: add
104
+ path: /edges/-
105
+ value: { from: derive-evidence-rejudge, on: outcome, map: { healed: dispatch, needs-owner: stopped } }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elanous",
3
3
  "mcpName": "io.github.ElanvitalAI/elanous",
4
- "version": "0.2.23",
4
+ "version": "0.2.24",
5
5
  "description": "Self-healing coding harness where eyes, hands, and memory all turn on one sentence — it authors its own goals, implements them in isolated worktrees, and reviews its own work.",
6
6
  "license": "Apache-2.0",
7
7
  "author": "Elanvital AI",
@@ -121,7 +121,7 @@ REFRESH="$(dirname "$LOADER")/refresh_api_key_cache.sh"
121
121
  if [ -f "$REFRESH" ] && ! grep -q "\"$ENV_NAME\"" "$REFRESH"; then
122
122
  echo ""
123
123
  echo " 🔲 ⓷ 다른 기계에도 퍼뜨리려면 — ⛔ «자동으로 안 넣었다»"
124
- echo " 먼저 AWS Secrets Manager 에 비밀 «$ENV_NAME» 을 만들고, 그 «뒤»에:"
124
+ echo " 먼저 AWS Secrets Manager 에 비밀 «${ENV_NAME}» 을 만들고, 그 «뒤»에:"
125
125
  echo " fetch_secret \"$ENV_NAME\" \"\${CACHE_DIR}/$FILE_NAME\""
126
126
  echo " ⚠️ 비밀이 «없는» 상태로 넣으면 그 스크립트가 set -e 라 다른 키 갱신까지 멈춘다."
127
127
  fi
@@ -13,7 +13,16 @@ import {
13
13
  type TypecheckError,
14
14
  } from '../src/typecheck-ratchet.js';
15
15
  import { debug } from '../src/debug/log.js';
16
- import { tscEnv } from '../src/typecheck-ratchet.js';
16
+ import {
17
+ ROOT_PLACEHOLDER,
18
+ baselineCacheEnabled,
19
+ computeBaselineCacheKey,
20
+ lookupBaselineCache,
21
+ storeBaselineCache,
22
+ toPlaceholderPaths,
23
+ type BaselineCacheOptions,
24
+ } from './tsc-baseline-cache.js';
25
+ import { TSC_OOM_RETRY_HEAP_MB, TSC_HEAP_MB, tscEnv } from '../src/typecheck-ratchet.js';
17
26
 
18
27
  /** Inherited GIT_DIR / GIT_WORK_TREE would make `--cwd <other tree>` still read the launcher's repo. */
19
28
  function gitEnv(base: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
@@ -40,19 +49,26 @@ function sh(cmd: string, cwd = process.cwd()): string {
40
49
 
41
50
  export type TscRun = { out: string; ran: boolean; why?: string };
42
51
 
43
- export { TSC_HEAP_MB, tscEnv } from '../src/typecheck-ratchet.js';
52
+ export { TSC_HEAP_MB, TSC_OOM_RETRY_HEAP_MB, tscEnv } from '../src/typecheck-ratchet.js';
44
53
  /** V8 힙 부족의 얼굴 — 「타입 에러」와 «다른 값»이다. */
45
54
  const OOM = /heap out of memory|Ineffective mark-compacts near heap limit/;
46
55
 
47
56
  /** tsc 실행 결과 — 실행 여부와 진단 출력을 분리한다. */
48
57
  export function runTsc(cmd: string, exec = execSync): TscRun {
49
- try {
50
- const out = exec(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], env: tscEnv(), maxBuffer: 64 * 1024 * 1024 }) as unknown as string;
51
- return { out: String(out ?? ''), ran: true };
52
- } catch (error: unknown) {
53
- const e = error as { status?: number | null; signal?: string | null; stdout?: string; stderr?: string; code?: string };
54
- const out = `${e.stdout ?? ''}${e.stderr ?? ''}`;
55
- if (OOM.test(out)) return { out, ran: false, why: `tsc 가 V8 힙 부족(OOM)으로 죽었다 — 타입 에러가 아니다 (NODE_OPTIONS=${tscEnv().NODE_OPTIONS})` };
58
+ type Attempt = { out: string; error?: { status?: number | null; signal?: string | null; code?: string } };
59
+ const run = (env: NodeJS.ProcessEnv): Attempt => {
60
+ try {
61
+ const out = exec(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], env, maxBuffer: 64 * 1024 * 1024 }) as unknown as string;
62
+ return { out: String(out ?? '') };
63
+ } catch (error: unknown) {
64
+ const e = error as { status?: number | null; signal?: string | null; stdout?: string; stderr?: string; code?: string };
65
+ return { out: `${e.stdout ?? ''}${e.stderr ?? ''}`, error: e };
66
+ }
67
+ };
68
+ const result = (attempt: Attempt, env: NodeJS.ProcessEnv): TscRun => {
69
+ const { out, error: e } = attempt;
70
+ if (OOM.test(out)) return { out, ran: false, why: `tsc 가 V8 힙 부족(OOM)으로 죽었다 — 타입 에러가 아니다 (NODE_OPTIONS=${env.NODE_OPTIONS})` };
71
+ if (!e) return { out, ran: true };
56
72
  if (e.signal || e.code === 'ENOENT' || e.status === null || e.status === undefined) {
57
73
  return { out, ran: false, why: `tsc 실행 실패 (signal=${String(e.signal)} code=${String(e.code)} status=${String(e.status)})` };
58
74
  }
@@ -64,7 +80,23 @@ export function runTsc(cmd: string, exec = execSync): TscRun {
64
80
  return { out, ran: false, why: `tsc 가 종료코드 ${e.status} 로 끝났는데 TS 진단이 한 건도 없다(래퍼 실패로 본다)` };
65
81
  }
66
82
  return { out, ran: true };
67
- }
83
+ };
84
+
85
+ const initialEnv = tscEnv();
86
+ const initial = run(initialEnv);
87
+ if (!OOM.test(initial.out)) return result(initial, initialEnv);
88
+
89
+ const retryEnv = {
90
+ ...initialEnv,
91
+ NODE_OPTIONS: `${(initialEnv.NODE_OPTIONS ?? '').replace(/--max-old-space-size(?:=|\s+)\d+/g, '').trim()} --max-old-space-size=${TSC_OOM_RETRY_HEAP_MB}`.trim(),
92
+ };
93
+ const retryResult = result(run(retryEnv), retryEnv);
94
+ debug.log('harness.host-regate', 'tsc-oom-retry', {
95
+ heapFrom: TSC_HEAP_MB,
96
+ heapTo: TSC_OOM_RETRY_HEAP_MB,
97
+ result: retryResult,
98
+ });
99
+ return retryResult;
68
100
  }
69
101
 
70
102
  export type ChangedTsFiles = {
@@ -784,7 +816,27 @@ export function rebaseWorktreePaths(diagnostics: readonly TypecheckError[], work
784
816
  return diagnostics.map((diagnostic) => ({ ...diagnostic, line: rebase(diagnostic.line), file: rebase(diagnostic.file) }));
785
817
  }
786
818
 
787
- export function readMergeBaseDiagnostics(base: string, command: string, cwd = process.cwd(), run = runTsc): BaselineDiagnostics {
819
+ export type BaselineCacheIo = BaselineCacheOptions & { log?: (message: string) => void };
820
+
821
+ /**
822
+ * 같은 base 커밋 ⊕ 같은 명령 ⊕ 같은 설정 해시면 저장된 진단을 재사용한다(워크트리·tsc 0회).
823
+ * 캐시의 어떤 실패도 던지지 않는다 — miss 로 떨어져 아래 측정이 그대로 돈다.
824
+ */
825
+ function lookupCachedBaseline(key: string, command: string, cwd: string, cacheIo: BaselineCacheIo): BaselineDiagnostics | undefined {
826
+ const lookup = lookupBaselineCache(key, cacheIo);
827
+ const result = lookup.result === 'hit' ? 'hit' : lookup.result === 'corrupt' ? 'corrupt' : 'miss';
828
+ cacheIo.log?.(`[tsc-gate] typecheck baseline-cache ${result === 'hit' ? 'hit' : 'miss'} ${key.slice(0, 12)}`);
829
+ debug.log('typecheck.gate', 'baseline-cache', { result, key, command });
830
+ if (lookup.result !== 'hit') return undefined;
831
+ return { diagnostics: rebaseWorktreePaths(lookup.diagnostics, ROOT_PLACEHOLDER, cwd) };
832
+ }
833
+
834
+ export function readMergeBaseDiagnostics(base: string, command: string, cwd = process.cwd(), run = runTsc, cacheIo: BaselineCacheIo = {}): BaselineDiagnostics {
835
+ const cacheKey = baselineCacheEnabled(cacheIo.env ?? process.env) ? computeBaselineCacheKey(base, command, cwd, cacheIo) : undefined;
836
+ if (cacheKey) {
837
+ const cached = lookupCachedBaseline(cacheKey, command, cwd, cacheIo);
838
+ if (cached) return cached;
839
+ }
788
840
  const workspace = mkdtempSync(join(tmpdir(), 'ci-typecheck-baseline-'));
789
841
  const worktree = join(workspace, 'base');
790
842
  try {
@@ -798,7 +850,11 @@ export function readMergeBaseDiagnostics(base: string, command: string, cwd = pr
798
850
  execSync(cmd, { ...options, cwd: worktree, maxBuffer: 64 * 1024 * 1024, env: tscEnv() }) as string) as typeof execSync;
799
851
  const result = run(command, baselineExec);
800
852
  if (!result.ran) return { unavailable: result.why ?? '기준 worktree tsc 실행 실패' };
801
- return { diagnostics: rebaseWorktreePaths(parseTypecheckErrors(result.out), worktree, cwd) };
853
+ const measured = parseTypecheckErrors(result.out);
854
+ if (cacheKey && !storeBaselineCache(cacheKey, command, toPlaceholderPaths(measured, worktree), cacheIo)) {
855
+ debug.log('typecheck.gate', 'baseline-cache', { result: 'store-failed', key: cacheKey, command });
856
+ }
857
+ return { diagnostics: rebaseWorktreePaths(measured, worktree, cwd) };
802
858
  } catch (error) {
803
859
  return { unavailable: error instanceof Error ? error.message : String(error) };
804
860
  } finally {
@@ -889,8 +945,9 @@ function inspectTscResult(tsc: TscRun, changed: ReadonlySet<string>, baseline: R
889
945
  export function runGate(io: Partial<GateIo> = {}): void {
890
946
  const cwd = io.cwd ?? process.cwd();
891
947
  const defaultChanged = () => changedTsFiles((cmd) => sh(cmd, cwd), process.env, cwd, io.baseRef);
892
- const { changedTsFiles: getChanged = defaultChanged, runTscCmd = (cmd: string) => runTsc(cmd, ((command, options) => execSync(command, { ...options, cwd, env: tscExecEnv(options?.env) })) as typeof execSync), log = (message: string) => console.log(message), warn = (message: string) => console.warn(message), error = (message: string) => console.error(message), exit = ((code: number) => process.exit(code)) as GateIo['exit'] } = io;
893
- const readBaselineDiagnostics = io.readBaselineDiagnostics ?? ((base: string, command: string) => readMergeBaseDiagnostics(base, command, cwd));
948
+ const defaultRunTsc = (cmd: string) => runTsc(cmd, ((command, options) => execSync(command, { ...options, cwd, env: tscExecEnv(options?.env) })) as typeof execSync);
949
+ const { changedTsFiles: getChanged = defaultChanged, runTscCmd = defaultRunTsc, log = (message: string) => console.log(message), warn = (message: string) => console.warn(message), error = (message: string) => console.error(message), exit = ((code: number) => process.exit(code)) as GateIo['exit'] } = io;
950
+ const readBaselineDiagnostics = io.readBaselineDiagnostics ?? ((base: string, command: string) => readMergeBaseDiagnostics(base, command, cwd, runTsc, { log }));
894
951
  // Set 주입은 기존 테스트 심이며 기준 revision이 없다. 실제 ChangedTsFiles 경로만 Git 관측을 요구한다.
895
952
  const requiredExportFields = io.requiredExportFields ?? ((changed: ReadonlySet<string>, base: string) => base === 'injected test seam'
896
953
  ? { fields: [], removedSymbols: [], parameterIncreases: [] }
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * BEDROCK-PROVIDER ② (0.2.24) — 호스트 `~/.aws` 프로필 → 풀 클러스터의 bedrock Pod 전용 Secret(`elanous-bedrock-aws`).
4
+ *
5
+ * ⛔ 값은 터미널·로그·파일 어디에도 안 낸다 — 자격은 메모리에서 바로 `kubectl apply -f -` 의 stdin 으로만 간다.
6
+ * 출력은 «키 이름 · 리전 · 대상» 뿐이다.
7
+ * ⛔ 기본은 «계획만»(dry-run · 클러스터 접촉 0). 실제로 만들려면 `--apply` — 대표·OP 승인 뒤에만 친다.
8
+ * ⛔ 임시 자격(세션 토큰 · SSO/역할)은 기본 거부 — Pod 수명 중 만료되면 자식이 403 으로 죽는다. Pod 용 정적 키(IAM 사용자 · bedrock-mantle:CreateInference 만)를 쓴다.
9
+ *
10
+ * 사용:
11
+ * bun scripts/fleet/bedrock-pod-secret.ts --context k3d-elanous-pool # 계획만(키 이름)
12
+ * bun scripts/fleet/bedrock-pod-secret.ts --context k3d-elanous-pool --apply # 만든다/갱신한다
13
+ * 옵션: --profile <이름>(기본 elanous-bedrock) · --namespace <ns>(기본 elanous-test) · --region <r>(기본 프로필 region)
14
+ * --allow-session-token(임시 자격을 알고 싣는다)
15
+ * 짝: docker/h1/policy-bedrock.yaml(이그레스) · src/task-orchestrator/surfaces/pod-bedrock-child.ts(발사 전 판정)
16
+ */
17
+ import { spawnSync } from 'node:child_process';
18
+ import { existsSync, readFileSync } from 'node:fs';
19
+ import { homedir } from 'node:os';
20
+ import { join } from 'node:path';
21
+ import { BEDROCK_POD_SECRET_NAME } from '../../src/task-orchestrator/surfaces/pod-bedrock-child.js';
22
+ import { regionFromAwsConfigText, validBedrockRegion, type BedrockCredentials } from '../../src/llm/bedrock.js';
23
+
24
+ export interface BedrockSecretArgs {
25
+ context?: string;
26
+ namespace: string;
27
+ profile: string;
28
+ region?: string;
29
+ apply: boolean;
30
+ allowSessionToken: boolean;
31
+ }
32
+
33
+ export function parseArgs(argv: readonly string[]): BedrockSecretArgs | { error: string } {
34
+ const out: BedrockSecretArgs = { namespace: 'elanous-test', profile: 'elanous-bedrock', apply: false, allowSessionToken: false };
35
+ for (let i = 0; i < argv.length; i++) {
36
+ const a = argv[i]!;
37
+ const value = () => { const v = argv[++i]; if (!v || v.startsWith('--')) throw new Error(`${a} 에 값이 없다`); return v; };
38
+ try {
39
+ if (a === '--context') out.context = value();
40
+ else if (a === '--namespace') out.namespace = value();
41
+ else if (a === '--profile') out.profile = value();
42
+ else if (a === '--region') out.region = value();
43
+ else if (a === '--apply') out.apply = true;
44
+ else if (a === '--allow-session-token') out.allowSessionToken = true;
45
+ else return { error: `모르는 인자: ${a}` };
46
+ } catch (e) { return { error: (e as Error).message }; }
47
+ }
48
+ if (!out.context) return { error: '--context <풀 문맥> 이 필요하다 — 어느 클러스터에 둘지 명시한다(기본 문맥에 조용히 쓰지 않는다)' };
49
+ return out;
50
+ }
51
+
52
+ /** Secret 매니페스트 — 값은 이 객체 안에만 있고, 호출자는 stdin 으로만 넘긴다. */
53
+ export function bedrockPodSecretManifest(input: { namespace: string; region: string; credentials: BedrockCredentials; name?: string }): Record<string, unknown> {
54
+ return {
55
+ apiVersion: 'v1', kind: 'Secret', type: 'Opaque',
56
+ metadata: { name: input.name ?? BEDROCK_POD_SECRET_NAME, namespace: input.namespace, labels: { 'elanous.secret': 'bedrock-aws' } },
57
+ stringData: {
58
+ AWS_ACCESS_KEY_ID: input.credentials.accessKeyId,
59
+ AWS_SECRET_ACCESS_KEY: input.credentials.secretAccessKey,
60
+ ...(input.credentials.sessionToken ? { AWS_SESSION_TOKEN: input.credentials.sessionToken } : {}),
61
+ AWS_REGION: input.region,
62
+ },
63
+ };
64
+ }
65
+
66
+ /** 사람에게 보이는 계획 — 키 «이름»만. */
67
+ export function describePlan(args: BedrockSecretArgs, region: string, manifest: Record<string, unknown>): string {
68
+ const keys = Object.keys((manifest as { stringData: Record<string, string> }).stringData);
69
+ return [
70
+ `대상: --context ${args.context} · ${args.namespace}/${BEDROCK_POD_SECRET_NAME}`,
71
+ `출처: ~/.aws 프로필 ${args.profile} · 리전 ${region}`,
72
+ `키: ${keys.join(', ')} (값은 출력하지 않는다)`,
73
+ ].join('\n');
74
+ }
75
+
76
+ export interface Deps {
77
+ resolve: (profile: string) => Promise<BedrockCredentials>;
78
+ readConfig: () => string | undefined;
79
+ kubectl: (args: string[], stdin: string) => { status: number | null; stdout: string; stderr: string };
80
+ print: (line: string) => void;
81
+ }
82
+
83
+ const defaultDeps: Deps = {
84
+ resolve: async (profile) => {
85
+ const { defaultProvider } = await import('@aws-sdk/credential-provider-node');
86
+ const c = await defaultProvider({ profile })();
87
+ return { accessKeyId: c.accessKeyId, secretAccessKey: c.secretAccessKey, ...(c.sessionToken ? { sessionToken: c.sessionToken } : {}) };
88
+ },
89
+ readConfig: () => {
90
+ const p = process.env.AWS_CONFIG_FILE?.trim() || join(homedir(), '.aws', 'config');
91
+ try { return existsSync(p) ? readFileSync(p, 'utf8') : undefined; } catch { return undefined; }
92
+ },
93
+ kubectl: (args, stdin) => {
94
+ const r = spawnSync('kubectl', args, { input: stdin, encoding: 'utf8', timeout: 60_000 });
95
+ return { status: r.status, stdout: r.stdout ?? '', stderr: r.stderr ?? '' };
96
+ },
97
+ print: (line) => console.log(line),
98
+ };
99
+
100
+ export async function run(argv: readonly string[], deps: Deps = defaultDeps): Promise<number> {
101
+ const args = parseArgs(argv);
102
+ if ('error' in args) { deps.print(`⛔ ${args.error}`); return 2; }
103
+ const region = validBedrockRegion(args.region ?? regionFromAwsConfigText(deps.readConfig() ?? '', args.profile));
104
+ if (!region) { deps.print(`⛔ 리전 없음 — --region 또는 ~/.aws/config 의 [profile ${args.profile}] region`); return 2; }
105
+ let credentials: BedrockCredentials;
106
+ try { credentials = await deps.resolve(args.profile); }
107
+ catch (e) { deps.print(`⛔ 프로필 ${args.profile} 자격을 못 풀었다 (${(e as { name?: string })?.name ?? 'Error'})`); return 2; } // ⛔ 메시지 원문은 싣지 않는다
108
+ if (credentials.sessionToken && !args.allowSessionToken) {
109
+ deps.print('⛔ 임시 자격(세션 토큰)이다 — Pod 수명 중 만료된다. Pod 용 정적 키를 쓰거나, 알고 싣는다면 --allow-session-token');
110
+ return 2;
111
+ }
112
+ const manifest = bedrockPodSecretManifest({ namespace: args.namespace, region, credentials });
113
+ deps.print(describePlan(args, region, manifest));
114
+ if (!args.apply) { deps.print('계획만(dry-run) — 클러스터에 쓰지 않았다. 만들려면 --apply(승인 뒤)'); return 0; }
115
+ const r = deps.kubectl(['--context', args.context!, 'apply', '-f', '-'], JSON.stringify(manifest));
116
+ // kubectl apply 의 출력은 «secret/<이름> created|configured» 뿐이다 — stderr 는 원문 대신 rc 만.
117
+ if (r.status !== 0) { deps.print(`⛔ kubectl apply 실패 rc=${r.status}`); return 1; }
118
+ deps.print(`✅ ${r.stdout.trim().split('\n')[0] ?? 'applied'}`);
119
+ return 0;
120
+ }
121
+
122
+ if (import.meta.main) process.exit(await run(process.argv.slice(2)));