elanous 0.2.4 → 0.2.5

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 (412) hide show
  1. package/README.md +3 -3
  2. package/apps/pwa/out/404/index.html +1 -1
  3. package/apps/pwa/out/404.html +1 -1
  4. package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 1751.50b96ea9c37b49b6.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +25 -0
  12. package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +5 -0
  20. package/apps/pwa/out/_next/static/chunks/4440-18bb160d95819f4e.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → 4daa2798-1363d725c79f3593.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{5791-bb82743fa6299562.js → 5348-bbf838e119661eee.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/5391-8793f88b03b30161.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7527.943753b6ed829f09.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 8617.465ca22a319c95b3.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/{5080-1613752891fcadb4.js → 8918-482b30ce2a8ebf4c.js} +3 -3
  43. package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9238.2cd5f47f4bf7a2c3.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 9704-3221c102623c8d73.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f89e9a303515a033.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/board/page-4f403cd060442c95.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-9fa879ebf5959096.js → page-0ac5d053f0444d21.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/control/{page-4472ddf1e2458e69.js → page-72bd384898d88955.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/morning/{page-112f7e477bda77fd.js → page-bccce0babceae30f.js} +1 -1
  63. package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6f3850d-7f324c6566002113.js} +1 -1
  85. package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/{webpack-e5bea36f183b25e6.js → webpack-2bf59c720fe9542c.js} +1 -1
  91. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
  92. package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → ktMqfrBbf8BMGac0jqLrb}/_buildManifest.js +1 -1
  93. package/apps/pwa/out/approvals/index.html +1 -1
  94. package/apps/pwa/out/approvals/index.txt +29 -27
  95. package/apps/pwa/out/autopilot/index.html +1 -1
  96. package/apps/pwa/out/autopilot/index.txt +29 -27
  97. package/apps/pwa/out/board/index.html +1 -1
  98. package/apps/pwa/out/board/index.txt +29 -27
  99. package/apps/pwa/out/botlab/index.html +1 -1
  100. package/apps/pwa/out/botlab/index.txt +26 -24
  101. package/apps/pwa/out/bots/index.html +1 -1
  102. package/apps/pwa/out/bots/index.txt +26 -24
  103. package/apps/pwa/out/chat/index.html +1 -1
  104. package/apps/pwa/out/chat/index.txt +26 -24
  105. package/apps/pwa/out/control/index.html +1 -1
  106. package/apps/pwa/out/control/index.txt +29 -27
  107. package/apps/pwa/out/design-check/index.html +1 -1
  108. package/apps/pwa/out/design-check/index.txt +29 -27
  109. package/apps/pwa/out/editor/index.html +1 -1
  110. package/apps/pwa/out/editor/index.txt +29 -27
  111. package/apps/pwa/out/healthz +1 -1
  112. package/apps/pwa/out/icons/elanous-16.png +0 -0
  113. package/apps/pwa/out/icons/elanous-180.png +0 -0
  114. package/apps/pwa/out/icons/elanous-192.png +0 -0
  115. package/apps/pwa/out/icons/elanous-32.png +0 -0
  116. package/apps/pwa/out/icons/elanous-512.png +0 -0
  117. package/apps/pwa/out/index.html +1 -1
  118. package/apps/pwa/out/index.txt +26 -24
  119. package/apps/pwa/out/intake/index.html +1 -1
  120. package/apps/pwa/out/intake/index.txt +29 -27
  121. package/apps/pwa/out/live/index.html +1 -1
  122. package/apps/pwa/out/live/index.txt +29 -27
  123. package/apps/pwa/out/manifest.webmanifest +5 -2
  124. package/apps/pwa/out/market/index.html +1 -1
  125. package/apps/pwa/out/market/index.txt +26 -24
  126. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  127. package/apps/pwa/out/missions/placeholder/index.txt +26 -24
  128. package/apps/pwa/out/morning/index.html +1 -1
  129. package/apps/pwa/out/morning/index.txt +29 -27
  130. package/apps/pwa/out/observatory/index.html +1 -1
  131. package/apps/pwa/out/observatory/index.txt +29 -27
  132. package/apps/pwa/out/reflection/index.html +1 -1
  133. package/apps/pwa/out/reflection/index.txt +27 -25
  134. package/apps/pwa/out/scheduler/index.html +1 -1
  135. package/apps/pwa/out/scheduler/index.txt +29 -27
  136. package/apps/pwa/out/sessions/index.html +1 -1
  137. package/apps/pwa/out/sessions/index.txt +26 -24
  138. package/apps/pwa/out/settings/devices/index.html +1 -1
  139. package/apps/pwa/out/settings/devices/index.txt +29 -27
  140. package/apps/pwa/out/settings/index.html +1 -1
  141. package/apps/pwa/out/settings/index.txt +29 -27
  142. package/apps/pwa/out/setup/done/index.html +1 -1
  143. package/apps/pwa/out/setup/done/index.txt +29 -27
  144. package/apps/pwa/out/setup/index.html +1 -1
  145. package/apps/pwa/out/setup/index.txt +29 -27
  146. package/apps/pwa/out/share/index.html +1 -1
  147. package/apps/pwa/out/share/index.txt +29 -27
  148. package/apps/pwa/out/showroom/index.html +1 -1
  149. package/apps/pwa/out/showroom/index.txt +26 -24
  150. package/apps/pwa/out/sw-strategies.js +44 -0
  151. package/apps/pwa/out/sw.js +6 -44
  152. package/apps/pwa/out/tasks/index.html +1 -1
  153. package/apps/pwa/out/tasks/index.txt +29 -27
  154. package/apps/pwa/out/term/index.html +1 -1
  155. package/apps/pwa/out/term/index.txt +29 -27
  156. package/apps/pwa/out/trace/index.html +1 -1
  157. package/apps/pwa/out/trace/index.txt +29 -27
  158. package/apps/pwa/out/vault/index.html +1 -1
  159. package/apps/pwa/out/vault/index.txt +29 -27
  160. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  161. package/apps/pwa/out/workflows/chat-ui/index.txt +29 -27
  162. package/apps/pwa/out/workflows/index.html +1 -1
  163. package/apps/pwa/out/workflows/index.txt +29 -27
  164. package/apps/pwa/out/workspace/index.html +1 -1
  165. package/apps/pwa/out/workspace/index.txt +29 -27
  166. package/apps/pwa/out/worktrees/index.html +1 -1
  167. package/apps/pwa/out/worktrees/index.txt +29 -27
  168. package/catalog/resources.yaml +6 -6
  169. package/docs/goal-context/steward-directives-2026-09-28.md +35 -37
  170. package/graphs/landing/landing-heal.yaml +1 -1
  171. package/graphs/release/recipes.yaml +8 -1
  172. package/graphs/release/release-loop.yaml +6 -1
  173. package/graphs/video/README.md +1 -0
  174. package/graphs/video/explainer-line.yaml +58 -0
  175. package/package.json +3 -1
  176. package/plugins/job-coach/.codex-plugin/plugin.json +18 -1
  177. package/plugins/job-coach/README.md +12 -0
  178. package/plugins/job-coach/connectors/ncs/server.ts +4 -3
  179. package/plugins/job-coach/graphs/gap-judge.ts +44 -0
  180. package/plugins/job-coach/graphs/recipes.yaml +27 -0
  181. package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
  182. package/plugins/job-coach/graphs/run-step.ts +211 -17
  183. package/plugins/job-coach/plugin.json +16 -3
  184. package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
  185. package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
  186. package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
  187. package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
  188. package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
  189. package/plugins/job-coach/skills/interview-to-profile/SKILL.md +18 -1
  190. package/scripts/backup/elanous-backup.sh +4 -1
  191. package/scripts/build-docs-site.ts +4 -3
  192. package/scripts/coord-channel-watch.sh +23 -4
  193. package/scripts/coord-post.sh +49 -12
  194. package/scripts/coord-tracks.json +5 -5
  195. package/scripts/eval-bot-vs-grok.ts +79 -0
  196. package/scripts/eval-grok-live-baseline.ts +36 -0
  197. package/scripts/fixtures/front-route-corpus.sample.json +17 -0
  198. package/scripts/fleet/node-setup.sh +46 -7
  199. package/scripts/landing-heal/must-fix-match.ts +26 -0
  200. package/scripts/landing-heal/run-mission.ts +114 -20
  201. package/scripts/lib/front-route-measurement.ts +131 -0
  202. package/scripts/lib/tui-sim-keys.ts +42 -0
  203. package/scripts/measure-front-route-classifier.ts +56 -0
  204. package/scripts/media/ocr-leak-scan.sh +21 -0
  205. package/scripts/public-export.ts +2 -3
  206. package/scripts/public-import-pr.ts +80 -6
  207. package/scripts/publish-internal-dist.ts +2 -3
  208. package/scripts/red-sweep-diff.ts +1 -1
  209. package/scripts/release-loop/auto-approve-node.ts +72 -0
  210. package/scripts/release-loop/gate-node.ts +332 -44
  211. package/scripts/release-loop/publish-node.ts +7 -3
  212. package/scripts/release-loop/release-docs.ts +20 -13
  213. package/scripts/release-loop/test-durations.ts +63 -0
  214. package/scripts/release-loop/upgrade-node.ts +3 -2
  215. package/scripts/test-audit-coverage-per-file.sh +16 -0
  216. package/scripts/test-audit-meaningless.ts +88 -0
  217. package/scripts/test-audit-overlap-and-weak.ts +73 -0
  218. package/scripts/test-deterministic.ts +27 -5
  219. package/scripts/tui-sim.ts +59 -14
  220. package/scripts/ux/bump-installed.sh +20 -0
  221. package/scripts/ux/lib/cdp.ts +72 -0
  222. package/scripts/ux/record-page.ts +50 -0
  223. package/skills/explainer-video/SKILL.md +99 -0
  224. package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
  225. package/skills/explainer-video/engine/build.mjs +431 -0
  226. package/skills/explainer-video/engine/vo.ts +37 -0
  227. package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
  228. package/src/agent/nested-agent-env.ts +1 -0
  229. package/src/agent-mission/driver.ts +95 -16
  230. package/src/agent-mission/mission-cli.ts +6 -0
  231. package/src/agent-mission/resource-ladder.ts +73 -25
  232. package/src/auth/acp-token.ts +16 -0
  233. package/src/auth/github-app-token.ts +112 -0
  234. package/src/autopilot/gh-rest-fallback.ts +177 -0
  235. package/src/autopilot/pr-manager.ts +51 -4
  236. package/src/boot/acp-server.ts +2 -16
  237. package/src/boot/daemon-tools/web-search.ts +2 -1
  238. package/src/boot/ws-bridge.ts +11 -0
  239. package/src/chat/index.ts +37 -8
  240. package/src/chat/log-scroll-key.ts +12 -0
  241. package/src/chat/submit-trace.ts +30 -0
  242. package/src/cli/agent-cli.ts +7 -2
  243. package/src/cli/decisions-cli.ts +94 -0
  244. package/src/cli/doctor-cli.ts +40 -54
  245. package/src/cli/doctor-readiness.ts +16 -24
  246. package/src/cli/intake-cli.ts +1 -1
  247. package/src/cli/mcp-call.ts +9 -0
  248. package/src/cli/mcp-gateway-cli.ts +7 -3
  249. package/src/cli/plugin-cli.ts +109 -11
  250. package/src/cli/pr-lineage.ts +2 -1
  251. package/src/cli/pwa-start.ts +3 -0
  252. package/src/cli/release-cli.ts +94 -7
  253. package/src/cli/self-update.ts +7 -4
  254. package/src/cli/start-cli.ts +33 -14
  255. package/src/dashboard/acp-boot.ts +3 -0
  256. package/src/dashboard/index.ts +62 -13
  257. package/src/dashboard/input/no-provider-reply.ts +13 -0
  258. package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
  259. package/src/dashboard/stale-install-check.ts +77 -0
  260. package/src/decisions/decision-ledger.ts +404 -0
  261. package/src/domains/outbound-alert.ts +8 -2
  262. package/src/domains/telegram-kind-route.ts +21 -0
  263. package/src/execution-loop/dispatch-task.ts +139 -0
  264. package/src/execution-loop/gate-decision-summary.ts +29 -0
  265. package/src/execution-loop/gates.ts +197 -0
  266. package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
  267. package/src/graph-kinds/plugin-nodes.ts +10 -2
  268. package/src/graph-runner/runner.ts +35 -5
  269. package/src/grounding/token.ts +12 -6
  270. package/src/harness/harness-cli-command.ts +68 -9
  271. package/src/harness/harness-pod-dispatch.ts +8 -2
  272. package/src/harness/harness-stop.ts +147 -18
  273. package/src/harness/self-send-decide.ts +26 -17
  274. package/src/harness/self-send-target.ts +22 -1
  275. package/src/harness/worktree-branch-prefix.ts +4 -3
  276. package/src/index.ts +56 -13
  277. package/src/instance/resolve.ts +6 -0
  278. package/src/intake-plane/collect-telegram-saved.ts +5 -0
  279. package/src/intake-plane/digest.ts +11 -2
  280. package/src/live/detail-switch.ts +8 -3
  281. package/src/llm/usable-llm.ts +32 -0
  282. package/src/loops/registry.ts +27 -5
  283. package/src/market/publish.ts +59 -3
  284. package/src/native-tool-catalog.ts +2 -2
  285. package/src/nexus/api/graph-approvals.ts +125 -0
  286. package/src/nexus/api/http-server.ts +60 -6
  287. package/src/nexus/api/log-fabric.ts +10 -1
  288. package/src/nexus/api/mcp-oauth-hint.ts +10 -9
  289. package/src/nexus/api/merge-approvals.ts +2 -1
  290. package/src/nexus/api/meta-api.ts +14 -0
  291. package/src/nexus/api/plugins-credentials-api.ts +47 -0
  292. package/src/nexus/api/plugins-market.ts +87 -3
  293. package/src/nexus/api/pod-credential-api.ts +68 -14
  294. package/src/nexus/api/public-routes.ts +7 -0
  295. package/src/nexus/api/trace.ts +57 -6
  296. package/src/nexus/boot/register-mcp-clients.ts +99 -14
  297. package/src/nexus/index.ts +33 -32
  298. package/src/nexus/outbound/router.ts +1 -1
  299. package/src/onboarding.ts +25 -2
  300. package/src/plugins/core/host.ts +14 -0
  301. package/src/plugins/install/market-fetch.ts +4 -3
  302. package/src/plugins/install/plugin-credentials.ts +106 -0
  303. package/src/plugins/install/plugin-install.ts +163 -32
  304. package/src/prompt-library/universal-preamble.ts +8 -2
  305. package/src/release-loop/checklist.ts +191 -0
  306. package/src/release-loop/release-note.ts +6 -3
  307. package/src/self-dev/dev-cli.ts +40 -20
  308. package/src/self-dev/dev-pipeline.ts +77 -1
  309. package/src/self-implement/gate-baseline.ts +3 -1
  310. package/src/self-implement/goal-author.ts +18 -1
  311. package/src/self-implement/host-regate.ts +6 -2
  312. package/src/self-implement/orchestrator.ts +7 -2
  313. package/src/self-implement/seams.ts +4 -2
  314. package/src/skills/tools/dev-harness.ts +42 -0
  315. package/src/steward/steward-cards.ts +45 -0
  316. package/src/steward/triage.ts +50 -14
  317. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +61 -3
  318. package/src/task-orchestrator/surfaces/pod-command-job.ts +27 -6
  319. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +39 -9
  320. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +16 -1
  321. package/src/task-orchestrator/surfaces/pod-source-receive.ts +51 -13
  322. package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -28
  323. package/src/telegram-report.ts +12 -6
  324. package/src/tui-client/acp-transport-ws-client.ts +72 -5
  325. package/src/tui.ts +3 -2
  326. package/src/user-config.ts +28 -2
  327. package/src/util/spawn-sync-output.ts +15 -0
  328. package/src/version/code-revision.ts +1 -1
  329. package/src/version/packed-revision.json +1 -1
  330. package/src/web-search/free.ts +77 -0
  331. package/src/web-search/index.ts +2 -0
  332. package/src/workflow-runtime/deps-bridge.ts +4 -3
  333. package/src/workflow-runtime/plugin-kind-node.ts +32 -4
  334. package/src/workflow-runtime/types.ts +2 -1
  335. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  336. package/apps/pwa/out/_next/static/chunks/1191-7b13a24117a689fa.js +0 -1
  337. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  338. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  339. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  340. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  341. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  342. package/apps/pwa/out/_next/static/chunks/2375-3fcae5186c64fe6b.js +0 -1
  343. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  344. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  345. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  346. package/apps/pwa/out/_next/static/chunks/319-d37df1b6e0cbeff4.js +0 -1
  347. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  348. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  349. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  350. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  351. package/apps/pwa/out/_next/static/chunks/4836-3c93795ab834381e.js +0 -1
  352. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  353. package/apps/pwa/out/_next/static/chunks/6090-1bd6077591603947.js +0 -1
  354. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  355. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  356. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  357. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  358. package/apps/pwa/out/_next/static/chunks/7457-f5cb1cc8db9f7453.js +0 -1
  359. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  360. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  361. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  362. package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +0 -1
  363. package/apps/pwa/out/_next/static/chunks/8142-011e1f474efb8b33.js +0 -1
  364. package/apps/pwa/out/_next/static/chunks/8519-0059d82bdb4812bf.js +0 -1
  365. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  366. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  367. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  368. package/apps/pwa/out/_next/static/chunks/9740-52467f244755917f.js +0 -1
  369. package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +0 -1
  370. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  371. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  372. package/apps/pwa/out/_next/static/chunks/app/approvals/page-21c3261af6ab377c.js +0 -1
  373. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1991445b8ea86274.js +0 -1
  374. package/apps/pwa/out/_next/static/chunks/app/board/page-4ebfaee2369fe248.js +0 -1
  375. package/apps/pwa/out/_next/static/chunks/app/bots/page-ca7c3cc305c3285a.js +0 -1
  376. package/apps/pwa/out/_next/static/chunks/app/chat/page-9951930add3d2051.js +0 -1
  377. package/apps/pwa/out/_next/static/chunks/app/design-check/page-4de08d4b766f134b.js +0 -1
  378. package/apps/pwa/out/_next/static/chunks/app/editor/page-7a975e2b9db1dfb7.js +0 -1
  379. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  380. package/apps/pwa/out/_next/static/chunks/app/intake/page-49270714ef35bb96.js +0 -1
  381. package/apps/pwa/out/_next/static/chunks/app/layout-33fbdf353e2a5982.js +0 -1
  382. package/apps/pwa/out/_next/static/chunks/app/live/page-259f122e2dd64317.js +0 -1
  383. package/apps/pwa/out/_next/static/chunks/app/market/page-65b82726753658e1.js +0 -1
  384. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4b8df3748dc06285.js +0 -1
  385. package/apps/pwa/out/_next/static/chunks/app/not-found-542a5c0006da637c.js +0 -1
  386. package/apps/pwa/out/_next/static/chunks/app/observatory/page-63ffb347831262ea.js +0 -1
  387. package/apps/pwa/out/_next/static/chunks/app/page-98e4e359d97263b4.js +0 -1
  388. package/apps/pwa/out/_next/static/chunks/app/reflection/page-97e24ac675ce576e.js +0 -1
  389. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ac6391f26391d89d.js +0 -1
  390. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f45c9d45ffc43bd.js +0 -1
  391. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-36995b9cb5d98218.js +0 -1
  392. package/apps/pwa/out/_next/static/chunks/app/settings/page-0c795b577988d63f.js +0 -1
  393. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b4311e2f71c6735a.js +0 -1
  394. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  395. package/apps/pwa/out/_next/static/chunks/app/setup/page-eb2381074df20dba.js +0 -1
  396. package/apps/pwa/out/_next/static/chunks/app/share/page-b01336e64eba01ae.js +0 -1
  397. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7af7f21c1f2858ef.js +0 -1
  398. package/apps/pwa/out/_next/static/chunks/app/tasks/page-a98ecd364586c89b.js +0 -1
  399. package/apps/pwa/out/_next/static/chunks/app/term/page-57f0502dfbfa089b.js +0 -1
  400. package/apps/pwa/out/_next/static/chunks/app/trace/page-3467d2e1abd8a14a.js +0 -1
  401. package/apps/pwa/out/_next/static/chunks/app/vault/page-7842ca23d53ba682.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-ae9ac882912b0198.js +0 -1
  403. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3a0d72e3f783bcef.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/app/workspace/page-f3b39fe8358c2a97.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-5a22af3181ac2afb.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/main-app-1457627bb302a22c.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  411. package/apps/pwa/out/_next/static/css/e66b7f5efc8df3f3.css +0 -1
  412. /package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → ktMqfrBbf8BMGac0jqLrb}/_ssgManifest.js +0 -0
