elanous 0.2.9 → 0.2.11

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 (694) 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/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  7. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  20. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  25. package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.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-1dcdc58fc2de2454.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f972fc1c00a62e88.js → page-b12b6d2f8d2d1aea.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.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-50cb2a0eb15e6c83.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/{page-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.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-239c17b911b84e72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.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/543f56bcb1f79fca.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 -0
  152. package/apps/pwa/out/ops/seats/index.txt +30 -0
  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 -0
  178. package/apps/pwa/out/today/index.txt +33 -0
  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/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/field/field-feed.yaml +2 -0
  194. package/graphs/implement-loop.yaml +1 -1
  195. package/graphs/intake/intake-daily.yaml +2 -1
  196. package/graphs/ops/recipes.yaml +3 -0
  197. package/graphs/ops/secret-exposure.yaml +24 -0
  198. package/graphs/release/recipes.yaml +3 -0
  199. package/graphs/release/release-loop.yaml +4 -1
  200. package/graphs/video/explainer-line.yaml +2 -2
  201. package/package.json +2 -1
  202. package/plugins/card-followup/graphs/run-step.ts +48 -13
  203. package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
  204. package/plugins/doc-draft/graphs/run-step.ts +13 -6
  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/ci-pwa-build-gate.ts +160 -0
  216. package/scripts/context-hooks/claude-stop.sh +4 -0
  217. package/scripts/context-hooks/emit.ts +24 -0
  218. package/scripts/context-hooks/post-tool-use.sh +4 -0
  219. package/scripts/coord-channel-watch.sh +54 -8
  220. package/scripts/coord-digest.ts +199 -0
  221. package/scripts/coord-post.sh +60 -3
  222. package/scripts/coord-requests-bridge.ts +143 -0
  223. package/scripts/field-feed/lib.ts +4 -0
  224. package/scripts/fleet/node-setup.sh +20 -3
  225. package/scripts/homebrew-formula-bump.ts +69 -0
  226. package/scripts/install.ps1 +68 -9
  227. package/scripts/install.sh +39 -12
  228. package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
  229. package/scripts/lib/tui-regress-checks.ts +146 -0
  230. package/scripts/marketing/measure-site-numbers.ts +169 -0
  231. package/scripts/measure-gate-shards.ts +309 -0
  232. package/scripts/memory-lifecycle-cycle.ts +2 -2
  233. package/scripts/mission-request-judge.ts +31 -1
  234. package/scripts/morning-report.ts +2 -2
  235. package/scripts/opportunity-scan.ts +1 -1
  236. package/scripts/ops-now-probe.ts +327 -0
  237. package/scripts/publish-internal-dist.ts +11 -1
  238. package/scripts/release-loop/auto-approve-node.ts +21 -4
  239. package/scripts/release-loop/cut-branch.ts +84 -0
  240. package/scripts/release-loop/cutoff.ts +19 -8
  241. package/scripts/release-loop/gate-node.ts +14 -13
  242. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  243. package/scripts/release-loop/node-verdict.ts +3 -3
  244. package/scripts/release-loop/ops-upgrade-node.ts +72 -16
  245. package/scripts/release-loop/release-readiness.ts +9 -0
  246. package/scripts/release-loop/tui-node-checks.ts +42 -0
  247. package/scripts/release-loop/tui-sim-node.ts +32 -8
  248. package/scripts/release-loop/unattended-release.ts +5 -3
  249. package/scripts/release-loop/version-node.ts +112 -13
  250. package/scripts/repo-watch-cycle.ts +1 -1
  251. package/scripts/retro-cycle.ts +2 -2
  252. package/scripts/schedule-health-report.ts +1 -1
  253. package/scripts/signal-digest-cycle.ts +2 -7
  254. package/scripts/signal-digest-photo.ts +11 -0
  255. package/scripts/storyboard/storyboard.ts +5 -161
  256. package/scripts/tech1-public-measure.ts +94 -0
  257. package/scripts/test-diet/lib.ts +30 -1
  258. package/scripts/test-diet/node.ts +83 -8
  259. package/scripts/test-timeout-audit.ts +114 -0
  260. package/scripts/tree-sync-alert.ts +1 -1
  261. package/scripts/tui-regress.ts +71 -0
  262. package/scripts/ux/demo-rehearsal.ts +243 -0
  263. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  264. package/scripts/waitlist-daily-digest.ts +1 -1
  265. package/skills/diagram-master/SKILL.md +366 -0
  266. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  267. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  268. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  269. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  270. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  271. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  272. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  273. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  274. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  275. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  276. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  277. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  278. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  279. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  280. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  281. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  282. package/skills/diagram-master/references/examples/README.md +69 -0
  283. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  284. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  285. package/skills/diagram-master/references/pyproject.toml +16 -0
  286. package/skills/diagram-master/references/quality-checklist.md +33 -0
  287. package/skills/diagram-master/references/routing-guide.md +164 -0
  288. package/skills/diagram-master/references/uv.lock +1356 -0
  289. package/skills/explainer-video/SKILL.md +4 -0
  290. package/skills/explainer-video/engine/reel.mjs +18 -13
  291. package/skills/explainer-video/engine/reel.sh +24 -5
  292. package/skills/explainer-video/engine/stitch.mjs +145 -0
  293. package/skills/google-workspace/SKILL.md +33 -0
  294. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  295. package/skills/grill-me/SKILL.md +1 -1
  296. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  297. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  298. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  299. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  300. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  301. package/skills/omni-crawl/SKILL.md +21 -11
  302. package/skills/omni-crawl/scripts/main.ts +6 -6
  303. package/skills/omni-crawl/src/router.ts +3 -3
  304. package/skills/omni-digest/SKILL.md +17 -9
  305. package/skills/omni-digest/digest.md +2 -2
  306. package/skills/omni-digest/src/fetch.ts +30 -3
  307. package/skills/pitch-deck/SKILL.md +36 -0
  308. package/skills/pitch-deck/template.html +80 -0
  309. package/skills/youtube-master/SKILL.md +163 -0
  310. package/skills/youtube-master/package-lock.json +558 -0
  311. package/skills/youtube-master/package.json +13 -0
  312. package/skills/youtube-master/references/study-note-template.md +124 -0
  313. package/skills/youtube-master/scripts/main.ts +435 -0
  314. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  315. package/skills/youtube-master/src/audio.ts +63 -0
  316. package/skills/youtube-master/src/domain-staging.ts +50 -0
  317. package/skills/youtube-master/src/env.ts +36 -0
  318. package/skills/youtube-master/src/obsidian.ts +155 -0
  319. package/skills/youtube-master/src/router.ts +110 -0
  320. package/skills/youtube-master/src/stt.ts +199 -0
  321. package/skills/youtube-master/src/study-note.ts +175 -0
  322. package/skills/youtube-master/src/summarize.ts +358 -0
  323. package/skills/youtube-master/src/transcript.ts +76 -0
  324. package/skills/youtube-master/src/types.ts +91 -0
  325. package/skills/youtube-master/src/util.ts +93 -0
  326. package/skills/youtube-master/src/youtube.ts +70 -0
  327. package/skills/youtube-master/tsconfig.json +13 -0
  328. package/src/acp/codex-approval-adapter.ts +9 -3
  329. package/src/acp/core-turn-bridge.ts +117 -18
  330. package/src/acp/fact-question.ts +11 -0
  331. package/src/acp/server.ts +53 -9
  332. package/src/acp/tool-approval.ts +126 -0
  333. package/src/acp/turn-runner.ts +36 -0
  334. package/src/agent/monad-agent-turn.ts +8 -0
  335. package/src/agent-mission/driver.ts +80 -10
  336. package/src/agent-mission/pty-decision.ts +71 -0
  337. package/src/agent-mission/review-loop.ts +30 -0
  338. package/src/ask-user-question/pending-questions.ts +25 -10
  339. package/src/ask-user-question/types.ts +9 -0
  340. package/src/auth/setup-link-tokens.ts +16 -5
  341. package/src/autopilot/build/integrity-gate.ts +12 -0
  342. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  343. package/src/autopilot/tool-registry.ts +2 -0
  344. package/src/boot/daemon-prompt-turn.ts +8 -0
  345. package/src/boot/daemon-runtime.ts +9 -3
  346. package/src/boot/daemon-tools/index.ts +8 -0
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/boot/daemon-tools/web-search.ts +4 -0
  349. package/src/card-followup/core.ts +109 -0
  350. package/src/chat/ctrl-c-in-input.ts +14 -0
  351. package/src/chat/index.ts +53 -0
  352. package/src/chat/pickers/state.ts +6 -2
  353. package/src/cli/agent-cli.ts +7 -0
  354. package/src/cli/decisions-cli.ts +25 -3
  355. package/src/cli/doctor-bundle-upload.ts +68 -0
  356. package/src/cli/doctor-cli.ts +38 -4
  357. package/src/cli/drive-input-jail.ts +101 -0
  358. package/src/cli/hooks-cli.ts +17 -3
  359. package/src/cli/make-cli.ts +43 -0
  360. package/src/cli/ops-cli.ts +20 -0
  361. package/src/cli/persona-cli.ts +90 -4
  362. package/src/cli/plugin-cli.ts +31 -22
  363. package/src/cli/pod-cli.ts +61 -2
  364. package/src/cli/pr-cli.ts +82 -17
  365. package/src/cli/pty-drive-cli.ts +41 -7
  366. package/src/cli/pty-drive-verdict.ts +40 -0
  367. package/src/cli/pwa-stop.ts +163 -13
  368. package/src/cli/pwa-test.ts +3 -0
  369. package/src/cli/release-cli.ts +80 -24
  370. package/src/cli/self-update.ts +14 -0
  371. package/src/cli/setup-cli.ts +43 -1
  372. package/src/cli/skills-cli.ts +17 -1
  373. package/src/cli/storyboard-cli.ts +37 -0
  374. package/src/cli/test-state-dir-flag.ts +11 -4
  375. package/src/connectors/linear.ts +146 -0
  376. package/src/context-bus/claude-hooks-install.ts +10 -0
  377. package/src/context-bus/context-now-surfaces.ts +48 -0
  378. package/src/context-bus/context-now.ts +104 -0
  379. package/src/context-bus/coord-events.ts +115 -0
  380. package/src/context-bus/external-events.ts +52 -0
  381. package/src/context-bus/long-term-memory.ts +108 -0
  382. package/src/dashboard/dashboard-boot-fixture.ts +23 -0
  383. package/src/dashboard/index.ts +63 -21
  384. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
  385. package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
  386. package/src/decisions/decision-cards.ts +58 -3
  387. package/src/decisions/decision-ledger.ts +85 -6
  388. package/src/decisions/decision-linear-projection.ts +157 -0
  389. package/src/decisions/web-push-decision-cards.ts +50 -0
  390. package/src/directive/interpretation-card.ts +36 -0
  391. package/src/discord/sprint21-runtime.ts +5 -1
  392. package/src/discord-self-message.ts +32 -0
  393. package/src/discord-slash-wire.ts +5 -1
  394. package/src/discord.ts +19 -2
  395. package/src/domains/coo-admin-tool.ts +62 -0
  396. package/src/domains/core-tools.ts +13 -4
  397. package/src/domains/elanous-card.ts +29 -0
  398. package/src/domains/ops-facts-tool.ts +76 -0
  399. package/src/domains/outbound-alert.ts +46 -13
  400. package/src/domains/release-tool.ts +168 -0
  401. package/src/domains/telegram-kind-route.ts +65 -9
  402. package/src/exec-requests/default-outputs.ts +25 -0
  403. package/src/exec-requests/planner.ts +106 -28
  404. package/src/exec-requests/runner.ts +123 -12
  405. package/src/exec-requests/store.ts +11 -2
  406. package/src/execution-loop/launch-gate.ts +100 -0
  407. package/src/field/field-media.ts +10 -7
  408. package/src/field/field-reel.ts +19 -5
  409. package/src/field-note/index.ts +201 -0
  410. package/src/field-note/transcribe.ts +248 -0
  411. package/src/git-fs/worktree.ts +45 -6
  412. package/src/graph-kinds/registry.ts +3 -3
  413. package/src/graph-runner/graph-approval-card.ts +113 -0
  414. package/src/graph-runner/graph-cli.ts +189 -4
  415. package/src/graph-runner/graph-grow-llm.ts +37 -0
  416. package/src/graph-runner/graph-grow.ts +47 -0
  417. package/src/graph-runner/graph-notify.ts +25 -3
  418. package/src/graph-runner/runner.ts +453 -35
  419. package/src/grok/agent-search.ts +8 -2
  420. package/src/guardian/secret-exposure-scan.ts +101 -0
  421. package/src/harness/browser-verify.ts +25 -2
  422. package/src/harness/harness-cli-command.ts +478 -42
  423. package/src/harness/harness-incidents-writer.fixture.ts +24 -0
  424. package/src/harness/harness-incidents.ts +129 -0
  425. package/src/harness/harness-pod-dispatch.ts +43 -23
  426. package/src/harness/harness-seams.ts +38 -4
  427. package/src/harness/harness-stop.ts +75 -6
  428. package/src/harness/launch-registry.ts +91 -0
  429. package/src/harness/process-garbage.ts +5 -3
  430. package/src/hitl/clarification-policy.ts +3 -1
  431. package/src/hooks/dispatch.ts +82 -0
  432. package/src/hooks/expose.ts +254 -0
  433. package/src/hooks/github-shadow.ts +108 -0
  434. package/src/hooks/providers.ts +71 -5
  435. package/src/hooks/queue.ts +1 -1
  436. package/src/hooks/receiver.ts +21 -20
  437. package/src/index.ts +206 -49
  438. package/src/intake-plane/author-goals.ts +37 -4
  439. package/src/intake-plane/categorize.ts +18 -46
  440. package/src/intake-plane/check.ts +3 -0
  441. package/src/intake-plane/discord-seat-work.ts +57 -2
  442. package/src/intake-plane/front-route-classifier.ts +33 -39
  443. package/src/intake-plane/persona-answer.ts +30 -0
  444. package/src/intake-plane/runtime-callables.ts +8 -1
  445. package/src/intake-plane/seat-doc-route.ts +170 -6
  446. package/src/intake-plane/telegram-seat-work.ts +80 -4
  447. package/src/intake-plane/telegram-work.ts +1 -0
  448. package/src/intake-plane/wish-folder.ts +67 -0
  449. package/src/intent-gate/gate.ts +30 -10
  450. package/src/live/detail-switch.ts +5 -0
  451. package/src/llm/difficulty.ts +57 -0
  452. package/src/llm/judge-layer.ts +101 -0
  453. package/src/llm/mission-router.ts +33 -19
  454. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  455. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  456. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  457. package/src/loops/contract/loop-agent.schema.json +138 -0
  458. package/src/loops/contract/validate.ts +64 -0
  459. package/src/loops/registry.ts +20 -6
  460. package/src/market/signed-index.ts +4 -0
  461. package/src/maturity/bot-command-maturity.ts +45 -0
  462. package/src/maturity/cli-maturity.ts +34 -0
  463. package/src/maturity/feature-maturity.ts +120 -1
  464. package/src/maturity/tui-slash-maturity.ts +31 -0
  465. package/src/memory.ts +32 -4
  466. package/src/model-tier/index.ts +2 -2
  467. package/src/model-tier/tier-resolver.ts +20 -20
  468. package/src/model-tier/types.ts +6 -6
  469. package/src/mss/logging/log-store.ts +15 -0
  470. package/src/nexus/api/config-model-tier.ts +5 -4
  471. package/src/nexus/api/exec-requests.ts +33 -3
  472. package/src/nexus/api/fabric-plans.ts +53 -0
  473. package/src/nexus/api/harness-api.ts +5 -1
  474. package/src/nexus/api/health.ts +2 -0
  475. package/src/nexus/api/http-server.ts +89 -1
  476. package/src/nexus/api/inside-events.ts +226 -0
  477. package/src/nexus/api/meta-api.ts +32 -8
  478. package/src/nexus/api/missions.ts +6 -1
  479. package/src/nexus/api/ops-api.ts +10 -1
  480. package/src/nexus/api/ops-seats-sources.ts +37 -7
  481. package/src/nexus/api/ops-seats.ts +49 -6
  482. package/src/nexus/api/outputs-route.ts +44 -0
  483. package/src/nexus/api/seat-requests.ts +132 -10
  484. package/src/nexus/api/sessions-store.ts +42 -0
  485. package/src/nexus/api/setup-codex-login.ts +160 -0
  486. package/src/nexus/api/sub-seat-charters.ts +34 -0
  487. package/src/nexus/api/tabs-mutations.ts +3 -1
  488. package/src/nexus/api/trace.ts +18 -6
  489. package/src/nexus/api/usage-api.ts +102 -0
  490. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  491. package/src/nexus/api/workflows.ts +80 -6
  492. package/src/nexus/index.ts +47 -4
  493. package/src/nexus/kinds/webterm.ts +2 -1
  494. package/src/nexus/webterm/pty.ts +6 -2
  495. package/src/onboarding/cli-auth-status.ts +80 -0
  496. package/src/onboarding/first-run.ts +89 -0
  497. package/src/onboarding/lan-address.ts +45 -0
  498. package/src/onboarding/voice-ai.ts +3 -3
  499. package/src/onboarding/web-first.ts +119 -24
  500. package/src/onboarding.ts +4 -0
  501. package/src/ops-now/ops-now-refresh.ts +100 -0
  502. package/src/org/seat-budget.ts +48 -0
  503. package/src/org/stall-escalation.ts +63 -0
  504. package/src/outputs/ledger.ts +120 -0
  505. package/src/persona/persona-todo.ts +79 -0
  506. package/src/persona/presets.ts +116 -2
  507. package/src/persona/team-set.ts +155 -0
  508. package/src/plugins/install/plugin-install.ts +14 -0
  509. package/src/plugins/maker/market-bundle.ts +109 -0
  510. package/src/plugins/maker/plugin-maker.ts +254 -11
  511. package/src/plugins/maker/wizard-generate.ts +103 -0
  512. package/src/pod-lease/admission.ts +150 -0
  513. package/src/pod-lease/dependency-state.ts +85 -0
  514. package/src/pod-lease/host-lease.ts +127 -0
  515. package/src/project/project-store.ts +115 -0
  516. package/src/project/project-suggestion.ts +16 -0
  517. package/src/project/session-context.ts +24 -0
  518. package/src/release-loop/checklist.ts +79 -5
  519. package/src/release-loop/feature-store.ts +159 -24
  520. package/src/release-loop/next-md-merge.ts +58 -0
  521. package/src/release-loop/release-note.ts +59 -4
  522. package/src/release-loop/release-schedule.ts +53 -0
  523. package/src/repl/index.ts +7 -0
  524. package/src/seat-dispatch/ceo-commands.ts +41 -8
  525. package/src/seat-dispatch/ceo-intent.ts +38 -0
  526. package/src/seat-dispatch/seat-ask.ts +130 -0
  527. package/src/seat-dispatch/seat-questions.ts +100 -0
  528. package/src/seat-loop/seat-loop.ts +750 -0
  529. package/src/seat-loop/seat-report.ts +99 -0
  530. package/src/self-dev/decompose.ts +66 -11
  531. package/src/self-dev/dev-cli.ts +4 -1
  532. package/src/self-dev/dev-pipeline.ts +37 -1
  533. package/src/self-dev/draft-sweep.ts +38 -33
  534. package/src/self-dev/draft-triage-rules.ts +8 -5
  535. package/src/self-dev/fabric-plan-core.ts +297 -0
  536. package/src/self-dev/orchestrate.ts +36 -4
  537. package/src/self-dev/release-path-guard.ts +62 -0
  538. package/src/self-dev/run-store.ts +10 -1
  539. package/src/self-dev/shard-aggregate.ts +230 -0
  540. package/src/self-dev/shard-placement.ts +60 -0
  541. package/src/self-dev/shard-plan.ts +48 -0
  542. package/src/self-dev/shard-pod-run.ts +77 -0
  543. package/src/self-dev/shard-run.ts +105 -0
  544. package/src/self-implement/execution-clarification.ts +115 -0
  545. package/src/self-implement/gate-baseline.ts +1 -1
  546. package/src/self-implement/gate-cli.ts +46 -4
  547. package/src/self-implement/gate-scope.ts +37 -7
  548. package/src/self-implement/graph-variant.ts +171 -0
  549. package/src/self-implement/harness-policy-gates.ts +1 -1
  550. package/src/self-implement/headless-elanous-driver.ts +22 -3
  551. package/src/self-implement/host-regate.ts +22 -1
  552. package/src/self-implement/importer-test-index.ts +2 -1
  553. package/src/self-implement/l8-merge-queue.ts +130 -0
  554. package/src/self-implement/orchestrator.ts +279 -12
  555. package/src/self-implement/pipeline-shape.ts +1 -1
  556. package/src/self-implement/route-consumer-test-index.ts +122 -0
  557. package/src/self-implement/run-status-mapping.ts +5 -3
  558. package/src/self-implement/seams.ts +72 -11
  559. package/src/self-implement/test-seams.ts +1 -0
  560. package/src/self-implement/uncommitted-work.ts +59 -0
  561. package/src/session/chat.ts +2 -0
  562. package/src/session/index.ts +45 -13
  563. package/src/shell-env-bootstrap.ts +17 -0
  564. package/src/skills/gift-install.ts +215 -0
  565. package/src/skills/tools/web-search.ts +4 -1
  566. package/src/steward/directive.ts +51 -2
  567. package/src/steward/launch.ts +266 -0
  568. package/src/steward/outcome-notify.ts +115 -0
  569. package/src/steward/steward-cards.ts +25 -11
  570. package/src/steward/triage-plan.ts +32 -4
  571. package/src/steward/triage.ts +129 -13
  572. package/src/steward/working-backwards.ts +64 -0
  573. package/src/storyboard/storyboard.ts +141 -0
  574. package/src/task-cards/card-cli.ts +25 -1
  575. package/src/task-cards/card-store.ts +2 -2
  576. package/src/task-orchestrator/mission.ts +5 -0
  577. package/src/task-orchestrator/store.ts +12 -3
  578. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  579. package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
  580. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  581. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  582. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  583. package/src/task-orchestrator/types.ts +2 -0
  584. package/src/telegram-card-followup.ts +153 -0
  585. package/src/telegram-commands.ts +10 -1
  586. package/src/telegram-project-command.ts +71 -0
  587. package/src/telegram-report.ts +29 -19
  588. package/src/telegram-run.ts +7 -0
  589. package/src/telegram.ts +58 -11
  590. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  591. package/src/tool-runtime/types.ts +4 -0
  592. package/src/tui-client/dashboard-session.ts +2 -0
  593. package/src/user-config.ts +216 -27
  594. package/src/version/packed-revision.json +1 -1
  595. package/src/web-push/notify-exec-request.ts +32 -0
  596. package/src/web-search/grok.ts +7 -1
  597. package/src/web-search/index.ts +28 -1
  598. package/src/web-search/provider.ts +4 -0
  599. package/src/web-search/x-intent.ts +5 -0
  600. package/src/workflow-runtime/executor.ts +277 -47
  601. package/src/workflow-runtime/index.ts +1 -0
  602. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  603. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  604. package/src/workflow-runtime/schema.ts +79 -4
  605. package/src/workflow-runtime/types.ts +35 -4
  606. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  617. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  618. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
  622. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  692. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
  693. package/src/dashboard/turn-typeahead-echo.ts +0 -23
  694. /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "."
11
+ },
12
+ "include": ["src/**/*.ts", "scripts/**/*.ts"]
13
+ }
@@ -103,6 +103,12 @@ export interface CodexApprovalAdapter {
103
103
  onMcpToolCall(req: CodexMcpToolCallRequest): Promise<CodexApprovalDecision>;
104
104
  }
