elanous 0.2.10 → 0.2.12

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 (615) 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/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  8. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  18. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  19. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  24. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -1
  152. package/apps/pwa/out/ops/seats/index.txt +22 -22
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -1
  178. package/apps/pwa/out/today/index.txt +23 -23
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/context/nightly-condense.yaml +21 -0
  192. package/graphs/context/recipes.yaml +12 -0
  193. package/graphs/demo/inside-seed.yaml +20 -0
  194. package/graphs/demo/recipes.yaml +12 -0
  195. package/graphs/drafts/draft-cleanup.yaml +19 -0
  196. package/graphs/drafts/recipes.yaml +23 -0
  197. package/graphs/intake/intake-daily.yaml +2 -1
  198. package/graphs/ops/recipes.yaml +3 -0
  199. package/graphs/ops/secret-exposure.yaml +24 -0
  200. package/graphs/release/recipes.yaml +3 -0
  201. package/graphs/release/release-loop.yaml +4 -1
  202. package/graphs/video/explainer-line.yaml +2 -2
  203. package/package.json +2 -1
  204. package/plugins/card-followup/examples/sample-card.png +0 -0
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/context-hooks/claude-stop.sh +4 -0
  216. package/scripts/context-hooks/emit.ts +24 -0
  217. package/scripts/context-hooks/post-tool-use.sh +4 -0
  218. package/scripts/coord-channel-watch.sh +12 -0
  219. package/scripts/coord-requests-bridge.ts +143 -0
  220. package/scripts/field-feed/lib.ts +4 -0
  221. package/scripts/fleet/node-setup.sh +20 -3
  222. package/scripts/homebrew-formula-bump.ts +69 -0
  223. package/scripts/lib/telegram-inject-args.ts +31 -0
  224. package/scripts/marketing/measure-site-numbers.ts +169 -0
  225. package/scripts/measure-gate-shards.ts +309 -0
  226. package/scripts/measure-pod-memory-by-goal.ts +130 -0
  227. package/scripts/mission-request-judge.ts +31 -1
  228. package/scripts/morning-report.ts +2 -2
  229. package/scripts/opportunity-scan.ts +1 -1
  230. package/scripts/release-loop/auto-approve-node.ts +21 -4
  231. package/scripts/release-loop/checklist-gate-node.ts +2 -1
  232. package/scripts/release-loop/cut-branch.ts +84 -0
  233. package/scripts/release-loop/gate-node.ts +22 -15
  234. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  235. package/scripts/release-loop/node-verdict.ts +3 -3
  236. package/scripts/release-loop/ops-upgrade-node.ts +47 -6
  237. package/scripts/release-loop/publish-node.ts +4 -1
  238. package/scripts/release-loop/tui-node-checks.ts +42 -0
  239. package/scripts/release-loop/tui-sim-node.ts +32 -8
  240. package/scripts/release-loop/unattended-release.ts +5 -3
  241. package/scripts/release-loop/version-node.ts +74 -13
  242. package/scripts/signal-digest-cycle.ts +2 -7
  243. package/scripts/signal-digest-photo.ts +11 -0
  244. package/scripts/tech1-public-measure.ts +94 -0
  245. package/scripts/telegram-inject.ts +14 -6
  246. package/scripts/test-diet/node.ts +1 -1
  247. package/scripts/test-diet/remeasure-list.ts +112 -0
  248. package/scripts/tui-regress.ts +2 -2
  249. package/scripts/ux/demo-rehearsal.ts +247 -0
  250. package/scripts/ux/demo-seed.ts +108 -0
  251. package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
  252. package/skills/diagram-master/SKILL.md +366 -0
  253. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  254. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  255. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  256. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  257. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  258. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  259. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  260. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  261. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  262. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  263. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  264. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  265. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  266. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  267. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  268. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  269. package/skills/diagram-master/references/examples/README.md +69 -0
  270. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  271. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  272. package/skills/diagram-master/references/pyproject.toml +16 -0
  273. package/skills/diagram-master/references/quality-checklist.md +33 -0
  274. package/skills/diagram-master/references/routing-guide.md +164 -0
  275. package/skills/diagram-master/references/uv.lock +1356 -0
  276. package/skills/google-workspace/SKILL.md +33 -0
  277. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  278. package/skills/grill-me/SKILL.md +1 -1
  279. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  280. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  281. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  282. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  283. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  284. package/skills/omni-crawl/SKILL.md +21 -11
  285. package/skills/omni-crawl/scripts/main.ts +6 -6
  286. package/skills/omni-crawl/src/router.ts +3 -3
  287. package/skills/omni-digest/SKILL.md +17 -9
  288. package/skills/omni-digest/digest.md +2 -2
  289. package/skills/omni-digest/src/fetch.ts +30 -3
  290. package/skills/pitch-deck/SKILL.md +2 -2
  291. package/skills/pitch-deck/template.html +2 -2
  292. package/skills/youtube-master/SKILL.md +163 -0
  293. package/skills/youtube-master/package-lock.json +558 -0
  294. package/skills/youtube-master/package.json +13 -0
  295. package/skills/youtube-master/references/study-note-template.md +124 -0
  296. package/skills/youtube-master/scripts/main.ts +435 -0
  297. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  298. package/skills/youtube-master/src/audio.ts +63 -0
  299. package/skills/youtube-master/src/domain-staging.ts +50 -0
  300. package/skills/youtube-master/src/env.ts +36 -0
  301. package/skills/youtube-master/src/obsidian.ts +155 -0
  302. package/skills/youtube-master/src/router.ts +110 -0
  303. package/skills/youtube-master/src/stt.ts +199 -0
  304. package/skills/youtube-master/src/study-note.ts +175 -0
  305. package/skills/youtube-master/src/summarize.ts +358 -0
  306. package/skills/youtube-master/src/transcript.ts +76 -0
  307. package/skills/youtube-master/src/types.ts +91 -0
  308. package/skills/youtube-master/src/util.ts +93 -0
  309. package/skills/youtube-master/src/youtube.ts +70 -0
  310. package/skills/youtube-master/tsconfig.json +13 -0
  311. package/src/acp/server.ts +5 -2
  312. package/src/agent-mission/driver.ts +215 -23
  313. package/src/agent-mission/pty-decision.ts +71 -0
  314. package/src/agent-mission/review-loop.ts +30 -0
  315. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  316. package/src/autopilot/pty-control-loop.ts +4 -1
  317. package/src/autopilot/tool-registry.ts +2 -0
  318. package/src/boot/daemon-prompt-turn.ts +5 -0
  319. package/src/boot/daemon-runtime.ts +9 -3
  320. package/src/boot/daemon-tools/web-search.ts +3 -0
  321. package/src/card-followup/core.ts +109 -0
  322. package/src/chat/index.ts +2 -0
  323. package/src/cli/drive-input-jail.ts +101 -0
  324. package/src/cli/hooks-cli.ts +17 -3
  325. package/src/cli/make-cli.ts +43 -0
  326. package/src/cli/persona-cli.ts +98 -9
  327. package/src/cli/plugin-cli.ts +31 -22
  328. package/src/cli/pod-cli.ts +36 -9
  329. package/src/cli/pod-memory-advice.ts +35 -0
  330. package/src/cli/pr-cli.ts +51 -15
  331. package/src/cli/pty-drive-cli.ts +41 -7
  332. package/src/cli/pty-drive-verdict.ts +40 -0
  333. package/src/cli/release-cli.ts +63 -10
  334. package/src/cli/setup-cli.ts +43 -1
  335. package/src/cli/skills-cli.ts +17 -1
  336. package/src/context-bus/claude-hooks-install.ts +10 -0
  337. package/src/context-bus/context-now-surfaces.ts +65 -0
  338. package/src/context-bus/context-now.ts +104 -0
  339. package/src/context-bus/coord-events.ts +2 -2
  340. package/src/context-bus/external-events.ts +52 -0
  341. package/src/context-bus/long-term-memory.ts +108 -0
  342. package/src/context-bus/nightly-condense.ts +153 -0
  343. package/src/context-bus/session-events.ts +35 -0
  344. package/src/dashboard/dashboard-status-lines.ts +2 -0
  345. package/src/dashboard/index.ts +17 -4
  346. package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
  347. package/src/decisions/decision-cards.ts +10 -3
  348. package/src/decisions/decision-ledger.ts +13 -5
  349. package/src/discord/sprint21-runtime.ts +5 -1
  350. package/src/discord-self-message.ts +32 -0
  351. package/src/discord-slash-wire.ts +5 -1
  352. package/src/discord.ts +17 -1
  353. package/src/domains/core-tools.ts +3 -2
  354. package/src/domains/outbound-alert.ts +105 -32
  355. package/src/domains/outbound-log-probe.ts +8 -0
  356. package/src/domains/telegram-kind-route.ts +51 -13
  357. package/src/exec-requests/default-outputs.ts +25 -0
  358. package/src/exec-requests/planner.ts +10 -2
  359. package/src/exec-requests/runner.ts +20 -6
  360. package/src/exec-requests/store.ts +3 -0
  361. package/src/execution-loop/launch-gate.ts +109 -0
  362. package/src/field/field-reel.ts +5 -1
  363. package/src/field-note/index.ts +201 -0
  364. package/src/field-note/telegram.ts +142 -0
  365. package/src/field-note/transcribe.ts +248 -0
  366. package/src/graph-kinds/registry.ts +3 -3
  367. package/src/graph-runner/graph-cli.ts +61 -1
  368. package/src/graph-runner/graph-grow-llm.ts +47 -0
  369. package/src/graph-runner/graph-grow.ts +50 -0
  370. package/src/graph-runner/runner.ts +329 -33
  371. package/src/grok/agent-search.ts +8 -2
  372. package/src/guardian/secret-exposure-scan.ts +101 -0
  373. package/src/harness/harness-cli-command.ts +375 -13
  374. package/src/harness/harness-pod-dispatch.ts +43 -23
  375. package/src/harness/harness-seams.ts +38 -4
  376. package/src/harness/harness-stop.ts +23 -4
  377. package/src/harness/launch-registry.ts +91 -0
  378. package/src/harness/process-garbage.ts +5 -3
  379. package/src/hooks/consult-intake.ts +153 -0
  380. package/src/hooks/dispatch.ts +82 -0
  381. package/src/hooks/expose.ts +254 -0
  382. package/src/hooks/github-shadow.ts +108 -0
  383. package/src/hooks/providers.ts +71 -5
  384. package/src/hooks/queue.ts +1 -1
  385. package/src/hooks/receiver.ts +94 -16
  386. package/src/index.ts +76 -14
  387. package/src/intake-plane/categorize.ts +18 -46
  388. package/src/intake-plane/discord-seat-work.ts +38 -2
  389. package/src/intake-plane/front-route-classifier.ts +33 -39
  390. package/src/intake-plane/persona-answer.ts +30 -0
  391. package/src/intake-plane/runtime-callables.ts +8 -1
  392. package/src/intake-plane/telegram-seat-work.ts +36 -2
  393. package/src/intake-plane/wish-card.ts +33 -0
  394. package/src/intake-plane/wish-folder.ts +67 -0
  395. package/src/intent-gate/gate.ts +30 -10
  396. package/src/live/detail-switch.ts +5 -0
  397. package/src/llm/difficulty.ts +57 -0
  398. package/src/llm/judge-layer.ts +101 -0
  399. package/src/llm/mission-router.ts +33 -19
  400. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  401. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  402. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  403. package/src/loops/contract/loop-agent.schema.json +138 -0
  404. package/src/loops/contract/validate.ts +64 -0
  405. package/src/loops/registry.ts +20 -6
  406. package/src/market/signed-index.ts +4 -0
  407. package/src/maturity/bot-command-maturity.ts +45 -0
  408. package/src/maturity/feature-maturity.ts +27 -4
  409. package/src/model-tier/index.ts +2 -2
  410. package/src/model-tier/tier-resolver.ts +20 -20
  411. package/src/model-tier/types.ts +6 -6
  412. package/src/mss/logging/log-store.ts +15 -0
  413. package/src/nexus/api/config-model-tier.ts +5 -4
  414. package/src/nexus/api/fabric-plans.ts +53 -0
  415. package/src/nexus/api/harness-api.ts +5 -1
  416. package/src/nexus/api/health.ts +2 -0
  417. package/src/nexus/api/http-server.ts +67 -8
  418. package/src/nexus/api/inside-events.ts +226 -0
  419. package/src/nexus/api/meta-api.ts +21 -8
  420. package/src/nexus/api/missions.ts +6 -1
  421. package/src/nexus/api/ops-seats.ts +33 -0
  422. package/src/nexus/api/outbound-report.ts +40 -7
  423. package/src/nexus/api/outputs-route.ts +44 -0
  424. package/src/nexus/api/personas.ts +95 -53
  425. package/src/nexus/api/seat-requests.ts +44 -2
  426. package/src/nexus/api/sessions-store.ts +17 -38
  427. package/src/nexus/api/sub-seat-charters.ts +34 -0
  428. package/src/nexus/api/tabs-mutations.ts +3 -1
  429. package/src/nexus/api/task-cards-api.ts +19 -0
  430. package/src/nexus/api/trace.ts +18 -6
  431. package/src/nexus/api/workflow-history.ts +88 -0
  432. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  433. package/src/nexus/api/workflows.ts +132 -6
  434. package/src/nexus/index.ts +2 -0
  435. package/src/nexus/kinds/webterm.ts +2 -1
  436. package/src/nexus/outbound/delivery-ledger.ts +17 -8
  437. package/src/nexus/outbound/router.ts +8 -3
  438. package/src/nexus/webterm/pty.ts +6 -2
  439. package/src/onboarding/cli-auth-status.ts +80 -0
  440. package/src/onboarding/voice-ai.ts +3 -3
  441. package/src/org/seat-budget.ts +48 -0
  442. package/src/org/stall-escalation.ts +63 -0
  443. package/src/outputs/ledger.ts +120 -0
  444. package/src/persona/persona-todo.ts +79 -0
  445. package/src/persona/presets.ts +123 -2
  446. package/src/persona/team-set.ts +155 -0
  447. package/src/plugins/install/plugin-install.ts +14 -0
  448. package/src/plugins/maker/market-bundle.ts +110 -0
  449. package/src/plugins/maker/plugin-maker.ts +254 -11
  450. package/src/plugins/maker/wizard-generate.ts +103 -0
  451. package/src/pod-lease/admission.ts +150 -0
  452. package/src/pod-lease/dependency-state.ts +85 -0
  453. package/src/pod-lease/host-lease.ts +127 -0
  454. package/src/project/project-suggestion.ts +16 -0
  455. package/src/project/session-context.ts +24 -0
  456. package/src/release-loop/checklist.ts +17 -5
  457. package/src/release-loop/feature-store.ts +29 -13
  458. package/src/release-loop/landed-but-yellow.ts +48 -0
  459. package/src/release-loop/next-md-merge.ts +58 -0
  460. package/src/release-loop/release-note.ts +59 -4
  461. package/src/seat-dispatch/seat-ask.ts +130 -0
  462. package/src/seat-dispatch/seat-questions.ts +100 -0
  463. package/src/seat-loop/seat-loop.ts +709 -29
  464. package/src/seat-loop/seat-report.ts +37 -2
  465. package/src/self-dev/dev-cli.ts +4 -1
  466. package/src/self-dev/dev-pipeline.ts +37 -1
  467. package/src/self-dev/draft-sweep.ts +79 -40
  468. package/src/self-dev/draft-triage-rules.ts +62 -7
  469. package/src/self-dev/fabric-plan-core.ts +297 -0
  470. package/src/self-dev/orchestrate.ts +36 -4
  471. package/src/self-dev/release-path-guard.ts +62 -0
  472. package/src/self-dev/shard-aggregate.ts +230 -0
  473. package/src/self-dev/shard-placement.ts +60 -0
  474. package/src/self-dev/shard-plan.ts +48 -0
  475. package/src/self-dev/shard-pod-run.ts +77 -0
  476. package/src/self-dev/shard-run.ts +105 -0
  477. package/src/self-implement/budget-gate.ts +29 -12
  478. package/src/self-implement/gate-baseline.ts +1 -1
  479. package/src/self-implement/gate-candidate-ranking.ts +60 -0
  480. package/src/self-implement/gate-cli.ts +40 -1
  481. package/src/self-implement/gate-scope.ts +44 -13
  482. package/src/self-implement/graph-variant.ts +171 -0
  483. package/src/self-implement/harness-policy-gates.ts +1 -1
  484. package/src/self-implement/headless-elanous-driver.ts +27 -3
  485. package/src/self-implement/host-regate.ts +22 -1
  486. package/src/self-implement/importer-test-index.ts +2 -1
  487. package/src/self-implement/l8-merge-queue.ts +130 -0
  488. package/src/self-implement/orchestrator.ts +257 -9
  489. package/src/self-implement/route-consumer-test-index.ts +122 -0
  490. package/src/self-implement/seams.ts +72 -11
  491. package/src/self-implement/test-seams.ts +2 -0
  492. package/src/self-implement/uncommitted-work.ts +59 -0
  493. package/src/session/index.ts +36 -13
  494. package/src/skills/gift-install.ts +215 -0
  495. package/src/skills/tools/web-search.ts +4 -1
  496. package/src/steward/launch.ts +42 -26
  497. package/src/steward/steward-cards.ts +17 -9
  498. package/src/steward/triage.ts +46 -14
  499. package/src/task-cards/card-cli.ts +25 -1
  500. package/src/task-orchestrator/mission.ts +5 -0
  501. package/src/task-orchestrator/store.ts +12 -3
  502. package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
  503. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  504. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  505. package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
  506. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  507. package/src/task-orchestrator/types.ts +2 -0
  508. package/src/telegram-card-followup.ts +16 -96
  509. package/src/telegram-commands.ts +31 -1
  510. package/src/telegram-project-command.ts +145 -0
  511. package/src/telegram-report.ts +21 -17
  512. package/src/telegram.ts +61 -8
  513. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  514. package/src/user-config.ts +110 -24
  515. package/src/version/packed-revision.json +1 -1
  516. package/src/web-search/grok.ts +7 -1
  517. package/src/web-search/index.ts +28 -1
  518. package/src/web-search/provider.ts +4 -0
  519. package/src/web-search/x-intent.ts +5 -0
  520. package/src/workflow-runtime/executor.ts +277 -47
  521. package/src/workflow-runtime/index.ts +1 -0
  522. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  523. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  524. package/src/workflow-runtime/schema.ts +79 -4
  525. package/src/workflow-runtime/types.ts +35 -4
  526. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  536. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  537. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  556. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  614. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  615. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
