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
@@ -73,6 +73,7 @@ export function publishWorkflowRunEvent(
73
73
  const detail: Record<string, unknown> = {
74
74
  runId: ctx.runId,
75
75
  workflowName: ctx.workflowName,
76
+ ...(evt.mode !== undefined ? { mode: evt.mode } : {}),
76
77
  };
77
78
  if (evt.type === 'node_start' || evt.type === 'node_skipped' || evt.type === 'node_done') {
78
79
  detail.nodeId = evt.nodeId;
@@ -32,7 +32,9 @@ import { requirePosixShellCommand } from '../../platform/default-shell.js';
32
32
  import { spawn } from 'child_process';
33
33
  import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
34
34
  import { join } from 'path';
35
+ import { debug } from '../../debug/log.js';
35
36
  import { elanousStateRoot } from '../../autopilot/state-paths.js';
37
+ import { getWorkflowHistoryVersion, listWorkflowHistory, snapshotBeforeSave } from './workflow-history.js';
36
38
  import {
37
39
  deleteWorkflow,
38
40
  discoverWorkflows,
@@ -40,8 +42,12 @@ import {
40
42
  parseWorkflowYaml,
41
43
  runWorkflow,
42
44
  saveWorkflow,
45
+ topoSort,
43
46
  type WorkflowDeps,
44
47
  type WorkflowEvent,
48
+ type WorkflowRunMode,
49
+ type NodeOutput,
50
+ type RunWorkflowOpts,
45
51
  } from '../../workflow-runtime/index.js';
46
52
  import { buildRunCft, buildRunSkill } from '../../workflow-runtime/deps-bridge.js';
47
53
  import {
@@ -59,6 +65,7 @@ import { runApprovalAcrossChannels } from './workflow-approval-multi-channel.js'
59
65
  interface RunRecord {
60
66
  runId: string;
61
67
  workflowName: string;
68
+ mode: WorkflowRunMode;
62
69
  startedAt: number;
63
70
  events: WorkflowEvent[];
64
71
  /** Settled state: undefined while running, true on workflow_done,
@@ -227,6 +234,45 @@ export function handleWorkflowGet(
227
234
  );
228
235
  }
229
236
 
237
+ export function handleWorkflowHistoryList(
238
+ req: Request,
239
+ name: string,
240
+ opts: MetaApiOpts,
241
+ ): Response {
242
+ if (!checkAuth(req, opts)) return jsonResponse({ error: 'unauthorized' }, 401);
243
+ if (req.method !== 'GET') return jsonResponse({ error: 'method-not-allowed', method: req.method }, 405);
244
+ const scope = new URL(req.url).searchParams.get('scope') === 'global' ? 'global' : 'project';
245
+ try {
246
+ return jsonResponse({ versions: listWorkflowHistory(name, { scope }) }, 200);
247
+ } catch (err) {
248
+ if (err instanceof Error && err.message === 'invalid workflow name') {
249
+ return jsonResponse({ error: 'bad_request', reason: err.message }, 400);
250
+ }
251
+ throw err;
252
+ }
253
+ }
254
+
255
+ export function handleWorkflowHistoryVersionGet(
256
+ req: Request,
257
+ name: string,
258
+ id: string,
259
+ opts: MetaApiOpts,
260
+ ): Response {
261
+ if (!checkAuth(req, opts)) return jsonResponse({ error: 'unauthorized' }, 401);
262
+ if (req.method !== 'GET') return jsonResponse({ error: 'method-not-allowed', method: req.method }, 405);
263
+ const scope = new URL(req.url).searchParams.get('scope') === 'global' ? 'global' : 'project';
264
+ try {
265
+ const yaml = getWorkflowHistoryVersion(name, id, { scope });
266
+ if (yaml === null) return jsonResponse({ error: 'not_found', name, id }, 404);
267
+ return jsonResponse({ yaml }, 200);
268
+ } catch (err) {
269
+ if (err instanceof Error && (err.message === 'invalid workflow name' || err.message === 'invalid workflow history version id')) {
270
+ return jsonResponse({ error: 'bad_request', reason: err.message }, 400);
271
+ }
272
+ throw err;
273
+ }
274
+ }
275
+
230
276
  export async function handleWorkflowPut(
231
277
  req: Request,
232
278
  name: string,
@@ -243,6 +289,17 @@ export async function handleWorkflowPut(
243
289
  return jsonResponse({ error: 'bad_request', reason: '`yaml` must be a string' }, 400);
244
290
  }
245
291
  const scope = scopeRaw === 'global' ? 'global' : 'project';
292
+ const parsed = parseWorkflowYaml(yamlText);
293
+ if (parsed.ok && parsed.workflow?.name === name) {
294
+ // Capture the existing file before saveWorkflow overwrites it; a failed snapshot is non-fatal.
295
+ try {
296
+ snapshotBeforeSave(name, { scope });
297
+ } catch (err) {
298
+ debug.log('nexus.workflow-history', 'snapshot-failed', {
299
+ name, scope, error: err instanceof Error ? err.message : String(err),
300
+ }, { level: 'warn' });
301
+ }
302
+ }
246
303
  const r = saveWorkflow(name, yamlText, { scope });
247
304
  if (!r.ok) {
248
305
  return jsonResponse(
@@ -384,10 +441,51 @@ export async function handleWorkflowRunStart(
384
441
  // so the PWA "▶ Run now" button runs the dependent chain straight
385
442
  // through. Default false preserves the production wire.
386
443
  const dryRun: boolean = Boolean(body && typeof body === 'object' && (body as { dryRun?: unknown }).dryRun === true);
444
+ const input = body && typeof body === 'object' ? body as Record<string, unknown> : {};
445
+ const { onlyNode, fromNode, fromRunId } = input;
446
+ if ('usePins' in input || (onlyNode !== undefined && (fromNode !== undefined || fromRunId !== undefined))
447
+ || (onlyNode !== undefined && (typeof onlyNode !== 'string' || !onlyNode.trim()))
448
+ || (fromNode !== undefined && (typeof fromNode !== 'string' || !fromNode.trim()))
449
+ || (fromRunId !== undefined && (typeof fromRunId !== 'string' || !fromRunId.trim()))
450
+ || (fromNode === undefined) !== (fromRunId === undefined)
451
+ || (input.mode !== undefined && input.mode !== 'test')) {
452
+ return jsonResponse({ error: 'bad_request', reason: 'invalid run selection' }, 400);
453
+ }
454
+ if ((onlyNode && !entry.definition.nodes.some(n => n.id === onlyNode))
455
+ || (fromNode && !entry.definition.nodes.some(n => n.id === fromNode))) {
456
+ return jsonResponse({ error: 'bad_request', reason: 'unknown selected node' }, 400);
457
+ }
458
+ let previousOutputs: Record<string, NodeOutput> | undefined;
459
+ if (typeof fromRunId === 'string') {
460
+ const previous = RUN_REGISTRY.get(fromRunId);
461
+ if (previous) {
462
+ if (previous.workflowName !== name || previous.ok === undefined) {
463
+ return jsonResponse({ error: 'bad_request', reason: 'source run must be settled for this workflow' }, 400);
464
+ }
465
+ const terminal = previous.events.find(e => e.type === 'workflow_done' || e.type === 'workflow_failed');
466
+ previousOutputs = terminal?.type === 'workflow_done' ? terminal.outputs
467
+ : terminal?.type === 'workflow_failed' ? terminal.partial : {};
468
+ } else {
469
+ const disk = readRunOutputSnapshot(fromRunId);
470
+ if (!disk || disk.workflowName !== name || (disk.status !== 'done' && disk.status !== 'failed')) {
471
+ return jsonResponse({ error: 'bad_request', reason: 'source run must be settled for this workflow' }, 400);
472
+ }
473
+ previousOutputs = disk.outputs;
474
+ }
475
+ let order: string[];
476
+ try { order = topoSort(entry.definition.nodes); }
477
+ catch { return jsonResponse({ error: 'bad_request', reason: 'invalid workflow topology' }, 400); }
478
+ const upstream = order.slice(0, order.indexOf(fromNode as string));
479
+ if (upstream.some(id => previousOutputs?.[id] === undefined)) {
480
+ return jsonResponse({ error: 'bad_request', reason: 'source run missing upstream outputs' }, 400);
481
+ }
482
+ }
483
+ const mode: WorkflowRunMode = input.mode === 'test' ? 'test' : onlyNode ? 'only' : fromNode ? 'from' : 'full';
387
484
  const runId = `wf-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
388
485
  const record: RunRecord = {
389
486
  runId,
390
487
  workflowName: name,
488
+ mode,
391
489
  startedAt: Date.now(),
392
490
  events: [],
393
491
  ok: undefined,
@@ -400,10 +498,14 @@ export async function handleWorkflowRunStart(
400
498
  void (async () => {
401
499
  const deps = buildDefaultWorkflowDeps({ runId });
402
500
  try {
403
- for await (const evt of runWorkflow(
404
- { workflow: entry.definition, arguments: args, runId, dryRun },
405
- deps,
406
- )) {
501
+ const runOpts: RunWorkflowOpts = {
502
+ workflow: entry.definition, arguments: args, runId, dryRun, mode,
503
+ ...(typeof onlyNode === 'string' ? { onlyNode } : {}),
504
+ ...(typeof fromNode === 'string' ? { fromNode } : {}),
505
+ ...(previousOutputs ? { previousOutputs } : {}),
506
+ };
507
+ for await (const runtimeEvent of runWorkflow(runOpts, deps)) {
508
+ const evt = { ...runtimeEvent, mode };
407
509
  record.events.push(evt);
408
510
  // §15.8(b) — fan into NexusEventBus → PWA invalidates queries
409
511
  // on push instead of polling. No-op when bus is unwired
@@ -423,13 +525,14 @@ export async function handleWorkflowRunStart(
423
525
  type: 'workflow_failed' as const,
424
526
  error: err instanceof Error ? err.message : String(err),
425
527
  partial: {},
528
+ mode,
426
529
  };
427
530
  record.events.push(failEvt);
428
531
  publishWorkflowRunEvent({ runId, workflowName: name }, failEvt);
429
532
  }
430
533
  })();
431
534
 
432
- return jsonResponse({ ok: true, runId }, 202);
535
+ return jsonResponse({ ok: true, runId, mode }, 202);
433
536
  }
434
537
 
435
538
  export function handleWorkflowRunGet(
@@ -444,6 +547,7 @@ export function handleWorkflowRunGet(
444
547
  {
445
548
  runId: rec.runId,
446
549
  workflowName: rec.workflowName,
550
+ mode: rec.mode,
447
551
  startedAt: rec.startedAt,
448
552
  ok: rec.ok,
449
553
  events: rec.events,
@@ -597,6 +701,21 @@ interface DiskRunSummary {
597
701
  * enough that abandoned runs don't pollute the list across sessions. */
598
702
  const STALE_RUNNING_AFTER_MS = 30 * 60 * 1000;
599
703
 
704
+ function readRunOutputSnapshot(runId: string): {
705
+ workflowName: string;
706
+ status: string;
707
+ outputs: Record<string, NodeOutput>;
708
+ } | null {
709
+ if (!/^wf-[A-Za-z0-9-]+$/.test(runId) || runId.includes('..')) return null;
710
+ try {
711
+ const parsed = JSON.parse(readFileSync(join(workflowsRunsRoot(), runId, 'run.json'), 'utf-8')) as {
712
+ workflowName?: string; status?: string; outputs?: Record<string, NodeOutput>;
713
+ };
714
+ if (!parsed.workflowName || !parsed.status || !parsed.outputs || typeof parsed.outputs !== 'object') return null;
715
+ return { workflowName: parsed.workflowName, status: parsed.status, outputs: parsed.outputs };
716
+ } catch { return null; }
717
+ }
718
+
600
719
  /** Read `<root>/<runId>/run.json` and translate into the same shape as
601
720
  * GET /runs/<id> serves from memory. Returns null when the file is
602
721
  * missing or unreadable. Events are reconstructed minimally from the
@@ -608,6 +727,7 @@ function loadRunFromDisk(runId: string): {
608
727
  ok: boolean | undefined;
609
728
  events: WorkflowEvent[];
610
729
  outputs: Record<string, unknown>;
730
+ mode?: WorkflowRunMode;
611
731
  } | null {
612
732
  if (!runId || runId.includes('/') || runId.includes('..')) return null;
613
733
  const root = workflowsRunsRoot();
@@ -623,6 +743,7 @@ function loadRunFromDisk(runId: string): {
623
743
  completedAt?: number;
624
744
  ok?: boolean;
625
745
  status?: string;
746
+ mode?: WorkflowRunMode;
626
747
  outputs?: Record<string, { output?: unknown }>;
627
748
  };
628
749
  if (!parsed.runId || !parsed.workflowName) return null;
@@ -634,7 +755,8 @@ function loadRunFromDisk(runId: string): {
634
755
  // so a polling client still sees the node_done sequence even
635
756
  // though the live run.json doesn't store events.
636
757
  const events: WorkflowEvent[] = [];
637
- events.push({ type: 'workflow_start', workflow: parsed.workflowName, runId: parsed.runId });
758
+ events.push({ type: 'workflow_start', workflow: parsed.workflowName, runId: parsed.runId,
759
+ ...(parsed.mode !== undefined ? { mode: parsed.mode } : {}) });
638
760
  const nodesDir = join(runDir, 'nodes');
639
761
  // Iterate `parsed.outputs` keys instead of `readdirSync(nodesDir)`
640
762
  // so the reconstructed node_done sequence is in execution order
@@ -673,6 +795,7 @@ function loadRunFromDisk(runId: string): {
673
795
  events.push({
674
796
  type: 'node_done',
675
797
  nodeId,
798
+ ...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
676
799
  result: {
677
800
  ok: nodeData.ok,
678
801
  output: nodeData.output ?? '',
@@ -684,6 +807,7 @@ function loadRunFromDisk(runId: string): {
684
807
  if (parsed.status === 'done') {
685
808
  events.push({
686
809
  type: 'workflow_done',
810
+ ...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
687
811
  outputs: Object.fromEntries(
688
812
  Object.entries(parsed.outputs ?? {}).map(([k, v]) => [
689
813
  k,
@@ -694,6 +818,7 @@ function loadRunFromDisk(runId: string): {
694
818
  } else if (parsed.status === 'failed') {
695
819
  events.push({
696
820
  type: 'workflow_failed',
821
+ ...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
697
822
  error: 'failed (see node events)',
698
823
  partial: Object.fromEntries(
699
824
  Object.entries(parsed.outputs ?? {}).map(([k, v]) => [
@@ -706,6 +831,7 @@ function loadRunFromDisk(runId: string): {
706
831
  return {
707
832
  runId: parsed.runId,
708
833
  workflowName: parsed.workflowName,
834
+ ...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
709
835
  startedAt: parsed.startedAt ?? 0,
710
836
  ok: parsed.status === 'done' ? true : parsed.status === 'failed' ? false : undefined,
711
837
  events,
@@ -1949,10 +1949,12 @@ export async function runNexus(opts: RunNexusOptions = {}): Promise<RunNexusHand
1949
1949
  const tab = registry.get(tabId);
1950
1950
  if (!tab || tab.spec.kind !== 'webterm') return;
1951
1951
  const cwdMeta = (tab.spec.meta as { cwd?: string } | undefined)?.cwd;
1952
+ const projectSessionId = (tab.spec.meta as { sessionId?: string } | undefined)?.sessionId;
1952
1953
  const backendFactory = effectiveWebtermSpawn
1953
1954
  ? () => {
1954
1955
  const decided = resolveWebtermCwd({
1955
1956
  ...(cwdMeta ? { tabCwd: cwdMeta } : {}),
1957
+ ...(projectSessionId ? { sessionId: projectSessionId } : {}),
1956
1958
  ...(runtimeToolCwd ? { toolCwd: runtimeToolCwd } : {}),
1957
1959
  instance: resolveCurrentInstance(),
1958
1960
  processCwd: process.cwd(),
@@ -24,6 +24,7 @@ export interface WebtermTabOpts {
24
24
  id?: string; // default: 'webterm:1'
25
25
  label?: string;
26
26
  cwd?: string;
27
+ sessionId?: string;
27
28
  }
28
29
 
29
30
  export const WEBTERM_KIND: TabKind = 'webterm';
@@ -34,7 +35,7 @@ export function createWebtermTabSpec(opts: WebtermTabOpts = {}): TabSpec {
34
35
  id,
35
36
  kind: WEBTERM_KIND,
36
37
  label: opts.label ?? id,
37
- ...(opts.cwd ? { meta: { cwd: opts.cwd } } : {}),
38
+ ...(opts.cwd || opts.sessionId ? { meta: { ...(opts.cwd ? { cwd: opts.cwd } : {}), ...(opts.sessionId ? { sessionId: opts.sessionId } : {}) } } : {}),
38
39
  };
39
40
  }
40
41
 
@@ -52,20 +52,29 @@ export function deliveryDedupKey(kind: string, text: string): string {
52
52
  return createHash('sha1').update(`${kind}\n${norm}`).digest('hex').slice(0, 16);
53
53
  }
54
54
 
55
- /** ① 중복 발사 제어 — 같은 dedupKey가 windowSec 내에 이미 발송됐나(재팬아웃 억제).
56
- * 보수적 짧은 창(기본 120s) — 크론 재시도·이중호출 같은 즉시 중복만 잡고,
57
- * 시간 지난 정당한 재발송은 통과. (의미 중복은 상류 signal-dedup 6h 담당.) */
58
- export function recentlyDelivered(
55
+ /** ① 중복 발사 제어 — windowSec 내 동일 메시지가 한 채널 이상 성공했으면 그 messageId.
56
+ * 실패 기록은 재시도를 막지 않는다. 짧은 창(기본 120s) 밖의 재발송은 통과. */
57
+ export function successfulDeliveryId(
59
58
  db: Database, dedupKey: string, windowSec = 120, nowMs: number = Date.now(),
60
- ): boolean {
59
+ ): string | null {
61
60
  // ⚠️ 축 ②(JS 임계 · db-window 참조) — 같은 파일의 `recentDeliveryCount` 와 동형이다.
62
61
  // SQL 안의 `datetime('now')` 를 쓰면 **시계를 주입할 수 없어** 테스트가 실제 시각에
63
62
  // 매달린다. 실제로 이 함수의 테스트가 고정 날짜로 seed 한 채 시간이 흘러 어느 날 빨개진
64
63
  // 시한폭탄이었다. `deliveries.ts` 는 ISO 로만 쓰므로 raw 비교가 옳고 인덱스도 산다.
65
64
  const row = db.prepare(
66
- `SELECT 1 FROM deliveries WHERE dedup_key = ? AND ts >= ? LIMIT 1`,
67
- ).get(dedupKey, sinceTs(SECONDS(windowSec), nowMs));
68
- return !!row;
65
+ `SELECT message_id FROM deliveries
66
+ WHERE dedup_key = ? AND ts >= ?
67
+ AND EXISTS (SELECT 1 FROM json_each(deliveries.channels) WHERE json_extract(value, '$.ok') = 1)
68
+ ORDER BY ts DESC LIMIT 1`,
69
+ ).get(dedupKey, sinceTs(SECONDS(windowSec), nowMs)) as { message_id: string } | null;
70
+ return row?.message_id ?? null;
71
+ }
72
+
73
+ /** 기존 boolean 호출부 호환 — 성공 배송 기록만 중복으로 센다. */
74
+ export function recentlyDelivered(
75
+ db: Database, dedupKey: string, windowSec = 120, nowMs: number = Date.now(),
76
+ ): boolean {
77
+ return successfulDeliveryId(db, dedupKey, windowSec, nowMs) !== null;
69
78
  }
70
79
 
71
80
  /** 최근 창(windowSec) 내 총 발송 수 — 버스트(밀림) 판정용. 전 kind 합산.
@@ -27,13 +27,14 @@
27
27
  // that boolean before falling back to direct Telegram).
28
28
 
29
29
  import { createHash } from 'node:crypto';
30
+ import { debug } from '../../debug/log.js';
30
31
  import { sendTelegramReport } from '../../telegram-report.js';
31
32
  import { getPushcutClient } from '../../pushcut/client.js';
32
33
  import type { UserConfig } from '../../user-config.js';
33
34
  import { formatForChannel, type OutboundChannelType, type OutboundMsg } from './format.js';
34
35
  import { spillLongContent } from '../../storage/content-spill.js';
35
36
  import {
36
- openDeliveryDb, deliveryDedupKey, recentlyDelivered, recordDelivery, type ChannelDelivery,
37
+ openDeliveryDb, deliveryDedupKey, successfulDeliveryId, recordDelivery, type ChannelDelivery,
37
38
  } from './delivery-ledger.js';
38
39
 
39
40
  // 채널 타입·메시지·분할기는 format.ts가 단일 출처 — 기존 소비처(test 등) 호환 재export.
@@ -71,6 +72,8 @@ export interface RouteResult {
71
72
  channels: ChannelResult[];
72
73
  /** 중복 발사 제어(dedup)로 재팬아웃이 억제됨 — 최근 동일 발송 존재. */
73
74
  suppressed?: boolean;
75
+ /** 억제 근거가 된 앞선 성공 발송의 식별자. */
76
+ suppressedBy?: string;
74
77
  /** 이 발송의 식별자(리드 동기화·회상 교차참조용). */
75
78
  messageId?: string;
76
79
  }
@@ -207,9 +210,11 @@ export async function routeOutbound(cfg: UserConfig, msg: OutboundMsg, deps: Rou
207
210
  // ① 중복 발사 제어 — 최근(120s) 동일 발송이면 재팬아웃 억제.
208
211
  if (ledger && deps.dedup !== false) {
209
212
  try {
210
- if (recentlyDelivered(ledger, dedupKey)) {
213
+ const suppressedBy = successfulDeliveryId(ledger, dedupKey);
214
+ if (suppressedBy) {
211
215
  if (ownLedger) ledger.close();
212
- return { delivered: true, channels: [], suppressed: true, messageId };
216
+ try { debug.log('outbound.send', 'suppressed', { kind: msg.kind, suppressedBy }); } catch { /* 관측 실패는 발송 결과에 영향 없음 */ }
217
+ return { delivered: true, channels: [], suppressed: true, suppressedBy, messageId };
213
218
  }
214
219
  } catch { /* 원장 조회 실패 — 억제 없이 진행 */ }
215
220
  }
@@ -31,6 +31,7 @@ import { startPty as realStartPty, onPtyEvent as realOnPtyEvent } from '../../pt
31
31
  import type { StartOpts, PtyHandle, PtyEvent } from '../../pty-shell/registry.js';
32
32
 
33
33
  import { debug } from '../../debug/log.js';
34
+ import { resolveSessionProjectContext } from '../../project/session-context.js';
34
35
 
35
36
  // ── PtyBackend interface ─────────────────────────────────────────────
36
37
 
@@ -229,15 +230,18 @@ export function createRegistryBackend(
229
230
  }
230
231
 
231
232
  /** 웹 터미널 셸이 열릴 작업 디렉토리를 정한다(실행 맥락 SSOT: 맥락은 «한 번» 정해지고 인자로 내려간다).
232
- * 순서: 탭이 명시한 cwd → 데몬이 정한 tool cwd → (격리 우주면) 우주 뿌리 → 데몬 프로세스 cwd.
233
+ * 순서: 탭이 명시한 cwd → 대화 프로젝트 폴더 → 데몬 tool cwd → (격리 우주면) 우주 뿌리 → 프로세스 cwd.
233
234
  * ⛔ 격리(test) 우주에서 `process.cwd()` 로 떨어지면 셸이 «사람 작업 트리»에서 열린다(🅕 실측 2026-09-26). */
234
235
  export function resolveWebtermCwd(input: {
235
236
  tabCwd?: string;
237
+ sessionId?: string;
236
238
  toolCwd?: string;
237
239
  instance: { kind: 'prod' | 'test'; root: string };
238
240
  processCwd: string;
239
- }): { cwd: string; source: 'tab' | 'tool-cwd' | 'isolated-root' | 'process-cwd' } {
241
+ }): { cwd: string; source: 'tab' | 'project' | 'tool-cwd' | 'isolated-root' | 'process-cwd' } {
240
242
  if (input.tabCwd) return { cwd: input.tabCwd, source: 'tab' };
243
+ const projectCwd = resolveSessionProjectContext(input.sessionId)?.cwd;
244
+ if (projectCwd) return { cwd: projectCwd, source: 'project' };
241
245
  if (input.toolCwd) return { cwd: input.toolCwd, source: 'tool-cwd' };
242
246
  if (input.instance.kind === 'test') return { cwd: input.instance.root, source: 'isolated-root' };
243
247
  return { cwd: input.processCwd, source: 'process-cwd' };
@@ -0,0 +1,80 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { accessSync, constants, statSync } from 'node:fs';
3
+ import { delimiter, join } from 'node:path';
4
+
5
+ export type SkillCli = 'gh' | 'gws' | 'op' | 'himalaya';
6
+
7
+ export interface CliAuthStatus {
8
+ cli: SkillCli;
9
+ found: boolean;
10
+ authenticated: boolean;
11
+ skippedReason?: string;
12
+ }
13
+
14
+ export interface CliAuthStatusDeps {
15
+ path?: string;
16
+ findExecutable?: (name: SkillCli, path: string) => string | null;
17
+ runStatus?: (executable: string, args: readonly string[]) => { status: number | null; stdout?: string; error?: unknown };
18
+ }
19
+
20
+ const STATUS_COMMANDS: readonly { cli: SkillCli; args: readonly string[] }[] = [
21
+ { cli: 'gh', args: ['auth', 'status'] },
22
+ { cli: 'gws', args: ['auth', 'status'] },
23
+ { cli: 'op', args: ['whoami'] },
24
+ { cli: 'himalaya', args: ['account', 'check'] },
25
+ ];
26
+
27
+ function findOnPath(name: SkillCli, path: string): string | null {
28
+ for (const directory of path.split(delimiter).filter(Boolean)) {
29
+ const executable = join(directory, name);
30
+ try {
31
+ accessSync(executable, constants.X_OK);
32
+ if (statSync(executable).isFile()) return executable;
33
+ } catch { /* Try the next PATH entry. */ }
34
+ }
35
+ return null;
36
+ }
37
+
38
+ function runReadOnlyStatus(executable: string, args: readonly string[]) {
39
+ const result = spawnSync(executable, [...args], {
40
+ encoding: 'utf8', timeout: 5_000, maxBuffer: 64 * 1024,
41
+ stdio: ['ignore', 'pipe', 'ignore'],
42
+ });
43
+ return { status: result.status, stdout: result.stdout, error: result.error };
44
+ }
45
+
46
+ function gwsHasSession(stdout: string | undefined): boolean {
47
+ try {
48
+ const status: unknown = JSON.parse(stdout ?? '');
49
+ if (!status || typeof status !== 'object' || Array.isArray(status)) return false;
50
+ const auth = status as Record<string, unknown>;
51
+ return auth.token_valid === true;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ /** No credential-file reads, login calls, prompts, or token-bearing output leave this probe. */
58
+ export function detectSkillCliAuth(deps: CliAuthStatusDeps = {}): CliAuthStatus[] {
59
+ const path = deps.path ?? process.env.PATH ?? '';
60
+ const find = deps.findExecutable ?? findOnPath;
61
+ const run = deps.runStatus ?? runReadOnlyStatus;
62
+ return STATUS_COMMANDS.map(({ cli, args }) => {
63
+ let executable: string | null;
64
+ try { executable = find(cli, path); }
65
+ catch { executable = null; }
66
+ if (!executable) return { cli, found: false, authenticated: false, skippedReason: 'not on PATH' };
67
+ try {
68
+ const result = run(executable, args);
69
+ if (result.error || result.status === null) {
70
+ return { cli, found: true, authenticated: false, skippedReason: 'status check unavailable' };
71
+ }
72
+ if (result.status !== 0 || (cli === 'gws' && !gwsHasSession(result.stdout))) {
73
+ return { cli, found: true, authenticated: false, skippedReason: 'not authenticated' };
74
+ }
75
+ return { cli, found: true, authenticated: true };
76
+ } catch {
77
+ return { cli, found: true, authenticated: false, skippedReason: 'status check unavailable' };
78
+ }
79
+ });
80
+ }
@@ -154,12 +154,12 @@ export async function askVoiceAI(
154
154
 
155
155
  if (mode === 'preset') {
156
156
  // Phase 2 catalog isn't shipped yet; the wizard records the intent
157
- // by keeping the user on Smart defaults but tagging persona='power'
157
+ // by keeping the user on Smart defaults but tagging profile='power'
158
158
  // so the auto-suggest hint in PWA opens the preset card directly.
159
159
  io.print(' (Preset catalog ships in Phase 2 · for now Smart defaults stay active.)');
160
160
  io.print(' elanous has noted your preference — preset hints will appear when ready.');
161
161
  return {
162
- modelTier: { persona: 'power' },
162
+ modelTier: { profile: 'power' },
163
163
  };
164
164
  }
165
165
 
@@ -175,7 +175,7 @@ export async function askVoiceAI(
175
175
 
176
176
  const answer: VoiceAIAnswer = {
177
177
  modelTier: {
178
- persona: 'custom',
178
+ profile: 'custom',
179
179
  voice: { stt: tier as ModelTier },
180
180
  },
181
181
  };
@@ -0,0 +1,48 @@
1
+ import { getUserConfig, type UserConfig } from '../user-config.js';
2
+ import type { SeatEntry } from '../seat-loop/seat-loop.js';
3
+
4
+ export const DEFAULT_DAILY_GOALS = 6;
5
+ export const DEFAULT_CONCURRENT_PODS = 2;
6
+
7
+ export type SeatBudgetResult = { allowed: true } | { allowed: false; reason: string };
8
+ export type RunningSeatPod = { seat: string; substrate?: string; status?: string };
9
+ export type SeatBudgetInput = {
10
+ seat: string;
11
+ now: Date;
12
+ ledger: readonly SeatEntry[];
13
+ running: readonly RunningSeatPod[];
14
+ config?: Pick<UserConfig, 'org'>;
15
+ };
16
+
17
+ function limit(value: unknown, fallback: number): number {
18
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : fallback;
19
+ }
20
+
21
+ function day(date: Date): string {
22
+ return new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Seoul', year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
23
+ }
24
+
25
+ /** A read-only seat quota judgment; the caller owns the launch and ledger write. */
26
+ export function checkSeatBudget({ seat, now, ledger, running, config }: SeatBudgetInput): SeatBudgetResult {
27
+ const override = (config ?? getUserConfig()).org?.budget?.[seat];
28
+ const dailyGoals = limit(override?.dailyGoals, DEFAULT_DAILY_GOALS);
29
+ const concurrentPods = limit(override?.concurrentPods, DEFAULT_CONCURRENT_PODS);
30
+ const today = day(now);
31
+ const launchedToday = ledger.filter((entry) => entry.seat === seat && entry.status === 'launched'
32
+ && Number.isFinite(Date.parse(entry.ts ?? entry.at))
33
+ && day(new Date(entry.ts ?? entry.at)) === today).length;
34
+ if (launchedToday >= dailyGoals) {
35
+ return { allowed: false, reason: `${seat} daily goals budget reached (${launchedToday}/${dailyGoals})` };
36
+ }
37
+ const active = running.filter((run) => run.seat === seat && (run.status === undefined || run.status === 'running' || run.status === 'unknown'));
38
+ // Confirmed = a Pod known to be running; an unknown substrate OR unknown liveness only counts as «cannot verify».
39
+ const pods = active.filter((run) => run.substrate === 'pod' && run.status !== 'unknown').length;
40
+ if (pods >= concurrentPods) {
41
+ return { allowed: false, reason: `${seat} concurrent Pods budget reached (${pods}/${concurrentPods})` };
42
+ }
43
+ const unknown = active.filter((run) => run.substrate === undefined || run.status === 'unknown').length;
44
+ if (pods + unknown >= concurrentPods) {
45
+ return { allowed: false, reason: `${seat} concurrent Pods budget cannot be verified (${pods} confirmed, ${unknown} unknown; limit ${concurrentPods})` };
46
+ }
47
+ return { allowed: true };
48
+ }
@@ -0,0 +1,63 @@
1
+ import type { Checklist, ChecklistItem } from '../release-loop/checklist.js';
2
+ import { parseOwner } from '../release-loop/checklist.js';
3
+ import type { SeatLoopConfig } from '../user-config.js';
4
+
5
+ export interface StallEscalation {
6
+ item: ChecklistItem;
7
+ from: string;
8
+ to: string;
9
+ stalledMin: number;
10
+ /** Stable start of this uninterrupted stall interval (independent of the observation clock). */
11
+ startedAt: string;
12
+ reason: 'red' | 'blocked';
13
+ }
14
+
15
+ /** A missing parent is intentional: OP has no automatic escalation destination. */
16
+ export const DEFAULT_STALL_PARENTS: Readonly<Record<string, string>> = { MK: 'OP', TC: 'OP', UX: 'OP' };
17
+ export const DEFAULT_RED_MINUTES = 30;
18
+ export const DEFAULT_BLOCKED_MINUTES = 60;
19
+
20
+ function stallReason(item: ChecklistItem): StallEscalation['reason'] | null {
21
+ if (item.status === 'red') return 'red';
22
+ return item.status === 'yellow' && item.disposition === 'block' ? 'blocked' : null;
23
+ }
24
+
25
+ /** Find the beginning of the current uninterrupted red/blocked interval, not the most recent evidence edit. */
26
+ function stallStart(item: ChecklistItem, history: Checklist['history'], reason: StallEscalation['reason']): number {
27
+ const changes = history.filter((entry) => entry.id === item.id && (entry.field === 'status' || entry.field === 'disposition'))
28
+ .filter((entry) => Number.isFinite(Date.parse(entry.at)))
29
+ .sort((a, b) => Date.parse(b.at) - Date.parse(a.at));
30
+ let status = item.status;
31
+ let disposition = item.disposition;
32
+ for (const entry of changes) {
33
+ const current = status === 'red' ? 'red' : status === 'yellow' && disposition === 'block' ? 'blocked' : null;
34
+ if (entry.field === 'status') status = entry.from as ChecklistItem['status'];
35
+ else disposition = entry.from as ChecklistItem['disposition'];
36
+ const previous = status === 'red' ? 'red' : status === 'yellow' && disposition === 'block' ? 'blocked' : null;
37
+ if (current === reason && previous !== reason) return Date.parse(entry.at);
38
+ }
39
+ return Date.parse(item.updatedAt);
40
+ }
41
+
42
+ /** Pure checklist snapshot judgment. Age is measured in minutes against the injected clock. */
43
+ export function findStalls(checklist: Checklist, config: SeatLoopConfig = { mode: 'off' }, now: Date = new Date()): StallEscalation[] {
44
+ const nowMs = now.getTime();
45
+ const parents = { ...DEFAULT_STALL_PARENTS, ...config.stall?.parents };
46
+ const results: StallEscalation[] = [];
47
+ for (const item of checklist.items) {
48
+ const reason = stallReason(item);
49
+ if (!reason || !item.owner) continue;
50
+ let from: string;
51
+ try { from = parseOwner(item.owner).seat; } catch { continue; }
52
+ const to = parents[from];
53
+ if (!to || to === from) continue;
54
+ const start = stallStart(item, checklist.history, reason);
55
+ if (!Number.isFinite(start) || start > nowMs) continue;
56
+ const stalledMin = (nowMs - start) / 60_000;
57
+ const threshold = reason === 'red' ? config.stall?.redMinutes ?? DEFAULT_RED_MINUTES
58
+ : config.stall?.blockedMinutes ?? DEFAULT_BLOCKED_MINUTES;
59
+ if (stalledMin < threshold) continue;
60
+ results.push({ item, from, to, stalledMin, startedAt: new Date(start).toISOString(), reason });
61
+ }
62
+ return results;
63
+ }