105
105
 
106
+ /** The 3-way approval question's id and labels — exported so a surface that
107
+ * answers approvals by yes/no (an ACP turn's client) can recognise it. */
108
+ export const CODEX_APPROVAL_QUESTION_ID = 'codex_approval';
109
+ export const CODEX_APPROVAL_OPT_ONCE = 'Allow once';
110
+ export const CODEX_APPROVAL_OPT_REJECT = 'Reject';
111
+
106
112
  /** Build a CodexApprovalAdapter. Intentionally minimal in Phase 3.A —
107
113
  * the handlers degrade gracefully when no approver is attached, and
108
114
  * the Phase 3.B app-server client will hook these methods up with real
@@ -131,10 +137,10 @@ export function createCodexApprovalAdapter(
131
137
  // multi-option question path is used. "Allow for session" maps to codex
132
138
  // `acceptForSession` so the sub-agent stops re-prompting for the rest of
133
139
  // the run.
134
- const OPT_ONCE = 'Allow once';
140
+ const OPT_ONCE = CODEX_APPROVAL_OPT_ONCE;
135
141
  const OPT_SESSION = 'Allow for session';
136
- const OPT_REJECT = 'Reject';
137
- const APPROVAL_QID = 'codex_approval';
142
+ const OPT_REJECT = CODEX_APPROVAL_OPT_REJECT;
143
+ const APPROVAL_QID = CODEX_APPROVAL_QUESTION_ID;
138
144
 
139
145
  /** Ask the user via the MULTI-OPTION question channel: Allow once /
140
146
  * Allow for session / Reject. Returns the scoped decision. Only called
@@ -46,7 +46,11 @@ import { getUserConfig } from '../user-config.js';
46
46
  import { getModelFamily } from '../models/prompts.js';
47
47
  import { resolveModelContextWindow } from '../models/context-window.js';
48
48
  import type { AcpServerOptions, AcpTurnContext } from './server.js';
49
+ import { acpToolDenialResult } from './tool-approval.js';
49
50
  import { readOriginSessionMeta } from './origin-session-meta.js';
51
+ import { isFactQuestion } from './fact-question.js';
52
+
53
+ const FACT_QUESTION_INSTRUCTION = '사실·최신 정보 질문이다. WebSearch 를 1~2회 쓰고 검색 결과(제목·스니펫·URL)로 답하라. 출처 링크를 붙여라. 셸·브라우저·파일 도구는 검색 결과로 부족할 때만. 도구 예산에 닿으면 지금까지 근거로 답하고 끝에 «더 찾아볼까요?»를 붙여라.';
50
54
 
51
55
  export interface CoreTurnBridgeDeps {
52
56
  /** Build the seed message list for this ACP prompt. Implementations
@@ -112,6 +116,28 @@ export interface CoreTurnBridgeDeps {
112
116
  * pegging the event loop. */