@@ -6,12 +6,14 @@
6
6
  // 명령 인자는 셸 문자열로 이어붙이지 않고 `"$@"` 로 따로 인용한다.
7
7
 
8
8
  import { spawnSync } from 'node:child_process';
9
+ import { isAbsolute } from 'node:path';
10
+ import { getUserConfig } from '../../user-config.js';
9
11
  import { debug } from '../../debug/log.js';
10
12
  import { effectiveInstanceRoot } from '../../instance/resolve.js';
11
13
  import { collectPodArtifacts } from './pod-artifact-return.js';
12
14
  import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
13
15
  import { readSkillEnvFiles } from './pod-skills.js';
14
- import { podSourceScript } from './pod-source-receive.js';
16
+ import { podSourceScript, type PodSource } from './pod-source-receive.js';
15
17
  import {
16
18
  POD_CHILD_REQUESTS,
17
19
  POD_JOB_DEADLINE_SECONDS,
@@ -73,6 +75,10 @@ export interface PodCommandJobInput {
73
75
  llm?: 'grok';
74
76
  /** 저장소를 clone 한다 — 비공개 저장소라 GitHub 토큰이 Secret 으로 간다(명시 opt-in). 기본은 clone 없이 `~/work` 에서 이미지의 `elanous` 로 돈다. */
75
77
  clone?: boolean;
78
+ hostMirror?: string;
79
+ /** 컨테이너 메모리 한도(기본 16Gi) — 게이트가 파일 하나 격리 Job 에 올린다. */
80
+ memoryLimit?: string;
81
+ source?: PodSource;
76
82
  deadlineSeconds: number;
77
83
  runId?: string;
78
84
  }
@@ -100,7 +106,7 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
100
106
  ...credLines,
101
107
  'curl -s -m 3 -o /dev/null http://host.orb.internal:31415/health && { echo "[pod] ISOLATION FAIL"; exit 3; }',
102
108
  ...(o.clone
103
- ? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript({ kind: 'default' }, o.repoUrl)]
109
+ ? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl)]
104
110
  : ['mkdir -p ~/work && cd ~/work']),