@@ -1,16 +1,20 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { execFile } from 'node:child_process';
3
- import { existsSync, linkSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { existsSync, linkSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
4
4
  import { dirname, join, resolve, sep } from 'node:path';
5
5
  import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
6
6
  import { getElanousConfigDir, getElanousConfigDirOverride } from '../elanous-config-dir.js';
7
7
  import { debug } from '../debug/log.js';
8
+ import { publishInsideEvent } from '../nexus/api/inside-events.js';
8
9
  import { elanousStateRoot } from '../autopilot/state-paths.js';
9
10
  import { listInstalledPlugins } from '../plugins/install/plugin-install.js';
10
11
  import { credentialStatus, pluginEnv } from '../plugins/install/plugin-credentials.js';
11
12
  import { effectiveInstanceRoot } from '../instance/resolve.js';
12
13
  import { loadNodeCatalog } from '../self-implement/graph-catalog.js';
13
- import { parseGraphTemplateYaml, type GraphEdgeSpec, type GraphNodeSpec } from '../self-implement/graph-yaml.js';
14
+ import { proposeGrowth, type GraphGrowth, type GrowthProposer, type GrowthRecipeEffect } from './graph-grow.js';
15
+ import { createLLMGrowthProposer } from './graph-grow-llm.js';
16
+ import { parseGraphTemplateYaml, type GraphEdgeSpec, type GraphNodeSpec, type GraphTemplateSpec } from '../self-implement/graph-yaml.js';
17
+ import { createGraphVariant, type GraphVariantPlan } from '../self-implement/graph-variant.js';
14
18
  import { psProcessStartMs, START_TOLERANCE_MS } from '../harness/harness-stop.js';
15
19
  import { executeBashNode } from '../workflow-runtime/nodes/bash.js';
16
20
  import type { BashNode, NodeExecContext, WorkflowDeps } from '../workflow-runtime/types.js';
@@ -24,6 +28,8 @@ export interface GraphRunState {
24
28
  finishedAt?: string;
25
29
  pid?: number;
26
30
  pidStartedAt?: string;
31
+ activeNode?: { nodeId: string; pid: number; pidStartedAt: string };
32
+ stoppedAt?: string;
27
33
  status: 'running' | 'done' | 'failed' | 'budget-exceeded' | 'awaiting-approval';
28
34
  path: string[];
29
35
  nodes: Array<{ nodeId: string; ok: boolean; exit: number | null; executed: boolean; output?: unknown; error?: string; decidedBy?: string; decidedAt?: string }>;
@@ -34,6 +40,10 @@ export interface GraphRunState {
34
40
  sourceHash?: string;
35
41
  graphSnapshot?: { graphSha: string; recipesSha: string };
36
42
  graphPath?: string;
43
+ variant?: { overlayId: string; goal: string; plan: GraphVariantPlan };
44
+ growth?: GraphGrowth[];
45
+ growthRejections?: Array<{ from: string; outcome: string; reason: string }>;
46
+ growthPark?: { from: string; outcome: string; reason: string };
37
47
  resume?: { from: string; at: string; previousStatus: GraphRunState['status']; graph?: 'snapshot' | 'current' };
38
48
  executed: number;
39
49
  dryRun: boolean;
@@ -43,12 +53,13 @@ export interface GraphRunState {
43
53
  export interface GraphRunOptions {
44
54
  input?: unknown;
45
55
  dryRun?: boolean;
56
+ variant?: { goal: string; plan: GraphVariantPlan };
46
57
  runId?: string;
47
58
  resumeRunId?: string;
48
59
  resumeGraphId?: string;
49
60
  fromNodeId?: string;
50
61
  useCurrentGraph?: boolean;
51
- deps?: { root?: string; runBash?: BashRun; log?: (event: string, data: Record<string, unknown>) => void; processStartMs?: (pid: number) => number | null };
62
+ deps?: { root?: string; runBash?: BashRun; log?: (event: string, data: Record<string, unknown>) => void; processStartMs?: (pid: number) => number | null; growthProposer?: GrowthProposer; growthLLM?: (prompt: string) => Promise<string>; classifyGrowthRecipe?: (node: GraphNodeSpec, resolved: { command?: string; approval?: string }) => GrowthRecipeEffect };
52
63
  }
53
64
 
54
65
  function safeSegment(value: string): string {
@@ -58,7 +69,7 @@ function safeSegment(value: string): string {
58
69
  return value;
59
70
  }
60
71
 
61
- type CommandRecipe = { command: string; timeout_ms?: number };
72
+ type CommandRecipe = { command: string; dry_run_command?: string; timeout_ms?: number };
62
73
  type Recipe = CommandRecipe | { approval: string };
63
74
 
64
75
  /** 접두 없는 recipe 가 카탈로그 역할이고, 그래프 옆 recipes.yaml 에 같은 키의 `{ command }` 가 있을 때만 cmd 처럼 실행한다. */
@@ -106,24 +117,44 @@ function recipesFor(path: string, recipeSource: string): Record<string, Recipe>
106
117
  recipes[id] = { approval: item.approval };
107
118
  } else {
108
119
  if (typeof item.command !== 'string' || !item.command.trim() ||
109
- (item.timeout_ms !== undefined && (!Number.isSafeInteger(item.timeout_ms) || (item.timeout_ms as number) <= 0))) {
120
+ (item.timeout_ms !== undefined && (!Number.isSafeInteger(item.timeout_ms) || (item.timeout_ms as number) <= 0)) ||
121
+ (item.dry_run_command !== undefined && (typeof item.dry_run_command !== 'string' || !item.dry_run_command.trim()))) {
110
122
  throw new Error(`invalid recipe: ${id}`);
111
123
  }
112
- recipes[id] = { command: item.command, ...(item.timeout_ms === undefined ? {} : { timeout_ms: item.timeout_ms as number }) };
124
+ recipes[id] = { command: item.command,
125
+ ...(item.dry_run_command === undefined ? {} : { dry_run_command: item.dry_run_command as string }),
126
+ ...(item.timeout_ms === undefined ? {} : { timeout_ms: item.timeout_ms as number }) };
113
127
  }
114
128
  }
115
129
  return recipes;
116
130
  }
117
131
 
118
- const realRunBash: BashRun = (body, opts) => new Promise((resolve, reject) => {
119
- execFile('/bin/bash', ['-c', body], { cwd: opts.cwd, env: opts.env, timeout: opts.timeoutMs, signal: opts.signal, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
120
- if (error && typeof (error as NodeJS.ErrnoException).code !== 'number') {
121
- reject(error);
122
- return;
132
+ function realRunBash(onSpawn: (pid: number) => boolean): BashRun {
133
+ return (body, opts) => new Promise((resolve, reject) => {
134
+ let unverified: ReturnType<typeof setTimeout> | undefined;
135
+ const child = execFile('/bin/bash', ['-c', body], { cwd: opts.cwd, env: opts.env, timeout: opts.timeoutMs, signal: opts.signal, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
136
+ if (unverified) clearTimeout(unverified);
137
+ if (error && typeof (error as NodeJS.ErrnoException).code !== 'number') {
138
+ reject(error);
139
+ return;
140
+ }
141
+ resolve({ stdout, stderr, exitCode: error ? (error as unknown as { code: number }).code : 0 });
142
+ });
143
+ if (child.pid) {
144
+ try {
145
+ if (!onSpawn(child.pid)) {
146
+ // A process can exit before ps observes it. A completed child is safe to report;
147
+ // an unverified child still running must not be left without a tracked PID.
148
+ unverified = setTimeout(() => {
149
+ if (child.exitCode !== null || child.signalCode !== null) return;
150
+ child.kill('SIGTERM');
151
+ reject(new Error(`cannot verify node process start: ${child.pid}`));
152
+ }, 500);
153
+ }
154
+ } catch (error) { child.kill('SIGTERM'); reject(error); }
123
155
  }
124
- resolve({ stdout, stderr, exitCode: error ? (error as unknown as { code: number }).code : 0 });
125
156
  });
126
- });
157
+ }
127
158
 
128
159
  function graphRunPath(graphId: string, runId: string, root: string): string {
129
160
  return join(root, 'graph-runs', safeSegment(graphId), `${safeSegment(runId)}.json`);
@@ -164,11 +195,77 @@ function persistGraphRun(state: GraphRunState): void {
164
195
  renameSync(temporary, state.statePath);
165
196
  }
166
197
 
198
+ /** A synchronous, per-ledger critical section shared by runner writes and stop/destroy. */
199
+ function withRunWriteLock<T>(file: string, work: () => T): T {
200
+ mkdirSync(dirname(file), { recursive: true });
201
+ const lock = `${file}.write.lock`;
202
+ const staged = `${lock}.${randomUUID()}.staged`;
203
+ mkdirSync(staged);
204
+ const until = Date.now() + 5_000;
205
+ let acquired = false;
206
+ try {
207
+ writeFileSync(join(staged, 'owner.json'), JSON.stringify({ pid: process.pid, started: Date.now() - process.uptime() * 1_000 }), { flag: 'wx' });
208
+ while (!acquired) {
209
+ try {
210
+ // Unlike mkdir(lock) followed by a write, publication exposes an already complete owner.
211
+ symlinkSync(staged, lock, 'dir');
212
+ acquired = true;
213
+ } catch (error) {
214
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
215
+ let owner: { pid: number; started: number } | undefined;
216
+ try { owner = JSON.parse(readFileSync(join(lock, 'owner.json'), 'utf8')); } catch { /* legacy unowned directory */ }
217
+ const ownerStart = owner && Number.isSafeInteger(owner.pid) && Number.isFinite(owner.started) ? psProcessStartMs(owner.pid) : undefined;
218
+ let stale = ownerStart !== undefined && (ownerStart === null || Math.abs(ownerStart - owner!.started) > START_TOLERANCE_MS);
219
+ if (!owner && !lstatSync(lock).isSymbolicLink()) {
220
+ // Legacy mkdir-before-owner crash: do not evict a writer still publishing its owner.
221
+ stale = Date.now() - statSync(lock).mtimeMs >= 5_000;
222
+ }
223
+ if (stale) {
224
+ try {
225
+ if (lstatSync(lock).isSymbolicLink()) {
226
+ const target = readlinkSync(lock);
227
+ if (!target.startsWith(`${lock}.`) || !target.endsWith('.staged')) throw new Error('invalid graph run write lock');
228
+ unlinkSync(lock);
229
+ rmSync(target, { recursive: true, force: true });
230
+ } else {
231
+ if (owner) unlinkSync(join(lock, 'owner.json'));
232
+ rmdirSync(lock);
233
+ }
234
+ } catch (cause) {
235
+ if ((cause as NodeJS.ErrnoException).code !== 'ENOENT') throw cause;
236
+ }
237
+ continue;
238
+ }
239
+ if (Date.now() >= until) throw new Error(`graph run write lock is held: ${file}`);
240
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
241
+ }
242
+ }
243
+ return work();
244
+ } finally {
245
+ if (acquired && existsSync(lock) && lstatSync(lock).isSymbolicLink() && readlinkSync(lock) === staged) unlinkSync(lock);
246
+ rmSync(staged, { recursive: true, force: true });
247
+ }
248
+ }
249
+
250
+ function persistOwnedRun(state: GraphRunState, expected: Pick<GraphRunState, 'pid' | 'pidStartedAt' | 'stoppedAt'>, allowRestart = false): void {
251
+ withRunWriteLock(state.statePath, () => {
252
+ let disk: GraphRunState;
253
+ try { disk = JSON.parse(readFileSync(state.statePath, 'utf8')) as GraphRunState; }
254
+ catch (cause) { throw new Error(`run was removed or unreadable: ${state.graphId}/${state.runId}`, { cause }); }
255
+ if (disk.graphId !== state.graphId || disk.runId !== state.runId || disk.pid !== expected.pid ||
256
+ disk.pidStartedAt !== expected.pidStartedAt || disk.stoppedAt !== expected.stoppedAt ||
257
+ (disk.stoppedAt !== undefined && !allowRestart)) {
258
+ throw new Error(`run was stopped or ownership changed: ${state.graphId}/${state.runId}`);
259
+ }
260
+ persistGraphRun(state);
261
+ });
262
+ }
263
+
167
264
  export interface ExpectedGraphApprovalVisit { nodeId: string; visit: number }
168
265
 
169
266
  export function decideGraphApproval(graphId: string, runId: string, decision: 'approved' | 'rejected', by?: string, root = effectiveInstanceRoot(), expected?: ExpectedGraphApprovalVisit): GraphRunState {
170
267
  const state = readGraphRun(graphId, runId, root);
171
- if (state.status !== 'awaiting-approval' || !state.pending || state.pending.decision ||
268
+ if (state.status !== 'awaiting-approval' || !state.pending || state.growthPark || state.pending.decision ||
172
269
  (expected && (state.dryRun || state.pending.nodeId !== expected.nodeId || state.path.at(-1) !== expected.nodeId ||
173
270
  !Number.isSafeInteger(expected.visit) || expected.visit < 1 ||
174
271
  state.path.filter(node => node === expected.nodeId).length !== expected.visit))) {
@@ -208,6 +305,22 @@ export function lastJsonObject(stdout: unknown): Record<string, unknown> | undef
208
305
  }
209
306
  }
210
307
 
308
+ /** Reconstruct the run-local edges from the ledger without rewriting the YAML snapshot. */
309
+ function withGrowth(graph: GraphTemplateSpec, growth: readonly GraphGrowth[]): GraphTemplateSpec {
310
+ return growth.reduce<GraphTemplateSpec>((current, item) => {
311
+ const edge = current.edges.find((candidate) => candidate.from === item.undo.removeOutcome.from);
312
+ if (!edge || !edge.map || !item.node || item.undo.removeNode !== item.node.nodeId ||
313
+ current.nodes.some((node) => node.nodeId === item.node.nodeId) ||
314
+ Object.hasOwn(edge.map, item.undo.removeOutcome.outcome) ||
315
+ !item.edges.some((added) => added.from === edge.from && added.map?.[item.undo.removeOutcome.outcome] === item.node.nodeId)) {
316
+ throw new Error('invalid saved graph growth');
317
+ }
318
+ return { ...current, nodes: [...current.nodes, item.node], edges: current.edges.map((candidate) => candidate === edge
319
+ ? { ...edge, map: { ...edge.map, [item.undo.removeOutcome.outcome]: item.node.nodeId } } : candidate)
320
+ .concat(item.undo.removeEdge ? [item.undo.removeEdge] : []) };
321
+ }, graph);
322
+ }
323
+
211
324
  /** 이름 붙은 결과: 산출의 `outcome` 이 그 간선 map 의 키면 그 목적지 — 아니면 종전 ok/fail(exit) → fallback. */
212
325
  function nextNode(edges: readonly GraphEdgeSpec[], nodeId: string, exitOutcome: 'ok' | 'fail', namedOutcome?: string): string | undefined {
213
326
  const edge = edges.find((e) => e.from === nodeId);
@@ -222,6 +335,7 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
222
335
  if (options.resumeRunId && options.runId) throw new Error('runId and resumeRunId cannot be combined');
223
336
  if (options.fromNodeId && !options.resumeRunId) throw new Error('--from requires --resume');
224
337
  if (options.useCurrentGraph && !options.resumeRunId) throw new Error('--use-current-graph requires --resume');
338
+ if (options.variant && options.resumeRunId) throw new Error('variant cannot be combined with --resume');
225
339
  const root = options.deps?.root ?? effectiveInstanceRoot();
226
340
  const matchingRuns = options.resumeRunId && !options.resumeGraphId
227
341
  ? listGraphRuns(root).runs.filter((run) => run.runId === options.resumeRunId && run.graphPath === resolve(path)) : [];
@@ -250,7 +364,22 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
250
364
  }
251
365
  const parsed = parseGraphTemplateYaml(stringifyYaml(document), path);
252
366
  if (!parsed.template || parsed.errors.length) throw new Error(parsed.errors.map((e) => `${e.path}: ${e.message}`).join('\n'));
253
- const graph = parsed.template;
367
+ let graph = parsed.template;
368
+ const variant = options.variant ? createGraphVariant({ template: graph, ...options.variant }) : undefined;
369
+ if (variant && !variant.ok) throw new Error(`graph variant rejected: ${JSON.stringify(variant.rejections)}`);
370
+ if (variant?.ok) graph = variant.template;
371
+ const variantSource = variant?.ok ? stringifyYaml({ ...document,
372
+ nodes: graph.nodes.map((node, index) => ({
373
+ ...((document.nodes as Record<string, unknown>[])[index] ?? {}), node_id: node.nodeId, kind: node.kind,
374
+ recipe: node.recipe, max_visits: node.maxVisits,
375
+ ...(node.contract ? { contract: node.contract } : {}),
376
+ })),
377
+ edges: graph.edges.map((edge, index) => ({
378
+ ...((document.edges as Record<string, unknown>[])[index] ?? {}), from: edge.from,
379
+ ...(edge.to === undefined ? { on: edge.on, map: edge.map } : { to: edge.to }),
380
+ ...(edge.fallback ? { fallback: edge.fallback } : {}),
381
+ })),
382
+ }) : source;
254
383
  const pluginRoot = elanousStateRoot();
255
384
  const graphFile = graphMode === 'snapshot' && !existsSync(path) ? resolve(path) : realpathSync(path);
256
385
  const installed = listInstalledPlugins(pluginRoot);
@@ -276,7 +405,7 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
276
405
  const recipes = recipesFor(path, recipeSource);
277
406
  const catalogRoles = new Set(loadNodeCatalog().roles.keys());
278
407
  // Bind a human decision to the exact graph and recipe contents, not just its id or approval prompt.
279
- const approvalSourceHash = createHash('sha256').update(source).update('\0').update(recipeSource).digest('hex');
408
+ const approvalSourceHash = createHash('sha256').update(variantSource).update('\0').update(recipeSource).digest('hex');
280
409
  // Resolve all commands before executing any node; an unknown recipe must never produce a partial publication.
281
410
  for (const node of graph.nodes) {
282
411
  if (node.recipe === 'none') continue;
@@ -307,12 +436,17 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
307
436
  const state: GraphRunState = options.resumeRunId
308
437
  ? readGraphRun(graphId, runId, root)
309
438
  : { graphId, runId, startedAt: new Date().toISOString(), ...runnerOwner, status: 'running', path: [], nodes: [], sourceHash: approvalSourceHash,
310
- graphSnapshot: { graphSha: createHash('sha256').update(source).digest('hex'), recipesSha: createHash('sha256').update(recipeSource).digest('hex') },
311
- graphPath: resolve(path), ...(options.input === undefined ? {} : { input: options.input }), executed: 0, dryRun: options.dryRun === true, statePath };
439
+ graphSnapshot: { graphSha: createHash('sha256').update(variantSource).digest('hex'), recipesSha: createHash('sha256').update(recipeSource).digest('hex') },
440
+ graphPath: resolve(path), ...(variant?.ok ? { variant: { overlayId: variant.overlay.overlayId, ...options.variant! } } : {}),
441
+ ...(options.input === undefined ? {} : { input: options.input }), executed: 0, dryRun: options.dryRun === true, statePath };
312
442
  if (options.resumeRunId && graphMode === 'snapshot' && state.sourceHash && state.sourceHash !== approvalSourceHash) {
313
443
  throw new Error('graph snapshot changed since run started');
314
444
  }
315
445
  if (options.resumeRunId && options.dryRun !== undefined && options.dryRun !== state.dryRun) throw new Error('cannot change dryRun when resuming');
446
+ if (options.resumeRunId && state.growth?.length && graphMode === 'current' && state.sourceHash !== approvalSourceHash) {
447
+ throw new Error('graph or recipes changed since grown run');
448
+ }
449
+ if (state.growth?.length) graph = withGrowth(graph, state.growth);
316
450
  if (options.fromNodeId) {
317
451
  if (state.status !== 'failed' || state.pending || state.dryRun) throw new Error('--from requires a failed, non-dry run without pending approval');
318
452
  if (graphMode === 'current' && (!state.sourceHash || state.sourceHash !== approvalSourceHash)) throw new Error('graph or recipes changed since failed run');
@@ -353,10 +487,14 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
353
487
  state.nodes = state.nodes.slice(0, from);
354
488
  state.executed = state.nodes.filter((node) => node.executed).length;
355
489
  state.status = 'running';
490
+ delete state.stoppedAt;
356
491
  Object.assign(state, runnerOwner);
357
492
  state.resume = { from: options.fromNodeId, at: new Date().toISOString(), previousStatus: 'failed', graph: graphMode };
358
493
  // Persist the restart boundary before executing it, so previous outputs remain durable.
359
- persistGraphRun(state);
494
+ persistOwnedRun(state, saved!, true);
495
+ }
496
+ if (options.resumeRunId && state.growthPark) {
497
+ throw new Error(`growth is parked for human confirmation: ${graphId}/${runId}`);
360
498
  }
361
499
  if (options.resumeRunId && state.status === 'running' && state.pending) {
362
500
  throw new Error(`run is not awaiting approval: ${graphId}/${runId}`);
@@ -377,12 +515,12 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
377
515
  const previousStatus = state.status;
378
516
  Object.assign(state, runnerOwner);
379
517
  state.resume = { from: state.pending?.nodeId ?? state.path.at(-1) ?? graph.entryNode, at: new Date().toISOString(), previousStatus, graph: graphMode };
380
- persistGraphRun(state);
518
+ persistOwnedRun(state, saved!);
381
519
  }
382
520
  if (options.resumeRunId) debug.log('graph.runs', 'resume', { graphId, runId, from: state.resume?.from, graph: graphMode });
383
521
  const persist = () => {
384
522
  if (state.status === 'done' || state.status === 'failed' || state.status === 'budget-exceeded') state.finishedAt ??= new Date().toISOString();
385
- persistGraphRun(state);
523
+ persistOwnedRun(state, runnerOwner);
386
524
  };
387
525
  const log = options.deps?.log ?? ((event: string, data: Record<string, unknown>) => debug.log('graph.runner', event, data));
388
526
  const visits = new Map<string, number>();
@@ -399,15 +537,16 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
399
537
  throw error;
400
538
  }
401
539
  mkdirSync(`${statePath}.graph`);
402
- writeFileSync(join(`${statePath}.graph`, 'graph.yaml'), source, { flag: 'wx' });
540
+ writeFileSync(join(`${statePath}.graph`, 'graph.yaml'), variantSource, { flag: 'wx' });
403
541
  writeFileSync(join(`${statePath}.graph`, 'recipes.yaml'), recipeSource, { flag: 'wx' });
404
542
  }
405
543
  while (current !== undefined) {
406
544
  const node = graph.nodes.find((n) => n.nodeId === current);
407
545
  if (!node) throw new Error(`undeclared node: ${current}`);
408
546
  const resumingPending = state.pending?.nodeId === current;
409
- const completed = [...state.nodes].reverse().find((recorded) => recorded.nodeId === current && recorded.executed);
410
- const resumingCompleted = options.resumeRunId !== undefined && !options.fromNodeId && !!completed && state.path.at(-1) === current && !resumingPending;
547
+ const completed = state.nodes.at(-1);
548
+ const resumingCompleted = options.resumeRunId !== undefined && !options.fromNodeId && completed?.nodeId === current &&
549
+ state.path.at(-1) === current && !resumingPending;
411
550
  if (!resumingPending && !resumingCompleted && (visits.get(current) ?? 0) >= node.maxVisits) {
412
551
  state.status = 'budget-exceeded';
413
552
  log('budget-exceeded', { graphId, runId, nodeId: current });
@@ -447,13 +586,14 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
447
586
  const startedAt = performance.now();
448
587
  console.error(`[graph] ${current} start (0.00s)`);
449
588
  debug.log('graph.run', 'node', { graphId, runId, nodeId: current, phase: 'start', dryRun: state.dryRun });
589
+ publishInsideEvent({ kind: 'node', graphId, runId, nodeId: current, phase: 'start' });
450
590
  log('node-start', { graphId, runId, nodeId: current, visit: visits.get(current), dryRun: state.dryRun });
451
591
  persist();
452
592
  let ok = approval && !state.dryRun ? state.pending?.decision === 'approved' : true;
453
593
  let exit: number | null = null;
454
594
  let error: string | undefined;
455
595
  let output: unknown;
456
- if (command && !state.dryRun && !resumingCompleted) {
596
+ if (command && (!state.dryRun || command.dry_run_command) && !resumingCompleted) {
457
597
  const outputs: Record<string, unknown> = Object.create(null);
458
598
  // 구조 산출(마지막 JSON 줄)이 있으면 그것을, 없으면 원문을 준다 — 다음 노드가 판단을 «값»으로 받는다.
459
599
  for (const previous of state.nodes) outputs[previous.nodeId] = lastJsonObject(previous.output) ?? previous.output ?? null;
@@ -464,9 +604,27 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
464
604
  const redactCredentials = (text: string) => Object.values(credentials).filter(value => value.length > 0)
465
605
  .reduce((safe, value) => safe.replaceAll(value, '[REDACTED]'), text);
466
606
  const runBash: BashRun = async (body, opts) => {
467
- const result = await (options.deps?.runBash ?? realRunBash)(body, opts);
468
- code = result.exitCode;
469
- return { ...result, stdout: redactCredentials(result.stdout), stderr: redactCredentials(result.stderr) };
607
+ const execute = options.deps?.runBash ?? realRunBash((pid) => {
608
+ // Publish the child before its start time is known, so a concurrent stop refuses instead of failing
609
+ // the ledger while an untracked node keeps working (REL8b review round 3).
610
+ state.activeNode = { nodeId: current!, pid, pidStartedAt: UNVERIFIED_NODE_START };
611
+ persist();
612
+ const started = (options.deps?.processStartMs ?? psProcessStartMs)(pid);
613
+ if (started === null) return false;
614
+ state.activeNode = { nodeId: current!, pid, pidStartedAt: new Date(started).toISOString() };
615
+ persist();
616
+ return true;
617
+ });
618
+ try {
619
+ const result = await execute(body, opts);
620
+ code = result.exitCode;
621
+ return { ...result, stdout: redactCredentials(result.stdout), stderr: redactCredentials(result.stderr) };
622
+ } finally {
623
+ if (state.activeNode?.nodeId === current) {
624
+ delete state.activeNode;
625
+ persist();
626
+ }
627
+ }
470
628
  };
471
629
  if (owner) debug.log('plugin.credentials', 'injected', { plugin: owner.name, fields: credentialFields, count: credentialFields.length });
472
630
  const env = { ...process.env };
@@ -480,9 +638,10 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
480
638
  debug.log('graph-runner', 'child-universe-pinned', { graphId, runId, node: current, configDir: env.ELANOUS_CONFIG_DIR, stateDir: env.ELANOUS_STATE_DIR });
481
639
  }
482
640
  env.ELANOUS_GRAPH_CONTEXT = contextPath;
641
+ env.ELANOUS_GRAPH_DRY_RUN = state.dryRun ? '1' : '0';
483
642
  env.ELANOUS_GRAPH_DIR = dirname(resolve(path));
484
643
  const ctx = { arguments: '', artifactsDir: dirname(statePath), outputs: {}, resolvedProvider: undefined, resolvedModel: undefined, toolPolicy: {}, env } as NodeExecContext;
485
- const result = await executeBashNode({ id: current, type: 'bash', bash: command.command, ...(command.timeout_ms ? { idle_timeout: command.timeout_ms } : {}) } as BashNode, ctx, { runBash } as WorkflowDeps);
644
+ const result = await executeBashNode({ id: current, type: 'bash', bash: state.dryRun ? command.dry_run_command! : command.command, ...(command.timeout_ms ? { idle_timeout: command.timeout_ms } : {}) } as BashNode, ctx, { runBash } as WorkflowDeps);
486
645
  output = result.output;
487
646
  ok = result.ok;
488
647
  exit = code;
@@ -499,18 +658,20 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
499
658
  if (approval && !state.dryRun && !command) {
500
659
  output = JSON.stringify({ outcome: ok ? 'approved' : 'rejected', ...(state.pending?.decidedBy === undefined ? {} : { decidedBy: state.pending.decidedBy }), decidedAt: state.pending?.decidedAt ?? null });
501
660
  }
502
- state.nodes.push({ nodeId: current, ok, exit, executed: !!command && !state.dryRun, ...((command || approval) && !state.dryRun && output !== undefined ? { output } : {}), ...(error ? { error } : {}),
661
+ state.nodes.push({ nodeId: current, ok, exit, executed: !!command && (!state.dryRun || !!command.dry_run_command), ...((command || approval) && (!state.dryRun || !!command?.dry_run_command) && output !== undefined ? { output } : {}), ...(error ? { error } : {}),
503
662
  ...(approval && state.pending ? { ...(state.pending.decidedBy === undefined ? {} : { decidedBy: state.pending.decidedBy }), decidedAt: state.pending.decidedAt } : {}) });
504
663
  }
505
664
  if (approval) {
506
665
  delete state.pending;
507
666
  delete state.approvalSourceHash;
508
667
  }
509
- const reported = command && !state.dryRun ? lastJsonObject(resumingCompleted ? completed?.output : output)?.outcome : undefined;
668
+ const reported = command && (!state.dryRun || command.dry_run_command) ? lastJsonObject(resumingCompleted ? completed?.output : output)?.outcome : undefined;
510
669
  const namedOutcome = typeof reported === 'string' ? reported : undefined;
511
670
  const seconds = Number(((performance.now() - startedAt) / 1000).toFixed(2));
512
671
  console.error(`[graph] ${current} ${ok ? 'ok' : 'fail'} (${seconds.toFixed(2)}s)`);
513
672
  debug.log('graph.run', 'node', { graphId, runId, nodeId: current, phase: ok ? 'ok' : 'fail', seconds, exit });
673
+ publishInsideEvent({ kind: 'node', graphId, runId, nodeId: current, phase: ok ? 'ok' : 'fail', seconds });
674
+ publishInsideEvent({ kind: 'verdict', graphId, runId, nodeId: current, verdict: ok ? 'ok' : 'fail', ...(namedOutcome === undefined ? {} : { outcome: namedOutcome }) });
514
675
  log('node-end', { graphId, runId, nodeId: current, ok, exit, ...(namedOutcome === undefined ? {} : { outcome: namedOutcome }), dryRun: state.dryRun });
515
676
  persist();
516
677
  if (graph.terminalNodes.includes(current)) {
@@ -518,7 +679,42 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
518
679
  persist();
519
680
  break;
520
681
  }
521
- current = nextNode(graph.edges, current, state.dryRun ? 'ok' : ok ? 'ok' : 'fail', state.dryRun ? undefined : namedOutcome);
682
+ const fromNodeId = current;
683
+ const edge = graph.edges.find((candidate) => candidate.from === current);
684
+ if (document.grow === 'on' && !state.dryRun && namedOutcome !== undefined &&
685
+ edge?.on === 'outcome' && edge.map && !Object.hasOwn(edge.map, namedOutcome) &&
686
+ !state.growth?.some((item) => item.undo.removeOutcome.from === current && item.undo.removeOutcome.outcome === namedOutcome) &&
687
+ !state.growthRejections?.some((item) => item.from === current && item.outcome === namedOutcome)) {
688
+ const result = (state.growth?.length ?? 0) >= 3 ? { ok: false as const, reason: 'growth limit 3 reached' }
689
+ : await proposeGrowth({ graph, nodeId: current, outcome: namedOutcome, runId, output: state.nodes.at(-1)?.output },
690
+ options.deps?.growthProposer ?? createLLMGrowthProposer(options.deps?.growthLLM), (candidate) => {
691
+ const resolved = resolveNodeRecipe(candidate, recipes, catalogRoles);
692
+ if (resolved.approval || (!resolved.command && candidate.recipe !== 'none')) return 'unknown';
693
+ return options.deps?.classifyGrowthRecipe?.(candidate, { command: resolved.command?.command }) ?? 'unknown';
694
+ });
695
+ if (result.ok) {
696
+ graph = result.graph;
697
+ state.growth ??= [];
698
+ state.growth.push(result.growth);
699
+ persist();
700
+ log('edge-added', { graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
701
+ debug.log('graph.run', 'edge-added', { graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
702
+ publishInsideEvent({ kind: 'edge-added', graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
703
+ } else {
704
+ state.growthRejections ??= [];
705
+ state.growthRejections.push({ from: current, outcome: namedOutcome, reason: result.reason });
706
+ if (result.park) {
707
+ state.status = 'awaiting-approval';
708
+ state.pending = { nodeId: current, message: result.reason, since: new Date().toISOString() };
709
+ state.growthPark = { from: current, outcome: namedOutcome, reason: result.reason };
710
+ persist();
711
+ break;
712
+ }
713
+ }
714
+ persist();
715
+ }
716
+ current = nextNode(graph.edges, current, state.dryRun && !command?.dry_run_command ? 'ok' : ok ? 'ok' : 'fail', namedOutcome);
717
+ if (current !== undefined) publishInsideEvent({ kind: 'edge', graphId, runId, from: fromNodeId, to: current });
522
718
  if (current === undefined) {
523
719
  state.status = 'failed';
524
720
  persist();
@@ -526,12 +722,112 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
526
722
  }
527
723
  return state;
528
724
  } finally {
529
- if (options.resumeRunId) rmdirSync(resumeLock);
725
+ if (options.resumeRunId && existsSync(resumeLock)) rmdirSync(resumeLock);
530
726
  }
531
727
  }
532
728
 
533
729
  export type GraphRunAlive = boolean | 'unknown';
534
730
 
731
+ /** activeNode.pidStartedAt while the node child is spawned but its start time is not read yet — stop must not pass it. */
732
+ const UNVERIFIED_NODE_START = 'unverified';
733
+ /** A failed run's empty resume lock younger than this may belong to a resume that has not persisted «running» yet. */
734
+ const RESUME_LOCK_GRACE_MS = 60_000;
735
+
736
+ function runArtifacts(state: GraphRunState): string[] {
737
+ const file = state.statePath;
738
+ const claims = readdirSync(dirname(file))
739
+ .filter(name => name.startsWith(`${state.runId}.json.`) && /^\d+\.decision\.json$/.test(name.slice(`${state.runId}.json.`.length)))
740
+ .map(name => join(dirname(file), name));
741
+ for (const claim of claims) {
742
+ if (lstatSync(claim).isSymbolicLink()) throw new Error('graph run artifact is a symlink');
743
+ let value: unknown;
744
+ try { value = JSON.parse(readFileSync(claim, 'utf8')); }
745
+ catch { throw new Error(`invalid graph run decision claim: ${claim}`); }
746
+ const visit = Number(claim.slice(`${file}.`.length, -'.decision.json'.length));
747
+ if (!isDecisionClaim(value) || !Number.isSafeInteger(visit) || visit < 1 ||
748
+ (value as { nodeId: string }).nodeId !== state.path[visit - 1]) {
749
+ throw new Error(`invalid graph run decision claim: ${claim}`);
750
+ }
751
+ }
752
+ return [file, `${file}.graph`, `${file}.contexts`, ...claims];
753
+ }
754
+
755
+ /** Manage only an identity-checked ledger in this instance, never a caller-supplied path. */
756
+ export function manageGraphRun(graphId: string, runId: string, action: 'stop' | 'destroy',
757
+ root = effectiveInstanceRoot(), processStartMs: (pid: number) => number | null = psProcessStartMs,
758
+ signal: (pid: number) => void = (pid) => process.kill(pid, 'SIGTERM')): GraphRunState {
759
+ const file = graphRunPath(safeSegment(graphId), safeSegment(runId), root);
760
+ return withRunWriteLock(file, () => {
761
+ if (lstatSync(join(root, 'graph-runs')).isSymbolicLink() || lstatSync(dirname(file)).isSymbolicLink() || lstatSync(file).isSymbolicLink()) throw new Error('graph run path is a symlink');
762
+ const state = readGraphRun(graphId, runId, root);
763
+ if (state.statePath !== file || !Array.isArray(state.path) || !Array.isArray(state.nodes) ||
764
+ !Number.isSafeInteger(state.executed) || state.executed < 0 || (state.status === 'running' && state.pending)) {
765
+ throw new Error(`invalid run state: ${graphId}/${runId}`);
766
+ }
767
+ for (const path of runArtifacts(state)) {
768
+ try { if (lstatSync(path).isSymbolicLink()) throw new Error('graph run artifact is a symlink'); }
769
+ catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
770
+ }
771
+ const live = graphRunAlive(state, processStartMs);
772
+ if (action === 'stop' && state.status !== 'running') throw new Error(`run is not running: ${graphId}/${runId}`);
773
+ const lock = `${file}.resume.lock`;
774
+ if (existsSync(lock) && (!lstatSync(lock).isDirectory() || readdirSync(lock).length > 0)) throw new Error('invalid resume lock');
775
+ if (existsSync(lock) && state.status !== 'running') {
776
+ // A resume persists «running» right after taking the lock; an older empty lock on a finished run is a crash leftover.
777
+ const ageMs = Date.now() - statSync(lock).mtimeMs;
778
+ if (ageMs < RESUME_LOCK_GRACE_MS) throw new Error(`run is being resumed: ${graphId}/${runId}`);
779
+ rmdirSync(lock);
780
+ debug.log('graph.runs', 'stale-resume-lock-cleared', { graphId, runId, ageMs: Math.round(ageMs), status: state.status });
781
+ }
782
+ if (state.status === 'running') {
783
+ if (live === 'unknown') throw new Error(`cannot verify run owner: ${graphId}/${runId}`);
784
+ if (live && state.pid === process.pid) throw new Error('cannot stop the current graph runner');
785
+ const node = state.activeNode;
786
+ if (node && (node.nodeId !== state.path.at(-1) || state.path.length !== state.nodes.length + 1)) throw new Error('active node does not match saved path');
787
+ if (state.path.length !== state.nodes.length && state.path.length !== state.nodes.length + 1) {
788
+ throw new Error('saved run path and node records do not match');
789
+ }
790
+ if (state.path.some((nodeId, i) => state.nodes[i] && state.nodes[i]?.nodeId !== nodeId) ||
791
+ state.executed !== state.nodes.filter(record => record.executed).length) throw new Error('saved run path and node records do not match');
792
+ if (node?.pidStartedAt === UNVERIFIED_NODE_START) {
793
+ // While the runner lives it will either verify this child or kill it; retry stop after that.
794
+ if (live) throw new Error(`node process start is not verified yet — retry stop: ${graphId}/${runId}`);
795
+ // Runner gone (e.g. reboot): the pid may be reused, so never signal an identity we could not verify.
796
+ debug.log('graph.runs', 'unverified-node-not-signaled', { graphId, runId, nodeId: node.nodeId, pid: node.pid });
797
+ } else if (node) {
798
+ const nodeAlive = graphRunAlive({ ...state, pid: node.pid, pidStartedAt: node.pidStartedAt }, processStartMs);
799
+ if (nodeAlive === 'unknown') throw new Error('cannot verify node process owner');
800
+ if (nodeAlive && node.pid === process.pid) throw new Error('cannot stop the current process');
801
+ if (nodeAlive && node.pid !== state.pid) {
802
+ try { signal(node.pid); }
803
+ catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error; }
804
+ }
805
+ }
806
+ if (state.path.length === state.nodes.length + 1) {
807
+ state.nodes.push({ nodeId: state.path.at(-1)!, ok: false, exit: null, executed: false, error: 'stopped before node completed' });
808
+ }
809
+ state.status = 'failed';
810
+ state.finishedAt = new Date().toISOString();
811
+ state.stoppedAt = state.finishedAt;
812
+ delete state.activeNode;
813
+ persistGraphRun(state);
814
+ try {
815
+ if (live) signal(state.pid!);
816
+ } catch (error) {
817
+ if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error;
818
+ } finally {
819
+ // The failed ledger is durable even if its runner vanished between verification and signaling.
820
+ if (existsSync(lock)) rmdirSync(lock);
821
+ }
822
+ } else if (existsSync(lock)) rmdirSync(lock);
823
+ if (action === 'destroy') {
824
+ for (const path of runArtifacts(state)) rmSync(path, { recursive: true, force: true });
825
+ }
826
+ debug.log('graph.runs', action, { graphId, runId, previousAlive: live, status: state.status });
827
+ return state;
828
+ });
829
+ }
830
+
535
831
  export function graphRunAlive(state: GraphRunState, processStartMs: (pid: number) => number | null = psProcessStartMs): GraphRunAlive {
536
832
  if (state.pid === undefined) return 'unknown';
537
833
  if (!Number.isSafeInteger(state.pid) || state.pid <= 0 || typeof state.pidStartedAt !== 'string') return false;
@@ -71,6 +71,8 @@ export interface GrokAgentSearchResult {
71
71
  /** Deduped source URLs, in first-seen order (annotations first, then
72
72
  * raw search_call sources). */
73
73
  citations: GrokCitation[];
74
+ /** URLs supplied by an actual x_search_call (not merely web citations). */
75
+ xSearchSources?: string[];
74
76
  /** Set when ok=false — a short diagnostic ('missing-api-key',
75
77
  * 'grok responses 4xx: …', 'threw: …'). */
76
78
  error?: string;
@@ -151,6 +153,7 @@ export function parseResponsesOutput(body: { output?: unknown[] } | null): GrokA
151
153
  const output = Array.isArray(body?.output) ? body!.output! : [];
152
154
  let text = '';
153
155
  const citations: GrokCitation[] = [];
156
+ const xSearchSources = new Set<string>();
154
157
  const seen = new Set<string>();
155
158
  const addCite = (url?: unknown, title?: unknown): void => {
156
159
  if (typeof url !== 'string' || !url || seen.has(url)) return;
@@ -179,9 +182,12 @@ export function parseResponsesOutput(body: { output?: unknown[] } | null): GrokA
179
182
  if ((item?.type === 'web_search_call' || item?.type === 'x_search_call')) {
180
183
  const action = item.action as Record<string, unknown> | undefined;
181
184
  const sources = Array.isArray(action?.sources) ? action!.sources as Array<Record<string, unknown>> : [];
182
- for (const s of sources) addCite(s?.url, s?.title);
185
+ for (const s of sources) {
186
+ addCite(s?.url, s?.title);
187
+ if (item.type === 'x_search_call' && typeof s?.url === 'string') xSearchSources.add(s.url);
188
+ }
183
189
  }
184
190
  }
185
191
 
186
- return { ok: true, status: 200, text: text.trim(), citations };
192
+ return { ok: true, status: 200, text: text.trim(), citations, xSearchSources: [...xSearchSources] };
187
193
  }