113
117
  export const DEFAULT_BRIDGE_ABORT_POLL_MS = 50;
114
118
 
119
+ /** PCH-2b — ask the ACP client before a write/shell tool runs. A denied,
120
+ * cancelled or timed-out tool is not run; the LLM gets a «not run» result. */
121
+ export function acpApprovalGatedDispatch(
122
+ turnCtx: AcpTurnContext,
123
+ dispatchTool: CoreTurnDispatchTool,
124
+ signal: AbortSignal,
125
+ ): CoreTurnDispatchTool {
126
+ const approveTool = turnCtx.approveTool;
127
+ if (!approveTool) return dispatchTool;
128
+ return async (name, args, dispatchCtx) => {
129
+ if (signal.aborted || turnCtx.isAborted()) return acpToolDenialResult(name, 'cancelled');
130
+ const approval = await approveTool({
131
+ toolCallId: dispatchCtx?.callId ?? `${name}-${Date.now().toString(36)}`,
132
+ toolName: name,
133
+ toolArgs: args,
134
+ });
135
+ if (!approval.allowed) return acpToolDenialResult(name, approval.reason);
136
+ if (signal.aborted || turnCtx.isAborted()) return acpToolDenialResult(name, 'cancelled');
137
+ return dispatchTool(name, args, dispatchCtx);
138
+ };
139
+ }
140
+
115
141
  /** Extract the trailing assistant message text from runCoreTurn's
116
142
  * `newMessages` array. emitTurnComplete (src/llm.ts:3835) appends
117
143
  * `{role:'assistant', content:[{type:'text', text:finalAssistantText}]}`
@@ -173,7 +199,23 @@ export function bridgeCoreTurnToAcp(
173
199
  }),
174
200
  );
175
201
  const modelOverride = deps.resolveModel?.({ sessionId: turnCtx.sessionId, userText: turnCtx.userText });
176
- const maxToolTurns = deps.resolveMaxToolTurns?.({ sessionId: turnCtx.sessionId });
202
+ const factQuestion = isFactQuestion(turnCtx.userText);
203
+ const explicitMaxToolTurns = deps.resolveMaxToolTurns?.({ sessionId: turnCtx.sessionId });
204
+ const maxToolTurns = explicitMaxToolTurns ?? (factQuestion ? getUserConfig().chat.factQuestion.maxToolTurns : undefined);
205
+ const turnMessages: LLMMessage[] = factQuestion
206
+ ? [{ role: 'system', content: FACT_QUESTION_INSTRUCTION }, ...messages]
207
+ : messages;
208
+ let toolCallCount = 0;
209
+ const toolKinds = new Set<string>();
210
+ const observeToolBudget = () => {
211
+ try {
212
+ debug.log('chat.turn', 'tool-budget', {
213
+ factQuestion, maxToolTurns: maxToolTurns ?? null,
214
+ count: toolCallCount, kinds: [...toolKinds],
215
+ });
216
+ } catch { /* observation cannot interrupt a turn */ }
217
+ };
218
+ observeToolBudget();
177
219
 