105
111
  `set -- ${quotedArgs}`,
106
112
  '"$@"',
@@ -125,16 +131,22 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
125
131
  initContainers: [{ name: 'isolation-gate', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', command: ['bash', '-c'], args: [GATE] }],
126
132
  containers: [{
127
133
  name: 'child', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never',
128
- resources: { requests: { ...POD_CHILD_REQUESTS }, limits: { memory: '16Gi', cpu: '4' } },
134
+ resources: { requests: { ...POD_CHILD_REQUESTS }, limits: { memory: o.memoryLimit ?? '16Gi', cpu: '4' } },
129
135
  command: ['bash', '-c'], args: [script],
130
136
  env: [
131
137
  ...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
132
138
  { name: 'ELANOUS_SUBSTRATE', value: 'pod' },
133
139
  { name: 'ELANOUS_POD_NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } },
134
140
  ],
135
- ...(secretKeys ? { volumeMounts: [{ name: 'creds', mountPath: '/creds', readOnly: true }] } : {}),
141
+ ...(secretKeys || o.hostMirror ? { volumeMounts: [
142
+ ...(secretKeys ? [{ name: 'creds', mountPath: '/creds', readOnly: true }] : []),
143
+ ...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : []),
144
+ ] } : {}),
136
145
  }],
137
- ...(secretKeys ? { volumes: [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] } : {}),
146
+ ...(secretKeys || o.hostMirror ? { volumes: [
147
+ ...(secretKeys ? [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] : []),
148
+ ...(o.hostMirror ? [{ name: 'host-mirror', hostPath: { path: o.hostMirror, type: 'Directory' } }] : []),
149
+ ] } : {}),
138
150
  },
139
151
  },
