elanous 0.2.10 → 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 (584) 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/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  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-54b32bd27726588d.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-35414e0a007b4082.js +1 -0
  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 -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/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/intake/intake-daily.yaml +2 -1
  194. package/graphs/ops/recipes.yaml +3 -0
  195. package/graphs/ops/secret-exposure.yaml +24 -0
  196. package/graphs/release/recipes.yaml +3 -0
  197. package/graphs/release/release-loop.yaml +4 -1
  198. package/graphs/video/explainer-line.yaml +2 -2
  199. package/package.json +2 -1
  200. package/plugins/elanous-hwp/README.md +25 -0
  201. package/plugins/elanous-hwp/cli.ts +22 -0
  202. package/plugins/elanous-hwp/converter.ts +237 -0
  203. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  204. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  205. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  206. package/plugins/elanous-hwp/plugin.json +16 -0
  207. package/plugins/elanous-hwp/plugin.ts +40 -0
  208. package/scripts/ci-public-export-leak-gate.ts +75 -14
  209. package/scripts/ci-public-leak-gate.ts +44 -9
  210. package/scripts/context-hooks/claude-stop.sh +4 -0
  211. package/scripts/context-hooks/emit.ts +24 -0
  212. package/scripts/context-hooks/post-tool-use.sh +4 -0
  213. package/scripts/coord-channel-watch.sh +12 -0
  214. package/scripts/coord-requests-bridge.ts +143 -0
  215. package/scripts/field-feed/lib.ts +4 -0
  216. package/scripts/fleet/node-setup.sh +20 -3
  217. package/scripts/homebrew-formula-bump.ts +69 -0
  218. package/scripts/marketing/measure-site-numbers.ts +169 -0
  219. package/scripts/measure-gate-shards.ts +309 -0
  220. package/scripts/mission-request-judge.ts +31 -1
  221. package/scripts/morning-report.ts +2 -2
  222. package/scripts/opportunity-scan.ts +1 -1
  223. package/scripts/release-loop/auto-approve-node.ts +21 -4
  224. package/scripts/release-loop/cut-branch.ts +84 -0
  225. package/scripts/release-loop/gate-node.ts +14 -13
  226. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  227. package/scripts/release-loop/node-verdict.ts +3 -3
  228. package/scripts/release-loop/tui-node-checks.ts +42 -0
  229. package/scripts/release-loop/tui-sim-node.ts +32 -8
  230. package/scripts/release-loop/unattended-release.ts +5 -3
  231. package/scripts/release-loop/version-node.ts +61 -10
  232. package/scripts/signal-digest-cycle.ts +2 -7
  233. package/scripts/signal-digest-photo.ts +11 -0
  234. package/scripts/tech1-public-measure.ts +94 -0
  235. package/scripts/test-diet/node.ts +1 -1
  236. package/scripts/tui-regress.ts +2 -2
  237. package/scripts/ux/demo-rehearsal.ts +243 -0
  238. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  239. package/skills/diagram-master/SKILL.md +366 -0
  240. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  241. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  242. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  243. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  244. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  245. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  246. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  247. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  248. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  249. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  250. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  251. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  252. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  253. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  254. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  255. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  256. package/skills/diagram-master/references/examples/README.md +69 -0
  257. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  258. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  259. package/skills/diagram-master/references/pyproject.toml +16 -0
  260. package/skills/diagram-master/references/quality-checklist.md +33 -0
  261. package/skills/diagram-master/references/routing-guide.md +164 -0
  262. package/skills/diagram-master/references/uv.lock +1356 -0
  263. package/skills/google-workspace/SKILL.md +33 -0
  264. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  265. package/skills/grill-me/SKILL.md +1 -1
  266. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  267. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  268. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  269. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  270. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  271. package/skills/omni-crawl/SKILL.md +21 -11
  272. package/skills/omni-crawl/scripts/main.ts +6 -6
  273. package/skills/omni-crawl/src/router.ts +3 -3
  274. package/skills/omni-digest/SKILL.md +17 -9
  275. package/skills/omni-digest/digest.md +2 -2
  276. package/skills/omni-digest/src/fetch.ts +30 -3
  277. package/skills/pitch-deck/SKILL.md +2 -2
  278. package/skills/pitch-deck/template.html +2 -2
  279. package/skills/youtube-master/SKILL.md +163 -0
  280. package/skills/youtube-master/package-lock.json +558 -0
  281. package/skills/youtube-master/package.json +13 -0
  282. package/skills/youtube-master/references/study-note-template.md +124 -0
  283. package/skills/youtube-master/scripts/main.ts +435 -0
  284. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  285. package/skills/youtube-master/src/audio.ts +63 -0
  286. package/skills/youtube-master/src/domain-staging.ts +50 -0
  287. package/skills/youtube-master/src/env.ts +36 -0
  288. package/skills/youtube-master/src/obsidian.ts +155 -0
  289. package/skills/youtube-master/src/router.ts +110 -0
  290. package/skills/youtube-master/src/stt.ts +199 -0
  291. package/skills/youtube-master/src/study-note.ts +175 -0
  292. package/skills/youtube-master/src/summarize.ts +358 -0
  293. package/skills/youtube-master/src/transcript.ts +76 -0
  294. package/skills/youtube-master/src/types.ts +91 -0
  295. package/skills/youtube-master/src/util.ts +93 -0
  296. package/skills/youtube-master/src/youtube.ts +70 -0
  297. package/skills/youtube-master/tsconfig.json +13 -0
  298. package/src/acp/server.ts +5 -2
  299. package/src/agent-mission/driver.ts +80 -10
  300. package/src/agent-mission/pty-decision.ts +71 -0
  301. package/src/agent-mission/review-loop.ts +30 -0
  302. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  303. package/src/autopilot/tool-registry.ts +2 -0
  304. package/src/boot/daemon-prompt-turn.ts +5 -0
  305. package/src/boot/daemon-runtime.ts +9 -3
  306. package/src/boot/daemon-tools/web-search.ts +3 -0
  307. package/src/card-followup/core.ts +109 -0
  308. package/src/chat/index.ts +1 -0
  309. package/src/cli/drive-input-jail.ts +101 -0
  310. package/src/cli/hooks-cli.ts +17 -3
  311. package/src/cli/make-cli.ts +43 -0
  312. package/src/cli/persona-cli.ts +90 -4
  313. package/src/cli/plugin-cli.ts +31 -22
  314. package/src/cli/pod-cli.ts +19 -9
  315. package/src/cli/pr-cli.ts +51 -15
  316. package/src/cli/pty-drive-cli.ts +41 -7
  317. package/src/cli/pty-drive-verdict.ts +40 -0
  318. package/src/cli/release-cli.ts +17 -4
  319. package/src/cli/setup-cli.ts +43 -1
  320. package/src/cli/skills-cli.ts +17 -1
  321. package/src/context-bus/claude-hooks-install.ts +10 -0
  322. package/src/context-bus/context-now-surfaces.ts +48 -0
  323. package/src/context-bus/context-now.ts +104 -0
  324. package/src/context-bus/coord-events.ts +2 -2
  325. package/src/context-bus/external-events.ts +52 -0
  326. package/src/context-bus/long-term-memory.ts +108 -0
  327. package/src/dashboard/index.ts +9 -4
  328. package/src/dashboard/slash-runtime/dashboard-handlers.ts +7 -1
  329. package/src/decisions/decision-cards.ts +10 -3
  330. package/src/decisions/decision-ledger.ts +13 -5
  331. package/src/discord/sprint21-runtime.ts +5 -1
  332. package/src/discord-self-message.ts +32 -0
  333. package/src/discord-slash-wire.ts +5 -1
  334. package/src/discord.ts +17 -1
  335. package/src/domains/core-tools.ts +3 -2
  336. package/src/domains/outbound-alert.ts +6 -1
  337. package/src/domains/telegram-kind-route.ts +51 -13
  338. package/src/exec-requests/default-outputs.ts +25 -0
  339. package/src/exec-requests/planner.ts +10 -2
  340. package/src/exec-requests/runner.ts +20 -6
  341. package/src/exec-requests/store.ts +3 -0
  342. package/src/execution-loop/launch-gate.ts +100 -0
  343. package/src/field/field-reel.ts +5 -1
  344. package/src/field-note/index.ts +201 -0
  345. package/src/field-note/transcribe.ts +248 -0
  346. package/src/graph-kinds/registry.ts +3 -3
  347. package/src/graph-runner/graph-cli.ts +61 -1
  348. package/src/graph-runner/graph-grow-llm.ts +37 -0
  349. package/src/graph-runner/graph-grow.ts +47 -0
  350. package/src/graph-runner/runner.ts +317 -25
  351. package/src/grok/agent-search.ts +8 -2
  352. package/src/guardian/secret-exposure-scan.ts +101 -0
  353. package/src/harness/harness-cli-command.ts +247 -7
  354. package/src/harness/harness-pod-dispatch.ts +43 -23
  355. package/src/harness/harness-seams.ts +38 -4
  356. package/src/harness/harness-stop.ts +23 -4
  357. package/src/harness/launch-registry.ts +91 -0
  358. package/src/harness/process-garbage.ts +5 -3
  359. package/src/hooks/dispatch.ts +82 -0
  360. package/src/hooks/expose.ts +254 -0
  361. package/src/hooks/github-shadow.ts +108 -0
  362. package/src/hooks/providers.ts +71 -5
  363. package/src/hooks/queue.ts +1 -1
  364. package/src/hooks/receiver.ts +21 -20
  365. package/src/index.ts +52 -14
  366. package/src/intake-plane/categorize.ts +18 -46
  367. package/src/intake-plane/discord-seat-work.ts +10 -0
  368. package/src/intake-plane/front-route-classifier.ts +33 -39
  369. package/src/intake-plane/persona-answer.ts +30 -0
  370. package/src/intake-plane/runtime-callables.ts +8 -1
  371. package/src/intake-plane/telegram-seat-work.ts +36 -2
  372. package/src/intake-plane/wish-folder.ts +67 -0
  373. package/src/intent-gate/gate.ts +30 -10
  374. package/src/live/detail-switch.ts +5 -0
  375. package/src/llm/difficulty.ts +57 -0
  376. package/src/llm/judge-layer.ts +101 -0
  377. package/src/llm/mission-router.ts +33 -19
  378. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  379. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  380. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  381. package/src/loops/contract/loop-agent.schema.json +138 -0
  382. package/src/loops/contract/validate.ts +64 -0
  383. package/src/loops/registry.ts +20 -6
  384. package/src/market/signed-index.ts +4 -0
  385. package/src/maturity/bot-command-maturity.ts +45 -0
  386. package/src/maturity/feature-maturity.ts +26 -4
  387. package/src/model-tier/index.ts +2 -2
  388. package/src/model-tier/tier-resolver.ts +20 -20
  389. package/src/model-tier/types.ts +6 -6
  390. package/src/mss/logging/log-store.ts +15 -0
  391. package/src/nexus/api/config-model-tier.ts +5 -4
  392. package/src/nexus/api/fabric-plans.ts +53 -0
  393. package/src/nexus/api/harness-api.ts +5 -1
  394. package/src/nexus/api/health.ts +2 -0
  395. package/src/nexus/api/http-server.ts +36 -0
  396. package/src/nexus/api/inside-events.ts +226 -0
  397. package/src/nexus/api/meta-api.ts +21 -8
  398. package/src/nexus/api/missions.ts +6 -1
  399. package/src/nexus/api/ops-seats.ts +33 -0
  400. package/src/nexus/api/outputs-route.ts +44 -0
  401. package/src/nexus/api/seat-requests.ts +44 -2
  402. package/src/nexus/api/sessions-store.ts +17 -38
  403. package/src/nexus/api/sub-seat-charters.ts +34 -0
  404. package/src/nexus/api/tabs-mutations.ts +3 -1
  405. package/src/nexus/api/trace.ts +18 -6
  406. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  407. package/src/nexus/api/workflows.ts +80 -6
  408. package/src/nexus/index.ts +2 -0
  409. package/src/nexus/kinds/webterm.ts +2 -1
  410. package/src/nexus/webterm/pty.ts +6 -2
  411. package/src/onboarding/cli-auth-status.ts +80 -0
  412. package/src/onboarding/voice-ai.ts +3 -3
  413. package/src/org/seat-budget.ts +48 -0
  414. package/src/org/stall-escalation.ts +63 -0
  415. package/src/outputs/ledger.ts +120 -0
  416. package/src/persona/persona-todo.ts +79 -0
  417. package/src/persona/presets.ts +116 -2
  418. package/src/persona/team-set.ts +155 -0
  419. package/src/plugins/install/plugin-install.ts +14 -0
  420. package/src/plugins/maker/market-bundle.ts +109 -0
  421. package/src/plugins/maker/plugin-maker.ts +254 -11
  422. package/src/plugins/maker/wizard-generate.ts +103 -0
  423. package/src/pod-lease/admission.ts +150 -0
  424. package/src/pod-lease/dependency-state.ts +85 -0
  425. package/src/pod-lease/host-lease.ts +127 -0
  426. package/src/project/project-suggestion.ts +16 -0
  427. package/src/project/session-context.ts +24 -0
  428. package/src/release-loop/checklist.ts +2 -2
  429. package/src/release-loop/feature-store.ts +5 -3
  430. package/src/release-loop/next-md-merge.ts +58 -0
  431. package/src/release-loop/release-note.ts +59 -4
  432. package/src/seat-dispatch/seat-ask.ts +130 -0
  433. package/src/seat-dispatch/seat-questions.ts +100 -0
  434. package/src/seat-loop/seat-loop.ts +548 -29
  435. package/src/seat-loop/seat-report.ts +37 -2
  436. package/src/self-dev/dev-cli.ts +4 -1
  437. package/src/self-dev/dev-pipeline.ts +37 -1
  438. package/src/self-dev/draft-sweep.ts +38 -33
  439. package/src/self-dev/draft-triage-rules.ts +8 -5
  440. package/src/self-dev/fabric-plan-core.ts +297 -0
  441. package/src/self-dev/orchestrate.ts +36 -4
  442. package/src/self-dev/release-path-guard.ts +62 -0
  443. package/src/self-dev/shard-aggregate.ts +230 -0
  444. package/src/self-dev/shard-placement.ts +60 -0
  445. package/src/self-dev/shard-plan.ts +48 -0
  446. package/src/self-dev/shard-pod-run.ts +77 -0
  447. package/src/self-dev/shard-run.ts +105 -0
  448. package/src/self-implement/gate-baseline.ts +1 -1
  449. package/src/self-implement/gate-cli.ts +40 -1
  450. package/src/self-implement/gate-scope.ts +37 -7
  451. package/src/self-implement/graph-variant.ts +171 -0
  452. package/src/self-implement/harness-policy-gates.ts +1 -1
  453. package/src/self-implement/headless-elanous-driver.ts +22 -3
  454. package/src/self-implement/host-regate.ts +22 -1
  455. package/src/self-implement/importer-test-index.ts +2 -1
  456. package/src/self-implement/l8-merge-queue.ts +130 -0
  457. package/src/self-implement/orchestrator.ts +242 -9
  458. package/src/self-implement/route-consumer-test-index.ts +122 -0
  459. package/src/self-implement/seams.ts +72 -11
  460. package/src/self-implement/test-seams.ts +1 -0
  461. package/src/self-implement/uncommitted-work.ts +59 -0
  462. package/src/session/index.ts +36 -13
  463. package/src/skills/gift-install.ts +215 -0
  464. package/src/skills/tools/web-search.ts +4 -1
  465. package/src/steward/launch.ts +42 -26
  466. package/src/steward/steward-cards.ts +17 -9
  467. package/src/steward/triage.ts +46 -14
  468. package/src/task-cards/card-cli.ts +25 -1
  469. package/src/task-orchestrator/mission.ts +5 -0
  470. package/src/task-orchestrator/store.ts +12 -3
  471. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  472. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  473. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  474. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  475. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  476. package/src/task-orchestrator/types.ts +2 -0
  477. package/src/telegram-card-followup.ts +16 -96
  478. package/src/telegram-commands.ts +10 -1
  479. package/src/telegram-project-command.ts +71 -0
  480. package/src/telegram-report.ts +21 -17
  481. package/src/telegram.ts +29 -3
  482. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  483. package/src/user-config.ts +102 -20
  484. package/src/version/packed-revision.json +1 -1
  485. package/src/web-search/grok.ts +7 -1
  486. package/src/web-search/index.ts +28 -1
  487. package/src/web-search/provider.ts +4 -0
  488. package/src/web-search/x-intent.ts +5 -0
  489. package/src/workflow-runtime/executor.ts +277 -47
  490. package/src/workflow-runtime/index.ts +1 -0
  491. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  492. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  493. package/src/workflow-runtime/schema.ts +79 -4
  494. package/src/workflow-runtime/types.ts +35 -4
  495. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  505. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  506. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  525. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  583. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  584. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -125,6 +125,9 @@ export interface LogQuery {
125
125
  /** event/data/category LIKE 부분 일치. */
126
126
  grep?: string;
127
127
  sessionId?: string;
128
+ /** Trace ownership: explicit row projectId takes precedence over session ownership. */
129
+ projectId?: string;
130
+ projectSessionIds?: readonly string[];
128
131
  sinceMs?: number;
129
132
  untilMs?: number;
130
133
  /** 증분 커서 — id > afterId 를 오름차순으로(SSE 드레인). */
@@ -397,6 +400,18 @@ export class LogStore {
397
400
  params.push(needle, needle, needle);
398
401
  }
399
402
  if (q.sessionId) { where.push('session_id = ?'); params.push(q.sessionId); }
403
+ if (q.projectId !== undefined) {
404
+ const sessionIds = [...new Set(q.projectSessionIds ?? [])];
405
+ // An explicit project tag wins, even if the row's session belongs to another project.
406
+ // Guard JSON extraction so malformed and absent payloads cannot match by accident.
407
+ const tagged = "CASE WHEN json_valid(data) THEN json_extract(data, '$.projectId') ELSE NULL END";
408
+ const session = "CASE WHEN json_valid(data) THEN json_extract(data, '$.sessionId') ELSE NULL END";
409
+ const untagged = "CASE WHEN json_valid(data) THEN json_type(data, '$.projectId') IS NULL ELSE 1 END";
410
+ where.push(`(${tagged} = ? OR (${untagged} AND (${sessionIds.length
411
+ ? `session_id IN (${sessionIds.map(() => '?').join(',')}) OR ${session} IN (${sessionIds.map(() => '?').join(',')})`
412
+ : '0'})))`);
413
+ params.push(q.projectId, ...sessionIds, ...sessionIds);
414
+ }
400
415
  if (q.sinceMs !== undefined) { where.push('ts_ms >= ?'); params.push(q.sinceMs); }
401
416
  if (q.untilMs !== undefined) { where.push('ts_ms <= ?'); params.push(q.untilMs); }
402
417
  if (q.afterId !== undefined) { where.push('id > ?'); params.push(q.afterId); }
@@ -39,7 +39,7 @@ function jsonResponse(body: unknown, status = 200): Response {
39
39
 
40
40
  import {
41
41
  isModelTier,
42
- isModelTierPersona,
42
+ isModelTierProfile,
43
43
  type BudgetUserConfig,
44
44
  type ModelTier,
45
45
  type ModelTierUserConfig,
@@ -74,9 +74,10 @@ function normalizeModelTier(v: unknown): ModelTierUserConfig | undefined | 'inva
74
74
  if (!v || typeof v !== 'object' || Array.isArray(v)) return 'invalid';
75
75
  const r = v as Record<string, unknown>;
76
76
  const out: ModelTierUserConfig = {};
77
- if (r.persona !== undefined) {
78
- if (!isModelTierPersona(r.persona)) return 'invalid';
79
- out.persona = r.persona;
77
+ const profile = r.profile === undefined ? r.persona : r.profile;
78
+ if (profile !== undefined) {
79
+ if (!isModelTierProfile(profile)) return 'invalid';
80
+ out.profile = profile;
80
81
  }
81
82
  if (r.preset !== undefined) {
82
83
  if (typeof r.preset !== 'string' || r.preset.trim().length === 0) return 'invalid';
@@ -0,0 +1,53 @@
1
+ import { effectiveInstanceRoot } from '../../instance/resolve.js';
2
+ import {
3
+ approveFabricPlan,
4
+ createFabricPlan,
5
+ loadFabricPlan,
6
+ type FabricPlan,
7
+ } from '../../self-dev/fabric-plan-core.js';
8
+ import { jsonResponse } from './json-response.js';
9
+
10
+ export interface FabricPlansRouteOpts {
11
+ create?: (root: string, request: string) => Promise<FabricPlan>;
12
+ }
13
+
14
+ /** This route never launches a plan. Only approval writes the fabric execution-candidate ledger. */
15
+ export async function handleFabricPlans(req: Request, opts: FabricPlansRouteOpts = {}): Promise<Response> {
16
+ const pathname = new URL(req.url).pathname;
17
+ const root = effectiveInstanceRoot();
18
+ if (pathname === '/v1/fabric/decompose') {
19
+ if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
20
+ let body: unknown;
21
+ try { body = await req.json(); }
22
+ catch { return jsonResponse({ error: 'invalid_json' }, 400); }
23
+ const request = body && typeof body === 'object' && !Array.isArray(body)
24
+ ? (body as Record<string, unknown>).request : undefined;
25
+ if (typeof request !== 'string' || !request.trim()) return jsonResponse({ error: 'invalid_request' }, 400);
26
+ try {
27
+ const plan = await (opts.create ?? createFabricPlan)(root, request);
28
+ return jsonResponse({ plan }, 201);
29
+ } catch (error) {
30
+ return jsonResponse({ error: 'decomposition_failed', reason: error instanceof Error ? error.message : String(error) }, 422);
31
+ }
32
+ }
33
+ const match = /^\/v1\/fabric\/plans\/([^/]+)(\/approve)?$/.exec(pathname);
34
+ if (!match) return jsonResponse({ error: 'not-found' }, 404);
35
+ let id: string;
36
+ try { id = decodeURIComponent(match[1]!); }
37
+ catch { return jsonResponse({ error: 'invalid_plan_id' }, 400); }
38
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id)) return jsonResponse({ error: 'invalid_plan_id' }, 400);
39
+ if (!match[2]) {
40
+ if (req.method !== 'GET') return jsonResponse({ error: 'method-not-allowed' }, 405);
41
+ const plan = loadFabricPlan(root, id);
42
+ return plan ? jsonResponse({ plan }) : jsonResponse({ error: 'not-found' }, 404);
43
+ }
44
+ if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
45
+ // The ledger transition is atomic and rejects a second approval; no draft is executable.
46
+ try {
47
+ return jsonResponse({ candidate: approveFabricPlan(root, id) });
48
+ } catch (error) {
49
+ if (error instanceof Error && error.message.startsWith('fabric plan not found:')) return jsonResponse({ error: 'not-found' }, 404);
50
+ if (error instanceof Error && error.message === 'fabric plan already approved') return jsonResponse({ error: 'already-approved' }, 409);
51
+ throw error;
52
+ }
53
+ }
@@ -19,6 +19,7 @@ import { resolveHarnessTarget } from '../../self-implement/harness-target-option
19
19
  import { queryRunningRuns, type RunningRunsResult } from '../../self-implement/running-runs.js';
20
20
  import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.js';
21
21
  import { createSeqTracker, makeEnvelope, type FeedbackEnvelope } from '../../feedback/envelope.js';
22
+ import { publishInsideEvent } from './inside-events.js';
22
23
 
23
24
  const JSON_HEADERS = { 'content-type': 'application/json; charset=utf-8' };
24
25
  const ASK_USAGE = 'usage: POST /v1/harness/ask with JSON body {"text":"<ask>"} — optional "target":"<path>" (홈 안의 git repo·디렉터리·파일)';
@@ -248,7 +249,10 @@ export async function handleHarnessAskPost(req: Request, _metaApi: HarnessMetaAp
248
249
  }
249
250
 
250
251
  const acceptanceId = deps.createAcceptanceId?.() ?? crypto.randomUUID();
251
- const log = deps.log ?? ((event, data) => debug.log('harness-http', event, data));
252
+ const log = (event: string, data: Record<string, unknown>) => {
253
+ (deps.log ?? ((name: string, payload: Record<string, unknown>) => debug.log('harness-http', name, payload)))(event, data);
254
+ publishInsideEvent({ ...data, kind: 'harness-run', event });
255
+ };
252
256
  const suppliedOrigin = (body as { origin?: unknown }).origin;
253
257
  const origin = suppliedOrigin === undefined ? null
254
258
  : readReportOrigin({ [REPORT_ORIGIN_ENV]: JSON.stringify(suppliedOrigin) });
@@ -128,6 +128,8 @@ export function handleHealth(
128
128
  universeRoot: safeUniverseRoot(),
129
129
  testUniverse: safeTestUniverse(),
130
130
  bindHost: safeBindHost(bind),
131
+ // W4 — POST /v1/workflows/:name/run understands onlyNode · fromNode+fromRunId · mode (PWA enables its run-mode buttons on this).
132
+ workflowRunModes: true as const,
131
133
  ...(setup?.mode === true
132
134
  ? { setupMode: true as const, setupMissing: setup.missing }
133
135
  : {}),
@@ -21,6 +21,7 @@ import type { TelegramEvent } from '../../workflow-runtime/triggers/telegram-sou
21
21
  import { spawnSync } from 'node:child_process';
22
22
  import { isAbsolute } from 'node:path';
23
23
  import { createProject, listProjects } from '../../project/project-store.js';
24
+ import { handleOutputsGet, type OutputsDeps } from './outputs-route.js';
24
25
  import { compareTokenConstTime } from '../../acp/transport/auth.js';
25
26
  import { ensureAuthToken } from '../../auth/acp-token.js';
26
27
  import type { NexusState } from '../state/state.js';
@@ -42,6 +43,7 @@ import { OPENAI_RELAY_PATH, tryHandleOpenAiRelay } from './openai-relay.js';
42
43
  import { handleHealth, type HealthSetupContext } from './health.js';
43
44
  import { handleTabsList, handleTabDetail, handleNexusSnapshot } from './tabs.js';
44
45
  import { handleSseEvents } from './events.js';
46
+ import { handleInsideEvents, INSIDE_EVENTS_PATH, startInsideEventRelay } from './inside-events.js';
45
47
  import { dispatchIntentPredictionRoute } from './intent-prediction.js';
46
48
  import { handleNotificationAction } from './notification-action.js';
47
49
  import { handleUserIntentEmit, handleUserIntentBatch } from './user-intents.js';
@@ -157,6 +159,7 @@ import {
157
159
  } from './vault-api.js';
158
160
  import { handleBuildsGet, parseBuildsPath } from './builds-api.js';
159
161
  import { handleHarnessAskPost, handleHarnessAskStatusGet, handleHarnessRunEventsGet, handleHarnessRunScreenGet, handleHarnessRunsGet, handleHarnessStopPost } from './harness-api.js';
162
+ import { handleFabricPlans, type FabricPlansRouteOpts } from './fabric-plans.js';
160
163
  import { dispatchPersonaRoute } from './personas.js';
161
164
  import { handleMe } from './operator.js';
162
165
  import { handleOpsApi } from './ops-api.js';
@@ -178,6 +181,7 @@ import { handleChannelBotsGet, handleChannelBotSet } from './setup-channel-bot.j
178
181
  import { handleLlmRoutePredict } from './llm-route-predict.js';
179
182
  import type { MissionRouter } from '../../llm/mission-router.js';
180
183
  import { handleContextFetchUrl } from './context-url.js';
184
+ import { contextNow } from '../../context-bus/context-now.js';
181
185
  import type { IntentPredictionService } from '../../intent-prediction/index.js';
182
186
  import type { NotificationActionLoopback } from '../../web-push/notification-action-loopback.js';
183
187
  import { handlePlatforms } from './platforms.js';
@@ -461,8 +465,11 @@ export function probeNexusHttpPort(
461
465
  export type NexusWsBridgeInit = Omit<WsBridgeOpts, 'hostname' | 'port'>;
462
466
 
463
467
  export interface NexusHttpServerOpts {
468
+ /** Optional fabric-plan ledger and decomposition seam; production uses the instance root and existing fabric decomposer. */
469
+ fabricPlans?: FabricPlansRouteOpts;
464
470
  /** Optional installer state root for isolated API consumers and tests. */
465
471
  pluginStateRoot?: string;
472
+ outputs?: OutputsDeps;
466
473
  execRequests?: ExecRequestRunner;
467
474
  seatRequests?: SeatRequestsDeps;
468
475
  consultRequests?: ConsultRequestsDeps;
@@ -790,11 +797,13 @@ export function startNexusHttpServer(opts: NexusHttpServerOpts): NexusHttpServer
790
797
  }
791
798
 
792
799
  const url = `http://${hostname}:${resolvedPort}`;
800
+ const stopInsideRelay = startInsideEventRelay();
793
801
  return {
794
802
  port: resolvedPort,
795
803
  hostname,
796
804
  url,
797
805
  stop() {
806
+ stopInsideRelay();
798
807
  try { server!.stop(true); } catch { /* idempotent */ }
799
808
  setInProcessOutbound(null);
800
809
  },
@@ -984,6 +993,11 @@ export async function routeRequest(
984
993
  }
985
994
  }
986
995
 
996
+ if (pathname === INSIDE_EVENTS_PATH) {
997
+ if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
998
+ return handleInsideEvents(req);
999
+ }
1000
+
987
1001
  if (pathname === LIVE_SHIPPED_PATH) {
988
1002
  return handleLiveShipped(req, { authorize: (request) => !!opts.metaApi && checkAuth(request, opts.metaApi) });
989
1003
  }
@@ -1312,11 +1326,21 @@ export async function routeRequest(
1312
1326
  return handleGraphsValidatePost(req, opts.metaApi);
1313
1327
  }
1314
1328
 
1329
+ if (pathname === '/v1/fabric/decompose' || pathname.startsWith('/v1/fabric/plans/')) {
1330
+ if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
1331
+ return handleFabricPlans(req, opts.fabricPlans);
1332
+ }
1333
+
1315
1334
  if (pathname === '/v1/projects' && (method === 'GET' || method === 'POST')) {
1316
1335
  if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
1317
1336
  return method === 'GET' ? handleProjectsGet() : handleProjectsPost(req);
1318
1337
  }
1319
1338
 
1339
+ if (method === 'GET' && pathname === '/v1/outputs') {
1340
+ if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
1341
+ return handleOutputsGet(req, opts.outputs);
1342
+ }
1343
+
1320
1344
  if (pathname === '/v1/config/chat-fast-path' && (method === 'GET' || method === 'PUT')) {
1321
1345
  if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
1322
1346
  return handleChatFastPathConfig(req);
@@ -1328,6 +1352,14 @@ export async function routeRequest(
1328
1352
  return (opts.usageHandler ?? handleUsageGet)();
1329
1353
  }
1330
1354
 
1355
+ // SK2 (PWA) list — GET must be routed before the non-GET block below; the original route sat inside it,
1356
+ // so the PWA banner's GET always fell through to «not-found» (found by the DEMO-RUNa rehearsal · 10-03).
1357
+ if (method === 'GET' && pathname === '/v1/skills/problems') {
1358
+ if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
1359
+ const { handleSkillProblems } = await import('./skill-problems.js');
1360
+ return handleSkillProblems(req, opts.metaApi);
1361
+ }
1362
+
1331
1363
  // Mutation routes (PR ι) — POST/PATCH/DELETE on /v1/nexus/tabs[/:id[/action]].
1332
1364
  // Templates POST handled here too (PR κ).
1333
1365
  // Config / secrets PUT/POST/DELETE here too (PR μ).
@@ -2775,6 +2807,10 @@ export async function routeRequest(
2775
2807
  const result = await dispatchPersonaRoute(req, pathname);
2776
2808
  if (result) return result;
2777
2809
  }
2810
+ if (pathname === '/v1/context/now') {
2811
+ if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
2812
+ return jsonResponse(contextNow({ ...(url.searchParams.has('topic') ? { topic: url.searchParams.get('topic') ?? '' } : {}) }));
2813
+ }
2778
2814
  // §6.3 (2026-05-09) — context URL fetch (showroom).
2779
2815
  // POST /v1/context/fetch-url
2780
2816
  if (pathname === '/v1/context/fetch-url') {
@@ -0,0 +1,226 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { appendFileSync, existsSync, mkdirSync, openSync, closeSync, readSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { StringDecoder } from 'node:string_decoder';
5
+ import { debug } from '../../debug/log.js';
6
+ import { nexusRootDir } from '../paths.js';
7
+ import { SSE_HEARTBEAT_MS } from './sse-heartbeat.js';
8
+
9
+ /** The node envelope matches apps/pwa/src/lib/inside-events.ts without importing browser code. */
10
+ export interface InsideNodeEvent {
11
+ kind: 'node';
12
+ graphId: string;
13
+ runId: string;
14
+ nodeId: string;
15
+ phase: 'start' | 'ok' | 'fail';
16
+ ts: string;
17
+ seconds?: number;
18
+ }
19
+
20
+ /** Other producers can add their own domain fields without changing the transport. */
21
+ export type InsideLiveEvent = InsideNodeEvent | ({ kind: string; ts: string } & Record<string, unknown>);
22
+ export type InsideEventInput = { kind: string; ts?: string } & Record<string, unknown>;
23
+
24
+ export const INSIDE_EVENTS_PATH = '/v1/inside/events';
25
+ const MAX_PENDING_FRAMES = 16;
26
+ const MAX_FRAME_BYTES = 64 * 1024;
27
+ const MASK = '[REDACTED]';
28
+ const SECRET_KEY = /(?:secret|password|passwd|token|api[_-]?key|authorization|credential|private[_-]?key|cookie|session[_-]?key)/i;
29
+ const INLINE_SECRET = /\b((?:Bearer|Basic)\s+|(?:sk|ghp|gho|ghu|ghs|ghr|github_pat|glpat|xox[baprs])[-_])[^\s"'`,;]+/gi;
30
+ const ASSIGNMENT_SECRET = /\b((?:api[_-]?key|(?:access[_-]?)?token|secret|password|authorization)\s*[:=]\s*)(?:(["'])[^\r\n]*?\2|[^\s"'`,;]+)/gi;
31
+
32
+ function maskString(value: string): string {
33
+ return value.replace(INLINE_SECRET, `$1${MASK}`)
34
+ .replace(ASSIGNMENT_SECRET, (_match, prefix: string, quote?: string) => `${prefix}${quote ?? ''}${MASK}${quote ?? ''}`);
35
+ }
36
+
37
+ /** Sanitize before fan-out; never put an unmasked payload in the subscriber queue. */
38
+ export function maskInsideEventValue(value: unknown, seen = new WeakSet<object>()): unknown {
39
+ if (typeof value === 'string') return maskString(value);
40
+ if (!value || typeof value !== 'object') return value;
41
+ if (seen.has(value)) return MASK;
42
+ seen.add(value);
43
+ if (Array.isArray(value)) {
44
+ const result = value.map((item) => maskInsideEventValue(item, seen));
45
+ seen.delete(value);
46
+ return result;
47
+ }
48
+ const result: Record<string, unknown> = {};
49
+ for (const [key, item] of Object.entries(value)) {
50
+ result[key] = SECRET_KEY.test(key) ? MASK : maskInsideEventValue(item, seen);
51
+ }
52
+ seen.delete(value);
53
+ return result;
54
+ }
55
+
56
+ type Listener = (event: InsideLiveEvent) => void;
57
+ const listeners = new Set<Listener>();
58
+ const RELAY_INTERVAL_MS = 20;
59
+ const RELAY_MAX_RECORD_BYTES = 64 * 1024;
60
+ const RELAY_ROTATE_BYTES = 4 * 1024 * 1024;
61
+ const RELAY_RETIRE_GRACE_MS = 2000;
62
+ const relayIdentity = randomUUID();
63
+
64
+ function relayPaths() {
65
+ const root = nexusRootDir();
66
+ return { root, pointer: join(root, 'inside-events-relay.json') };
67
+ }
68
+
69
+ function dispatch(event: InsideLiveEvent): void {
70
+ for (const listener of listeners) {
71
+ try { listener(event); } catch { /* a disconnected observer must not stop a run */ }
72
+ }
73
+ }
74
+
75
+ /** Each daemon owns its journal; child processes append masked records to that journal.
76
+ * The journal rotates once fully consumed past RELAY_ROTATE_BYTES: the pointer moves to a fresh file and the old one is
77
+ * drained for a grace period (producers that read the old pointer may still append) before it is removed. */
78
+ export function startInsideEventRelay(opts: { rotateBytes?: number; retireGraceMs?: number } = {}): () => void {
79
+ const { root, pointer } = relayPaths();
80
+ mkdirSync(root, { recursive: true });
81
+ const rotateBytes = opts.rotateBytes ?? RELAY_ROTATE_BYTES;
82
+ const retireGraceMs = opts.retireGraceMs ?? RELAY_RETIRE_GRACE_MS;
83
+ type Journal = { file: string; offset: number; pending: string; decoder: StringDecoder; retireAt?: number };
84
+ const journals: Journal[] = [];
85
+ let descriptor = '';
86
+ const open = (): Journal => {
87
+ const id = randomUUID();
88
+ const file = join(root, `inside-events-${id}.jsonl`);
89
+ writeFileSync(file, '', { mode: 0o600, flag: 'wx' });
90
+ descriptor = JSON.stringify({ pid: process.pid, id });
91
+ writeFileSync(pointer, descriptor, { mode: 0o600 });
92
+ const journal: Journal = { file, offset: 0, pending: '', decoder: new StringDecoder('utf8') };
93
+ journals.push(journal);
94
+ return journal;
95
+ };
96
+ let current = open();
97
+ const drain = (journal: Journal): void => {
98
+ const size = statSync(journal.file).size;
99
+ if (size < journal.offset) { journal.offset = 0; journal.pending = ''; journal.decoder = new StringDecoder('utf8'); }
100
+ while (size > journal.offset) {
101
+ const count = Math.min(size - journal.offset, 1024 * 1024);
102
+ const chunk = Buffer.alloc(count);
103
+ const fd = openSync(journal.file, 'r');
104
+ let length: number;
105
+ try { length = readSync(fd, chunk, 0, count, journal.offset); }
106
+ finally { closeSync(fd); }
107
+ if (length <= 0) break;
108
+ journal.offset += length;
109
+ // A chunk boundary may split a multi-byte character; the decoder carries the partial bytes into the next read.
110
+ journal.pending += journal.decoder.write(chunk.subarray(0, length));
111
+ const lines = journal.pending.split('\n');
112
+ journal.pending = lines.pop() ?? '';
113
+ if (journal.pending.length > RELAY_MAX_RECORD_BYTES) journal.pending = '';
114
+ for (const line of lines) {
115
+ if (line.length > RELAY_MAX_RECORD_BYTES) continue;
116
+ try {
117
+ const record = JSON.parse(line) as { origin?: string; event?: InsideEventInput };
118
+ if (record.origin === relayIdentity || !record.event || typeof record.event.kind !== 'string'
119
+ || !/^[a-z][a-z0-9._-]*$/i.test(record.event.kind)) continue;
120
+ dispatch(maskInsideEventValue(record.event) as InsideLiveEvent);
121
+ } catch { /* malformed producer record */ }
122
+ }
123
+ }
124
+ };
125
+ const remove = (journal: Journal): void => {
126
+ try { unlinkSync(journal.file); } catch { /* already removed */ }
127
+ journals.splice(journals.indexOf(journal), 1);
128
+ };
129
+ const timer = setInterval(() => {
130
+ for (const journal of [...journals]) {
131
+ try { drain(journal); } catch { /* journal disappeared during shutdown */ }
132
+ if (journal.retireAt !== undefined && Date.now() >= journal.retireAt && journal.pending === '') remove(journal);
133
+ }
134
+ if (current.offset >= rotateBytes && current.pending === '') {
135
+ try {
136
+ current.retireAt = Date.now() + retireGraceMs;
137
+ current = open();
138
+ debug.log('inside.events', 'relay-rotated', { journals: journals.length });
139
+ } catch { /* keep appending to the current journal */ }
140
+ }
141
+ }, RELAY_INTERVAL_MS);
142
+ timer.unref();
143
+ return () => {
144
+ clearInterval(timer);
145
+ try { if (readFileSync(pointer, 'utf8') === descriptor) unlinkSync(pointer); } catch { /* another daemon owns it */ }
146
+ for (const journal of [...journals]) remove(journal);
147
+ };
148
+ }
149
+
150
+ /** Ordered local delivery plus best-effort cross-process delivery to the current daemon. */
151
+ export function publishInsideEvent(event: InsideEventInput): void {
152
+ if (!event || typeof event.kind !== 'string' || !/^[a-z][a-z0-9._-]*$/i.test(event.kind)) return;
153
+ const safe = maskInsideEventValue({ ...event, ts: event.ts ?? new Date().toISOString() }) as InsideLiveEvent;
154
+ dispatch(safe);
155
+ try {
156
+ const { root, pointer } = relayPaths();
157
+ if (!existsSync(pointer)) return;
158
+ const descriptor = JSON.parse(readFileSync(pointer, 'utf8')) as { pid?: number; id?: string };
159
+ if (!Number.isSafeInteger(descriptor.pid) || typeof descriptor.id !== 'string' || !/^[a-f0-9-]{36}$/.test(descriptor.id)) return;
160
+ process.kill(descriptor.pid!, 0);
161
+ const file = join(root, `inside-events-${descriptor.id}.jsonl`);
162
+ const line = JSON.stringify({ origin: relayIdentity, event: safe }) + '\n';
163
+ if (Buffer.byteLength(line) > RELAY_MAX_RECORD_BYTES) return;
164
+ appendFileSync(file, line, { mode: 0o600, flag: 'a' });
165
+ } catch { /* a missing daemon must not interrupt the producer */ }
166
+ }
167
+
168
+ export function subscribeInsideEvent(listener: Listener): () => void {
169
+ listeners.add(listener);
170
+ return () => { listeners.delete(listener); };
171
+ }
172
+
173
+ /** No history/replay: the stream starts at the moment a client subscribes. */
174
+ export function handleInsideEvents(req: Request): Response {
175
+ if (req.method !== 'GET') return new Response(null, { status: 405, headers: { allow: 'GET' } });
176
+ const encoder = new TextEncoder();
177
+ let cleanup: (() => void) | undefined;
178
+ const stream = new ReadableStream<Uint8Array>({
179
+ start(controller) {
180
+ let closed = false;
181
+ let unsubscribe = () => {};
182
+ let heartbeat: ReturnType<typeof setInterval> | undefined;
183
+ const onAbort = () => close();
184
+ cleanup = () => {
185
+ if (closed) return;
186
+ closed = true;
187
+ if (heartbeat !== undefined) clearInterval(heartbeat);
188
+ unsubscribe();
189
+ req.signal.removeEventListener('abort', onAbort);
190
+ };
191
+ const close = () => {
192
+ cleanup?.();
193
+ try { controller.close(); } catch { /* cancelled already */ }
194
+ };
195
+ const send = (text: string): void => {
196
+ if (closed) return;
197
+ const bytes = encoder.encode(text);
198
+ if (bytes.byteLength > MAX_FRAME_BYTES || (controller.desiredSize ?? 0) <= 0) {
199
+ close();
200
+ return;
201
+ }
202
+ try { controller.enqueue(bytes); } catch { close(); }
203
+ };
204
+ if (req.signal.aborted) {
205
+ close();
206
+ return;
207
+ }
208
+ unsubscribe = subscribeInsideEvent((event) => {
209
+ send(`event: ${event.kind}\ndata: ${JSON.stringify(event)}\n\n`);
210
+ });
211
+ heartbeat = setInterval(() => send(': ping\n\n'), SSE_HEARTBEAT_MS);
212
+ req.signal.addEventListener('abort', onAbort, { once: true });
213
+ if (req.signal.aborted) close();
214
+ else send(': inside events stream\n\n');
215
+ },
216
+ cancel() { cleanup?.(); },
217
+ }, { highWaterMark: MAX_PENDING_FRAMES, size: () => 1 });
218
+ return new Response(stream, {
219
+ headers: {
220
+ 'content-type': 'text/event-stream; charset=utf-8',
221
+ 'cache-control': 'no-cache, no-transform',
222
+ 'x-accel-buffering': 'no',
223
+ connection: 'keep-alive',
224
+ },
225
+ });
226
+ }
@@ -81,6 +81,7 @@ import { createPwaConfirmChannel, createPwaQuestionChannel } from './hitl-pwa-ch
81
81
  import type { NexusEventBus } from './event-bus.js';
82
82
  import { jsonResponse } from './http-server.js';
83
83
  import { defaultChatEventBus } from './chat-event-bus.js';
84
+ import { resolveSessionProjectContext } from '../../project/session-context.js';
84
85
 
85
86
  const MIME_BY_EXT: Record<string, string> = {
86
87
  '.png': 'image/png',
@@ -803,13 +804,18 @@ export async function handlePromptPost(
803
804
  ): Promise<Response> {
804
805
  if (!checkAuth(req, opts)) return authFailureResponse(req, opts);
805
806
  if (!opts.history) return jsonResponse({ error: RUNTIME_NOT_WIRED }, 503);
806
- let body: DaemonPromptBody;
807
+ let rawBody: unknown;
807
808
  try {
808
- body = (await req.json()) as DaemonPromptBody;
809
+ rawBody = await req.json();
809
810
  } catch {
810
811
  return badRequest('invalid JSON body');
811
812
  }
812
- const parsed = parseDaemonPromptBody(body, opts.systemPrompt);
813
+ if (!rawBody || typeof rawBody !== 'object' || Array.isArray(rawBody)) {
814
+ return badRequest('userText or userContent required');
815
+ }
816
+ const body = rawBody as DaemonPromptBody;
817
+ const projectContext = resolveSessionProjectContext(typeof body.sessionId === 'string' ? body.sessionId : undefined);
818
+ const parsed = parseDaemonPromptBody(body, projectContext?.instructions ? [opts.systemPrompt, projectContext.instructions].filter(Boolean).join('\n\n') : opts.systemPrompt);
813
819
  if (!parsed.ok) return badRequest(parsed.reason);
814
820
  const submit = createDaemonPromptTurnSubmit({
815
821
  kind: 'submit-turn',
@@ -843,7 +849,8 @@ export async function handlePromptPost(
843
849
  ...((owner) => owner ? { verifiedOwner: owner } : {})(promptVerifiedOwner(req, opts)),
844
850
  ...(resolvePromptHitlChannels(typeof body.sessionId === 'string' ? body.sessionId : '', opts) ?? {}),
845
851
  ...(effectiveSurface ? { toolSurface: effectiveSurface } : {}),
846
- ...(opts.toolCwd ? { toolCwd: opts.toolCwd } : {}),
852
+ ...(projectContext?.cwd || opts.toolCwd ? { toolCwd: projectContext?.cwd ?? opts.toolCwd } : {}),
853
+ ...(projectContext?.instructions ? { projectInstructions: projectContext.instructions } : {}),
847
854
  dispatchToolErrorMessage: 'NEXUS prompt runtime has no tool surface (start nexus with `--tools readonly|webterm`)',
848
855
  });
849
856
  },
@@ -930,13 +937,18 @@ export async function handlePromptStreamPost(
930
937
  ): Promise<Response> {
931
938
  if (!checkAuth(req, opts)) return authFailureResponse(req, opts);
932
939
  if (!opts.history) return jsonResponse({ error: RUNTIME_NOT_WIRED }, 503);
933
- let body: DaemonPromptBody;
940
+ let rawBody: unknown;
934
941
  try {
935
- body = (await req.json()) as DaemonPromptBody;
942
+ rawBody = await req.json();
936
943
  } catch {
937
944
  return badRequest('invalid JSON body');
938
945
  }
939
- const parsed = parseDaemonPromptBody(body, opts.systemPrompt);
946
+ if (!rawBody || typeof rawBody !== 'object' || Array.isArray(rawBody)) {
947
+ return badRequest('userText or userContent required');
948
+ }
949
+ const body = rawBody as DaemonPromptBody;
950
+ const projectContext = resolveSessionProjectContext(typeof body.sessionId === 'string' ? body.sessionId : undefined);
951
+ const parsed = parseDaemonPromptBody(body, projectContext?.instructions ? [opts.systemPrompt, projectContext.instructions].filter(Boolean).join('\n\n') : opts.systemPrompt);
940
952
  if (!parsed.ok) return badRequest(parsed.reason);
941
953
  // M6 PR 1 (PLAN-rich-dev-feedback-multi-surface · 2026-05-13) — opt-in
942
954
  // debug-tap. PWA `/chat?debug-tap=on` propagates the query down to
@@ -1201,7 +1213,8 @@ export async function handlePromptStreamPost(
1201
1213
  ...((owner) => owner ? { verifiedOwner: owner } : {})(promptVerifiedOwner(req, opts)),
1202
1214
  ...(resolvePromptHitlChannels(typeof body.sessionId === 'string' ? body.sessionId : '', opts) ?? {}),
1203
1215
  ...(effectiveSurface ? { toolSurface: effectiveSurface } : {}),
1204
- ...(opts.toolCwd ? { toolCwd: opts.toolCwd } : {}),
1216
+ ...(projectContext?.cwd || opts.toolCwd ? { toolCwd: projectContext?.cwd ?? opts.toolCwd } : {}),
1217
+ ...(projectContext?.instructions ? { projectInstructions: projectContext.instructions } : {}),
1205
1218
  signal: turnAbortController.signal,
1206
1219
  onTextDelta: dualEmitTextDelta,
1207
1220
  onImageBlock: dualEmitImageBlock,
@@ -20,6 +20,7 @@
20
20
  * Query params (list):
21
21
  * status=<MissionStatus> filter by status (active / planning / ...)
22
22
  * goalSlug=<slug> filter by goal binding
23
+ * projectId=<id> filter by project association
23
24
  *
24
25
  * Cross-ref:
25
26
  * src/task-orchestrator/store.ts (listMissions · getMission ·
@@ -53,6 +54,7 @@ export interface MissionCardWire {
53
54
  status: MissionStatus;
54
55
  priority: Mission['priority'];
55
56
  goalSlug: string | null;
57
+ projectId?: string;
56
58
  taskCount: number;
57
59
  /** Counts so the PWA mission lane shows progress at a glance. */
58
60
  taskStatusCounts: Record<string, number>;
@@ -85,6 +87,7 @@ export function summarise(mission: Mission, tasks: readonly Task[]): MissionCard
85
87
  status: mission.status,
86
88
  priority: mission.priority,
87
89
  goalSlug: mission.goalSlug ?? null,
90
+ ...(mission.projectId !== undefined ? { projectId: mission.projectId } : {}),
88
91
  taskCount: tasks.length,
89
92
  taskStatusCounts,
90
93
  surfaceKindCounts,
@@ -103,9 +106,11 @@ export function handleMissionsList(
103
106
  const url = new URL(req.url);
104
107
  const statusParam = url.searchParams.get('status');
105
108
  const goalSlug = url.searchParams.get('goalSlug') ?? undefined;
106
- const filter: { status?: MissionStatus; goalSlug?: string } = {};
109
+ const projectId = url.searchParams.get('projectId') ?? undefined;
110
+ const filter: { status?: MissionStatus; goalSlug?: string; projectId?: string } = {};
107
111
  if (statusParam && isMissionStatus(statusParam)) filter.status = statusParam;
108
112
  if (goalSlug) filter.goalSlug = goalSlug;
113
+ if (projectId !== undefined) filter.projectId = projectId;
109
114
 
110
115
  const store = new TaskStore();
111
116
  try {