178
220
  // 2026-05-03 PM++ — Track streamed text so onTurnComplete can
179
221
  // detect runtime-injected synthesis (W5-E/W5-F/W5-G) and surface
@@ -235,17 +277,29 @@ export function bridgeCoreTurnToAcp(
235
277
  } catch {
236
278
  // Observability must not prevent the turn from reaching its dispatcher.
237
279
  }
280
+ const approvedDispatch = acpApprovalGatedDispatch(turnCtx, deps.dispatchTool, ctrl.signal);
281
+ const dispatchTool: CoreTurnDispatchTool = factQuestion && maxToolTurns !== undefined && maxToolTurns > 0
282
+ ? async (name, args, dispatchCtx) => {
283
+ if (toolCallCount >= maxToolTurns) {
284
+ return { error: 'Tool budget reached. Answer using the evidence already collected.' };
285
+ }
286
+ toolCallCount += 1;
287
+ toolKinds.add(name);
288
+ observeToolBudget();
289
+ return approvedDispatch(name, args, dispatchCtx);
290
+ }
291
+ : approvedDispatch;
238
292
  await runTurnDispatch({
239
293
  sessionId: turnCtx.sessionId,
240
294
  ...(originSessionId ? { originSessionId } : {}),
241
295
  ...(turnCtx.userText ? { userText: turnCtx.userText } : {}),
242
- messages,
296
+ messages: turnMessages,
243
297
  tools,
244
- dispatchTool: deps.dispatchTool,
298
+ dispatchTool,
245
299
  signal: ctrl.signal,
246
300
  ...(modelOverride !== undefined ? { modelOverride } : {}),
247
301
  ...(maxToolTurns !== undefined ? { maxToolTurns } : {}),
248
- ...(deps.budgetGrant !== undefined ? { budgetGrant: deps.budgetGrant } : {}),
302
+ ...((!factQuestion || explicitMaxToolTurns !== undefined) && deps.budgetGrant !== undefined ? { budgetGrant: deps.budgetGrant } : {}),
249
303
  callbacks: {
250
304
  onText: (delta) => {
251
305
  // Fire-and-forget: ACP `push` is async but the core-turn
@@ -262,7 +316,14 @@ export function bridgeCoreTurnToAcp(
262
316
  // callers see today. Fire-and-forget for the same reason
263
317
  // onText is: callbacks are synchronous, `turnCtx.push*` is
264
318
  // async, ordering is preserved by the SDK.
265
- onToolCall: (call) => { void turnCtx.pushToolCall(call); },
319
+ onToolCall: (call) => {
320
+ if (!factQuestion || maxToolTurns === undefined || maxToolTurns <= 0) {
321
+ toolCallCount += 1;
322
+ toolKinds.add(call.name);
323
+ observeToolBudget();
324
+ }
325
+ void turnCtx.pushToolCall(call);
326
+ },
266
327
  onToolResult: (call) => { void turnCtx.pushToolResult(call); },
267
328
  onUsage: (usage) => { void turnCtx.pushUsage(usage); },
268
329
  // Codex Responses API reasoning summary stream. Currently
@@ -301,26 +362,64 @@ export function bridgeCoreTurnToAcp(
301
362
  // re-emit would cause the "displayed then deleted then
302
363
  // re-displayed" flicker the user reported.
303
364
  const finalAssistantText = extractLastAssistantText(newMessages);
304
- const synthesisAlreadyStreamed =
305
- finalAssistantText !== null
306
- && finalAssistantText.length > 0
365
+ const budgetReached = factQuestion && maxToolTurns !== undefined
366
+ && maxToolTurns > 0 && toolCallCount >= maxToolTurns;
367
+ const followup = '더 찾아볼까요?';
368
+ const needsFollowup = budgetReached && finalAssistantText !== null
369
+ && finalAssistantText.trim().length > 0
370
+ && !finalAssistantText.trimEnd().endsWith(followup);
371
+ let lastAssistantIndex = -1;
372
+ for (let i = newMessages.length - 1; i >= 0; i--) {
373
+ if (newMessages[i]?.role === 'assistant') { lastAssistantIndex = i; break; }
374
+ }
375
+ const followupSuffix = `\n${followup}`;
376
+ const completedMessages: LLMMessage[] = needsFollowup
377
+ ? newMessages.map((message, index) => {
378
+ if (index !== lastAssistantIndex) return message;
379
+ if (typeof message.content === 'string') {
380
+ return { ...message, content: message.content + followupSuffix };
381
+ }
382
+ if (Array.isArray(message.content)) {
383
+ let lastTextIndex = -1;
384
+ for (let blockIndex = message.content.length - 1; blockIndex >= 0; blockIndex--) {
385
+ if (message.content[blockIndex]?.type === 'text') { lastTextIndex = blockIndex; break; }
386
+ }
387
+ if (lastTextIndex >= 0) {
388
+ return { ...message, content: message.content.map((block, blockIndex) =>
389
+ blockIndex === lastTextIndex && block.type === 'text'
390
+ ? { ...block, text: block.text + followupSuffix }
391
+ : block) };
392
+ }
393
+ }
394
+ return message;
395
+ })
396
+ : newMessages;
397
+ const visibleFinalText = needsFollowup ? extractLastAssistantText(completedMessages) : finalAssistantText;
398
+ const originalFinalStreamed = needsFollowup && finalAssistantText !== null
307
399
  && streamedTextSum.endsWith(finalAssistantText);
400
+ const synthesisAlreadyStreamed =
401
+ visibleFinalText !== null
402
+ && visibleFinalText.length > 0
403
+ && streamedTextSum.endsWith(visibleFinalText);
308
404
  const needsReSurface =
309
- finalAssistantText !== null
310
- && finalAssistantText !== streamedTextSum
311
- && !synthesisAlreadyStreamed;
312
- if (debug.enabled && finalAssistantText !== null) {
405
+ visibleFinalText !== null
406
+ && visibleFinalText !== streamedTextSum
407
+ && !synthesisAlreadyStreamed
408
+ && !originalFinalStreamed;
409
+ if (debug.enabled && visibleFinalText !== null) {
313
410
  debug.log('llm.synthesis-surface', 'acp-bridge.surface-final-text', {
314
411
  streamedChars: streamedTextSum.length,
315
- finalChars: finalAssistantText.length,
316
- delta: finalAssistantText.length - streamedTextSum.length,
412
+ finalChars: visibleFinalText.length,
413
+ delta: visibleFinalText.length - streamedTextSum.length,
317
414
  startsWithStreamed: streamedTextSum.length > 0
318
- && finalAssistantText.startsWith(streamedTextSum),
415
+ && visibleFinalText.startsWith(streamedTextSum),
319
416
  endsWithStreamedTail: synthesisAlreadyStreamed,
320
417
  needsReSurface,
321
418
  });
322
419
  }
323
- if (needsReSurface) {
420
+ if (originalFinalStreamed) {
421
+ void turnCtx.push(followupSuffix);
422
+ } else if (needsReSurface) {
324
423
  // Emit a clear-then-replace pair so clients that follow
325
424
  // the empty-chunk-as-clear convention (dashboard plain
326
425
  // chat) reset their per-round buffer before receiving
@@ -329,12 +428,12 @@ export function bridgeCoreTurnToAcp(
329
428
  // would only have the new finalAssistantText delta to
330
429
  // work with anyway).
331
430
  void turnCtx.push('');
332
- void turnCtx.push(finalAssistantText!);
431
+ void turnCtx.push(visibleFinalText!);
333
432
  }
334
433
  if (deps.onTurnComplete) {
335
434
  await deps.onTurnComplete({
336
435
  sessionId: turnCtx.sessionId,
337
- newMessages,
436
+ newMessages: completedMessages,
338
437
  });
339
438
  }
340
439
  },
@@ -0,0 +1,11 @@
1
+ export function isFactQuestion(userText: string): boolean {
2
+ const text = userText.trim();
3
+ if (!text || text.length > 120 || /[\r\n]/.test(text)) return false;
4
+ if (/`|\bsrc\/|(?:^|[\s/])[^\s/]+\.(?:ts|tsx|js|jsx|json|md|py|sh|yaml|yml)\b|고쳐|구현|실행|만들어|수정|디버그|파일|읽어|열어|저장|작성|삭제|편집|검색해|찾아줘|보여줘|\/cc\b|delegate_code_agent/i.test(text)) return false;
5
+ // A request («…해줘?», «재시작해», «restart …») is work, not a fact question — even with a «?» or «지금»(round 3: «지금 서버를 재시작해줘?»).
6
+ const request = text.replace(/알려\s*(?:줘|주세요|줄래|주실래요)[??]?$/, '');
7
+ if (/(?:해|해\s*줘|해\s*주세요|하세요|해라|하자|줘|주세요|줄래|주실래요|봐|봐줘)[??]?$/.test(request)) return false;
8
+ if (/재시작|시작|중지|멈춰|꺼|켜|설치|배포|돌려|보내|올려|지워|바꿔|추가|업데이트|재부팅|재실행|정리|등록|\b(?:restart|start|stop|run|install|deploy|delete|remove|create|update|fix|kill|reboot)\b/i.test(text)) return false;
9
+ if (!/[??]$|(?:뭐야|무엇인가요|인가요|나요|입니까|얼마야|언제야|누구야|알려줘|알려주세요)$/.test(text)) return false;
10
+ return /최근|최신|지금|현재|몇|언제|누가|누구|얼마|가격|버전|출시|최저시급|\b(?:latest|current|when|who|how many|how much|price|version|release)\b/i.test(text);
11
+ }
package/src/acp/server.ts CHANGED
@@ -101,6 +101,8 @@ import { readOriginSessionMeta } from './origin-session-meta.js';
101
101
  import type { CodexPlugin } from './codex-plugins.js';
102
102
  import { flattenMcpServersToCodexConfig } from './codex-approval-adapter.js';
103
103
  import { runAcpTurn } from './turn-runner.js';
104
+ import type { AcpPermissionApprovalRequest } from './client.js';
105
+ import { createAcpSessionApprovalPolicy, type AcpToolApprovalResult } from './tool-approval.js';
104
106
  import { projectPwaToolResult, type ToolResultMeta } from '../nexus/api/meta-api.js';
105
107
  import type { LlmBrand } from '../llm-vision-capability.js';
106
108
  import {
@@ -233,9 +235,14 @@ export interface AcpServerOptions {
233
235
  * receives the user message text and a push() for streaming back
234
236
  * assistant chunks. When omitted, the server echoes the prompt. */
235
237
  runTurn?: (ctx: AcpTurnContext) => Promise<void>;
238
+ /** PCH-2b — ask the client before write/shell tools run ('ask', default).
239
+ * 'off' keeps the host's own approvals (the in-process TUI dashboard). */
240
+ toolApproval?: 'ask' | 'off';
236
241
  /** ACP standalone entry: require session cwd or an explicit boot default. */
237
242
  requireSessionToolCwd?: boolean;
238
243
  bootToolCwd?: string;
244
+ /** Optional PTY factory for the web terminal; production uses PreviewTerminal. */
245
+ createWebTerminal?: (opts: ConstructorParameters<typeof import('../preview/terminal.js').PreviewTerminal>[0]) => import('../preview/terminal.js').PreviewTerminal;
239
246
  /** Test seam for exercising stdio EOF with controlled byte streams. */
240
247
  stdioInput?: ReadableStream<Uint8Array>;
241
248
  stdioOutput?: WritableStream<Uint8Array>;
@@ -850,6 +857,8 @@ export interface AcpTurnContext {
850
857
  toolArgs?: Record<string, unknown>;
851
858
  timeoutMs?: number;
852
859
  }) => Promise<AcpApprovalDecision>;
860
+ /** The session-scoped gate used by core-turn tool dispatchers. */
861
+ approveTool?: (req: Parameters<AcpTurnContext['requestApproval']>[0]) => Promise<AcpToolApprovalResult>;
853
862
  }
854
863
 
855
864
  /** F1 — Phase 3 · resolved decision from `AcpTurnContext.requestApproval`.
@@ -866,6 +875,14 @@ export type AcpApprovalDecision =
866
875
  * `_PERMISSION_DEFAULT_TIMEOUT_S`; overrideable per call. */
867
876
  export const DEFAULT_APPROVAL_TIMEOUT_MS = 60_000;
868
877
 
878
+ export {
879
+ acpToolDenialResult,
880
+ createAcpSessionApprovalPolicy,
881
+ requiresAcpToolApproval,
882
+ type AcpToolApprovalResult,
883
+ type AcpToolDenialReason,
884
+ } from './tool-approval.js';
885
+
869
886
  /** ACP streaming Phase E (PLAN-pwa-webterm-voice-control v1.2 · 2026-05-07) —
870
887
  * module-level handle to the broadcaster owned by the active runAcpServer
871
888
  * instance. The chat REST handler (`src/nexus/api/meta-api.ts handlePromptStreamPost`)
@@ -991,6 +1008,7 @@ interface AcpServerContext {
991
1008
  /** One skip diagnostic per session, cleared when its last peer leaves. */
992
1009
  plainEnvelopeLogged: Set<string>;
993
1010
  dualRole: DualRoleManager;
1011
+ approvalPolicy: ReturnType<typeof createAcpSessionApprovalPolicy>;
994
1012
  /** Mints the unique suffix of a new session id. Injected so tests can
995
1013
  * pin it deterministically — production wires `mintAcpSessionToken`. */
996
1014
  nextSessionToken: () => string;
@@ -1054,7 +1072,7 @@ function wireAcpConnection(
1054
1072
  stream: ReturnType<typeof ndJsonStream>,
1055
1073
  ctx: AcpServerContext,
1056
1074
  ): AgentSideConnection {
1057
- const { sessions, sessionPeers, awarePeers, plainEnvelopeLogged, dualRole, opts } = ctx;
1075
+ const { sessions, sessionPeers, awarePeers, plainEnvelopeLogged, dualRole, approvalPolicy, opts } = ctx;
1058
1076
  // 2026-05-13 (M2 of AskUserQuestion cross-surface) — bound connection
1059
1077
  // widened to expose `extMethod` + `extNotification` (SDK's elanous
1060
1078
  // extension escape hatch). pushAskRequest / pushAskCancel route through
@@ -1771,7 +1789,9 @@ function wireAcpConnection(
1771
1789
  );
1772
1790
  };
1773
1791
  const requestApproval: AcpTurnContext['requestApproval'] = async (approvalReq) => {
1774
- const timeoutMs = approvalReq.timeoutMs ?? DEFAULT_APPROVAL_TIMEOUT_MS;
1792
+ const timeoutMs = approvalReq.timeoutMs
1793
+ ?? (await import('../user-config.js')).getUserConfig().acp.toolApproval?.timeoutMs
1794
+ ?? DEFAULT_APPROVAL_TIMEOUT_MS;
1775
1795
  const optionBase = `${approvalReq.toolCallId}-`;
1776
1796
  const options = [
1777
1797
  { optionId: `${optionBase}allow-once`, name: 'Allow once', kind: 'allow_once' as const },
@@ -1787,6 +1807,8 @@ function wireAcpConnection(
1787
1807
  },
1788
1808
  options,
1789
1809
  });
1810
+ // A late rejection after the timeout won the race must not go unhandled.
1811
+ permissionPromise.catch(() => undefined);
1790
1812
  let timer: ReturnType<typeof setTimeout> | null = null;
1791
1813
  const timeoutPromise = new Promise<'timeout'>((resolve) => {
1792
1814
  timer = setTimeout(() => resolve('timeout'), timeoutMs);
@@ -1972,6 +1994,7 @@ function wireAcpConnection(
1972
1994
  }
1973
1995
  }
1974
1996
 
1997
+ const rejectedThisTurn = new Set<string>();
1975
1998
  const turnCtx: AcpTurnContext = {
1976
1999
  sessionId: req.sessionId,
1977
2000
  cwd: s.cwd,
@@ -1987,6 +2010,10 @@ function wireAcpConnection(
1987
2010
  pushSessionUpdate,
1988
2011
  pushUsage,
1989
2012
  requestApproval,
2013
+ ...(opts.toolApproval !== 'off'
2014
+ ? { approveTool: (approvalReq: Parameters<AcpTurnContext['requestApproval']>[0]) =>
2015
+ approvalPolicy.resolve(req.sessionId, approvalReq, requestApproval, rejectedThisTurn) }
2016
+ : {}),
1990
2017
  };
1991
2018
 
1992
2019
  // RC — intercept hook runs first. Lets the host treat the
@@ -2020,6 +2047,20 @@ function wireAcpConnection(
2020
2047
  chatId: req.sessionId,
2021
2048
  cwd: s.cwd,
2022
2049
  codexArgs: s.codexArgs,
2050
+ ...(turnCtx.approveTool ? {
2051
+ // PCH-2b — codex asks this turn's ACP client instead of auto-approving.
2052
+ permissionApprover: async (approvalReq: AcpPermissionApprovalRequest) => {
2053
+ if (s.aborted) return false;
2054
+ const decision = await turnCtx.approveTool!({
2055
+ toolCallId: `codex-${randomBytes(6).toString('hex')}`,
2056
+ // «codex exec» · «codex network» · «codex mcp» — allow-always is per kind.
2057
+ toolName: /^codex [a-z]+/.exec(approvalReq.title)?.[0] ?? `codex ${approvalReq.kind ?? 'action'}`,
2058
+ ...(approvalReq.rawInput && typeof approvalReq.rawInput === 'object' && !Array.isArray(approvalReq.rawInput)
2059
+ ? { toolArgs: approvalReq.rawInput as Record<string, unknown> } : {}),
2060
+ });
2061
+ return decision.allowed && !s.aborted;
2062
+ },
2063
+ } : {}),
2023
2064
  streamer: { edit: (text) => { void push(text); } },
2024
2065
  });
2025
2066
  } else if (opts.runTurn) {
@@ -2151,7 +2192,8 @@ function wireAcpConnection(
2151
2192
  throw new Error('terminal/spawn: sessionId required');
2152
2193
  }
2153
2194
  const tid = resolveAcpTerminalId(p.terminalId);
2154
- const cwd = typeof p.cwd === 'string' && p.cwd.length > 0 ? p.cwd : process.cwd();
2195
+ const cwd = typeof p.cwd === 'string' && p.cwd.length > 0 ? p.cwd
2196
+ : (await import('../project/session-context.js')).resolveSessionProjectContext(p.sessionId)?.cwd ?? process.cwd();
2155
2197
  const cols = typeof p.cols === 'number' && p.cols > 0 ? p.cols : 80;
2156
2198
  const rows = typeof p.rows === 'number' && p.rows > 0 ? p.rows : 24;
2157
2199
 
@@ -2169,8 +2211,8 @@ function wireAcpConnection(
2169
2211
  const adopted = matches.find((match) => match.pt.isAlive);
2170
2212
  const existing = sameSession?.isAlive ? sameSession : adopted?.pt;
2171
2213
  if (existing) {
2214
+ registerPreviewTerminalForWebTap(existing, p.sessionId, tid, handle);
2172
2215
  if (existing !== sameSession && adopted) {
2173
- registerPreviewTerminalForWebTap(existing, p.sessionId, tid, handle);
2174
2216
  debug.log('webterm.acp', 'spawn.adopt', {
2175
2217
  terminalId: tid, fromSessions: adopted.sessionIds, toSession: p.sessionId,
2176
2218
  });
@@ -2195,7 +2237,7 @@ function wireAcpConnection(
2195
2237
  }
2196
2238
 
2197
2239
  const { PreviewTerminal } = await import('../preview/terminal.js');
2198
- const pt = new PreviewTerminal({
2240
+ const pt = (opts.createWebTerminal ?? ((terminalOpts) => new PreviewTerminal(terminalOpts)))({
2199
2241
  cols, rows, cwd,
2200
2242
  // Web-terminal child shell renders inside the PWA's xterm.js,
2201
2243
  // which implements the xterm-256color terminfo. When the daemon
@@ -2207,10 +2249,10 @@ function wireAcpConnection(
2207
2249
  // appear duplicated. Pinning TERM to xterm-256color matches
2208
2250
  // the actual rendering surface and makes the redraws idempotent.
2209
2251
  termName: 'xterm-256color',
2210
- // ★ P0b-2 (실행 substrate 통합·기본 off) — 이 진짜 PWA/iOS 라이브 셸을 공유 registry 버스로
2211
- // 흡수(정체성·크로스서피스 goto·3-스택 통합). 라이브 렌더(yazi/마우스/커서/alt-screen) 검증이
2212
- // 기기 왕복을 요하므로 per-run env 로만 켠다(대표가 별도 부팅해 수습). 미설정=기존 dup-fd(무회귀).
2213
- useRegistry: process.env.ELANOUS_PREVIEW_TERMINAL_REGISTRY === '1',
2252
+ // The shared PTY bus delivers output to PreviewTerminal's headless
2253
+ // renderer and ACP taps. The direct /dev/fd duplicate can observe
2254
+ // shell exit without ever reading its prompt (black web terminal).
2255
+ useRegistry: true,
2214
2256
  ...(typeof p.shell === 'string' && p.shell.length > 0 ? { shell: p.shell } : {}),
2215
2257
  onExit: () => {
2216
2258
  void import('../web-terminal/preview-tap-registry.js')
@@ -3343,6 +3385,7 @@ function wireAcpConnection(
3343
3385
  if (remaining === 0) {
3344
3386
  sessionPeers.delete(sid);
3345
3387
  plainEnvelopeLogged.delete(sid);
3388
+ approvalPolicy.clearSession(sid);
3346
3389
  }
3347
3390
  if (debug.enabled) {
3348
3391
  debug.log('acp.peer.unregister', sid, { remainingPeers: remaining });
@@ -3487,6 +3530,7 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
3487
3530
  awarePeers,
3488
3531
  plainEnvelopeLogged,
3489
3532
  dualRole,
3533
+ approvalPolicy: createAcpSessionApprovalPolicy(),
3490
3534
  nextSessionToken: mintAcpSessionToken,
3491
3535
  agentName: opts.agentName ?? 'elanous-agent',
3492
3536
  agentVersion: opts.agentVersion ?? readPkgVersion(),
@@ -0,0 +1,126 @@
1
+ // PCH-2b (0.2.10 · security D-20261002-08) — ACP turns ask the client before
2
+ // write/shell tools run; «allow always» is remembered per session and tool.
3
+ // Goal: 내부 문서 `ASK-pwa-chat-turns-run-write-and-shell-tools-without-approval-2026-10-02`
4
+ import { debug } from '../debug/log.js';
5
+ import type { AcpApprovalDecision, AcpTurnContext } from './server.js';
6
+
7
+ /** PCH-2b — tools that write files or run shell commands. ACP turns (PWA·iOS·
8
+ * remote TUI) ask the client before these run; everything else runs as before.
9
+ * One list, here, because the daemon catalog has no read-only/mutating flag. */
10
+ const ACP_APPROVAL_TOOLS = new Set([
11
+ 'write', 'edit', 'multiedit', 'notebookedit', 'applypatch', 'apply_patch', 'patch',
12
+ 'bash', 'shell', 'runshell', 'exec_command',
13
+ 'ptyshellstart', 'ptyshellsend', 'webterminalinput',
14
+ 'delegate_code_agent',
15
+ ]);
16
+ export function requiresAcpToolApproval(toolName: string): boolean {
17
+ const name = toolName.startsWith('functions.') ? toolName.slice('functions.'.length) : toolName;
18
+ // Codex app-server only sends a permission request when it wants to act.
19
+ return ACP_APPROVAL_TOOLS.has(name.toLowerCase()) || name.startsWith('codex ');
20
+ }
21
+
22
+ export type AcpToolDenialReason = 'rejected' | 'cancelled' | 'timeout' | 'error';
23
+ export type AcpToolApprovalResult =
24
+ | { allowed: true }
25
+ | { allowed: false; reason: AcpToolDenialReason };
26
+
27
+ /** The tool result the LLM sees when a protected tool was not run. */
28
+ export function acpToolDenialResult(toolName: string, reason: AcpToolDenialReason): { error: string } {
29
+ if (reason === 'rejected') {
30
+ return { error: `${toolName}: 사람이 이 호출을 거절했다. 같은 턴에서 같은 도구를 다시 요청하지 말고, 이유를 묻거나 다른 길을 제안하라 — 실행하지 않았다 (tool not run: approval ${reason})` };
31
+ }
32
+ if (reason === 'timeout') {
33
+ return { error: `${toolName}: 사람의 답이 없었다(시한 초과) — 실행하지 않았다. 사용자에게 한 줄로 알려라 (tool not run: approval ${reason})` };
34
+ }
35
+ const why = reason === 'cancelled' ? '승인 요청이 취소됐다' : '승인을 받지 못했다';
36
+ return { error: `${toolName}: ${why} — 실행하지 않았다 (tool not run: approval ${reason})` };
37
+ }
38
+
39
+ /** One policy per ACP server: grants are scoped to the session AND exact tool
40
+ * name, not to a turn, connection, argument set, or other session. */
41
+ export function createAcpSessionApprovalPolicy(): {
42
+ resolve: (
43
+ sessionId: string,
44
+ request: Parameters<AcpTurnContext['requestApproval']>[0],
45
+ requestApproval: AcpTurnContext['requestApproval'],
46
+ rejectedThisTurn?: Set<string>,
47
+ ) => Promise<AcpToolApprovalResult>;
48
+ clearSession: (sessionId: string) => void;
49
+ } {
50
+ const alwaysAllowed = new Map<string, Set<string>>();
51
+ const sessionGenerations = new Map<string, number>();
52
+ const observe = (event: 'requested' | 'decided' | 'timeout' | 'remembered', sessionId: string, tool: string, outcome?: string) => {
53
+ // Tool arguments are deliberately not logged.
54
+ debug.log('acp.approval', event, { sessionId, tool, ...(outcome !== undefined ? { outcome } : {}) });
55
+ };
56
+ // Same-turn calls to one tool are asked one at a time, so a concurrent second call sees the first's denial
57
+ // instead of opening a second sheet (round 1 should-fix).
58
+ const turnInflight = new WeakMap<Set<string>, Map<string, Promise<void>>>();
59
+ const decide = async (
60
+ sessionId: string,
61
+ request: Parameters<AcpTurnContext['requestApproval']>[0],
62
+ requestApproval: AcpTurnContext['requestApproval'],
63
+ rejectedThisTurn?: Set<string>,
64
+ ): Promise<AcpToolApprovalResult> => {
65
+ if (rejectedThisTurn?.has(request.toolName)) {
66
+ debug.log('acp.approval', 'repeat-denied', { sessionId, tool: request.toolName });
67
+ return { allowed: false, reason: 'rejected' };
68
+ }
69
+ if (alwaysAllowed.get(sessionId)?.has(request.toolName)) {
70
+ observe('remembered', sessionId, request.toolName, 'allow-always');
71
+ return { allowed: true };
72
+ }
73
+ const generation = sessionGenerations.get(sessionId) ?? 0;
74
+ observe('requested', sessionId, request.toolName);
75
+ let decision: AcpApprovalDecision;
76
+ try {
77
+ decision = await requestApproval(request);
78
+ } catch {
79
+ observe('decided', sessionId, request.toolName, 'error');
80
+ return { allowed: false, reason: 'error' };
81
+ }
82
+ observe(decision === 'timeout' ? 'timeout' : 'decided', sessionId, request.toolName, decision);
83
+ if (generation !== (sessionGenerations.get(sessionId) ?? 0)) return { allowed: false, reason: 'cancelled' };
84
+ if (decision === 'allow-always') {
85
+ let tools = alwaysAllowed.get(sessionId);
86
+ if (!tools) {
87
+ tools = new Set();
88
+ alwaysAllowed.set(sessionId, tools);
89
+ }
90
+ tools.add(request.toolName);
91
+ }
92
+ if (decision === 'allow-once' || decision === 'allow-always') return { allowed: true };
93
+ if (decision === 'deny-once' || decision === 'deny-always') rejectedThisTurn?.add(request.toolName);
94
+ return {
95
+ allowed: false,
96
+ reason: decision === 'timeout' ? 'timeout' : decision === 'cancelled' ? 'cancelled' : 'rejected',
97
+ };
98
+ };
99
+ return {
100
+ async resolve(sessionId, request, requestApproval, rejectedThisTurn) {
101
+ if (!requiresAcpToolApproval(request.toolName)) return { allowed: true };
102
+ if (!rejectedThisTurn) return decide(sessionId, request, requestApproval);
103
+ let inflight = turnInflight.get(rejectedThisTurn);
104
+ if (!inflight) {
105
+ inflight = new Map();
106
+ turnInflight.set(rejectedThisTurn, inflight);
107
+ }
108
+ const prior = inflight.get(request.toolName);
109
+ let release!: () => void;
110
+ const mine = new Promise<void>((done) => { release = done; });
111
+ const chained = (prior ?? Promise.resolve()).then(() => mine);
112
+ inflight.set(request.toolName, chained);
113
+ try {
114
+ if (prior) await prior;
115
+ return await decide(sessionId, request, requestApproval, rejectedThisTurn);
116
+ } finally {
117
+ release();
118
+ if (inflight.get(request.toolName) === chained) inflight.delete(request.toolName);
119
+ }
120
+ },
121
+ clearSession(sessionId) {
122
+ alwaysAllowed.delete(sessionId);
123
+ sessionGenerations.set(sessionId, (sessionGenerations.get(sessionId) ?? 0) + 1);
124
+ },
125
+ };
126
+ }
@@ -40,6 +40,11 @@ import { unsafeBrandSessionUri } from '../mss/uri/brand.js';
40
40
  import { debug } from '../debug/log.js';
41
41
  import type { AgentStatusStore } from '../agent-status/store.js';
42
42
  import type { AcpPermissionApprover, AcpQuestionApprover } from './client.js';
43
+ import {
44
+ CODEX_APPROVAL_OPT_ONCE,
45
+ CODEX_APPROVAL_OPT_REJECT,
46
+ CODEX_APPROVAL_QUESTION_ID,
47
+ } from './codex-approval-adapter.js';
43
48
  import type { ConfirmChannel } from '../hitl/confirm.js';
44
49
  import type { QuestionChannel } from '../hitl/question.js';
45
50
  import {
@@ -69,6 +74,7 @@ import { getUserConfig } from '../user-config.js';
69
74
  // ACP `cancelled`), matching the pre-existing default-deny posture for
70
75
  // unattended turns — so nothing hangs when a surface opts out.
71
76
  const turnHitlChannels = new Map<string, ConfirmChannel[]>();
77
+ const turnPermissionApprovers = new Map<string, AcpPermissionApprover>();
72
78
  /** Parallel registry for multi-option question channels (same keying
73
79
  * as `turnHitlChannels`). Present ⇒ the question approver fans out
74
80
  * real N-option prompts; absent ⇒ it falls back to yes/no collapse
@@ -81,6 +87,8 @@ const turnHitlQuestionChannels = new Map<string, QuestionChannel[]>();
81
87
  const HITL_TURN_TIMEOUT_MS = 120_000;
82
88
 
83
89
  const surfacePermissionApprover: AcpPermissionApprover = async (req) => {
90
+ const turnApprover = turnPermissionApprovers.get(req.sessionId);
91
+ if (turnApprover) return turnApprover(req);
84
92
  // Autonomous by default: edit/command PERMISSIONS auto-approve. Asking the
85
93
  // human to approve every write defeats delegation (the interactive-editor
86
94
  // paradigm ACP inherited doesn't fit autonomous telegram delegation).
@@ -102,7 +110,31 @@ const surfacePermissionApprover: AcpPermissionApprover = async (req) => {
102
110
  return answer;
103
111
  };
104
112
 
113
+ /** PCH-2b — answer codex's 3-way approval question with a yes/no permission
114
+ * approver. Returns null when the request is not that question. */
115
+ export async function answerCodexApprovalQuestion(
116
+ req: Parameters<AcpQuestionApprover>[0],
117
+ approver: AcpPermissionApprover,
118
+ ): Promise<Awaited<ReturnType<AcpQuestionApprover>> | null> {
119
+ const q = req.questions[0];
120
+ if (req.questions.length !== 1 || q?.id !== CODEX_APPROVAL_QUESTION_ID) return null;
121
+ const approved = await approver({
122
+ backendId: req.backendId,
123
+ sessionId: req.sessionId,
124
+ title: q.question,
125
+ options: [],
126
+ });
127
+ return { answers: { [q.id]: approved ? CODEX_APPROVAL_OPT_ONCE : CODEX_APPROVAL_OPT_REJECT } };
128
+ }
129
+
105
130
  const surfaceQuestionApprover: AcpQuestionApprover = async (req) => {
131
+ // PCH-2b — an ACP server turn answers codex's approval question through its
132
+ // own client (yes/no), not the messenger HITL channels.
133
+ const turnApprover = turnPermissionApprovers.get(req.sessionId);
134
+ if (turnApprover) {
135
+ const answered = await answerCodexApprovalQuestion(req, turnApprover);
136
+ if (answered) return answered;
137
+ }
106
138
  const channels = turnHitlChannels.get(req.sessionId);
107
139
  if (!channels || channels.length === 0) return { answers: {}, cancelled: true };
108
140
  // When the surface provided real multi-option QuestionChannels, fan
@@ -306,6 +338,8 @@ export interface RunAcpTurnOpts {
306
338
  cwd?: string;
307
339
  /** Session-scoped Codex app-server configuration arguments. */
308
340
  codexArgs?: readonly string[];
341
+ /** ACP server turn's permission request, routed through its client rather than the messenger HITL channel. */
342
+ permissionApprover?: AcpPermissionApprover;
309
343
  /** Soft focus budget (tool-turns) for a TARGETED slash invocation
310
344
  * (`/cc`·/cdx·/gem). When set, a tight-budget directive is prepended
311
345
  * to the prompt so the sub-agent stays focused (minimize re-reads /
@@ -663,6 +697,7 @@ export async function runAcpTurn(opts: RunAcpTurnOpts): Promise<RunAcpTurnResult
663
697
  // session id (== the `req.sessionId` seen in requestPermission).
664
698
  const hasHitl = !!opts.hitlConfirmChannels && opts.hitlConfirmChannels.length > 0;
665
699
  if (hasHitl) turnHitlChannels.set(sessionId, opts.hitlConfirmChannels!);
700
+ if (opts.permissionApprover) turnPermissionApprovers.set(sessionId, opts.permissionApprover);
666
701
  const hasHitlQuestions = !!opts.hitlQuestionChannels && opts.hitlQuestionChannels.length > 0;
667
702
  if (hasHitlQuestions) turnHitlQuestionChannels.set(sessionId, opts.hitlQuestionChannels!);
668
703
 
@@ -784,6 +819,7 @@ export async function runAcpTurn(opts: RunAcpTurnOpts): Promise<RunAcpTurnResult
784
819
  } finally {
785
820
  inFlightTurns.delete(key);
786
821
  if (hasHitl) turnHitlChannels.delete(sessionId);
822
+ if (opts.permissionApprover) turnPermissionApprovers.delete(sessionId);
787
823
  if (hasHitlQuestions) turnHitlQuestionChannels.delete(sessionId);
788
824
  }
789
825
  }