140
152
  },
@@ -188,6 +200,10 @@ export interface RunPodCommandOptions {
188
200
  skills?: readonly string[];
189
201
  llm?: 'grok';
190
202
  clone?: boolean;
203
+ hostMirror?: string;
204
+ /** 컨테이너 메모리 한도(기본 16Gi). */
205
+ memoryLimit?: string;
206
+ source?: PodSource;
191
207
  ghToken?: () => string;
192
208
  deadlineSeconds?: number;
193
209
  namespace?: string;
@@ -207,6 +223,7 @@ export interface RunPodCommandOptions {
207
223
  sleep?: (ms: number) => Promise<void>;
208
224
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
209
225
  env?: NodeJS.ProcessEnv;
226
+ configHostMirror?: () => string | undefined;
210
227
  }
211
228
 
212
229
  function jobFinished(types: string): 'complete' | 'failed' | null {
@@ -243,6 +260,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
243
260
  const deadlineSeconds = options.deadlineSeconds ?? POD_COMMAND_DEADLINE_SECONDS;
244
261
  const name = options.name ?? podJobName(`cmd-${Date.now().toString(36)}`);
245
262
  const env = options.env ?? process.env;
263
+ const hostMirror = (options.hostMirror ?? env.ELANOUS_POD_HOST_MIRROR
264
+ ?? (options.configHostMirror ?? (() => getUserConfig().pod?.hostMirror))())?.trim() || undefined;
265
+ if (hostMirror && !isAbsolute(hostMirror)) throw new Error('pod.hostMirror must be an absolute directory path');
246
266
 
247
267
  let member: PodPoolMember | null = null;
248
268
  let pool = options.poolScheduler;
@@ -307,7 +327,8 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
307
327
  const manifest = podCommandJobManifest({
308
328
  name, namespace, image: member?.imageRef ?? image,
309
329
  ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
310
- repoUrl, command, skills, ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}), deadlineSeconds,
330
+ repoUrl, command, skills, ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
331
+ ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(options.memoryLimit ? { memoryLimit: options.memoryLimit } : {}), deadlineSeconds,
311
332
  ...(options.runId ? { runId: options.runId } : {}),
312
333
  });
313
334
  kubectl(['-n', namespace, 'delete', 'job', name, '--ignore-not-found']);
@@ -125,13 +125,18 @@ export function createPodLedgerFollower(opts: {
125
125
  let disabled = false;
126
126
  let lastProgressAt = now();
127
127
  let lastProgressEvent: string | null = null;
128
+ let lastActivityMeasuredAt = lastProgressAt;
129
+ let lastActivityLogAt = -Infinity;
128
130
  let nextStallMinute = stallMinutes;
129
131
  let stalled = false;
130
- function checkStall() {
132
+ function checkStall(ledgerRead: boolean, activityMeasured: boolean) {
131
133
  const idleMinutes = Math.max(0, (now() - lastProgressAt) / 60_000);
132
134
  if (idleMinutes >= nextStallMinute) {
133
135
  log('self-implement.pod', 'stalled', { runId: opts.runId, lastProgressEvent, idleMinutes });
134
- onStall(`[pod] 진행 없음 ${Math.floor(idleMinutes)}분 — 마지막 진행 ${lastProgressEvent ?? '없음'}`);
136
+ const observation = ledgerRead
137
+ ? (activityMeasured ? '원장·작업 트리 모두 조용함' : '원장 조용함')
138
+ : '원장 못 잼';
139
+ onStall(`[pod] 진행 없음 ${Math.floor(idleMinutes)}분 — ${observation} · 마지막 진행 ${lastProgressEvent ?? '없음'}${activityMeasured ? '' : ' (작업 트리 못 잼)'}`);
135
140
  stalled = true;
136
141
  nextStallMinute = (Math.floor(idleMinutes / stallMinutes) + 1) * stallMinutes;
137
142
  }
@@ -145,13 +150,38 @@ export function createPodLedgerFollower(opts: {
145
150
  log('self-implement.pod', 'ledger-live-skipped', { runId: opts.runId, reason: 'host-ledger-exists' });
146
151
  return;
147
152
  }
148
- const r = opts.exec(`f="\${ELANOUS_STATE_DIR:-$HOME/.elanous}/run-ledger/${opts.runId}.jsonl"; [ -f "$f" ] || exit 0; tail -c +${offset + 1} "$f"`);
149
- if (r.status !== 0) { log('self-implement.pod', 'ledger-live-unavailable', { runId: opts.runId, status: r.status, stderr: r.stderr.trim().slice(0, 200) }); checkStall(); return; }
150
- if (!r.stdout) { checkStall(); return; }
151
- offset += Buffer.byteLength(r.stdout);
152
- const text = pending + r.stdout;
153
+ const since = `${Math.floor(lastActivityMeasuredAt / 1000)}.${String(lastActivityMeasuredAt % 1000).padStart(3, '0')}`;
154
+ const measurementStartedAt = now();
155
+ const until = `${Math.floor(measurementStartedAt / 1000)}.${String(measurementStartedAt % 1000).padStart(3, '0')}`;
156
+ const r = opts.exec(`s="\${ELANOUS_STATE_DIR:-$HOME/.elanous}"; f="$s/run-ledger/${opts.runId}.jsonl"; w="$s/worktrees"; if [ -f "$f" ]; then tail -c +${offset + 1} "$f" || exit 1; fi; target=''; matches=0; for tree in "$w"/*/*.worktrees/*; do [ -e "$tree/.git" ] || continue; owner=$(git -C "$tree" config --worktree --get elanous.harness.owner 2>/dev/null) || continue; [ "$owner" = 'dev:${opts.runId}' ] || continue; target="$tree"; matches=$((matches + 1)); done; if [ "$matches" -eq 1 ]; then activity=$(find "$target" -type d \\( -name .git -o -name node_modules \\) -prune -o -type f -newermt '@${since}' ! -newermt '@${until}' -printf . 2>/dev/null) && printf '\\nELANOUS_ACTIVITY %s\\n' "\${#activity}" || printf '\\nELANOUS_ACTIVITY_ERROR\\n'; else printf '\\nELANOUS_ACTIVITY_ERROR\\n'; fi`);
157
+ if (r.status !== 0) { log('self-implement.pod', 'ledger-live-unavailable', { runId: opts.runId, status: r.status, stderr: r.stderr.trim().slice(0, 200) }); checkStall(false, false); return; }
158
+ const marker = r.stdout.lastIndexOf('\nELANOUS_ACTIVITY');
159
+ const activityLine = marker < 0 ? '' : r.stdout.slice(marker + 1);
160
+ const activityMatch = /^ELANOUS_ACTIVITY (0|[1-9]\d*)\n$/.exec(activityLine);
161
+ const activityMeasured = !!activityMatch && Number.isSafeInteger(Number(activityMatch[1]));
162
+ // A missing measurement trailer is still a usable ledger response unless it contains activity protocol bytes.
163
+ const ledgerBytes = marker < 0 ? (r.stdout.includes('ELANOUS_ACTIVITY') ? '' : r.stdout) : r.stdout.slice(0, marker);
164
+ if (activityMeasured) {
165
+ lastActivityMeasuredAt = measurementStartedAt;
166
+ const files = Number(activityMatch![1]);
167
+ if (files > 0) {
168
+ const idleMinutes = Math.max(0, (now() - lastProgressAt) / 60_000);
169
+ if (stalled) log('self-implement.pod', 'stall-cleared', { runId: opts.runId, idleMinutes });
170
+ stalled = false;
171
+ lastProgressAt = now();
172
+ lastProgressEvent = 'worktree-activity';
173
+ nextStallMinute = stallMinutes;
174
+ if (now() - lastActivityLogAt >= 5 * 60_000) {
175
+ log('self-implement.pod', 'worktree-activity', { runId: opts.runId, files });
176
+ lastActivityLogAt = now();
177
+ }
178
+ }
179
+ }
180
+ if (!ledgerBytes) { checkStall(true, activityMeasured); return; }
181
+ offset += Buffer.byteLength(ledgerBytes);
182
+ const text = pending + ledgerBytes;
153
183
  const cut = text.lastIndexOf('\n');
154
- if (cut < 0) { pending = text; checkStall(); return; }
184
+ if (cut < 0) { pending = text; checkStall(true, activityMeasured); return; }
155
185
  const complete = text.slice(0, cut + 1);
156
186
  pending = text.slice(cut + 1);
157
187
  mkdirSync(dir, { recursive: true });
@@ -171,7 +201,7 @@ export function createPodLedgerFollower(opts: {
171
201
  lastProgressEvent = event;
172
202
  nextStallMinute = stallMinutes;
173
203
  }
174
- checkStall();
204
+ checkStall(true, activityMeasured);
175
205
  },
176
206
  };
177
207
  }
@@ -13,6 +13,7 @@ type PackOptions = {
13
13
  paths?: string[];
14
14
  outDir: string;
15
15
  maxSizeBytes?: number;
16
+ mirrorHead?: string;
16
17
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
17
18
  };
18
19
 
@@ -108,7 +109,21 @@ export function packSourceBundle(options: PackOptions): PackedBundle {
108
109
  ref = `refs/elanous/pod-source/${randomUUID()}`;
109
110
  git(root, env, 'update-ref', ref, headCommit);
110
111
  createdBundle = true;
111
- git(root, env, 'bundle', 'create', bundlePath, `${baseCommit}..${ref}`);
112
+ let bundleRevision = ref;
113
+ if (options.mirrorHead !== undefined) {
114
+ // A thin bundle is usable only when its excluded history belongs to the packed base's lineage.
115
+ const mirrorHead = options.mirrorHead;
116
+ let sharedHistory = false;
117
+ if (/^[0-9a-f]{40,64}$/.test(mirrorHead)) {
118
+ try {
119
+ git(root, env, 'cat-file', '-e', `${mirrorHead}^{commit}`);
120
+ git(root, env, 'merge-base', '--is-ancestor', mirrorHead, baseCommit);
121
+ sharedHistory = true;
122
+ } catch { /* The mirror is unavailable or unrelated; include all history instead. */ }
123
+ }
124
+ bundleRevision = sharedHistory ? `${mirrorHead}..${ref}` : ref;
125
+ }
126
+ git(root, env, 'bundle', 'create', bundlePath, bundleRevision);
112
127
  git(root, env, 'update-ref', '-d', ref, headCommit);
113
128
  ref = undefined;
114
129
  const sizeBytes = statSync(bundlePath).size;
@@ -30,11 +30,33 @@ function assertSize(value: number): number {
30
30
  }
31
31
 
32
32
  /** Job 스크립트의 원천 단계. 성공 갈래는 `ELANOUS_POD_SOURCE <kind> <HEAD>` 로 끝난다. */
33
- export function podSourceScript(source: PodSource, repoUrl: string): string {
34
- const clone = `git clone -q --depth 50 '${repoUrl}' repo`;
33
+ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath = '/host-mirror'): string {
34
+ const quotedUrl = `'${repoUrl.replace(/'/g, `'\\''`)}'`;
35
+ const quotedMirror = `'${mirrorPath.replace(/'/g, `'\\''`)}'`;
36
+ const clone = `git clone -q --depth 50 ${quotedUrl} repo`;
37
+ const start = [
38
+ 'if [ -e repo ]; then exit 5; fi',
39
+ `if [ -d ${quotedMirror} ] && git -C ${quotedMirror} rev-parse --verify HEAD >/dev/null 2>&1 && git clone -q --shared -- ${quotedMirror} repo && git -C repo rev-parse --verify HEAD >/dev/null 2>&1; then`,
40
+ ` git -C repo remote set-url origin ${quotedUrl} || exit 5`,
41
+ ' source_via=mirror',
42
+ 'else',
43
+ ' if [ -e repo ]; then rm -r -- repo || exit 5; fi',
44
+ ` ${clone} || exit 5`,
45
+ ' source_via=github',
46
+ 'fi',
47
+ "printf 'ELANOUS_POD_SOURCE_VIA %s\\n' \"$source_via\"",
48
+ 'cd repo || exit 5',
49
+ ];
35
50
  if (source.kind === 'default') {
36
51
  return [
37
- `${clone} && cd repo || exit 5`,
52
+ ...start,
53
+ 'if [ "$source_via" = mirror ]; then',
54
+ ' remote_head=$(git ls-remote origin HEAD | cut -f1) || exit 5',
55
+ ' if ! [[ "$remote_head" =~ ^[0-9a-f]{40}$ ]]; then exit 5; fi',
56
+ ' if [ "$remote_head" != "$(git rev-parse HEAD)" ]; then',
57
+ ' git fetch --depth 50 origin HEAD && git reset --hard FETCH_HEAD || exit 5',
58
+ ' fi',
59
+ 'fi',
38
60
  'head=$(git rev-parse HEAD)',
39
61
  "printf 'ELANOUS_POD_SOURCE default %s\\n' \"$head\"",
40
62
  ].join('\n');
@@ -42,9 +64,9 @@ export function podSourceScript(source: PodSource, repoUrl: string): string {
42
64
  if (source.kind === 'commit') {
43
65
  const sha = assertSha(source.sha, 'sha');
44
66
  return [
45
- `${clone} && cd repo || exit 5`,
46
- `git fetch --depth 1 origin ${sha}`,
47
- `git checkout --detach ${sha}`,
67
+ ...start,
68
+ `if ! git cat-file -e '${sha}^{commit}' 2>/dev/null; then git fetch --depth 1 origin ${sha} || exit 5; fi`,
69
+ `git checkout --detach ${sha} || exit 5`,
48
70
  'head=$(git rev-parse HEAD)',
49
71
  "printf 'ELANOUS_POD_SOURCE commit %s\\n' \"$head\"",
50
72
  ].join('\n');
@@ -52,9 +74,11 @@ export function podSourceScript(source: PodSource, repoUrl: string): string {
52
74
  if (source.kind === 'pr') {
53
75
  const n = assertPositiveInt(source.number);
54
76
  return [
55
- `${clone} && cd repo || exit 5`,
56
- `git fetch --depth 50 origin pull/${n}/head:pr-${n}`,
57
- `git checkout pr-${n}`,
77
+ ...start,
78
+ `pr_sha=$(git ls-remote origin refs/pull/${n}/head | cut -f1) || exit 5`,
79
+ 'if ! [[ "$pr_sha" =~ ^[0-9a-f]{40}$ ]]; then exit 5; fi',
80
+ `if ! git cat-file -e "$pr_sha^{commit}" 2>/dev/null; then git fetch --depth 50 origin pull/${n}/head || exit 5; fi`,
81
+ `git checkout -B pr-${n} "$pr_sha" || exit 5`,
58
82
  'head=$(git rev-parse HEAD)',
59
83
  "printf 'ELANOUS_POD_SOURCE pr %s\\n' \"$head\"",
60
84
  ].join('\n');
@@ -82,10 +106,24 @@ export function podSourceScript(source: PodSource, repoUrl: string): string {
82
106
  " printf 'ELANOUS_POD_SOURCE_MISMATCH sha256\\n'",
83
107
  ' exit 3',
84
108
  'fi',
85
- 'git clone /tmp/source.bundle repo',
86
- `git -C repo checkout --detach ${headCommit}`,
87
- 'head=$(git -C repo rev-parse HEAD)',
109
+ 'if [ -e repo ]; then exit 5; fi',
110
+ `if [ -d ${quotedMirror} ] && git -C ${quotedMirror} rev-parse --verify HEAD >/dev/null 2>&1 && git clone -q --shared -- ${quotedMirror} repo && git -C repo rev-parse --verify HEAD >/dev/null 2>&1; then`,
111
+ ` git -C repo remote set-url origin ${quotedUrl} || exit 5`,
112
+ ' if git -C repo bundle verify /tmp/source.bundle >/dev/null 2>&1; then',
113
+ ' git -C repo fetch /tmp/source.bundle "refs/elanous/pod-source/*:refs/remotes/bundle/*" || exit 5',
114
+ ' else',
115
+ ' rm -r -- repo || exit 5',
116
+ ' git clone /tmp/source.bundle repo || exit 5',
117
+ ' git -C repo fetch /tmp/source.bundle "refs/elanous/pod-source/*:refs/remotes/bundle/*" || exit 5',
118
+ ' fi',
119
+ 'else',
120
+ ' if [ -e repo ]; then rm -r -- repo || exit 5; fi',
121
+ ' git clone /tmp/source.bundle repo || exit 5',
122
+ ' git -C repo fetch /tmp/source.bundle "refs/elanous/pod-source/*:refs/remotes/bundle/*" || exit 5',
123
+ 'fi',
124
+ `git -C repo checkout --detach ${headCommit} || exit 5`,
125
+ 'head=$(git -C repo rev-parse HEAD) || exit 5',
88
126
  "printf 'ELANOUS_POD_SOURCE bundle %s\\n' \"$head\"",
89
- 'cd repo',
127
+ 'cd repo || exit 5',
90
128
  ].join('\n');
91
129
  }