@weavecode/weave 0.1.6 → 0.1.7

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 (340) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +3 -3
  2. package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
  3. package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
  4. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -2
  6. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  7. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  9. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  10. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  11. package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
  12. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +1 -1
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +1 -0
  14. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +2 -2
  15. package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
  16. package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
  17. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +3 -3
  18. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  19. package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
  20. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  21. package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
  22. package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
  23. package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
  24. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  25. package/node_modules/@weavecode/cli/dist/init/provision.js +1 -1
  26. package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
  27. package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
  28. package/node_modules/@weavecode/cli/dist/parser.js +1 -1
  29. package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
  30. package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
  31. package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
  32. package/node_modules/@weavecode/cli/package.json +5 -5
  33. package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
  34. package/node_modules/@weavecode/core/dist/harness.d.ts +11 -0
  35. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  36. package/node_modules/@weavecode/core/dist/platform.js +1 -1
  37. package/node_modules/@weavecode/core/dist/types.js +1 -1
  38. package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
  39. package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
  40. package/node_modules/@weavecode/core/package.json +1 -1
  41. package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -4
  42. package/node_modules/@weavecode/harness/dist/claude/capture.js +9 -9
  43. package/node_modules/@weavecode/harness/dist/claude/commands.js +2 -2
  44. package/node_modules/@weavecode/harness/dist/claude/config.js +2 -2
  45. package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
  46. package/node_modules/@weavecode/harness/dist/claude/edits.js +1 -1
  47. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  48. package/node_modules/@weavecode/harness/dist/claude/images.js +2 -2
  49. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  50. package/node_modules/@weavecode/harness/dist/claude/liveness.js +1 -1
  51. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -1
  52. package/node_modules/@weavecode/harness/dist/claude/messaging.js +2 -2
  53. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
  54. package/node_modules/@weavecode/harness/dist/claude/narration.js +1 -1
  55. package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
  56. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -1
  57. package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
  58. package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
  59. package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
  60. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -2
  61. package/node_modules/@weavecode/harness/dist/claude/resume.js +1 -1
  62. package/node_modules/@weavecode/harness/dist/claude/rewind.js +1 -1
  63. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -1
  64. package/node_modules/@weavecode/harness/dist/claude/side-question.js +2 -2
  65. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +14 -14
  66. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -1
  67. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -2
  68. package/node_modules/@weavecode/harness/dist/claude/transcript-cursor.js +2 -2
  69. package/node_modules/@weavecode/harness/dist/claude/transcript.js +7 -7
  70. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  71. package/node_modules/@weavecode/harness/dist/codex/capture.js +2 -2
  72. package/node_modules/@weavecode/harness/dist/codex/commands.js +4 -4
  73. package/node_modules/@weavecode/harness/dist/codex/config.js +2 -2
  74. package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
  75. package/node_modules/@weavecode/harness/dist/codex/event-source.js +2 -2
  76. package/node_modules/@weavecode/harness/dist/codex/images.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  78. package/node_modules/@weavecode/harness/dist/codex/liveness.js +1 -1
  79. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/codex/messaging.js +2 -2
  81. package/node_modules/@weavecode/harness/dist/codex/narration.js +1 -1
  82. package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
  83. package/node_modules/@weavecode/harness/dist/codex/plugins.js +3 -3
  84. package/node_modules/@weavecode/harness/dist/codex/provision.js +1 -1
  85. package/node_modules/@weavecode/harness/dist/codex/questions.js +2 -2
  86. package/node_modules/@weavecode/harness/dist/codex/rollout.js +5 -5
  87. package/node_modules/@weavecode/harness/dist/codex/side-question.js +4 -4
  88. package/node_modules/@weavecode/harness/dist/codex/titles.js +4 -4
  89. package/node_modules/@weavecode/harness/dist/codex/toml.js +13 -13
  90. package/node_modules/@weavecode/harness/dist/codex/transcript.js +2 -2
  91. package/node_modules/@weavecode/harness/dist/driver.d.ts +7 -0
  92. package/node_modules/@weavecode/harness/dist/driver.js +1 -1
  93. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
  94. package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
  95. package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
  96. package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
  97. package/node_modules/@weavecode/harness/dist/shared/json-cap.js +1 -1
  98. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -1
  99. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -3
  100. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -2
  101. package/node_modules/@weavecode/harness/package.json +2 -2
  102. package/node_modules/@weavecode/server/dist/config/dotted.js +1 -1
  103. package/node_modules/@weavecode/server/dist/config/profiles.js +2 -2
  104. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  105. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  106. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  107. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -3
  108. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  110. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  111. package/node_modules/@weavecode/server/dist/daemon/config-routes.js +1 -1
  112. package/node_modules/@weavecode/server/dist/daemon/cron.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  114. package/node_modules/@weavecode/server/dist/daemon/dashboard-pusher.js +1 -1
  115. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/decision-config.js +2 -2
  117. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  118. package/node_modules/@weavecode/server/dist/daemon/entry.js +2 -2
  119. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  121. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  122. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/liveness.js +1 -1
  124. package/node_modules/@weavecode/server/dist/daemon/mcp-orchestration.js +1 -1
  125. package/node_modules/@weavecode/server/dist/daemon/narration-watcher.js +2 -2
  126. package/node_modules/@weavecode/server/dist/daemon/opener/backend-ghostty.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/opener/backend-iterm.js +1 -1
  128. package/node_modules/@weavecode/server/dist/daemon/opener/backend-konsole.js +2 -2
  129. package/node_modules/@weavecode/server/dist/daemon/opener/backend-terminal-app.js +1 -1
  130. package/node_modules/@weavecode/server/dist/daemon/opener/backend-wezterm.js +1 -1
  131. package/node_modules/@weavecode/server/dist/daemon/opener/backend-wt.js +1 -1
  132. package/node_modules/@weavecode/server/dist/daemon/opener/backend.js +1 -1
  133. package/node_modules/@weavecode/server/dist/daemon/opener/launch.js +1 -1
  134. package/node_modules/@weavecode/server/dist/daemon/opener/pty-terminals.js +4 -4
  135. package/node_modules/@weavecode/server/dist/daemon/opener/shared.js +1 -1
  136. package/node_modules/@weavecode/server/dist/daemon/opener/wezterm-mux.js +1 -1
  137. package/node_modules/@weavecode/server/dist/daemon/opener/wt.js +3 -3
  138. package/node_modules/@weavecode/server/dist/daemon/opener.js +1 -1
  139. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  140. package/node_modules/@weavecode/server/dist/daemon/project-files.js +2 -2
  141. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  142. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  143. package/node_modules/@weavecode/server/dist/daemon/prompt-images.js +1 -1
  144. package/node_modules/@weavecode/server/dist/daemon/routes/hooks-admin.js +1 -1
  145. package/node_modules/@weavecode/server/dist/daemon/routes/market.js +1 -1
  146. package/node_modules/@weavecode/server/dist/daemon/routes/orchestration.js +1 -1
  147. package/node_modules/@weavecode/server/dist/daemon/routes/path-refs.js +1 -1
  148. package/node_modules/@weavecode/server/dist/daemon/routes/project-files.js +1 -1
  149. package/node_modules/@weavecode/server/dist/daemon/routes/projects.js +1 -1
  150. package/node_modules/@weavecode/server/dist/daemon/routes/search.js +1 -1
  151. package/node_modules/@weavecode/server/dist/daemon/routes/session-control.js +1 -1
  152. package/node_modules/@weavecode/server/dist/daemon/routes/session-insights.js +1 -1
  153. package/node_modules/@weavecode/server/dist/daemon/routes/settings-statusline.js +1 -1
  154. package/node_modules/@weavecode/server/dist/daemon/routes/uploads.js +1 -1
  155. package/node_modules/@weavecode/server/dist/daemon/routes/visualizations.js +1 -1
  156. package/node_modules/@weavecode/server/dist/daemon/routes/watches.js +1 -1
  157. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -8
  158. package/node_modules/@weavecode/server/dist/daemon/session-open.d.ts +17 -0
  159. package/node_modules/@weavecode/server/dist/daemon/session-open.js +1 -1
  160. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  161. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  162. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  163. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -1
  164. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  165. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  166. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  167. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.js +1 -1
  168. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  169. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  170. package/node_modules/@weavecode/server/dist/daemon/upload-sessions.js +1 -1
  171. package/node_modules/@weavecode/server/dist/db/db.js +2 -2
  172. package/node_modules/@weavecode/server/dist/db/layout.js +1 -1
  173. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  174. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  175. package/node_modules/@weavecode/server/dist/hooks/dashboard-rate.js +1 -1
  176. package/node_modules/@weavecode/server/dist/hooks/decision-judge.js +1 -1
  177. package/node_modules/@weavecode/server/dist/hooks/delivery/ack-gate.js +1 -1
  178. package/node_modules/@weavecode/server/dist/hooks/delivery/channels.js +1 -1
  179. package/node_modules/@weavecode/server/dist/hooks/delivery/keys.js +1 -1
  180. package/node_modules/@weavecode/server/dist/hooks/delivery/queue.js +1 -1
  181. package/node_modules/@weavecode/server/dist/hooks/delivery/relay.js +1 -1
  182. package/node_modules/@weavecode/server/dist/hooks/delivery/send.js +2 -2
  183. package/node_modules/@weavecode/server/dist/hooks/delivery/views.d.ts +3 -1
  184. package/node_modules/@weavecode/server/dist/hooks/delivery/views.js +1 -1
  185. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  186. package/node_modules/@weavecode/server/dist/hooks/edge-extract.js +1 -1
  187. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  188. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  189. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -2
  190. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  191. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  192. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +5 -5
  193. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  194. package/node_modules/@weavecode/server/dist/hooks/orchestration-engine.js +7 -7
  195. package/node_modules/@weavecode/server/dist/hooks/orchestration-graph.js +1 -1
  196. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  197. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  198. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  199. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  200. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  201. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  202. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  203. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  204. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  205. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  206. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -1
  207. package/node_modules/@weavecode/server/dist/hooks/synthetic-sessions.js +1 -1
  208. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  209. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  210. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  211. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  212. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  213. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  214. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  215. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  216. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -1
  217. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  218. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -2
  219. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  220. package/node_modules/@weavecode/server/dist/install/installer.js +1 -1
  221. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  222. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  223. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  224. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  225. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  226. package/node_modules/@weavecode/server/dist/install/project-config.js +1 -1
  227. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  228. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  229. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  230. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  231. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  232. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  233. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  234. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  235. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  236. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  237. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  238. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  239. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  240. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +4 -4
  241. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  242. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  243. package/node_modules/@weavecode/server/dist/repositories/orchestrations.js +7 -7
  244. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  245. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  246. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  247. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  248. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  249. package/node_modules/@weavecode/server/dist/repositories/uploads.js +11 -11
  250. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  251. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -1
  252. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -3
  253. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  254. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  255. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  256. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  257. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  258. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  259. package/node_modules/@weavecode/server/package.json +4 -4
  260. package/node_modules/@weavecode/server/web/dist/assets/{abnfDiagram-WEYOIA3C-CbIFQh0R.js → abnfDiagram-WEYOIA3C-DDeQkTf5.js} +1 -1
  261. package/node_modules/@weavecode/server/web/dist/assets/{arc-DH8-rYAa.js → arc-CRZTRyjb.js} +1 -1
  262. package/node_modules/@weavecode/server/web/dist/assets/{architectureDiagram-ZHVYKT53-qnv6S0sc.js → architectureDiagram-ZHVYKT53-Dj54DE3O.js} +1 -1
  263. package/node_modules/@weavecode/server/web/dist/assets/{blockDiagram-RJAE7QA3-pT5eO-cB.js → blockDiagram-RJAE7QA3-BIH8mSIZ.js} +1 -1
  264. package/node_modules/@weavecode/server/web/dist/assets/{c4Diagram-XDPPPE54-DHDBDMb1.js → c4Diagram-XDPPPE54-5YoKWFOD.js} +1 -1
  265. package/node_modules/@weavecode/server/web/dist/assets/channel-5VM93AJ8.js +1 -0
  266. package/node_modules/@weavecode/server/web/dist/assets/{chunk-2E7WHVMD-CT951PH5.js → chunk-2E7WHVMD-B653kMXt.js} +1 -1
  267. package/node_modules/@weavecode/server/web/dist/assets/{chunk-2Q5K7J3B-E5AD7_ZY.js → chunk-2Q5K7J3B-f_A4_eDz.js} +1 -1
  268. package/node_modules/@weavecode/server/web/dist/assets/{chunk-4EMNKR2T-DWz9qkcy.js → chunk-4EMNKR2T-v5j5qNGj.js} +1 -1
  269. package/node_modules/@weavecode/server/web/dist/assets/{chunk-55XCU76K-D-SgWD8w.js → chunk-55XCU76K-CgEqeP7j.js} +1 -1
  270. package/node_modules/@weavecode/server/web/dist/assets/{chunk-5VM5RSS4-ci6YzbO5.js → chunk-5VM5RSS4-BeROhLXN.js} +1 -1
  271. package/node_modules/@weavecode/server/web/dist/assets/{chunk-JWPE2WC7-CY4mr2f4.js → chunk-JWPE2WC7-D6dXb_jr.js} +1 -1
  272. package/node_modules/@weavecode/server/web/dist/assets/{chunk-VQ5W62QI-CON8zyg8.js → chunk-VQ5W62QI-CnHdSEMi.js} +1 -1
  273. package/node_modules/@weavecode/server/web/dist/assets/{chunk-XXDRQBXY-DXXXZ4pW.js → chunk-XXDRQBXY-BkG_e6PE.js} +1 -1
  274. package/node_modules/@weavecode/server/web/dist/assets/{chunk-ZCHMQSOR-CukvPvkM.js → chunk-ZCHMQSOR-DxR-fxzs.js} +2 -2
  275. package/node_modules/@weavecode/server/web/dist/assets/{classDiagram-v2-4MYWR3UA-GiWZ9xtF.js → classDiagram-v2-4MYWR3UA-DQe1b_k8.js} +1 -1
  276. package/node_modules/@weavecode/server/web/dist/assets/{cose-bilkent-JH36ORCC-D7aJ-akq.js → cose-bilkent-JH36ORCC-DThrA8S5.js} +1 -1
  277. package/node_modules/@weavecode/server/web/dist/assets/{cynefin-EF2NZ3EQ-9B__MaRM.js → cynefin-EF2NZ3EQ-OZotFKUu.js} +1 -1
  278. package/node_modules/@weavecode/server/web/dist/assets/{cynefinDiagram-WF24UDRP-B2ujZh2k.js → cynefinDiagram-WF24UDRP-DJjq2hfT.js} +1 -1
  279. package/node_modules/@weavecode/server/web/dist/assets/{dagre-NK4GIZVX-nHaB6IWf.js → dagre-NK4GIZVX-C2vH93HT.js} +1 -1
  280. package/node_modules/@weavecode/server/web/dist/assets/{diagram-CBK3MWTC-xKfjDvgr.js → diagram-CBK3MWTC-DrF_ScM-.js} +1 -1
  281. package/node_modules/@weavecode/server/web/dist/assets/{diagram-I5XIIV2D-BHT2-5mY.js → diagram-I5XIIV2D-D1qoUJ4t.js} +1 -1
  282. package/node_modules/@weavecode/server/web/dist/assets/{diagram-ODIL2UCW-CckywF4W.js → diagram-ODIL2UCW-D9A6W8oB.js} +1 -1
  283. package/node_modules/@weavecode/server/web/dist/assets/{diagram-PFBEJUXE-Dpjlc7Wh.js → diagram-PFBEJUXE-PeI-eyu2.js} +1 -1
  284. package/node_modules/@weavecode/server/web/dist/assets/{diagram-RJA3I4VV-M6WznOaW.js → diagram-RJA3I4VV-DITY0Rd8.js} +1 -1
  285. package/node_modules/@weavecode/server/web/dist/assets/{diagram-TYUNFSNR-DgRJ3zL1.js → diagram-TYUNFSNR-D5KieEw5.js} +1 -1
  286. package/node_modules/@weavecode/server/web/dist/assets/{ebnfDiagram-V4P3TTPT-BzzVN__a.js → ebnfDiagram-V4P3TTPT-DDylK-gz.js} +1 -1
  287. package/node_modules/@weavecode/server/web/dist/assets/{elk-QONTBCTQ-Ch6Gs9G9.js → elk-QONTBCTQ-D3xrVg0U.js} +1 -1
  288. package/node_modules/@weavecode/server/web/dist/assets/{erDiagram-KYQIGQAA-COxT-Pxb.js → erDiagram-KYQIGQAA-y_V1cor7.js} +1 -1
  289. package/node_modules/@weavecode/server/web/dist/assets/{flowDiagram-IUGLLWBU-CJVWnTBa.js → flowDiagram-IUGLLWBU-BJ8Z0MkF.js} +1 -1
  290. package/node_modules/@weavecode/server/web/dist/assets/{ganttDiagram-R7GPNTJY-BkRpWPUl.js → ganttDiagram-R7GPNTJY-C0q-CS1T.js} +1 -1
  291. package/node_modules/@weavecode/server/web/dist/assets/{gitGraphDiagram-PDYL7XHY-Ba8BJcvZ.js → gitGraphDiagram-PDYL7XHY-BYTComiB.js} +1 -1
  292. package/node_modules/@weavecode/server/web/dist/assets/index-BKxAxaVG.js +1091 -0
  293. package/node_modules/@weavecode/server/web/dist/assets/index-C0Sd4MH7.css +11 -0
  294. package/node_modules/@weavecode/server/web/dist/assets/{infoDiagram-MVDRKAX5-HTQ5FUNK.js → infoDiagram-MVDRKAX5-DtixgjLP.js} +1 -1
  295. package/node_modules/@weavecode/server/web/dist/assets/{ishikawaDiagram-HPEHV2GE-BNjEDIZy.js → ishikawaDiagram-HPEHV2GE-ChEnND76.js} +1 -1
  296. package/node_modules/@weavecode/server/web/dist/assets/{journeyDiagram-BOSHW7O7-Cao6h91a.js → journeyDiagram-BOSHW7O7-DHcNtpYF.js} +1 -1
  297. package/node_modules/@weavecode/server/web/dist/assets/{kanban-definition-FNSA4HC5-CXIx2CHQ.js → kanban-definition-FNSA4HC5-Dft7qpW5.js} +1 -1
  298. package/node_modules/@weavecode/server/web/dist/assets/{linear-65WmlvQb.js → linear-DEo11t-X.js} +1 -1
  299. package/node_modules/@weavecode/server/web/dist/assets/{mermaid.core-D39fi_iR.js → mermaid.core-D_Dp_Kl2.js} +4 -4
  300. package/node_modules/@weavecode/server/web/dist/assets/{mindmap-definition-6OY57UG3-DHqpz_AK.js → mindmap-definition-6OY57UG3-CM6OAd_-.js} +1 -1
  301. package/node_modules/@weavecode/server/web/dist/assets/{pegDiagram-ECIUJNBX-Cpy1nsER.js → pegDiagram-ECIUJNBX-_QkY0h8Q.js} +1 -1
  302. package/node_modules/@weavecode/server/web/dist/assets/{pieDiagram-GNMPY74T-B1IyNqzr.js → pieDiagram-GNMPY74T-ZGr5vtDj.js} +1 -1
  303. package/node_modules/@weavecode/server/web/dist/assets/{quadrantDiagram-D57K4MC3-zSM6o7mB.js → quadrantDiagram-D57K4MC3-D8pQ_PU2.js} +1 -1
  304. package/node_modules/@weavecode/server/web/dist/assets/{railroadDiagram-Y72NRBL7-oM4XJIwA.js → railroadDiagram-Y72NRBL7-DUIo-WmA.js} +1 -1
  305. package/node_modules/@weavecode/server/web/dist/assets/{requirementDiagram-EQYSW5RA-CbCLBjHf.js → requirementDiagram-EQYSW5RA-C90DU5Ny.js} +1 -1
  306. package/node_modules/@weavecode/server/web/dist/assets/{sankeyDiagram-SY24JHO5-BucVk6EP.js → sankeyDiagram-SY24JHO5-B_poYGgJ.js} +1 -1
  307. package/node_modules/@weavecode/server/web/dist/assets/{sequenceDiagram-BLEHNHQU-Dg8CYEnT.js → sequenceDiagram-BLEHNHQU-DDW7b2Dn.js} +1 -1
  308. package/node_modules/@weavecode/server/web/dist/assets/{sizeCapture-INFHLROL-C51zb7Oc.js → sizeCapture-INFHLROL-CmKoqX6K.js} +1 -1
  309. package/node_modules/@weavecode/server/web/dist/assets/{stateDiagram-v2-A6IESKWZ-BvK2l3is.js → stateDiagram-v2-A6IESKWZ-CkVMAyxG.js} +1 -1
  310. package/node_modules/@weavecode/server/web/dist/assets/{swimlanes-B3ENRKFQ-Ds7QOfXW.js → swimlanes-B3ENRKFQ-Dm_Omzky.js} +1 -1
  311. package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-Bjj8ZA4d.js +8 -0
  312. package/node_modules/@weavecode/server/web/dist/assets/{timeline-definition-JXYKGLGB-CadU4Qq4.js → timeline-definition-JXYKGLGB-DnhkRGLb.js} +1 -1
  313. package/node_modules/@weavecode/server/web/dist/assets/{usecaseDiagram-WPOLBNNX-BYuZwTDZ.js → usecaseDiagram-WPOLBNNX-_TdIjC6Z.js} +1 -1
  314. package/node_modules/@weavecode/server/web/dist/assets/{vennDiagram-Q3Y3IDCW-C7zgxe07.js → vennDiagram-Q3Y3IDCW-FzgsymXB.js} +1 -1
  315. package/node_modules/@weavecode/server/web/dist/assets/{wardleyDiagram-IVAIDKWA-DA4Otf4s.js → wardleyDiagram-IVAIDKWA-BwqimStC.js} +1 -1
  316. package/node_modules/@weavecode/server/web/dist/assets/{xychartDiagram-4URNHDU4-Bs5YGwMU.js → xychartDiagram-4URNHDU4-CFjjVPIV.js} +1 -1
  317. package/node_modules/@weavecode/server/web/dist/icons/apple-touch-icon.png +0 -0
  318. package/node_modules/@weavecode/server/web/dist/icons/icon-192.png +0 -0
  319. package/node_modules/@weavecode/server/web/dist/icons/icon-512.png +0 -0
  320. package/node_modules/@weavecode/server/web/dist/icons/icon-maskable-512.png +0 -0
  321. package/node_modules/@weavecode/server/web/dist/index.html +11 -2
  322. package/node_modules/@weavecode/server/web/dist/manifest.webmanifest +16 -0
  323. package/node_modules/@weavecode/templates/package.json +2 -2
  324. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/README.md +3 -8
  325. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/package.json +1 -1
  326. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/tslib.d.ts +4 -2
  327. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/tslib.es6.js +10 -1
  328. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/tslib.es6.mjs +10 -1
  329. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/tslib/tslib.js +10 -1
  330. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/README.md +3 -8
  331. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/package.json +1 -1
  332. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/tslib.d.ts +4 -2
  333. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/tslib.es6.js +10 -1
  334. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/tslib.es6.mjs +10 -1
  335. package/node_modules/selfsigned/node_modules/pkijs/node_modules/tslib/tslib.js +10 -1
  336. package/package.json +6 -6
  337. package/node_modules/@weavecode/server/web/dist/assets/channel-BHPeeuzN.js +0 -1
  338. package/node_modules/@weavecode/server/web/dist/assets/index-CtifxEiF.css +0 -11
  339. package/node_modules/@weavecode/server/web/dist/assets/index-FwH9INgS.js +0 -1090
  340. package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-ByBF02UJ.js +0 -8
@@ -1,2 +1,2 @@
1
- import{execFile as H}from"node:child_process";import{lstat as $,mkdir as J,readFile as k,readdir as R,realpath as O,rename as T,stat as D,writeFile as V}from"node:fs/promises";import{readdirSync as q,rmSync as G}from"node:fs";import f from"node:path";import{promisify as K}from"node:util";import{getIndexDir as L}from"../db/paths.js";const Q=K(H);export const MAX_INDEX_FILES=3e5,INDEX_VERSION=2;const M=3e4,A=10*6e4,U=3,Y=new Set(["node_modules",".git","dist","build","out",".next","target","coverage",".turbo"]);async function v(t,n){try{const{stdout:e}=await Q("git",["ls-files","-z",...n],{cwd:t,timeout:1e4,maxBuffer:67108864,windowsHide:!0});return e.split("\0").filter(Boolean)}catch{return null}}async function Z(t){const n=await v(t,["--stage"]),e=[],s=[];for(const i of n??[])i.startsWith("160000 ")?e.push(i.slice(i.indexOf(" ")+1)):i.startsWith("120000 ")&&s.push(i.slice(i.indexOf(" ")+1));return{links:e,symlinks:s}}function E(t){return $(f.join(t,".git")).then(()=>!0,()=>!1)}async function tt(t){try{let n=f.join(t,".git");if(!(await $(n)).isDirectory()){const i=/^gitdir:\s*(.+)$/m.exec(await k(n,"utf8"));if(!i)return null;n=f.resolve(t,i[1].trim())}const e=(await k(f.join(n,"HEAD"),"utf8")).trim(),s=e.startsWith("ref: ")?await(async()=>{const i=e.slice(5);try{return(await k(f.join(n,i),"utf8")).trim()}catch{const r=(await k(f.join(n,"packed-refs"),"utf8")).split(`
2
- `).find(o=>o.endsWith(` ${i}`));return r?r.slice(0,r.indexOf(" ")):null}})():e;return s!==null&&/^[0-9a-f]{40}$/i.test(s)?s.slice(0,7):null}catch{return null}}async function nt(t){const n=await v(t,["--others","--ignored","--exclude-standard","--directory"]),e=[];for(const s of n??[]){if(!s.endsWith("/"))continue;const i=s.slice(0,-1);await E(f.join(t,i))&&e.push(i)}return e}async function W(t,n=""){const[e,s,i]=await Promise.all([v(t,["--cached","--others","--exclude-standard"]),Z(t),nt(t)]);if(!e)return null;const r=new Set;for(const c of s.links)r.add(c);for(const c of e)c.endsWith("/")&&r.add(c.slice(0,-1));for(const c of i)r.add(c);const o=new Set;for(const c of s.symlinks)if(!r.has(c))try{(await D(f.join(t,c))).isDirectory()&&o.add(c)}catch{}const a=e.filter(c=>!c.endsWith("/")&&!r.has(c)&&!o.has(c)).map(c=>n+c),u=[...r,...o].map(c=>n+c),d={};for(const c of r){const l=f.join(t,c);if(!await E(l))continue;const m=await tt(l);m&&(d[`${n}${c}`]=m);const p=await W(l,`${n}${c}/`);p&&(a.push(...p.files),u.push(...p.links),Object.assign(d,p.heads))}const g=new Set([await O(t).catch(()=>t)]);for(const c of o){const l=f.join(t,c),m=await O(l).catch(()=>null);if(m===null||g.has(m))continue;g.add(m);const p=`${n}${c}/`;for(let h=a.length-1;h>=0;h--)a[h].startsWith(p)&&a.splice(h,1);const y=await W(l,p)??{files:await N(l),links:[],heads:{}};a.push(...y.files),u.push(...y.links),Object.assign(d,y.heads)}return{files:a,links:u,heads:d}}async function N(t){const n=[],e=new Set([await O(t).catch(()=>t)]),s=async i=>{if(n.length>=MAX_INDEX_FILES)return;let r;try{r=await R(f.join(t,i),{withFileTypes:!0})}catch{return}for(const o of r){if(n.length>=MAX_INDEX_FILES)return;const a=i?`${i}/${o.name}`:o.name;if(o.isDirectory()||o.isSymbolicLink()){if(Y.has(o.name))continue;if(o.isSymbolicLink()){let u;try{u=(await D(f.join(t,a))).isDirectory()}catch{u=!1}if(!u){o.name!==".git"&&n.push(a);continue}const d=await O(f.join(t,a)).catch(()=>null);if(d===null||e.has(d))continue;e.add(d);try{await s(a)}finally{e.delete(d)}}else await s(a)}else o.isFile()&&o.name!==".git"&&n.push(a)}};return await s(""),n}function _(t){const n=new Set;for(const e of t){let s=e.lastIndexOf("/");for(;s>0;){const i=e.slice(0,s);if(n.has(i))break;n.add(i),s=i.lastIndexOf("/")}}return[...n].sort()}async function I(t){try{let n=f.join(t,".git");if(!(await $(n)).isDirectory()){const s=/^gitdir:\s*(.+)$/m.exec(await k(n,"utf8"));if(!s)return null;n=f.resolve(t,s[1].trim())}const e=await D(f.join(n,"index"));return`${e.mtimeMs}:${e.size}`}catch{return null}}async function et(t){const n=await W(t),e=n?.files??await N(t),s=e.length>MAX_INDEX_FILES,i=s?e.slice(0,MAX_INDEX_FILES):e;i.sort();const r=n?.links??[],o=[...new Set([..._(i),...r,..._(r)])].sort();return{v:INDEX_VERSION,root:t,at:Date.now(),stamp:await I(t),truncated:s,files:i,dirs:o,...n&&Object.keys(n.heads).length>0?{submodules:n.heads}:{}}}export function hydrateIndex(t){const n=new Array(t.files.length);for(let r=0;r<t.files.length;r++)n[r]=t.files[r].toLowerCase();const e=new Array(t.dirs.length);for(let r=0;r<t.dirs.length;r++)e[r]=t.dirs[r].toLowerCase();const s=new Map,i=r=>{let o=s.get(r);return o||s.set(r,o={dirs:[],files:[],sorted:!1}),o};for(const r of t.dirs)i(r.slice(0,Math.max(0,r.lastIndexOf("/")))).dirs.push(r);for(const r of t.files)i(r.slice(0,Math.max(0,r.lastIndexOf("/")))).files.push(r);return{...t,lower:n,dirLower:e,children:s,submodules:t.submodules??{}}}export async function buildIndex(t){return hydrateIndex(await et(t))}const w=new Map,b=new Map;let F=null;export function setFileIndexRoot(t){F=t}function z(t){return f.join(F??L(),`${t}.json`)}function st(t){return{v:t.v,root:t.root,at:t.at,stamp:t.stamp,truncated:t.truncated,files:t.files,dirs:t.dirs,...Object.keys(t.submodules).length>0?{submodules:{...t.submodules}}:{}}}async function it(t,n){const e=z(t),s=`${e}.tmp`;try{await J(f.dirname(e),{recursive:!0}),await V(s,JSON.stringify(st(n)),"utf8"),await T(s,e)}catch{}}async function P(t,n){try{const e=JSON.parse(await k(z(t),"utf8"));return e?.v!==INDEX_VERSION||e.root!==n||!Array.isArray(e.files)||!Array.isArray(e.dirs)?null:e}catch{return null}}function S(t,n){for(w.delete(t),w.set(t,n);w.size>U;){const e=w.keys().next().value;if(e===void 0)break;w.delete(e)}}function C(t,n){const e=b.get(t);if(e)return e;const s=buildIndex(n).then(r=>(S(t,r),it(t,r),r));b.set(t,s);const i=()=>{b.delete(t)};return s.then(i,i),s}export async function projectFileIndex(t,n,e={}){if(e.fresh){const o=b.get(t);if(o)return o}const s=w.get(t);s&&s.root!==n&&w.delete(t);const i=s&&s.root===n?s:null;if(i&&e.fresh)return C(t,n).catch(()=>{}),i;if(i&&await I(n)===i.stamp){if(Date.now()-i.at<M)return i;w.delete(t)}else i&&w.delete(t);const r=b.get(t);if(r)return r;if(!i){const o=await P(t,n);if(o&&Date.now()-o.at<A){const a=hydrateIndex(o);if(e.fresh)return S(t,a),C(t,n).catch(()=>{}),a;if(await I(n)===o.stamp)return S(t,a),a}}return C(t,n)}export async function peekCachedIndex(t,n,e={}){const s=w.get(t);if(s&&s.root===n)return Date.now()-s.at<M&&await I(n)===s.stamp?s:(w.delete(t),null);const i=e.maxStaleMs??A,r=await P(t,n);if(r&&Date.now()-r.at<i&&await I(n)===r.stamp){const o=hydrateIndex(r);return S(t,o),o}return null}export function clearFileIndexCache(){w.clear()}export function pruneFileIndexes(t){const n=F??L(),e=new Set(t.map(i=>`${i}.json`));let s;try{s=q(n)}catch{return}for(const i of s)if(!(!i.endsWith(".json")||e.has(i)))try{G(f.join(n,i))}catch{}}const X=new Intl.Collator(void 0,{numeric:!0});export function listDirOf(t,n){const e=t.children.get(n);if(!e)return[];e.sorted||(e.dirs.sort(X.compare),e.files.sort(X.compare),e.sorted=!0);const s=[];for(const i of e.dirs){const r=t.submodules[i];s.push(r?{path:i,kind:"dir",head:r}:{path:i,kind:"dir"})}for(const i of e.files)s.push({path:i,kind:"file"});return s}function rt(t,n){return t.startsWith(n)?3:t.includes(n)?2:ot(t,n)?1:-1}function ot(t,n){let e=0;for(let s=0;s<t.length&&e<n.length;s++)t[s]===n[e]&&e++;return e===n.length}function at(t,n,e){const s=t.lastIndexOf("/")+1,i=t.slice(s).toLowerCase();if(n===3||n===2){const a=i.indexOf(e);return a<0?[]:[[s+a,e.length]]}const r=[];let o=0;for(let a=0;a<i.length&&o<e.length;a++)i[a]===e[o]&&(r.push([s+a,1]),o++);return r}function B(t,n){return n.rank-t.rank||t.len-n.len||t.path.localeCompare(n.path)}const ct=8,lt=1024;function ft(t,n){if(!n)return 0;let e=0,s=t.length;for(;e<s;){const i=e+s>>1;t[i]<n?e=i+1:s=i}return e}export function startMatch(t,n,e,s=""){const i=n.trim().toLowerCase(),r=s?`${s}/`:"",o=[];let a=i&&e>0?"files":"done",u=0,d=0,g=!1;const c=(l,m)=>{const p=l.slice(l.lastIndexOf("/")+1).toLowerCase(),y=rt(p,i);if(y<0)return;d++;const h={path:l,kind:m,rank:y,len:l.length};if(o.length===e&&B(h,o[e-1])>=0)return;const j=o.length===e;let x=j?e-1:o.length;for(j?o[e-1]=h:o.push(h);x>0&&B(h,o[x-1])<0;)o[x]=o[x-1],x--;o[x]=h};return{step(l){const m=Date.now()+l;let p=0;for(;a!=="done";){const y=a==="files"?t.files:t.dirs,h=a==="files"?"file":"dir";for(u===0&&(u=ft(y,r));u<y.length;){const j=y[u];if(r&&!j.startsWith(r))break;if(c(j,h),u++,o.length===e&&o[e-1].rank===3)return g=!0,a="done",!0;if((++p&lt-1)===0&&Date.now()>m)return!1}u=0,a=a==="files"?"dirs":"done"}return!0},result(){return{hits:o.map(l=>({path:l.path,kind:l.kind,ranges:at(l.path,l.rank,i)})),total:g?o.length:d,capped:g}}}}export async function matchPaths(t,n,e,s=""){const i=startMatch(t,n,e,s);for(;!i.step(ct);)await new Promise(r=>setImmediate(r));return i.result()}
1
+ import{execFile as X}from"node:child_process";import{lstat as $,mkdir as V,readFile as x,readdir as z,realpath as b,rename as B,stat as A,writeFile as G}from"node:fs/promises";import{readdirSync as J,rmSync as Y}from"node:fs";import f from"node:path";import{promisify as K}from"node:util";import{getIndexDir as v}from"../db/paths.js";const Q=K(X);export const MAX_INDEX_FILES=3e5,INDEX_VERSION=2;const F=3e4,W=10*6e4,U=3,Z=new Set(["node_modules",".git","dist","build","out",".next","target","coverage",".turbo"]);async function M(t,e){try{const{stdout:n}=await Q("git",["ls-files","-z",...e],{cwd:t,timeout:1e4,maxBuffer:67108864,windowsHide:!0});return n.split("\0").filter(Boolean)}catch{return null}}async function q(t){const e=await M(t,["--stage"]),n=[],i=[];for(const s of e??[])s.startsWith("160000 ")?n.push(s.slice(s.indexOf(" ")+1)):s.startsWith("120000 ")&&i.push(s.slice(s.indexOf(" ")+1));return{links:n,symlinks:i}}function I(t){return $(f.join(t,".git")).then(()=>!0,()=>!1)}async function tt(t){try{let e=f.join(t,".git");if(!(await $(e)).isDirectory()){const s=/^gitdir:\s*(.+)$/m.exec(await x(e,"utf8"));if(!s)return null;e=f.resolve(t,s[1].trim())}const n=(await x(f.join(e,"HEAD"),"utf8")).trim(),i=n.startsWith("ref: ")?await(async()=>{const s=n.slice(5);try{return(await x(f.join(e,s),"utf8")).trim()}catch{const a=(await x(f.join(e,"packed-refs"),"utf8")).split(`
2
+ `).find(o=>o.endsWith(` ${s}`));return a?a.slice(0,a.indexOf(" ")):null}})():n;return i!==null&&/^[0-9a-f]{40}$/i.test(i)?i.slice(0,7):null}catch{return null}}async function et(t){const e=await M(t,["--others","--ignored","--exclude-standard","--directory"]),n=[];for(const i of e??[]){if(!i.endsWith("/"))continue;const s=i.slice(0,-1);await I(f.join(t,s))&&n.push(s)}return n}async function C(t,e=""){const[n,i,s]=await Promise.all([M(t,["--cached","--others","--exclude-standard"]),q(t),et(t)]);if(!n)return null;const r=new Set;for(const c of i.links)r.add(c);for(const c of n)c.endsWith("/")&&r.add(c.slice(0,-1));for(const c of s)r.add(c);const a=new Set;for(const c of i.symlinks)if(!r.has(c))try{(await A(f.join(t,c))).isDirectory()&&a.add(c)}catch{}const o=n.filter(c=>!c.endsWith("/")&&!r.has(c)&&!a.has(c)).map(c=>e+c),u=[...r,...a].map(c=>e+c),d={};for(const c of r){const l=f.join(t,c);if(!await I(l))continue;const p=await tt(l);p&&(d[`${e}${c}`]=p);const m=await C(l,`${e}${c}/`);m&&(o.push(...m.files),u.push(...m.links),Object.assign(d,m.heads))}const y=new Set([await b(t).catch(()=>t)]);for(const c of a){const l=f.join(t,c),p=await b(l).catch(()=>null);if(p===null||y.has(p))continue;y.add(p);const m=`${e}${c}/`;for(let h=o.length-1;h>=0;h--)o[h].startsWith(m)&&o.splice(h,1);const g=await C(l,m)??{files:await j(l),links:[],heads:{}};o.push(...g.files),u.push(...g.links),Object.assign(d,g.heads)}return{files:o,links:u,heads:d}}async function j(t){const e=[],n=new Set([await b(t).catch(()=>t)]),i=async s=>{if(e.length>=MAX_INDEX_FILES)return;let r;try{r=await z(f.join(t,s),{withFileTypes:!0})}catch{return}for(const a of r){if(e.length>=MAX_INDEX_FILES)return;const o=s?`${s}/${a.name}`:a.name;if(a.isDirectory()||a.isSymbolicLink()){if(Z.has(a.name))continue;if(a.isSymbolicLink()){let u;try{u=(await A(f.join(t,o))).isDirectory()}catch{u=!1}if(!u){a.name!==".git"&&e.push(o);continue}const d=await b(f.join(t,o)).catch(()=>null);if(d===null||n.has(d))continue;n.add(d);try{await i(o)}finally{n.delete(d)}}else await i(o)}else a.isFile()&&a.name!==".git"&&e.push(o)}};return await i(""),e}function N(t){const e=new Set;for(const n of t){let i=n.lastIndexOf("/");for(;i>0;){const s=n.slice(0,i);if(e.has(s))break;e.add(s),i=s.lastIndexOf("/")}}return[...e].sort()}async function O(t){try{let e=f.join(t,".git");if(!(await $(e)).isDirectory()){const i=/^gitdir:\s*(.+)$/m.exec(await x(e,"utf8"));if(!i)return null;e=f.resolve(t,i[1].trim())}const n=await A(f.join(e,"index"));return`${n.mtimeMs}:${n.size}`}catch{return null}}async function nt(t){const e=await C(t),n=e?.files??await j(t),i=n.length>MAX_INDEX_FILES,s=i?n.slice(0,MAX_INDEX_FILES):n;s.sort();const r=e?.links??[],a=[...new Set([...N(s),...r,...N(r)])].sort();return{v:INDEX_VERSION,root:t,at:Date.now(),stamp:await O(t),truncated:i,files:s,dirs:a,...e&&Object.keys(e.heads).length>0?{submodules:e.heads}:{}}}export function hydrateIndex(t){const e=new Array(t.files.length);for(let r=0;r<t.files.length;r++)e[r]=t.files[r].toLowerCase();const n=new Array(t.dirs.length);for(let r=0;r<t.dirs.length;r++)n[r]=t.dirs[r].toLowerCase();const i=new Map,s=r=>{let a=i.get(r);return a||i.set(r,a={dirs:[],files:[],sorted:!1}),a};for(const r of t.dirs)s(r.slice(0,Math.max(0,r.lastIndexOf("/")))).dirs.push(r);for(const r of t.files)s(r.slice(0,Math.max(0,r.lastIndexOf("/")))).files.push(r);return{...t,lower:e,dirLower:n,children:i,submodules:t.submodules??{}}}export async function buildIndex(t){return hydrateIndex(await nt(t))}const w=new Map,D=new Map;let E=null;export function setFileIndexRoot(t){E=t}function H(t){return f.join(E??v(),`${t}.json`)}function it(t){return{v:t.v,root:t.root,at:t.at,stamp:t.stamp,truncated:t.truncated,files:t.files,dirs:t.dirs,...Object.keys(t.submodules).length>0?{submodules:{...t.submodules}}:{}}}async function st(t,e){const n=H(t),i=`${n}.tmp`;try{await V(f.dirname(n),{recursive:!0}),await G(i,JSON.stringify(it(e)),"utf8"),await B(i,n)}catch{}}async function P(t,e){try{const n=JSON.parse(await x(H(t),"utf8"));return n?.v!==INDEX_VERSION||n.root!==e||!Array.isArray(n.files)||!Array.isArray(n.dirs)?null:n}catch{return null}}function _(t,e){for(w.delete(t),w.set(t,e);w.size>U;){const n=w.keys().next().value;if(n===void 0)break;w.delete(n)}}function L(t,e){const n=D.get(t);if(n)return n;const i=buildIndex(e).then(r=>(_(t,r),st(t,r),r));D.set(t,i);const s=()=>{D.delete(t)};return i.then(s,s),i}export async function projectFileIndex(t,e,n={}){if(n.fresh){const a=D.get(t);if(a)return a}const i=w.get(t);i&&i.root!==e&&w.delete(t);const s=i&&i.root===e?i:null;if(s&&n.fresh)return L(t,e).catch(()=>{}),s;if(s&&await O(e)===s.stamp){if(Date.now()-s.at<F)return s;w.delete(t)}else s&&w.delete(t);const r=D.get(t);if(r)return r;if(!s){const a=await P(t,e);if(a&&Date.now()-a.at<W){const o=hydrateIndex(a);if(n.fresh)return _(t,o),L(t,e).catch(()=>{}),o;if(await O(e)===a.stamp)return _(t,o),o}}return L(t,e)}export async function peekCachedIndex(t,e,n={}){const i=w.get(t);if(i&&i.root===e)return Date.now()-i.at<F&&await O(e)===i.stamp?i:(w.delete(t),null);const s=n.maxStaleMs??W,r=await P(t,e);if(r&&Date.now()-r.at<s&&await O(e)===r.stamp){const a=hydrateIndex(r);return _(t,a),a}return null}export function clearFileIndexCache(){w.clear()}export function pruneFileIndexes(t){const e=E??v(),n=new Set(t.map(s=>`${s}.json`));let i;try{i=J(e)}catch{return}for(const s of i)if(!(!s.endsWith(".json")||n.has(s)))try{Y(f.join(e,s))}catch{}}const R=new Intl.Collator(void 0,{numeric:!0});export function listDirOf(t,e){const n=t.children.get(e);if(!n)return[];n.sorted||(n.dirs.sort(R.compare),n.files.sort(R.compare),n.sorted=!0);const i=[];for(const s of n.dirs){const r=t.submodules[s];i.push(r?{path:s,kind:"dir",head:r}:{path:s,kind:"dir"})}for(const s of n.files)i.push({path:s,kind:"file"});return i}function rt(t,e){return t.startsWith(e)?3:t.includes(e)?2:at(t,e)?1:-1}function at(t,e){let n=0;for(let i=0;i<t.length&&n<e.length;i++)t[i]===e[n]&&n++;return n===e.length}function ot(t,e,n){const i=t.lastIndexOf("/")+1,s=t.slice(i).toLowerCase();if(e===3||e===2){const o=s.indexOf(n);return o<0?[]:[[i+o,n.length]]}const r=[];let a=0;for(let o=0;o<s.length&&a<n.length;o++)s[o]===n[a]&&(r.push([i+o,1]),a++);return r}function T(t,e){return e.rank-t.rank||t.len-e.len||t.path.localeCompare(e.path)}const ct=8,lt=1024;function ft(t,e){if(!e)return 0;let n=0,i=t.length;for(;n<i;){const s=n+i>>1;t[s]<e?n=s+1:i=s}return n}export function startMatch(t,e,n,i=""){const s=e.trim().toLowerCase(),r=i?`${i}/`:"",a=[];let o=s&&n>0?"files":"done",u=0,d=0,y=!1;const c=(l,p)=>{const m=l.slice(l.lastIndexOf("/")+1).toLowerCase(),g=rt(m,s);if(g<0)return;d++;const h={path:l,kind:p,rank:g,len:l.length};if(a.length===n&&T(h,a[n-1])>=0)return;const S=a.length===n;let k=S?n-1:a.length;for(S?a[n-1]=h:a.push(h);k>0&&T(h,a[k-1])<0;)a[k]=a[k-1],k--;a[k]=h};return{step(l){const p=Date.now()+l;let m=0;for(;o!=="done";){const g=o==="files"?t.files:t.dirs,h=o==="files"?"file":"dir";for(u===0&&(u=ft(g,r));u<g.length;){const S=g[u];if(r&&!S.startsWith(r))break;if(c(S,h),u++,a.length===n&&a[n-1].rank===3)return y=!0,o="done",!0;if((++m&lt-1)===0&&Date.now()>p)return!1}u=0,o=o==="files"?"dirs":"done"}return!0},result(){return{hits:a.map(l=>({path:l.path,kind:l.kind,ranges:ot(l.path,l.rank,s)})),total:y?a.length:d,capped:y}}}}export async function matchPaths(t,e,n,i=""){const s=startMatch(t,e,n,i);for(;!s.step(ct);)await new Promise(r=>setImmediate(r));return s.result()}
@@ -1,2 +1,2 @@
1
- import{spawn as c}from"node:child_process";import{readFile as m}from"node:fs/promises";import f from"node:path";import{HARNESS_KEYS as d,isHarness as w}from"@weavecode/core";import{isVersionAtLeast as S}from"../hooks/toolkit.js";export async function projectHarnessIds(r){const e=[d[0]];let s;try{s=await m(f.join(r,".weave","config.yaml"),"utf-8")}catch{return e}const t=s.split(`
2
- `).find(i=>i.startsWith("harnesses:"));if(!t)return e;try{const i=JSON.parse(t.slice(t.indexOf(":")+1).trim()),n=Array.isArray(i)?i.filter(w):[];return n.length>0?n:e}catch{return e}}const h=6e5,a=new Map;export function probeBinVersion(r){return new Promise(e=>{let s="";const t=process.platform==="win32"?c(`${r} --version`,{windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):c(r,["--version"],{windowsHide:!0,stdio:["ignore","pipe","pipe"]}),i=setTimeout(()=>{t.kill("SIGKILL"),e(null)},5e3);t.stdout?.on("data",n=>s+=n.toString()),t.on("error",()=>{clearTimeout(i),e(null)}),t.on("close",()=>{clearTimeout(i);const n=/(\d+\.\d+\.\d+)/.exec(s);e(n?n[1]:null)})})}function y(r){const e=a.get(r);if(e&&Date.now()-e.at<h)return e.value;const s=probeBinVersion(r).then(t=>(t===null&&a.delete(r),t));return a.set(r,{at:Date.now(),value:s}),s}export async function projectHarnesses(r,e,s=y){const t=await projectHarnessIds(r);return Promise.all(t.map(async i=>{const n=e?.get(i)?.resume;if(!n?.bin)return{id:i,canStartSession:!1};if(!n.minVersion)return{id:i,canStartSession:!0};const o=await s(n.bin),l=n.minVersion.split(".").map(u=>Number.parseInt(u,10)),p=o===null||S(o,l);return{id:i,canStartSession:p,version:o,minVersion:n.minVersion}}))}export async function withProjectHarnesses(r,e,s){return Promise.all(r.map(async t=>({...t,harnesses:await projectHarnesses(t.path,e,s)})))}
1
+ import{spawn as c}from"node:child_process";import{readFile as m}from"node:fs/promises";import f from"node:path";import{HARNESS_KEYS as d,isHarness as w}from"@weavecode/core";import{isVersionAtLeast as h}from"../hooks/toolkit.js";export async function projectHarnessIds(n){const e=[d[0]];let s;try{s=await m(f.join(n,".weave","config.yaml"),"utf-8")}catch{return e}const t=s.split(`
2
+ `).find(o=>o.startsWith("harnesses:"));if(!t)return e;try{const o=JSON.parse(t.slice(t.indexOf(":")+1).trim()),r=Array.isArray(o)?o.filter(w):[];return r.length>0?r:e}catch{return e}}const S=6e5,a=new Map;export function probeBinVersion(n){return new Promise(e=>{let s="";const t=process.platform==="win32"?c(`${n} --version`,{windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):c(n,["--version"],{windowsHide:!0,stdio:["ignore","pipe","pipe"]}),o=setTimeout(()=>{t.kill("SIGKILL"),e(null)},5e3);t.stdout?.on("data",r=>s+=r.toString()),t.on("error",()=>{clearTimeout(o),e(null)}),t.on("close",()=>{clearTimeout(o);const r=/(\d+\.\d+\.\d+)/.exec(s);e(r?r[1]:null)})})}function y(n){const e=a.get(n);if(e&&Date.now()-e.at<S)return e.value;const s=probeBinVersion(n).then(t=>(t===null&&a.delete(n),t));return a.set(n,{at:Date.now(),value:s}),s}export async function projectHarnesses(n,e,s=y){const t=await projectHarnessIds(n);return Promise.all(t.map(async o=>{const r=e?.get(o)?.resume;if(!r?.bin)return{id:o,canStartSession:!1};if(!r.minVersion)return{id:o,canStartSession:!0};const i=await s(r.bin),l=r.minVersion.split(".").map(p=>Number.parseInt(p,10)),u=i===null||h(i,l);return{id:o,canStartSession:u,version:i,minVersion:r.minVersion}}))}export async function withProjectHarnesses(n,e,s){return Promise.all(n.map(async t=>({...t,harnesses:await projectHarnesses(t.path,e,s)})))}
@@ -1 +1 @@
1
- export class ProjectUpdatesRefresher{snapshot;bus;shouldRun;lastCounts=null;lastFingerprint=null;running=!1;constructor(n,s,t,i=()=>!0){this.snapshot=n,this.bus=s,this.shouldRun=i,t.subscribe(r=>{r.kind==="plugin.reloaded"&&this.refreshNow()})}async refreshNow(n=!1){if(!this.running&&!(!n&&!this.shouldRun())){this.running=!0;try{const s=await this.snapshot();this.lastCounts=s;const t=JSON.stringify(s);if(t===this.lastFingerprint)return;this.lastFingerprint=t,this.bus.emit({key:"updates",payload:{counts:s}})}catch{}finally{this.running=!1}}}onSubscriberJoin(){this.lastCounts!==null&&(this.lastFingerprint=JSON.stringify(this.lastCounts),this.bus.emit({key:"updates",payload:{counts:this.lastCounts}})),this.refreshNow(!0)}}
1
+ export class ProjectUpdatesRefresher{snapshot;bus;shouldRun;lastCounts=null;lastFingerprint=null;running=!1;constructor(i,s,t,n=()=>!0){this.snapshot=i,this.bus=s,this.shouldRun=n,t.subscribe(r=>{r.kind==="plugin.reloaded"&&this.refreshNow()})}async refreshNow(i=!1){if(!this.running&&!(!i&&!this.shouldRun())){this.running=!0;try{const s=await this.snapshot();this.lastCounts=s;const t=JSON.stringify(s);if(t===this.lastFingerprint)return;this.lastFingerprint=t,this.bus.emit({key:"updates",payload:{counts:s}})}catch{}finally{this.running=!1}}}onSubscriberJoin(){this.lastCounts!==null&&(this.lastFingerprint=JSON.stringify(this.lastCounts),this.bus.emit({key:"updates",payload:{counts:this.lastCounts}})),this.refreshNow(!0)}}
@@ -1 +1 @@
1
- import{imagesSurfaceFor as T}from"../surfaces.js";const I=/\[Image #\d+\]/gi,y=64,b=64*1024*1024,v=12e4,N=t=>t.replace(I,"").replace(/\s+/g," ").trim(),x={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};function O(t,e,n){const r=t.hookEvents?.listBySession(e,2e3,void 0,["UserPromptSubmit"])??[],o=[];for(const i of r){if(n.get(i.id)?.length)continue;const c=S(i.payload);!c||!c.match(I)||o.push({eventId:i.id,at:i.createdAt,text:N(c)})}return o}function S(t){try{const e=JSON.parse(t).raw;return typeof e?.prompt=="string"&&e.prompt?e.prompt:null}catch{return null}}function w(t,e,n){for(let r=n.length-1;r>=0;r--)try{const o=JSON.parse(n[r].payload).transcriptPath;if(typeof o=="string"&&o)return o}catch{}return t.sessionProbe?.transcriptPathOf(e)??null}export async function importPromptImages(t,e,n){const r=n?T(n):null;if(!r||!t.hookEvents||!t.uploads)return 0;const o=t.uploads.imagesBySession(e),i=O(t,e,o);if(i.length===0)return 0;const c=t.hookEvents.listBySession(e),u=await r.sessionImages({sessionId:e,transcriptPath:w(t,e,c)});if(!u?.length)return 0;let a=0,s=0;for(const p of u){if(a>=y||s>=b)break;const m=E(i,p.text,p.at);if(!m)continue;const l=[];for(const f of p.images){if(a>=y||s>=b)break;const g=x[f.mediaType];if(!g)continue;const d=Buffer.from(f.bytes),h=t.uploads.save({name:`pasted-${a+1}${g}`,mediaType:f.mediaType,bytes:d,dir:t.uploadDir??null});l.includes(h.id)||l.push(h.id),a+=1,s+=d.length}l.length>0&&t.uploads.linkToEvent(m.eventId,l)}return a}function E(t,e,n){const r=N(e),o=r===""?[]:t.filter(s=>s.text===r),i=o.length>0?o:r===""?t.filter(s=>s.text===""):[];if(i.length===0)return null;const c=n?Date.parse(n):NaN;let u=null,a=Number.POSITIVE_INFINITY;for(const s of i){const p=Number.isNaN(c)||!s.at?Number.POSITIVE_INFINITY:Math.abs(Date.parse(s.at)-c);p<a&&(u=s,a=p)}return!u||o.length===0&&!(a<=v)?null:(t.splice(t.indexOf(u),1),u)}export function needsImageImport(t,e){return t.some(n=>{if(n.eventType!=="UserPromptSubmit"||e?.get(n.id)?.length)return!1;const r=S(n.payload);return!!r&&/\[Image #\d+\]/i.test(r)})}const P=new Set;export async function importPromptImagesOnce(t,e,n){if(P.has(e))return!1;P.add(e);try{return await importPromptImages(t,e,n)>0}catch{return!1}}
1
+ import{imagesSurfaceFor as N}from"../surfaces.js";const d=/\[Image #\d+\]/gi,b=64,I=64*1024*1024,P=12e4,E=t=>t.replace(d,"").replace(/\s+/g," ").trim(),w={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};function _(t,e,n){const r=t.hookEvents?.listBySession(e,2e3,void 0,["UserPromptSubmit"])??[],o=[];for(const i of r){if(n.get(i.id)?.length)continue;const c=S(i.payload);!c||!c.match(d)||o.push({eventId:i.id,at:i.createdAt,text:E(c)})}return o}function S(t){try{const e=JSON.parse(t).raw;return typeof e?.prompt=="string"&&e.prompt?e.prompt:null}catch{return null}}function O(t,e,n){for(let r=n.length-1;r>=0;r--)try{const o=JSON.parse(n[r].payload).transcriptPath;if(typeof o=="string"&&o)return o}catch{}return t.sessionProbe?.transcriptPathOf(e)??null}export async function importPromptImages(t,e,n){const r=n?N(n):null;if(!r||!t.hookEvents||!t.uploads)return 0;const o=t.uploads.imagesBySession(e),i=_(t,e,o);if(i.length===0)return 0;const c=t.hookEvents.listBySession(e),u=await r.sessionImages({sessionId:e,transcriptPath:O(t,e,c)});if(!u?.length)return 0;let s=0,a=0;for(const l of u){if(s>=b||a>=I)break;const m=x(i,l.text,l.at);if(!m)continue;const p=[];for(const f of l.images){if(s>=b||a>=I)break;const g=w[f.mediaType];if(!g)continue;const h=Buffer.from(f.bytes),y=t.uploads.save({name:`pasted-${s+1}${g}`,mediaType:f.mediaType,bytes:h,dir:t.uploadDir??null});p.includes(y.id)||p.push(y.id),s+=1,a+=h.length}p.length>0&&t.uploads.linkToEvent(m.eventId,p)}return s}function x(t,e,n){const r=E(e),o=r===""?[]:t.filter(a=>a.text===r),i=o.length>0?o:r===""?t.filter(a=>a.text===""):[];if(i.length===0)return null;const c=n?Date.parse(n):NaN;let u=null,s=Number.POSITIVE_INFINITY;for(const a of i){const l=Number.isNaN(c)||!a.at?Number.POSITIVE_INFINITY:Math.abs(Date.parse(a.at)-c);l<s&&(u=a,s=l)}return!u||o.length===0&&!(s<=P)?null:(t.splice(t.indexOf(u),1),u)}export function needsImageImport(t,e){return t.some(n=>{if(n.eventType!=="UserPromptSubmit"||e?.get(n.id)?.length)return!1;const r=S(n.payload);return!!r&&/\[Image #\d+\]/i.test(r)})}const T=new Set;export async function importPromptImagesOnce(t,e,n){if(T.has(e))return!1;T.add(e);try{return await importPromptImages(t,e,n)>0}catch{return!1}}
@@ -1 +1 @@
1
- import{z as a}from"zod";import{HandlerConfigSchema as y,HookDispatchStatusSchema as v,HookRuleFilterSchema as I,HookRuleSourceSchema as R}from"@weavecode/core";import{readJson as d,sendJson as t}from"../http.js";import{installPlugin as j,uninstallPlugin as E}from"../../hooks/plugin-installer.js";import{effective as S,setProjectEnabled as w}from"../../hooks/plugin-project-state.js";const P=a.object({name:a.string().min(1),enabled:a.boolean().optional(),priority:a.number().int().optional(),projectId:a.number().int().nullable(),source:R,filter:I.optional(),handler:y,timeoutMs:a.number().int().positive().optional(),record:a.boolean().optional()}),T=P.partial(),H=a.object({enabled:a.boolean()}),O=a.object({enabled:a.boolean(),projectId:a.number().int().optional()}),U=a.object({sessionId:a.string().min(1)}),C=a.object({src:a.string().min(1)});export async function handleHookAdminRoutes(s,e,o,l,c){if(l==="/hooks/rules"){if(!o.hookRegistry)return t(e,503,{error:"Hooks subsystem unavailable"}),!0;if(s.method==="GET"){const r=c.searchParams.get("projectId"),n=r!=null&&r!==""?Number(r):void 0;return t(e,200,{rules:o.hookRegistry.list(n)}),!0}if(s.method==="POST"){try{const r=P.parse(await d(s)),n=o.hookRegistry.create(r);t(e,201,{rule:n})}catch(r){t(e,400,{error:r instanceof Error?r.message:"Invalid rule body"})}return!0}}const m=l.match(/^\/hooks\/rules\/([^/]+)$/);if(m){if(!o.hookRegistry)return t(e,503,{error:"Hooks subsystem unavailable"}),!0;const r=decodeURIComponent(m[1]);if(s.method==="PUT"){try{const n=T.parse(await d(s)),i=o.hookRegistry.update(r,n);if(!i)return t(e,404,{error:"Rule not found"}),!0;t(e,200,{rule:i})}catch(n){t(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}if(s.method==="DELETE")return o.hookRegistry.remove(r)?(t(e,200,{ok:!0}),!0):(t(e,404,{error:"Rule not found"}),!0)}const g=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(g&&s.method==="POST"){if(!o.hookRegistry)return t(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const r=H.parse(await d(s)),n=o.hookRegistry.setEnabled(decodeURIComponent(g[1]),r.enabled);if(!n)return t(e,404,{error:"Rule not found"}),!0;t(e,200,{rule:n})}catch(r){t(e,400,{error:r instanceof Error?r.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(s.method==="GET"){const r=c.searchParams.get("projectId");if(r==null||r==="")return t(e,200,{plugins:o.hookPlugins?.list()??[]}),!0;const n=o.projects.getById(Number(r));if(!n)return t(e,404,{error:"Project not found"}),!0;if(!o.pluginStates)return t(e,503,{error:"Plugin states unavailable"}),!0;const i=o.pluginStates;return t(e,200,{plugins:(o.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const h=S(n,u.id,{states:i})?"active":"disabled";return h===u.status?u:{...u,status:h}})}),!0}if(s.method==="POST"){if(!o.hookPlugins)return t(e,503,{error:"Plugin loader unavailable"}),!0;try{const r=C.parse(await d(s)),n=await j(r.src);await o.hookPlugins.reloadAll(),t(e,201,n)}catch(r){t(e,400,{error:r instanceof Error?r.message:"Install failed"})}return!0}}const f=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(f&&s.method==="POST"){if(!o.hookPlugins)return t(e,503,{error:"Plugin loader unavailable"}),!0;const r=decodeURIComponent(f[1]);return await E(r)?(await o.hookPlugins.reloadAll(),t(e,200,{ok:!0}),!0):(t(e,404,{error:"Plugin directory not found"}),!0)}if(l==="/hooks/plugins/rescan"&&s.method==="POST"){if(!o.hookPlugins)return t(e,503,{error:"Plugin loader unavailable"}),!0;try{await o.hookPlugins.rescan(),t(e,200,{ok:!0,plugins:o.hookPlugins.list().length})}catch(r){t(e,500,{error:r instanceof Error?r.message:"Rescan failed"})}return!0}const p=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(p&&s.method==="POST"){if(!o.hookPlugins)return t(e,503,{error:"Plugin loader unavailable"}),!0;try{const r=O.parse(await d(s)),n=decodeURIComponent(p[1]);if(r.projectId!==void 0){const i=o.projects.getById(r.projectId);return i?o.hookPlugins.list().some(u=>u.id===n)?(w(i,n,r.enabled,{projects:o.projects}),t(e,200,{ok:!0}),!0):(t(e,404,{error:"Plugin not found"}),!0):(t(e,404,{error:"Project not found"}),!0)}if(!o.hookPlugins.setPluginEnabled(n,r.enabled))return t(e,404,{error:"Plugin not found"}),!0;t(e,200,{ok:!0})}catch(r){t(e,400,{error:r instanceof Error?r.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&s.method==="GET"){if(!o.hookDispatches)return t(e,503,{error:"Hooks subsystem unavailable"}),!0;const r=c.searchParams.get("ruleId")??void 0,n=c.searchParams.get("status"),i=n?v.parse(n):void 0,u=c.searchParams.get("sessionId")??void 0,h=c.searchParams.get("limit"),k=h?Number(h):void 0;return t(e,200,{dispatches:o.hookDispatches.list({ruleId:r,status:i,sessionId:u,limit:Number.isFinite(k)?k:void 0})}),!0}const b=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(b&&s.method==="POST"){if(!o.hookRunner)return t(e,503,{error:"Resume runner unavailable"}),!0;let r;try{r=U.parse(await d(s)).sessionId}catch(i){return t(e,400,{error:i instanceof Error?i.message:"Invalid body"}),!0}const n=await o.hookRunner.run(Number(b[1]),r);return n.ok?t(e,200,{ok:!0,dispatchId:n.dispatchId}):t(e,n.status,{error:n.error}),!0}return!1}
1
+ import{z as u}from"zod";import{HandlerConfigSchema as I,HookDispatchStatusSchema as p,HookRuleFilterSchema as R,HookRuleSourceSchema as j}from"@weavecode/core";import{readJson as h,sendJson as r}from"../http.js";import{installPlugin as v,uninstallPlugin as w}from"../../hooks/plugin-installer.js";import{effective as E,setProjectEnabled as S}from"../../hooks/plugin-project-state.js";const y=u.object({name:u.string().min(1),enabled:u.boolean().optional(),priority:u.number().int().optional(),projectId:u.number().int().nullable(),source:j,filter:R.optional(),handler:I,timeoutMs:u.number().int().positive().optional(),record:u.boolean().optional()}),T=y.partial(),H=u.object({enabled:u.boolean()}),B=u.object({enabled:u.boolean(),projectId:u.number().int().optional()}),O=u.object({sessionId:u.string().min(1)}),U=u.object({src:u.string().min(1)});export async function handleHookAdminRoutes(i,o,e,l,d){if(l==="/hooks/rules"){if(!e.hookRegistry)return r(o,503,{error:"Hooks subsystem unavailable"}),!0;if(i.method==="GET"){const t=d.searchParams.get("projectId"),n=t!=null&&t!==""?Number(t):void 0;return r(o,200,{rules:e.hookRegistry.list(n)}),!0}if(i.method==="POST"){try{const t=y.parse(await h(i)),n=e.hookRegistry.create(t);r(o,201,{rule:n})}catch(t){r(o,400,{error:t instanceof Error?t.message:"Invalid rule body"})}return!0}}const g=l.match(/^\/hooks\/rules\/([^/]+)$/);if(g){if(!e.hookRegistry)return r(o,503,{error:"Hooks subsystem unavailable"}),!0;const t=decodeURIComponent(g[1]);if(i.method==="PUT"){try{const n=T.parse(await h(i)),s=e.hookRegistry.update(t,n);if(!s)return r(o,404,{error:"Rule not found"}),!0;r(o,200,{rule:s})}catch(n){r(o,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}if(i.method==="DELETE")return e.hookRegistry.remove(t)?(r(o,200,{ok:!0}),!0):(r(o,404,{error:"Rule not found"}),!0)}const m=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(m&&i.method==="POST"){if(!e.hookRegistry)return r(o,503,{error:"Hooks subsystem unavailable"}),!0;try{const t=H.parse(await h(i)),n=e.hookRegistry.setEnabled(decodeURIComponent(m[1]),t.enabled);if(!n)return r(o,404,{error:"Rule not found"}),!0;r(o,200,{rule:n})}catch(t){r(o,400,{error:t instanceof Error?t.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(i.method==="GET"){const t=d.searchParams.get("projectId");if(t==null||t==="")return r(o,200,{plugins:e.hookPlugins?.list()??[]}),!0;const n=e.projects.getById(Number(t));if(!n)return r(o,404,{error:"Project not found"}),!0;if(!e.pluginStates)return r(o,503,{error:"Plugin states unavailable"}),!0;const s=e.pluginStates;return r(o,200,{plugins:(e.hookPlugins?.list()??[]).map(a=>{if(a.status==="rejected")return a;const c=E(n,a.id,{states:s})?"active":"disabled";return c===a.status?a:{...a,status:c}})}),!0}if(i.method==="POST"){if(!e.hookPlugins)return r(o,503,{error:"Plugin loader unavailable"}),!0;try{const t=U.parse(await h(i)),n=await v(t.src);await e.hookPlugins.reloadAll(),r(o,201,n)}catch(t){r(o,400,{error:t instanceof Error?t.message:"Install failed"})}return!0}}const f=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(f&&i.method==="POST"){if(!e.hookPlugins)return r(o,503,{error:"Plugin loader unavailable"}),!0;const t=decodeURIComponent(f[1]);return await w(t)?(await e.hookPlugins.reloadAll(),r(o,200,{ok:!0}),!0):(r(o,404,{error:"Plugin directory not found"}),!0)}if(l==="/hooks/plugins/rescan"&&i.method==="POST"){if(!e.hookPlugins)return r(o,503,{error:"Plugin loader unavailable"}),!0;try{await e.hookPlugins.rescan(),r(o,200,{ok:!0,plugins:e.hookPlugins.list().length})}catch(t){r(o,500,{error:t instanceof Error?t.message:"Rescan failed"})}return!0}const b=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(b&&i.method==="POST"){if(!e.hookPlugins)return r(o,503,{error:"Plugin loader unavailable"}),!0;try{const t=B.parse(await h(i)),n=decodeURIComponent(b[1]);if(t.projectId!==void 0){const a=e.projects.getById(t.projectId);return a?e.hookPlugins.list().some(c=>c.id===n)?(S(a,n,t.enabled,{projects:e.projects}),r(o,200,{ok:!0}),!0):(r(o,404,{error:"Plugin not found"}),!0):(r(o,404,{error:"Project not found"}),!0)}if(!e.hookPlugins.setPluginEnabled(n,t.enabled))return r(o,404,{error:"Plugin not found"}),!0;r(o,200,{ok:!0})}catch(t){r(o,400,{error:t instanceof Error?t.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&i.method==="GET"){if(!e.hookDispatches)return r(o,503,{error:"Hooks subsystem unavailable"}),!0;const t=d.searchParams.get("ruleId")??void 0,n=d.searchParams.get("status"),s=n?p.parse(n):void 0,a=d.searchParams.get("sessionId")??void 0,c=d.searchParams.get("limit"),P=c?Number(c):void 0;return r(o,200,{dispatches:e.hookDispatches.list({ruleId:t,status:s,sessionId:a,limit:Number.isFinite(P)?P:void 0})}),!0}const k=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(k&&i.method==="POST"){if(!e.hookRunner)return r(o,503,{error:"Resume runner unavailable"}),!0;let t;try{t=O.parse(await h(i)).sessionId}catch(s){return r(o,400,{error:s instanceof Error?s.message:"Invalid body"}),!0}const n=await e.hookRunner.run(Number(k[1]),t);return n.ok?r(o,200,{ok:!0,dispatchId:n.dispatchId}):r(o,n.status,{error:n.error}),!0}return!1}
@@ -1 +1 @@
1
- import{homedir as v}from"node:os";import Q from"node:path";import{checkHarness as X,isHarness as A}from"@weavecode/core";import{readBody as h,sendJson as r}from"../http.js";import{FingerprintCache as z}from"../../install/fingerprint.js";import{installSkill as Y,uninstallSkill as Z,installFileAsset as ee,uninstallFileAsset as te,InstallConflictError as x,AssetNotFoundError as E}from"../../install/installer.js";import{isFileAssetCategory as H}from"../../install/file-assets.js";import{installGlobalSkill as re,uninstallGlobalSkill as ae,readGlobalSkillGroups as ie,resolveGlobalSkillDir as q,listGlobalSkillFiles as se,readGlobalSkillFile as ne,ClaudeJsonCorruptError as oe}from"../../install/global-config.js";import{CodexTomlCorruptError as le}from"../../install/codex-toml.js";import{forgetInstalled as ce,recordInstalled as me}from"../../install/install-ledger.js";import{readProjectFile as ue,readGlobalFile as de,PathEscapeError as pe,FileTooLargeError as fe}from"../../install/reader.js";import{readMcpRows as he}from"../../install/mcp-rows.js";import{setMcpEnableOverride as ge}from"../../install/settings-mcp.js";import{applyUpdate as ye,syncAll as be}from"../../install/apply-update.js";import{buildLibraryIndex as ke}from"../../install/library-index.js";import{detectUpdates as we}from"../../install/updates.js";import{detectPluginTemplateUpdates as Se}from"../../install/plugin-templates.js";import{detectInitFileUpdates as ve,needsInit as Ie}from"../../install/init-files.js";import{getLibraryScan as K,invalidateScan as y}from"../../install/scan-cache.js";import{installCapabilities as Pe}from"../../install/capabilities.js";import{BUILTIN_MCP_SERVERS as je}from"../../install/builtin-mcp.js";import{readPluginRows as Ee}from"../../install/plugin-rows.js";import{installPluginPack as Ne}from"../../install/plugin-install.js";import{importFromDir as Oe,importFromGit as Te,importLibraryIntoMarket as $e}from"../../market/import.js";import{marketDir as N,readManifest as Be}from"../../market/manifest.js";import{marketIdOf as Me}from"../../market/identity.js";import{isInsideDir as O,toRelPosix as Ce}from"../../market/resolve.js";import{checkMarketUpdates as Je}from"../../market/updates.js";import{refreshMarketItems as Re}from"../../market/refresh.js";import{ensureBuiltinMarket as Ge,isBuiltinMarketDir as S}from"../../market/builtin.js";import{removeInstalled as Le}from"../../market/install-link.js";import{syncPlugins as Fe}from"../../hooks/plugin-project-state.js";import{assetSurfaces as De,pluginStateSurfaces as Ue,pluginSurfaces as W,pluginSurfaceFor as _}from"../../surfaces.js";function V(s){return s.scope==="user"||s.category==="plugin"?!1:s.category==="mcp"?!!I(s.agent)?.mcpScopes().includes("project"):!0}function I(s){const t=s??"claude";return De().find(i=>i.harness===t)}function P(s,t){t instanceof x?s.statusCode=409:t instanceof E?s.statusCode=404:t instanceof oe||t instanceof le?s.statusCode=500:s.statusCode=400,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:t instanceof Error?t.message:"Install failed"}))}function T(s,t){t instanceof pe?s.statusCode=403:t instanceof fe?s.statusCode=413:t instanceof E?s.statusCode=404:s.statusCode=400,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:t instanceof Error?t.message:"Read failed"}))}async function j(s,t){const i=O(s.path,N(t)),m=i?await Be(s.path):null,p=S(s.path,t);return{id:s.id,kind:s.kind,addedAt:s.addedAt,path:s.path,relPath:O(s.path,t)?Ce(s.path,t):null,resourceId:i?Q.basename(s.path):null,managed:i,builtin:p,namespace:i?Me(s.path,N(t)):void 0,legacy:!m&&!p,source:p?"builtin":m?.source??"legacy",origin:m?.origin??null,importedAt:m?.importedAt??null,commit:m?.commit??null,tags:await xe(s.path)}}const Ae={command:"command",agent:"agent",workflow:"workflow",rule:"rules","output-style":"output-style"};async function ze(s){const{plugins:t,skills:i,mcp:m,files:p}=await K(s),w={},g=(f,b)=>{b>0&&(w[f]=(w[f]??0)+b)};g("skill",i.length),g("mcp",m.length);for(const[f,b]of Object.entries(p))g(Ae[f]??f,b.length);return g("plugin",t.length),g("mods",t.filter(f=>f.kind==="mod"||f.components.includes("mod")).length),w}async function xe(s){try{return await ze(s)}catch{return{}}}export async function handleMarketRoutes(s,t,i,m,p){if(m==="/capabilities"&&s.method==="GET")return r(t,200,Pe()),!0;if(m==="/libraries"&&s.method==="GET")return r(t,200,{libraries:i.libraries?i.libraries.list():[]}),!0;if(m==="/libraries"&&s.method==="POST"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;let a;try{a=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!a.path||!a.kind)return r(t,400,{error:'Missing "path" or "kind"'}),!0;if(!["skill","mcp","both"].includes(a.kind))return r(t,400,{error:'Invalid "kind" (skill|mcp|both)'}),!0;const e=i.libraries.add({path:a.path,kind:a.kind});return i.dataBus?.emit({key:"libraries"}),r(t,201,e),!0}const w=m.match(/^\/libraries\/(\d+)\/assets$/);if(w&&s.method==="GET"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(w[1]));if(!a)return r(t,404,{error:"Library not found"}),!0;const{plugins:e,skills:n,mcp:o,files:l}=await K(a.path),c=a.kind==="skill"||a.kind==="both"?e:[],u=a.kind==="mcp"||a.kind==="both"?o:[],d=a.kind==="skill"||a.kind==="both"?Object.values(l).flat():null;return r(t,200,{library:a,skills:n,mcp:u,files:d,plugins:c}),!0}const g=m.match(/^\/libraries\/(\d+)$/);if(g&&s.method==="DELETE"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;const a=Number(g[1]),e=i.libraries.getById(a);return e&&await y(e.path),i.libraries.remove(a),i.dataBus?.emit({key:"libraries"}),i.dataBus?.emit({key:"market"}),r(t,200,{ok:!0}),!0}if(m==="/market"&&s.method==="GET"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;const a=await Promise.all(i.libraries.list().map(e=>j(e,i.libraries.dataRoot)));return r(t,200,{items:a}),!0}if(m==="/market"&&s.method==="POST"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;let a;try{a=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const e={libraries:i.libraries,dataRoot:i.libraries.dataRoot};try{if(a.kind==="dir"&&a.path){const n=await Oe(a.path,e);n.refreshed&&i.fingerprintCache?.invalidate(n.dir),await y(n.dir),i.dataBus?.emit({key:"market"}),r(t,201,{item:await j(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}else if(a.kind==="git"&&a.url){const n=await Te(a.url,e);n.refreshed&&i.fingerprintCache?.invalidate(n.dir),await y(n.dir),i.dataBus?.emit({key:"market"}),r(t,201,{item:await j(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}else r(t,400,{error:'Invalid body (kind: "dir" + path | "git" + url)'})}catch(n){r(t,400,{error:n instanceof Error?n.message:"Import failed"})}return!0}if(m==="/market/check-updates"&&s.method==="POST"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;let a={};const e=(await h(s)).trim();if(e)try{a=JSON.parse(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const n=i.libraries.list().filter(l=>!S(l.path,i.libraries.dataRoot)).filter(l=>!a.ids?.length||a.ids.includes(l.id));for(const l of n)await y(l.path);const o=await Je(n.map(l=>({id:l.id,dir:l.path})));return i.dataBus?.emit({key:"market"}),r(t,200,{results:o}),!0}if(m==="/market/refresh"&&s.method==="POST"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;let a={};const e=(await h(s)).trim();if(e)try{a=JSON.parse(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const n=i.libraries.list().filter(d=>!a.ids?.length||a.ids.includes(d.id)),o=[];for(const d of n.filter(k=>S(k.path,i.libraries.dataRoot))){const k=await Ge({libraries:i.libraries});o.push({id:d.id,status:k.error?"failed":"refreshed"})}const l=n.filter(d=>!S(d.path,i.libraries.dataRoot)).map(d=>({id:d.id,dir:d.path})),c=[...await Re(l,{libraries:i.libraries,dataRoot:i.libraries.dataRoot}),...o],u=new Map(l.map(d=>[d.id,d.dir]));for(const d of c)if(d.status==="refreshed"){const k=u.get(d.id);k&&(i.fingerprintCache?.invalidate(k),await y(k))}return i.dataBus?.emit({key:"market"}),r(t,200,{results:c}),!0}const f=m.match(/^\/market\/(\d+)$/);if(f&&s.method==="DELETE"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(f[1]));if(!a)return r(t,404,{error:"Library not found"}),!0;if(S(a.path,i.libraries.dataRoot))return r(t,409,{error:"Built-in market is owned by weave and cannot be deleted",note:"It is re-materialized from @weavecode/templates on every daemon start."}),!0;if(!O(a.path,N(i.libraries.dataRoot)))return r(t,400,{error:"Not a market resource (legacy row \u2014 use DELETE /libraries/:id)"}),!0;let e;try{await(i.pluginSurface??_("claude")).removeMarketplace(a.path)}catch(n){e=`Host marketplace deregistration failed: ${n instanceof Error?n.message:String(n)}`}return await Le(a.path),i.libraries.remove(a.id),await y(a.path),i.dataBus?.emit({key:"market"}),i.dataBus?.emit({key:"libraries"}),r(t,200,{ok:!0,removed:a.path,installedCopiesKept:!0,...e?{warning:e}:{},note:"The host cascade-uninstalls plugins installed from this market; other installed copies are kept."}),!0}const b=m.match(/^\/libraries\/(\d+)\/market-import$/);if(b&&s.method==="POST"){if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(b[1]));if(!a)return r(t,404,{error:"Library not found"}),!0;try{const e=a.path,n=await $e(a,{libraries:i.libraries,dataRoot:i.libraries.dataRoot});await y(e),await y(n.dir),r(t,200,{item:await j(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}catch(e){r(t,400,{error:e instanceof Error?e.message:"Import failed"})}return!0}const $=m.match(/^\/projects\/(\d+)\/install$/);if($&&s.method==="POST"){const a=i.projects.getById(Number($[1]));let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!a&&V(e))return r(t,404,{error:"Project not found"}),!0;const n=a?.path??"";try{if(e.category==="skill"){if(!e.name||!e.sourceDir)return r(t,400,{error:'Missing "name" or "sourceDir"'}),!0;const o=e.agent??"claude",l=e.scope==="user"?await re(e.sourceDir,e.name,o):await Y(n,e.sourceDir,e.name,o);r(t,201,{category:"skill",name:e.name,scope:e.scope??"project",agent:o,path:l})}else if(e.category&&H(e.category)){if(!e.name||!e.sourceFile)return r(t,400,{error:'Missing "name" or "sourceFile"'}),!0;const o=e.agent??"claude",l=e.scope??"project",c=await ee(n,e.category,e.name,e.sourceFile,o,l);r(t,201,{category:e.category,name:e.name,scope:l,agent:o,path:c})}else if(e.category==="mcp"){if(!e.name||!e.mcpConfig)return r(t,400,{error:'Missing "name" or "mcpConfig"'}),!0;const o=e.agent??"claude",l=I(o);if(!l)return r(t,400,{error:`Unsupported agent: ${o}`}),!0;const c=l.mcpScopes(),u=e.scope??c[0];if(!u||!c.includes(u))return r(t,400,{error:`MCP servers for ${o} are ${c.join("/")}-level only \u2014 scope "${e.scope}" is not available`}),!0;if(e.name in await l.mcpRead(u,n,v()))return P(t,new x(`MCP server "${e.name}" is already configured`)),!0;await l.mcpWrite(u,n,v(),e.name,e.mcpConfig),u==="project"&&await me(n,{category:"mcp",name:e.name,agent:o}),r(t,201,{category:"mcp",name:e.name,scope:u,agent:o})}else if(e.category==="plugin"){if(!e.name||!e.sourceDir)return r(t,400,{error:'Missing "name" or "sourceDir"'}),!0;if(e.scope&&e.scope!=="user")return r(t,400,{error:'Plugin install currently only supports scope "user"'}),!0;const o=e.agent??"claude",l=W().find(d=>d.harness===o);if(!l)return r(t,400,{error:`No plugin install surface for runtime: ${o}`}),!0;const c=o==="claude"&&i.pluginSurface?i.pluginSurface:l.surface,u=await Ne(c,{dir:e.sourceDir,name:e.name,version:e.version,description:e.description});i.dataBus?.emit({key:"toolkit"}),r(t,201,{category:"plugin",key:u.key,scope:"user",agent:o,alreadyInstalled:u.alreadyInstalled})}else r(t,400,{error:'Invalid "category" (skill|mcp|plugin|command|agent|workflow|rule|output-style)'})}catch(o){P(t,o)}return!0}const B=m.match(/^\/projects\/(\d+)\/mcp\/builtin$/);if(B&&s.method==="POST"){const a=i.projects.getById(Number(B[1]));let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const n=je.find(d=>d.name===e.name);if(!n)return r(t,404,{error:`Unknown built-in MCP server: ${e.name??""}`}),!0;if(!a)return r(t,404,{error:"Project not found"}),!0;const o=e.agent??"claude",l=I(o);if(!l||!l.mcpScopes().includes("user"))return r(t,400,{error:`MCP servers for ${o} have no user scope`}),!0;const c=i.auth?.getLocalToken()??"",u={type:"http",url:`http://127.0.0.1:${i.port}${n.path}`,...c?{headers:{"x-weave-local":c}}:{}};try{await l.mcpWrite("user",a.path,v(),n.name,u),r(t,201,{category:"mcp",name:n.name,scope:"user",agent:o})}catch(d){r(t,400,{error:d instanceof Error?d.message:"Install failed"})}return!0}const M=m.match(/^\/projects\/(\d+)\/uninstall$/);if(M&&s.method==="POST"){const a=i.projects.getById(Number(M[1]));let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!a&&V(e))return r(t,404,{error:"Project not found"}),!0;const n=a?.path??"";try{if(e.category==="skill"){if(!e.name)return r(t,400,{error:'Missing "name"'}),!0;const o=e.agent??"claude";e.scope==="user"?await ae(e.name,o):await Z(n,e.name,o)}else if(e.category&&H(e.category)){if(!e.name)return r(t,400,{error:'Missing "name"'}),!0;await te(n,e.category,e.name,e.agent??"claude",e.scope??"project")}else if(e.category==="mcp"){if(!e.name)return r(t,400,{error:'Missing "name"'}),!0;const o=e.agent??"claude",l=I(o);if(!l)return r(t,400,{error:`Unsupported agent: ${o}`}),!0;const c=l.mcpScopes(),u=e.scope??c[0];if(!u||!c.includes(u))return r(t,400,{error:`MCP servers for ${o} are ${c.join("/")}-level only \u2014 scope "${e.scope}" is not available`}),!0;if(!await l.mcpRemove(u,n,v(),e.name))return P(t,new E(`MCP server "${e.name}" is not configured`)),!0;u==="project"&&await ce(n,{category:"mcp",name:e.name,agent:o})}else return r(t,400,{error:'Invalid "category" (skill|mcp|command|agent|workflow|rule|output-style)'}),!0;r(t,200,{ok:!0})}catch(o){P(t,o)}return!0}const C=m.match(/^\/projects\/(\d+)\/asset-file$/);if(C&&s.method==="GET"){const a=i.projects.getById(Number(C[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;const e=p.searchParams.get("path");if(!e)return r(t,400,{error:'Missing "path" query parameter'}),!0;try{const n=await ue(a.path,e);r(t,200,{path:e,content:n.content,size:n.size})}catch(n){T(t,n)}return!0}if(m==="/global-file"&&s.method==="GET"){const a=p.searchParams.get("path");if(!a)return r(t,400,{error:'Missing "path" query parameter'}),!0;try{const e=await de(a);r(t,200,{path:a,content:e.content,size:e.size})}catch(e){T(t,e)}return!0}const J=m.match(/^\/projects\/(\d+)\/mcp$/);if(J&&s.method==="GET"){const a=i.projects.getById(Number(J[1]));return a?(r(t,200,{rows:await he(a.path)}),!0):(r(t,404,{error:"Project not found"}),!0)}const R=m.match(/^\/projects\/(\d+)\/harness-checks$/);if(R&&s.method==="GET"){const a=i.projects.getById(Number(R[1]));return a?(r(t,200,{checks:await X(a.path)}),!0):(r(t,404,{error:"Project not found"}),!0)}if(m.match(/^\/projects\/(\d+)\/skills\/global$/)&&s.method==="GET")return r(t,200,{groups:await ie()}),!0;if(m.match(/^\/projects\/(\d+)\/skills\/global\/files$/)&&s.method==="GET"){const a=p.searchParams.get("source"),e=p.searchParams.get("name"),n=p.searchParams.get("pluginKey")??void 0;if(!a||!e)return r(t,400,{error:'Missing "source" or "name" query parameter'}),!0;const o=await q(a,e,n);return o?(r(t,200,{files:await se(o)}),!0):(r(t,404,{error:"Skill not found"}),!0)}if(m.match(/^\/projects\/(\d+)\/skills\/global\/file$/)&&s.method==="GET"){const a=p.searchParams.get("source"),e=p.searchParams.get("name"),n=p.searchParams.get("pluginKey")??void 0,o=p.searchParams.get("path");if(!a||!e||!o)return r(t,400,{error:'Missing "source", "name" or "path" query parameter'}),!0;const l=await q(a,e,n);if(!l)return r(t,404,{error:"Skill not found"}),!0;try{const c=await ne(l,o);r(t,200,{path:o,content:c.content,size:c.size})}catch(c){T(t,c)}return!0}const G=m.match(/^\/projects\/(\d+)\/plugins\/state$/);if(G){const a=i.projects.getById(Number(G[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;if(s.method==="GET")return r(t,200,{rows:await Ee(a.path)}),!0;if(s.method==="PUT"){let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!A(e.runtime)||!e.key||!e.scope||!["user","project","local"].includes(e.scope)||!e.state||!["on","off","inherit"].includes(e.state))return r(t,400,{error:'Missing or invalid "runtime"/"key"/"scope" (user|project|local)/"state" (on|off|inherit)'}),!0;const n=e.scope,o=e.state;try{const l=W().find(c=>c.harness===e.runtime);if(l)await(e.runtime==="claude"&&i.pluginSurface?i.pluginSurface:l.surface).setEnabledOverride(a.path,n,e.key,o);else{const c=Ue().find(u=>u.harness===e.runtime);if(!c||n!=="user"||o==="inherit")return r(t,400,{error:"This runtime only supports user-scope on/off overrides"}),!0;await c.state.writeGlobalEnabled(e.key,o==="on")}i.dataBus?.emit({key:"toolkit"}),r(t,200,{ok:!0})}catch(l){r(t,400,{error:l instanceof Error?l.message:"Plugin state write failed"})}return!0}}if(m.match(/^\/projects\/(\d+)\/plugins\/uninstall$/)&&s.method==="POST"){let a;try{a=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!A(a.runtime)||!a.key)return r(t,400,{error:'Missing or invalid "runtime"/"key"'}),!0;try{const e=a.runtime==="claude"&&i.pluginSurface?i.pluginSurface:_(a.runtime),{name:n,market:o}=e.parsePluginKey(a.key);await e.uninstall(n,o),r(t,200,{ok:!0})}catch(e){r(t,400,{error:e instanceof Error?e.message:"Plugin uninstall failed"})}return!0}const L=m.match(/^\/projects\/(\d+)\/mcp\/enable$/);if(L){const a=i.projects.getById(Number(L[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;if(s.method==="PUT"){let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}return!e.name||!e.state?(r(t,400,{error:'Missing "name" or "state"'}),!0):["on","off","inherit"].includes(e.state)?(await ge(a.path,e.name,e.state),r(t,200,{ok:!0}),!0):(r(t,400,{error:'Invalid "state" (on|off|inherit)'}),!0)}}const F=m.match(/^\/projects\/(\d+)\/updates$/);if(F&&s.method==="GET"){const a=i.projects.getById(Number(F[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;const e=i.fingerprintCache??new z;if(!i.libraries){const o=await Se(a.path,e),l=await ve(a.path);return r(t,200,{skills:[],mcp:[],files:[],pluginTemplates:o,initFiles:l,available:o.filter(c=>c.outdated).length+l.filter(c=>c.outdated&&c.syncClass==="auto").length,needsInit:Ie(l)}),!0}const n=await we(a.path,i.libraries.list(),e);return r(t,200,n),!0}const D=m.match(/^\/projects\/(\d+)\/update$/);if(D&&s.method==="POST"){const a=i.projects.getById(Number(D[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;let e;try{e=JSON.parse(await h(s))}catch{return r(t,400,{error:"Invalid JSON body"}),!0}if(!e.category||!e.name||!e.scope)return r(t,400,{error:'Missing "category", "name", or "scope"'}),!0;if(!["skill","mcp","command","agent","workflow","rule","output-style"].includes(e.category))return r(t,400,{error:'Invalid "category"'}),!0;try{const n=await ke(i.libraries.list());await ye(a.path,{category:e.category,name:e.name,scope:e.scope,agent:e.agent},n),r(t,200,{ok:!0,category:e.category,name:e.name,scope:e.scope})}catch(n){r(t,400,{error:n instanceof Error?n.message:"Update failed"})}return!0}const U=m.match(/^\/projects\/(\d+)\/sync-all$/);if(U&&s.method==="POST"){const a=i.projects.getById(Number(U[1]));if(!a)return r(t,404,{error:"Project not found"}),!0;if(!i.libraries)return r(t,503,{error:"Libraries unavailable"}),!0;try{const e=i.fingerprintCache??new z,n=await be(a.path,i.libraries.list(),e);let o=n;try{const l=i.hookPlugins?.list().map(u=>u.id)??[],c=Fe(a,l,{projects:i.projects});o={...n,pluginSync:{syncedAt:c}}}catch{}r(t,200,o),i.updatesRefresher?.refreshNow(!0)}catch(e){r(t,400,{error:e instanceof Error?e.message:"Sync failed"})}return!0}return!1}
1
+ import{homedir as j}from"node:os";import X from"node:path";import{checkHarness as Y,isHarness as A}from"@weavecode/core";import{readBody as g,sendJson as e}from"../http.js";import{FingerprintCache as z}from"../../install/fingerprint.js";import{installSkill as Z,uninstallSkill as q,installFileAsset as tt,uninstallFileAsset as rt,InstallConflictError as x,AssetNotFoundError as M}from"../../install/installer.js";import{isFileAssetCategory as K}from"../../install/file-assets.js";import{installGlobalSkill as et,uninstallGlobalSkill as at,readGlobalSkillGroups as it,resolveGlobalSkillDir as H,listGlobalSkillFiles as ot,readGlobalSkillFile as nt,ClaudeJsonCorruptError as ct}from"../../install/global-config.js";import{CodexTomlCorruptError as lt}from"../../install/codex-toml.js";import{forgetInstalled as st,recordInstalled as ut}from"../../install/install-ledger.js";import{readProjectFile as mt,readGlobalFile as ft,PathEscapeError as dt,FileTooLargeError as pt}from"../../install/reader.js";import{readMcpRows as gt}from"../../install/mcp-rows.js";import{setMcpEnableOverride as ht}from"../../install/settings-mcp.js";import{applyUpdate as bt,syncAll as yt}from"../../install/apply-update.js";import{buildLibraryIndex as kt}from"../../install/library-index.js";import{detectUpdates as wt}from"../../install/updates.js";import{detectPluginTemplateUpdates as St}from"../../install/plugin-templates.js";import{detectInitFileUpdates as jt,needsInit as vt}from"../../install/init-files.js";import{getLibraryScan as _,invalidateScan as b}from"../../install/scan-cache.js";import{installCapabilities as It}from"../../install/capabilities.js";import{BUILTIN_MCP_SERVERS as Pt}from"../../install/builtin-mcp.js";import{readPluginRows as Mt}from"../../install/plugin-rows.js";import{installPluginPack as Et}from"../../install/plugin-install.js";import{importFromDir as Nt,importFromGit as Ot,importLibraryIntoMarket as Tt}from"../../market/import.js";import{marketDir as E,readManifest as Ct}from"../../market/manifest.js";import{marketIdOf as $t}from"../../market/identity.js";import{isInsideDir as N,toRelPosix as Bt}from"../../market/resolve.js";import{checkMarketUpdates as Ft}from"../../market/updates.js";import{refreshMarketItems as Jt}from"../../market/refresh.js";import{ensureBuiltinMarket as Gt,isBuiltinMarketDir as S}from"../../market/builtin.js";import{removeInstalled as Lt}from"../../market/install-link.js";import{syncPlugins as Rt}from"../../hooks/plugin-project-state.js";import{assetSurfaces as Dt,pluginStateSurfaces as Ut,pluginSurfaces as W,pluginSurfaceFor as V}from"../../surfaces.js";function Q(o){return o.scope==="user"||o.category==="plugin"?!1:o.category==="mcp"?!!v(o.agent)?.mcpScopes().includes("project"):!0}function v(o){const r=o??"claude";return Dt().find(i=>i.harness===r)}function I(o,r){r instanceof x?o.statusCode=409:r instanceof M?o.statusCode=404:r instanceof ct||r instanceof lt?o.statusCode=500:o.statusCode=400,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:r instanceof Error?r.message:"Install failed"}))}function O(o,r){r instanceof dt?o.statusCode=403:r instanceof pt?o.statusCode=413:r instanceof M?o.statusCode=404:o.statusCode=400,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:r instanceof Error?r.message:"Read failed"}))}async function P(o,r){const i=N(o.path,E(r)),u=i?await Ct(o.path):null,d=S(o.path,r);return{id:o.id,kind:o.kind,addedAt:o.addedAt,path:o.path,relPath:N(o.path,r)?Bt(o.path,r):null,resourceId:i?X.basename(o.path):null,managed:i,builtin:d,namespace:i?$t(o.path,E(r)):void 0,legacy:!u&&!d,source:d?"builtin":u?.source??"legacy",origin:u?.origin??null,importedAt:u?.importedAt??null,commit:u?.commit??null,tags:await xt(o.path)}}const At={command:"command",agent:"agent",workflow:"workflow",rule:"rules","output-style":"output-style"};async function zt(o){const{plugins:r,skills:i,mcp:u,files:d}=await _(o),w={},h=(p,y)=>{y>0&&(w[p]=(w[p]??0)+y)};h("skill",i.length),h("mcp",u.length);for(const[p,y]of Object.entries(d))h(At[p]??p,y.length);return h("plugin",r.length),h("mods",r.filter(p=>p.kind==="mod"||p.components.includes("mod")).length),w}async function xt(o){try{return await zt(o)}catch{return{}}}export async function handleMarketRoutes(o,r,i,u,d){if(u==="/capabilities"&&o.method==="GET")return e(r,200,It()),!0;if(u==="/libraries"&&o.method==="GET")return e(r,200,{libraries:i.libraries?i.libraries.list():[]}),!0;if(u==="/libraries"&&o.method==="POST"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;let a;try{a=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!a.path||!a.kind)return e(r,400,{error:'Missing "path" or "kind"'}),!0;if(!["skill","mcp","both"].includes(a.kind))return e(r,400,{error:'Invalid "kind" (skill|mcp|both)'}),!0;const t=i.libraries.add({path:a.path,kind:a.kind});return i.dataBus?.emit({key:"libraries"}),e(r,201,t),!0}const w=u.match(/^\/libraries\/(\d+)\/assets$/);if(w&&o.method==="GET"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(w[1]));if(!a)return e(r,404,{error:"Library not found"}),!0;const{plugins:t,skills:n,mcp:c,files:l}=await _(a.path),s=a.kind==="skill"||a.kind==="both"?t:[],m=a.kind==="mcp"||a.kind==="both"?c:[],f=a.kind==="skill"||a.kind==="both"?Object.values(l).flat():null;return e(r,200,{library:a,skills:n,mcp:m,files:f,plugins:s}),!0}const h=u.match(/^\/libraries\/(\d+)$/);if(h&&o.method==="DELETE"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;const a=Number(h[1]),t=i.libraries.getById(a);return t&&await b(t.path),i.libraries.remove(a),i.dataBus?.emit({key:"libraries"}),i.dataBus?.emit({key:"market"}),e(r,200,{ok:!0}),!0}if(u==="/market"&&o.method==="GET"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;const a=await Promise.all(i.libraries.list().map(t=>P(t,i.libraries.dataRoot)));return e(r,200,{items:a}),!0}if(u==="/market"&&o.method==="POST"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;let a;try{a=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const t={libraries:i.libraries,dataRoot:i.libraries.dataRoot};try{if(a.kind==="dir"&&a.path){const n=await Nt(a.path,t);n.refreshed&&i.fingerprintCache?.invalidate(n.dir),await b(n.dir),i.dataBus?.emit({key:"market"}),e(r,201,{item:await P(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}else if(a.kind==="git"&&a.url){const n=await Ot(a.url,t);n.refreshed&&i.fingerprintCache?.invalidate(n.dir),await b(n.dir),i.dataBus?.emit({key:"market"}),e(r,201,{item:await P(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}else e(r,400,{error:'Invalid body (kind: "dir" + path | "git" + url)'})}catch(n){e(r,400,{error:n instanceof Error?n.message:"Import failed"})}return!0}if(u==="/market/check-updates"&&o.method==="POST"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;let a={};const t=(await g(o)).trim();if(t)try{a=JSON.parse(t)}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const n=i.libraries.list().filter(l=>!S(l.path,i.libraries.dataRoot)).filter(l=>!a.ids?.length||a.ids.includes(l.id));for(const l of n)await b(l.path);const c=await Ft(n.map(l=>({id:l.id,dir:l.path})));return i.dataBus?.emit({key:"market"}),e(r,200,{results:c}),!0}if(u==="/market/refresh"&&o.method==="POST"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;let a={};const t=(await g(o)).trim();if(t)try{a=JSON.parse(t)}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const n=i.libraries.list().filter(f=>!a.ids?.length||a.ids.includes(f.id)),c=[];for(const f of n.filter(k=>S(k.path,i.libraries.dataRoot))){const k=await Gt({libraries:i.libraries});c.push({id:f.id,status:k.error?"failed":"refreshed"})}const l=n.filter(f=>!S(f.path,i.libraries.dataRoot)).map(f=>({id:f.id,dir:f.path})),s=[...await Jt(l,{libraries:i.libraries,dataRoot:i.libraries.dataRoot}),...c],m=new Map(l.map(f=>[f.id,f.dir]));for(const f of s)if(f.status==="refreshed"){const k=m.get(f.id);k&&(i.fingerprintCache?.invalidate(k),await b(k))}return i.dataBus?.emit({key:"market"}),e(r,200,{results:s}),!0}const p=u.match(/^\/market\/(\d+)$/);if(p&&o.method==="DELETE"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(p[1]));if(!a)return e(r,404,{error:"Library not found"}),!0;if(S(a.path,i.libraries.dataRoot))return e(r,409,{error:"Built-in market is owned by weave and cannot be deleted",note:"It is re-materialized from @weavecode/templates on every daemon start."}),!0;if(!N(a.path,E(i.libraries.dataRoot)))return e(r,400,{error:"Not a market resource (legacy row \u2014 use DELETE /libraries/:id)"}),!0;let t;try{await(i.pluginSurface??V("claude")).removeMarketplace(a.path)}catch(n){t=`Host marketplace deregistration failed: ${n instanceof Error?n.message:String(n)}`}return await Lt(a.path),i.libraries.remove(a.id),await b(a.path),i.dataBus?.emit({key:"market"}),i.dataBus?.emit({key:"libraries"}),e(r,200,{ok:!0,removed:a.path,installedCopiesKept:!0,...t?{warning:t}:{},note:"The host cascade-uninstalls plugins installed from this market; other installed copies are kept."}),!0}const y=u.match(/^\/libraries\/(\d+)\/market-import$/);if(y&&o.method==="POST"){if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;const a=i.libraries.getById(Number(y[1]));if(!a)return e(r,404,{error:"Library not found"}),!0;try{const t=a.path,n=await Tt(a,{libraries:i.libraries,dataRoot:i.libraries.dataRoot});await b(t),await b(n.dir),e(r,200,{item:await P(i.libraries.getById(n.libraryId),i.libraries.dataRoot)})}catch(t){e(r,400,{error:t instanceof Error?t.message:"Import failed"})}return!0}const T=u.match(/^\/projects\/(\d+)\/install$/);if(T&&o.method==="POST"){const a=i.projects.getById(Number(T[1]));let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!a&&Q(t))return e(r,404,{error:"Project not found"}),!0;const n=a?.path??"";try{if(t.category==="skill"){if(!t.name||!t.sourceDir)return e(r,400,{error:'Missing "name" or "sourceDir"'}),!0;const c=t.agent??"claude",l=t.scope==="user"?await et(t.sourceDir,t.name,c):await Z(n,t.sourceDir,t.name,c);e(r,201,{category:"skill",name:t.name,scope:t.scope??"project",agent:c,path:l})}else if(t.category&&K(t.category)){if(!t.name||!t.sourceFile)return e(r,400,{error:'Missing "name" or "sourceFile"'}),!0;const c=t.agent??"claude",l=t.scope??"project",s=await tt(n,t.category,t.name,t.sourceFile,c,l);e(r,201,{category:t.category,name:t.name,scope:l,agent:c,path:s})}else if(t.category==="mcp"){if(!t.name||!t.mcpConfig)return e(r,400,{error:'Missing "name" or "mcpConfig"'}),!0;const c=t.agent??"claude",l=v(c);if(!l)return e(r,400,{error:`Unsupported agent: ${c}`}),!0;const s=l.mcpScopes(),m=t.scope??s[0];if(!m||!s.includes(m))return e(r,400,{error:`MCP servers for ${c} are ${s.join("/")}-level only \u2014 scope "${t.scope}" is not available`}),!0;if(t.name in await l.mcpRead(m,n,j()))return I(r,new x(`MCP server "${t.name}" is already configured`)),!0;await l.mcpWrite(m,n,j(),t.name,t.mcpConfig),m==="project"&&await ut(n,{category:"mcp",name:t.name,agent:c}),e(r,201,{category:"mcp",name:t.name,scope:m,agent:c})}else if(t.category==="plugin"){if(!t.name||!t.sourceDir)return e(r,400,{error:'Missing "name" or "sourceDir"'}),!0;if(t.scope&&t.scope!=="user")return e(r,400,{error:'Plugin install currently only supports scope "user"'}),!0;const c=t.agent??"claude",l=W().find(f=>f.harness===c);if(!l)return e(r,400,{error:`No plugin install surface for runtime: ${c}`}),!0;const s=c==="claude"&&i.pluginSurface?i.pluginSurface:l.surface,m=await Et(s,{dir:t.sourceDir,name:t.name,version:t.version,description:t.description});i.dataBus?.emit({key:"toolkit"}),e(r,201,{category:"plugin",key:m.key,scope:"user",agent:c,alreadyInstalled:m.alreadyInstalled})}else e(r,400,{error:'Invalid "category" (skill|mcp|plugin|command|agent|workflow|rule|output-style)'})}catch(c){I(r,c)}return!0}const C=u.match(/^\/projects\/(\d+)\/mcp\/builtin$/);if(C&&o.method==="POST"){const a=i.projects.getById(Number(C[1]));let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const n=Pt.find(f=>f.name===t.name);if(!n)return e(r,404,{error:`Unknown built-in MCP server: ${t.name??""}`}),!0;if(!a)return e(r,404,{error:"Project not found"}),!0;const c=t.agent??"claude",l=v(c);if(!l||!l.mcpScopes().includes("user"))return e(r,400,{error:`MCP servers for ${c} have no user scope`}),!0;const s=i.auth?.getLocalToken()??"",m={type:"http",url:`http://127.0.0.1:${i.port}${n.path}`,...s?{headers:{"x-weave-local":s}}:{}};try{await l.mcpWrite("user",a.path,j(),n.name,m),e(r,201,{category:"mcp",name:n.name,scope:"user",agent:c})}catch(f){e(r,400,{error:f instanceof Error?f.message:"Install failed"})}return!0}const $=u.match(/^\/projects\/(\d+)\/uninstall$/);if($&&o.method==="POST"){const a=i.projects.getById(Number($[1]));let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!a&&Q(t))return e(r,404,{error:"Project not found"}),!0;const n=a?.path??"";try{if(t.category==="skill"){if(!t.name)return e(r,400,{error:'Missing "name"'}),!0;const c=t.agent??"claude";t.scope==="user"?await at(t.name,c):await q(n,t.name,c)}else if(t.category&&K(t.category)){if(!t.name)return e(r,400,{error:'Missing "name"'}),!0;await rt(n,t.category,t.name,t.agent??"claude",t.scope??"project")}else if(t.category==="mcp"){if(!t.name)return e(r,400,{error:'Missing "name"'}),!0;const c=t.agent??"claude",l=v(c);if(!l)return e(r,400,{error:`Unsupported agent: ${c}`}),!0;const s=l.mcpScopes(),m=t.scope??s[0];if(!m||!s.includes(m))return e(r,400,{error:`MCP servers for ${c} are ${s.join("/")}-level only \u2014 scope "${t.scope}" is not available`}),!0;if(!await l.mcpRemove(m,n,j(),t.name))return I(r,new M(`MCP server "${t.name}" is not configured`)),!0;m==="project"&&await st(n,{category:"mcp",name:t.name,agent:c})}else return e(r,400,{error:'Invalid "category" (skill|mcp|command|agent|workflow|rule|output-style)'}),!0;e(r,200,{ok:!0})}catch(c){I(r,c)}return!0}const B=u.match(/^\/projects\/(\d+)\/asset-file$/);if(B&&o.method==="GET"){const a=i.projects.getById(Number(B[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;const t=d.searchParams.get("path");if(!t)return e(r,400,{error:'Missing "path" query parameter'}),!0;try{const n=await mt(a.path,t);e(r,200,{path:t,content:n.content,size:n.size})}catch(n){O(r,n)}return!0}if(u==="/global-file"&&o.method==="GET"){const a=d.searchParams.get("path");if(!a)return e(r,400,{error:'Missing "path" query parameter'}),!0;try{const t=await ft(a);e(r,200,{path:a,content:t.content,size:t.size})}catch(t){O(r,t)}return!0}const F=u.match(/^\/projects\/(\d+)\/mcp$/);if(F&&o.method==="GET"){const a=i.projects.getById(Number(F[1]));return a?(e(r,200,{rows:await gt(a.path)}),!0):(e(r,404,{error:"Project not found"}),!0)}const J=u.match(/^\/projects\/(\d+)\/harness-checks$/);if(J&&o.method==="GET"){const a=i.projects.getById(Number(J[1]));return a?(e(r,200,{checks:await Y(a.path)}),!0):(e(r,404,{error:"Project not found"}),!0)}if(u.match(/^\/projects\/(\d+)\/skills\/global$/)&&o.method==="GET")return e(r,200,{groups:await it()}),!0;if(u.match(/^\/projects\/(\d+)\/skills\/global\/files$/)&&o.method==="GET"){const a=d.searchParams.get("source"),t=d.searchParams.get("name"),n=d.searchParams.get("pluginKey")??void 0;if(!a||!t)return e(r,400,{error:'Missing "source" or "name" query parameter'}),!0;const c=await H(a,t,n);return c?(e(r,200,{files:await ot(c)}),!0):(e(r,404,{error:"Skill not found"}),!0)}if(u.match(/^\/projects\/(\d+)\/skills\/global\/file$/)&&o.method==="GET"){const a=d.searchParams.get("source"),t=d.searchParams.get("name"),n=d.searchParams.get("pluginKey")??void 0,c=d.searchParams.get("path");if(!a||!t||!c)return e(r,400,{error:'Missing "source", "name" or "path" query parameter'}),!0;const l=await H(a,t,n);if(!l)return e(r,404,{error:"Skill not found"}),!0;try{const s=await nt(l,c);e(r,200,{path:c,content:s.content,size:s.size})}catch(s){O(r,s)}return!0}const G=u.match(/^\/projects\/(\d+)\/plugins\/state$/);if(G){const a=i.projects.getById(Number(G[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;if(o.method==="GET")return e(r,200,{rows:await Mt(a.path)}),!0;if(o.method==="PUT"){let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!A(t.runtime)||!t.key||!t.scope||!["user","project","local"].includes(t.scope)||!t.state||!["on","off","inherit"].includes(t.state))return e(r,400,{error:'Missing or invalid "runtime"/"key"/"scope" (user|project|local)/"state" (on|off|inherit)'}),!0;const n=t.scope,c=t.state;try{const l=W().find(s=>s.harness===t.runtime);if(l)await(t.runtime==="claude"&&i.pluginSurface?i.pluginSurface:l.surface).setEnabledOverride(a.path,n,t.key,c);else{const s=Ut().find(m=>m.harness===t.runtime);if(!s||n!=="user"||c==="inherit")return e(r,400,{error:"This runtime only supports user-scope on/off overrides"}),!0;await s.state.writeGlobalEnabled(t.key,c==="on")}i.dataBus?.emit({key:"toolkit"}),e(r,200,{ok:!0})}catch(l){e(r,400,{error:l instanceof Error?l.message:"Plugin state write failed"})}return!0}}if(u.match(/^\/projects\/(\d+)\/plugins\/uninstall$/)&&o.method==="POST"){let a;try{a=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!A(a.runtime)||!a.key)return e(r,400,{error:'Missing or invalid "runtime"/"key"'}),!0;try{const t=a.runtime==="claude"&&i.pluginSurface?i.pluginSurface:V(a.runtime),{name:n,market:c}=t.parsePluginKey(a.key);await t.uninstall(n,c),e(r,200,{ok:!0})}catch(t){e(r,400,{error:t instanceof Error?t.message:"Plugin uninstall failed"})}return!0}const L=u.match(/^\/projects\/(\d+)\/mcp\/enable$/);if(L){const a=i.projects.getById(Number(L[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;if(o.method==="PUT"){let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}return!t.name||!t.state?(e(r,400,{error:'Missing "name" or "state"'}),!0):["on","off","inherit"].includes(t.state)?(await ht(a.path,t.name,t.state),e(r,200,{ok:!0}),!0):(e(r,400,{error:'Invalid "state" (on|off|inherit)'}),!0)}}const R=u.match(/^\/projects\/(\d+)\/updates$/);if(R&&o.method==="GET"){const a=i.projects.getById(Number(R[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;const t=i.fingerprintCache??new z;if(!i.libraries){const c=await St(a.path,t),l=await jt(a.path);return e(r,200,{skills:[],mcp:[],files:[],pluginTemplates:c,initFiles:l,available:c.filter(s=>s.outdated).length+l.filter(s=>s.outdated&&s.syncClass==="auto").length,needsInit:vt(l)}),!0}const n=await wt(a.path,i.libraries.list(),t);return e(r,200,n),!0}const D=u.match(/^\/projects\/(\d+)\/update$/);if(D&&o.method==="POST"){const a=i.projects.getById(Number(D[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;let t;try{t=JSON.parse(await g(o))}catch{return e(r,400,{error:"Invalid JSON body"}),!0}if(!t.category||!t.name||!t.scope)return e(r,400,{error:'Missing "category", "name", or "scope"'}),!0;if(!["skill","mcp","command","agent","workflow","rule","output-style"].includes(t.category))return e(r,400,{error:'Invalid "category"'}),!0;try{const c=await kt(i.libraries.list());await bt(a.path,{category:t.category,name:t.name,scope:t.scope,agent:t.agent},c),e(r,200,{ok:!0,category:t.category,name:t.name,scope:t.scope})}catch(c){e(r,400,{error:c instanceof Error?c.message:"Update failed"})}return!0}const U=u.match(/^\/projects\/(\d+)\/sync-all$/);if(U&&o.method==="POST"){const a=i.projects.getById(Number(U[1]));if(!a)return e(r,404,{error:"Project not found"}),!0;if(!i.libraries)return e(r,503,{error:"Libraries unavailable"}),!0;try{const t=i.fingerprintCache??new z,n=await yt(a.path,i.libraries.list(),t);let c=n;try{const l=i.hookPlugins?.list().map(m=>m.id)??[],s=Rt(a,l,{projects:i.projects});c={...n,pluginSync:{syncedAt:s}}}catch{}e(r,200,c),i.updatesRefresher?.refreshNow(!0)}catch(t){e(r,400,{error:t instanceof Error?t.message:"Sync failed"})}return!0}return!1}
@@ -1 +1 @@
1
- import{z as i}from"zod";import{nextRunAt as E,parseCron as x}from"../cron.js";import{validateOrchestration as R}from"../../hooks/orchestration-graph.js";import{graphDirections as S,toRunSummary as j}from"../../repositories/orchestrations.js";import{readBody as v,readJson as k,sendJson as n}from"../http.js";const B=i.object({id:i.string().min(1).max(128),kind:i.enum(["session","webhook","trigger"]),webhookToken:i.string().min(1).max(200).optional(),url:i.string().max(2e3).optional(),secret:i.string().max(400).optional(),autoFire:i.boolean().optional()}),w=i.object({name:i.string().min(1).max(200),startText:i.string().max(2e4).optional(),projectId:i.number().int().optional(),nodes:i.array(B).min(1),edges:i.array(i.object({id:i.string().min(1).max(64),from:i.string().min(1),to:i.string().min(1),text:i.string().max(2e4),extract:i.string().max(4e3).optional(),condition:i.string().max(4e3).optional(),when:i.string().max(500).optional()})),cron:i.string().max(200).nullish(),enabled:i.boolean().optional()}),N=w.partial(),P=i.object({text:i.string().min(1).max(2e4).optional(),entries:i.array(i.string().min(1)).optional()}),O=i.object({nodeId:i.string().min(1).max(128)}),$=new Set(["running","done","failed","cancelled","interrupted"]);function g(s,e){const r=s.searchParams.get(e);if(r==null||r==="")return;const c=Number(r);return Number.isFinite(c)?c:void 0}function I(s){const e=s.cron?x(s.cron):null;return{...s,nextRunAt:e?E(e):null}}function T(s,e){const r=e.name.trim();if(!r)return{ok:!1,error:"Name is required"};const c=R(e);if(!c.ok)return{ok:!1,error:c.error};const d=e.cron?.trim()||null;if(d&&!x(d))return{ok:!1,error:`Invalid cron expression: ${d}`};for(const u of e.nodes)if(u.kind==="session"&&!s.hookSessions?.getBySessionId(u.id))return{ok:!1,error:`Unknown session: ${u.id}`};const{entries:f}=S(e.nodes,e.edges),m=f.filter(u=>u.kind==="session");let l=e.projectId??null;if(m.length>0){const u=s.hookSessions.getBySessionId(m[0].id);if(l!=null&&l!==u.projectId)return{ok:!1,error:"projectId must match the entry sessions"};if(l=u.projectId,l==null)return{ok:!1,error:"Entry session has no project"};for(const h of m)if(s.hookSessions.getBySessionId(h.id).projectId!==l)return{ok:!1,error:"All entry sessions must belong to the same project"}}else{const u=e.nodes.find(h=>h.kind==="session");u&&(l=s.hookSessions.getBySessionId(u.id).projectId??l)}return l==null?{ok:!1,error:"projectId is required for webhook-only orchestrations"}:{ok:!0,value:{name:r,projectId:l,startText:(e.startText??"").trim(),nodes:e.nodes,edges:e.edges,cron:d}}}function M(s,e){for(const r of s.orchestrationRuns?.listRunning()??[])r.orchestrationId===e&&s.orchestrationEngine?.cancel(r.id)}export async function handleOrchestrationRoutes(s,e,r,c,d){if(c==="/messaging/orchestrations"){if(!r.orchestrations)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;if(s.method==="GET"){const o=g(d,"projectId"),t=o===void 0?r.orchestrations.list():r.orchestrations.listByProject(o);return n(e,200,{orchestrations:t.map(I)}),!0}if(s.method==="POST"){let o;try{o=w.parse(await k(s))}catch(a){return n(e,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const t=T(r,o);return t.ok?(n(e,201,{ok:!0,orchestration:I(r.orchestrations.insert({...t.value,enabled:o.enabled}))}),!0):(n(e,400,{error:t.error}),!0)}}const f=c.match(/^\/messaging\/orchestrations\/(\d+)$/);if(f){const o=Number(f[1]);if(s.method==="PUT"){if(!r.orchestrations)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=r.orchestrations.getById(o);if(!t)return n(e,404,{error:"Orchestration not found"}),!0;let a;try{a=N.parse(await k(s))}catch(b){return n(e,400,{error:b instanceof Error?b.message:"Invalid body"}),!0}const p=T(r,{name:a.name??t.name,startText:a.startText??t.startText,projectId:a.projectId??(t.nodes.some(b=>b.kind==="session")?void 0:t.projectId),nodes:a.nodes??t.nodes,edges:a.edges??t.edges,cron:a.cron===void 0?t.cron:a.cron});return p.ok?(n(e,200,{ok:!0,orchestration:I(r.orchestrations.update(o,{...p.value,enabled:a.enabled}))}),!0):(n(e,400,{error:p.error}),!0)}if(s.method==="DELETE")return r.orchestrations?r.orchestrations.getById(o)?(M(r,o),r.orchestrations.deleteById(o),n(e,200,{ok:!0,orchestrationId:o}),!0):(n(e,404,{error:"Orchestration not found"}),!0):(n(e,503,{error:"Messaging subsystem unavailable"}),!0)}const m=c.match(/^\/messaging\/orchestrations\/(\d+)\/trigger$/);if(m&&s.method==="POST"){if(!r.orchestrationEngine||!r.orchestrations)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;let o={};try{const a=(await v(s)).trim();a&&(o=P.parse(JSON.parse(a)))}catch{return n(e,400,{error:"Invalid body"}),!0}const t=await r.orchestrationEngine.start(Number(m[1]),"manual",o.text,o.entries);return t.ok?(n(e,201,{ok:!0,runId:t.runId}),!0):(n(e,t.status,{error:t.error}),!0)}const l=c.match(/^\/messaging\/orchestrations\/(\d+)\/rotate-webhook$/);if(l&&s.method==="POST"){if(!r.orchestrations)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=O.parse(await k(s))}catch(a){return n(e,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const t=r.orchestrations.rotateNodeToken(Number(l[1]),o.nodeId);return t?(n(e,200,{ok:!0,webhookToken:t}),!0):(n(e,404,{error:"Webhook entry node not found"}),!0)}const u=c.match(/^\/webhooks\/orchestrate\/([A-Za-z0-9_-]+)$/);if(u&&s.method==="POST"){if(!r.orchestrations||!r.orchestrationEngine)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=r.orchestrations.getByNodeToken(u[1]);if(!o)return n(e,404,{error:"Unknown webhook token"}),!0;const t=(await v(s)).trim().slice(0,2e4),a=await r.orchestrationEngine.start(o.row.id,"webhook",t||void 0,[o.nodeId]);return a.ok?(n(e,202,{ok:!0,runId:a.runId}),!0):(n(e,a.status,{error:a.error}),!0)}if(c==="/messaging/orchestration-runs"){if(!r.orchestrationRuns)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;if(s.method==="GET"){const o=d.searchParams.get("status")||void 0;if(o&&!$.has(o))return n(e,400,{error:`Unknown run status: ${o}`}),!0;const t=r.orchestrationRuns.query({orchestrationId:g(d,"orchestrationId"),projectId:g(d,"projectId"),status:o,text:d.searchParams.get("text")||void 0,before:g(d,"before"),limit:g(d,"limit")});return n(e,200,{runs:t.runs.map(j),nextBefore:t.nextBefore}),!0}if(s.method==="DELETE"){const o=d.searchParams.get("scope")==="all"?"all":"finished",t=g(d,"projectId");if(o==="all")for(const a of r.orchestrationRuns.listRunning())t!=null&&a.projectId!==t||r.orchestrationEngine?.cancel(a.id);return n(e,200,{ok:!0,deleted:r.orchestrationRuns.clear(o,t)}),!0}}const h=c.match(/^\/messaging\/orchestration-runs\/(\d+)$/);if(h&&s.method==="GET"){if(!r.orchestrationRuns)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=r.orchestrationRuns.getById(Number(h[1]));return o?(n(e,200,{run:{...j(o),state:o.state}}),!0):(n(e,404,{error:"Run not found"}),!0)}const y=c.match(/^\/messaging\/orchestration-runs\/(\d+)\/cancel$/);if(y&&s.method==="POST"){if(!r.orchestrationRuns)return n(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=r.orchestrationRuns.getById(Number(y[1]));return o?o.status!=="running"?(n(e,409,{error:`Run already ${o.status}`}),!0):(r.orchestrationEngine?.cancel(o.id)||r.orchestrationRuns.finish(o.id,"cancelled"),n(e,200,{ok:!0,runId:o.id}),!0):(n(e,404,{error:"Run not found"}),!0)}return!1}
1
+ import{z as i}from"zod";import{nextRunAt as E,parseCron as j}from"../cron.js";import{validateOrchestration as S}from"../../hooks/orchestration-graph.js";import{graphDirections as B,toRunSummary as w}from"../../repositories/orchestrations.js";import{readBody as R,readJson as k,sendJson as o}from"../http.js";const M=i.object({id:i.string().min(1).max(128),kind:i.enum(["session","webhook","trigger"]),webhookToken:i.string().min(1).max(200).optional(),url:i.string().max(2e3).optional(),secret:i.string().max(400).optional(),autoFire:i.boolean().optional()}),T=i.object({name:i.string().min(1).max(200),startText:i.string().max(2e4).optional(),projectId:i.number().int().optional(),nodes:i.array(M).min(1),edges:i.array(i.object({id:i.string().min(1).max(64),from:i.string().min(1),to:i.string().min(1),text:i.string().max(2e4),extract:i.string().max(4e3).optional(),condition:i.string().max(4e3).optional(),when:i.string().max(500).optional()})),cron:i.string().max(200).nullish(),enabled:i.boolean().optional()}),N=T.partial(),O=i.object({text:i.string().min(1).max(2e4).optional(),entries:i.array(i.string().min(1)).optional()}),P=i.object({nodeId:i.string().min(1).max(128)}),$=new Set(["running","done","failed","cancelled","interrupted"]);function m(s,r){const t=s.searchParams.get(r);if(t==null||t==="")return;const c=Number(t);return Number.isFinite(c)?c:void 0}function I(s){const r=s.cron?j(s.cron):null;return{...s,nextRunAt:r?E(r):null}}function v(s,r){const t=r.name.trim();if(!t)return{ok:!1,error:"Name is required"};const c=S(r);if(!c.ok)return{ok:!1,error:c.error};const u=r.cron?.trim()||null;if(u&&!j(u))return{ok:!1,error:`Invalid cron expression: ${u}`};for(const d of r.nodes)if(d.kind==="session"&&!s.hookSessions?.getBySessionId(d.id))return{ok:!1,error:`Unknown session: ${d.id}`};const{entries:g}=B(r.nodes,r.edges),h=g.filter(d=>d.kind==="session");let l=r.projectId??null;if(h.length>0){const d=s.hookSessions.getBySessionId(h[0].id);if(l!=null&&l!==d.projectId)return{ok:!1,error:"projectId must match the entry sessions"};if(l=d.projectId,l==null)return{ok:!1,error:"Entry session has no project"};for(const f of h)if(s.hookSessions.getBySessionId(f.id).projectId!==l)return{ok:!1,error:"All entry sessions must belong to the same project"}}else{const d=r.nodes.find(f=>f.kind==="session");d&&(l=s.hookSessions.getBySessionId(d.id).projectId??l)}return l==null?{ok:!1,error:"projectId is required for webhook-only orchestrations"}:{ok:!0,value:{name:t,projectId:l,startText:(r.startText??"").trim(),nodes:r.nodes,edges:r.edges,cron:u}}}function _(s,r){for(const t of s.orchestrationRuns?.listRunning()??[])t.orchestrationId===r&&s.orchestrationEngine?.cancel(t.id)}export async function handleOrchestrationRoutes(s,r,t,c,u){if(c==="/messaging/orchestrations"){if(!t.orchestrations)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;if(s.method==="GET"){const e=m(u,"projectId"),n=e===void 0?t.orchestrations.list():t.orchestrations.listByProject(e);return o(r,200,{orchestrations:n.map(I)}),!0}if(s.method==="POST"){let e;try{e=T.parse(await k(s))}catch(a){return o(r,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const n=v(t,e);return n.ok?(o(r,201,{ok:!0,orchestration:I(t.orchestrations.insert({...n.value,enabled:e.enabled}))}),!0):(o(r,400,{error:n.error}),!0)}}const g=c.match(/^\/messaging\/orchestrations\/(\d+)$/);if(g){const e=Number(g[1]);if(s.method==="PUT"){if(!t.orchestrations)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;const n=t.orchestrations.getById(e);if(!n)return o(r,404,{error:"Orchestration not found"}),!0;let a;try{a=N.parse(await k(s))}catch(b){return o(r,400,{error:b instanceof Error?b.message:"Invalid body"}),!0}const y=v(t,{name:a.name??n.name,startText:a.startText??n.startText,projectId:a.projectId??(n.nodes.some(b=>b.kind==="session")?void 0:n.projectId),nodes:a.nodes??n.nodes,edges:a.edges??n.edges,cron:a.cron===void 0?n.cron:a.cron});return y.ok?(o(r,200,{ok:!0,orchestration:I(t.orchestrations.update(e,{...y.value,enabled:a.enabled}))}),!0):(o(r,400,{error:y.error}),!0)}if(s.method==="DELETE")return t.orchestrations?t.orchestrations.getById(e)?(_(t,e),t.orchestrations.deleteById(e),o(r,200,{ok:!0,orchestrationId:e}),!0):(o(r,404,{error:"Orchestration not found"}),!0):(o(r,503,{error:"Messaging subsystem unavailable"}),!0)}const h=c.match(/^\/messaging\/orchestrations\/(\d+)\/trigger$/);if(h&&s.method==="POST"){if(!t.orchestrationEngine||!t.orchestrations)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;let e={};try{const a=(await R(s)).trim();a&&(e=O.parse(JSON.parse(a)))}catch{return o(r,400,{error:"Invalid body"}),!0}const n=await t.orchestrationEngine.start(Number(h[1]),"manual",e.text,e.entries);return n.ok?(o(r,201,{ok:!0,runId:n.runId}),!0):(o(r,n.status,{error:n.error}),!0)}const l=c.match(/^\/messaging\/orchestrations\/(\d+)\/rotate-webhook$/);if(l&&s.method==="POST"){if(!t.orchestrations)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;let e;try{e=P.parse(await k(s))}catch(a){return o(r,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const n=t.orchestrations.rotateNodeToken(Number(l[1]),e.nodeId);return n?(o(r,200,{ok:!0,webhookToken:n}),!0):(o(r,404,{error:"Webhook entry node not found"}),!0)}const d=c.match(/^\/webhooks\/orchestrate\/([A-Za-z0-9_-]+)$/);if(d&&s.method==="POST"){if(!t.orchestrations||!t.orchestrationEngine)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;const e=t.orchestrations.getByNodeToken(d[1]);if(!e)return o(r,404,{error:"Unknown webhook token"}),!0;const n=(await R(s)).trim().slice(0,2e4),a=await t.orchestrationEngine.start(e.row.id,"webhook",n||void 0,[e.nodeId]);return a.ok?(o(r,202,{ok:!0,runId:a.runId}),!0):(o(r,a.status,{error:a.error}),!0)}if(c==="/messaging/orchestration-runs"){if(!t.orchestrationRuns)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;if(s.method==="GET"){const e=u.searchParams.get("status")||void 0;if(e&&!$.has(e))return o(r,400,{error:`Unknown run status: ${e}`}),!0;const n=t.orchestrationRuns.query({orchestrationId:m(u,"orchestrationId"),projectId:m(u,"projectId"),status:e,text:u.searchParams.get("text")||void 0,before:m(u,"before"),limit:m(u,"limit")});return o(r,200,{runs:n.runs.map(w),nextBefore:n.nextBefore}),!0}if(s.method==="DELETE"){const e=u.searchParams.get("scope")==="all"?"all":"finished",n=m(u,"projectId");if(e==="all")for(const a of t.orchestrationRuns.listRunning())n!=null&&a.projectId!==n||t.orchestrationEngine?.cancel(a.id);return o(r,200,{ok:!0,deleted:t.orchestrationRuns.clear(e,n)}),!0}}const f=c.match(/^\/messaging\/orchestration-runs\/(\d+)$/);if(f&&s.method==="GET"){if(!t.orchestrationRuns)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;const e=t.orchestrationRuns.getById(Number(f[1]));return e?(o(r,200,{run:{...w(e),state:e.state}}),!0):(o(r,404,{error:"Run not found"}),!0)}const x=c.match(/^\/messaging\/orchestration-runs\/(\d+)\/cancel$/);if(x&&s.method==="POST"){if(!t.orchestrationRuns)return o(r,503,{error:"Messaging subsystem unavailable"}),!0;const e=t.orchestrationRuns.getById(Number(x[1]));return e?e.status!=="running"?(o(r,409,{error:`Run already ${e.status}`}),!0):(t.orchestrationEngine?.cancel(e.id)||t.orchestrationRuns.finish(e.id,"cancelled"),o(r,200,{ok:!0,runId:e.id}),!0):(o(r,404,{error:"Run not found"}),!0)}return!1}
@@ -1 +1 @@
1
- import{isHarness as I}from"@weavecode/core";import{readJson as P,sendJson as t}from"../http.js";import{messagingSurfaceFor as R}from"../../surfaces.js";import{projectFileIndex as b}from"../project-files.js";function k(e,n,s){if(!n.hookSessions||!n.hookEvents)return t(e,503,{error:"Hooks subsystem unavailable"}),null;const r=n.hookSessions.getBySessionId(s);return r?r.projectId==null?(t(e,400,{error:"Session is not bound to a project"}),null):n.projects.getById(r.projectId)||(t(e,404,{error:"Project not found"}),null):(t(e,404,{error:"Session not found"}),null)}function j(e,n){if(!e.hookEvents)return null;const s=e.hookEvents.listBySession(n,1),r=s[s.length-1]?.source;return I(r)?r:null}function y(e,n,s){const r=j(n,s),o=r?R(r):null;return(o?.pathRefs??null)||(t(e,409,{error:r?o?.unsupportedReasons?.pathRefs??`Harness "${r}" has no path reference syntax`:"Session has no hook events to determine its harness"}),null)}function S(e){if(e==null||e==="")return null;const n=Number(e);return Number.isInteger(n)&&n>0?n:null}function x(e,n){let s=0,r=e.length-1;for(;s<=r;){const o=s+r>>1,f=e[o];if(f===n)return!0;f<n?s=o+1:r=o-1}return!1}export async function handlePathRefRoutes(e,n,s,r,o){const f=r.match(/^\/sessions\/([^/]+)\/ref$/);if(f&&e.method==="GET"){const h=decodeURIComponent(f[1]);if(!k(n,s,h))return!0;const a=y(n,s,h);if(!a)return!0;const u=(o.searchParams.get("path")??"").replace(/^\/+|\/+$/g,"");if(!u)return t(n,400,{error:'Missing "path" query parameter'}),!0;const c=o.searchParams.get("kind")==="dir"?"dir":"file";if(!a.kinds.includes(c))return t(n,409,{error:`Harness does not accept "${c}" references`}),!0;const l=S(o.searchParams.get("start")),d=S(o.searchParams.get("end"));return a.lines?l==null?(t(n,200,{ref:a.expression({path:u,kind:c})}),!0):d!=null&&d<l?(t(n,400,{error:'"end" must not precede "start"'}),!0):(t(n,200,{ref:a.expression({path:u,kind:c,lines:{start:l,end:d??l}})}),!0):(t(n,200,{ref:a.expression({path:u,kind:c})}),!0)}const g=r.match(/^\/sessions\/([^/]+)\/refs\/recognize$/);if(g&&e.method==="POST"){const h=decodeURIComponent(g[1]),a=k(n,s,h);if(!a)return!0;const u=y(n,s,h);if(!u)return!0;let c="";try{const i=await P(e);c=typeof i?.text=="string"?i.text:""}catch{return t(n,400,{error:"Body must be JSON"}),!0}const l=await b(a.id,a.path),d=[];for(const i of u.recognize(c)){const p=i.kind==="dir"&&x(l.dirs,i.path)?"dir":x(l.files,i.path)?"file":null;if(!p||!u.kinds.includes(p))continue;const m=i.lines&&u.lines?i.lines:void 0;d.push({start:i.start,end:i.end,ref:u.expression({path:i.path,kind:p,...m?{lines:m}:{}}),path:i.path,kind:p,...m?{lines:m}:{}})}return t(n,200,{refs:d}),!0}return!1}
1
+ import{isHarness as I}from"@weavecode/core";import{readJson as j,sendJson as o}from"../http.js";import{messagingSurfaceFor as P}from"../../surfaces.js";import{projectFileIndex as R}from"../project-files.js";function S(t,e,r){if(!e.hookSessions||!e.hookEvents)return o(t,503,{error:"Hooks subsystem unavailable"}),null;const n=e.hookSessions.getBySessionId(r);if(!n)return o(t,404,{error:"Session not found"}),null;if(n.projectId==null)return o(t,400,{error:"Session is not bound to a project"}),null;const s=e.projects.getById(n.projectId);return s||(o(t,404,{error:"Project not found"}),null)}function b(t,e){if(!t.hookEvents)return null;const r=t.hookEvents.listBySession(e,1),n=r[r.length-1]?.source;return I(n)?n:null}function k(t,e,r){const n=b(e,r),s=n?P(n):null,a=s?.pathRefs??null;return a||(o(t,409,{error:n?s?.unsupportedReasons?.pathRefs??`Harness "${n}" has no path reference syntax`:"Session has no hook events to determine its harness"}),null)}function x(t){if(t==null||t==="")return null;const e=Number(t);return Number.isInteger(e)&&e>0?e:null}function y(t,e){let r=0,n=t.length-1;for(;r<=n;){const s=r+n>>1,a=t[s];if(a===e)return!0;a<e?r=s+1:n=s-1}return!1}export async function handlePathRefRoutes(t,e,r,n,s){const a=n.match(/^\/sessions\/([^/]+)\/ref$/);if(a&&t.method==="GET"){const d=decodeURIComponent(a[1]);if(!S(e,r,d))return!0;const u=k(e,r,d);if(!u)return!0;const c=(s.searchParams.get("path")??"").replace(/^\/+|\/+$/g,"");if(!c)return o(e,400,{error:'Missing "path" query parameter'}),!0;const f=s.searchParams.get("kind")==="dir"?"dir":"file";if(!u.kinds.includes(f))return o(e,409,{error:`Harness does not accept "${f}" references`}),!0;const l=x(s.searchParams.get("start")),h=x(s.searchParams.get("end"));return u.lines?l==null?(o(e,200,{ref:u.expression({path:c,kind:f})}),!0):h!=null&&h<l?(o(e,400,{error:'"end" must not precede "start"'}),!0):(o(e,200,{ref:u.expression({path:c,kind:f,lines:{start:l,end:h??l}})}),!0):(o(e,200,{ref:u.expression({path:c,kind:f})}),!0)}const g=n.match(/^\/sessions\/([^/]+)\/refs\/recognize$/);if(g&&t.method==="POST"){const d=decodeURIComponent(g[1]),u=S(e,r,d);if(!u)return!0;const c=k(e,r,d);if(!c)return!0;let f="";try{const i=await j(t);f=typeof i?.text=="string"?i.text:""}catch{return o(e,400,{error:"Body must be JSON"}),!0}const l=await R(u.id,u.path),h=[];for(const i of c.recognize(f)){const p=i.kind==="dir"&&y(l.dirs,i.path)?"dir":y(l.files,i.path)?"file":null;if(!p||!c.kinds.includes(p))continue;const m=i.lines&&c.lines?i.lines:void 0;h.push({start:i.start,end:i.end,ref:c.expression({path:i.path,kind:p,...m?{lines:m}:{}}),path:i.path,kind:p,...m?{lines:m}:{}})}return o(e,200,{refs:h}),!0}return!1}
@@ -1 +1 @@
1
- import{lstat as v,readFile as F,stat as j}from"node:fs/promises";import P from"node:path";import{sendJson as n}from"../http.js";import{listDirOf as O,matchPaths as k,projectFileIndex as z}from"../project-files.js";import{resolveWithinProject as N}from"../../install/reader.js";const S=4*1024*1024,I=1024*1024,L=8192;function B(r){const e=Number(r);return!Number.isFinite(e)||e<=0?100:Math.min(200,Math.floor(e))}function H(r){switch(r.slice(r.lastIndexOf(".")+1).toLowerCase()){case"png":return"image/png";case"jpg":case"jpeg":return"image/jpeg";case"gif":return"image/gif";case"webp":return"image/webp";default:return null}}function M(r){switch(r.slice(r.lastIndexOf(".")+1).toLowerCase()){case"html":case"htm":return"text/html; charset=utf-8";case"svg":return"image/svg+xml";case"pdf":return"application/pdf";default:return null}}const T=new Set(["docx","doc","xlsx","xls","pptx","ppt","zip","gz","tar","rar","7z","exe","dll","bin","woff","woff2","ttf","otf","ico","mp4","mp3","wav","mov"]);function $(r){const e=r.slice(r.lastIndexOf(".")+1).toLowerCase();return T.has(e)?"application/octet-stream":null}export async function handleProjectFileRoutes(r,e,w,x,m){const y=x.match(/^\/projects\/(\d+)\/files$/);if(y&&r.method==="GET"){const i=w.projects.getById(Number(y[1]));if(!i)return n(e,404,{error:"Project not found"}),!0;const a=await z(i.id,i.path,{fresh:m.searchParams.get("fresh")==="1"}),p=m.searchParams.get("q")??"",c=(m.searchParams.get("dir")??"").replace(/^\/+|\/+$/g,""),h=B(m.searchParams.get("limit"));if(p.trim()){const{hits:t,total:s,capped:l}=await k(a,p,h,c);return n(e,200,{root:i.path,dir:c,total:s,capped:l,truncated:a.truncated,entries:t.map(o=>({path:o.path,name:o.path.slice(o.path.lastIndexOf("/")+1),kind:o.kind,ranges:o.ranges,...a.submodules[o.path]?{head:a.submodules[o.path]}:{}}))}),!0}const u=O(a,c),d=await Promise.all(u.slice(0,h).map(async t=>{const s={path:t.path,name:t.path.slice(t.path.lastIndexOf("/")+1),kind:t.kind,...t.head?{head:t.head}:{}},l=P.join(i.path,t.path),[o,f]=await Promise.all([v(l).catch(()=>null),t.kind==="file"?j(l).catch(()=>null):Promise.resolve(null)]),g=o?.isSymbolicLink()?{symlink:!0}:null;return f?{...s,...g,size:f.size,mtime:f.mtime.toISOString()}:g?{...s,...g}:s}));return n(e,200,{root:i.path,dir:c,total:u.length,capped:!1,truncated:a.truncated,entries:d}),!0}const b=x.match(/^\/projects\/(\d+)\/file$/);if(b&&r.method==="GET"){const i=w.projects.getById(Number(b[1]));if(!i)return n(e,404,{error:"Project not found"}),!0;const a=m.searchParams.get("path");if(!a)return n(e,400,{error:'Missing "path" query parameter'}),!0;let p;try{p=N(i.path,a)}catch{return n(e,403,{error:"Path escapes the project"}),!0}let c;try{c=await j(p)}catch{return n(e,404,{error:"File not found"}),!0}if(!c.isFile())return n(e,404,{error:"Not a file"}),!0;if(c.size>S)return n(e,413,{error:"File too large to preview"}),!0;const h=H(a),u=M(a),d=$(a);let t=await F(p);if(!h&&!u&&!d){if(t.subarray(0,L).includes(0))return n(e,415,{error:"Binary file"}),!0;if(t.length>I){const s=t.subarray(0,I),l=s.lastIndexOf(10);t=l>0?s.subarray(0,l):s,e.setHeader("x-weave-truncated","1")}}return u&&e.setHeader("content-security-policy","sandbox"),d&&e.setHeader("content-disposition",`attachment; filename*=UTF-8''${encodeURI(P.basename(a))}`),e.writeHead(200,{"content-type":h??u??d??"text/plain; charset=utf-8","content-length":String(t.length),"cache-control":"private, max-age=60"}),e.end(t),!0}return!1}
1
+ import{lstat as O,readFile as T,stat as j}from"node:fs/promises";import I from"node:path";import{sendJson as n}from"../http.js";import{listDirOf as E,matchPaths as F,projectFileIndex as S}from"../project-files.js";import{resolveWithinProject as v}from"../../install/reader.js";const N=4*1024*1024,P=1024*1024,_=8192;function k(r){const t=Number(r);return!Number.isFinite(t)||t<=0?100:Math.min(200,Math.floor(t))}function B(r){switch(r.slice(r.lastIndexOf(".")+1).toLowerCase()){case"png":return"image/png";case"jpg":case"jpeg":return"image/jpeg";case"gif":return"image/gif";case"webp":return"image/webp";default:return null}}function M(r){switch(r.slice(r.lastIndexOf(".")+1).toLowerCase()){case"html":case"htm":return"text/html; charset=utf-8";case"svg":return"image/svg+xml";case"pdf":return"application/pdf";default:return null}}const z=new Set(["docx","doc","xlsx","xls","pptx","ppt","zip","gz","tar","rar","7z","exe","dll","bin","woff","woff2","ttf","otf","ico","mp4","mp3","wav","mov"]);function L(r){const t=r.slice(r.lastIndexOf(".")+1).toLowerCase();return z.has(t)?"application/octet-stream":null}export async function handleProjectFileRoutes(r,t,x,w,f){const y=w.match(/^\/projects\/(\d+)\/files$/);if(y&&r.method==="GET"){const i=x.projects.getById(Number(y[1]));if(!i)return n(t,404,{error:"Project not found"}),!0;const a=await S(i.id,i.path,{fresh:f.searchParams.get("fresh")==="1"}),u=f.searchParams.get("q")??"",c=(f.searchParams.get("dir")??"").replace(/^\/+|\/+$/g,""),m=k(f.searchParams.get("limit"));if(u.trim()){const{hits:e,total:o,capped:l}=await F(a,u,m,c);return n(t,200,{root:i.path,dir:c,total:o,capped:l,truncated:a.truncated,entries:e.map(s=>({path:s.path,name:s.path.slice(s.path.lastIndexOf("/")+1),kind:s.kind,ranges:s.ranges,...a.submodules[s.path]?{head:a.submodules[s.path]}:{}}))}),!0}const p=E(a,c),d=await Promise.all(p.slice(0,m).map(async e=>{const o={path:e.path,name:e.path.slice(e.path.lastIndexOf("/")+1),kind:e.kind,...e.head?{head:e.head}:{}},l=I.join(i.path,e.path),[s,h]=await Promise.all([O(l).catch(()=>null),e.kind==="file"?j(l).catch(()=>null):Promise.resolve(null)]),g=s?.isSymbolicLink()?{symlink:!0}:null;return h?{...o,...g,size:h.size,mtime:h.mtime.toISOString()}:g?{...o,...g}:o}));return n(t,200,{root:i.path,dir:c,total:p.length,capped:!1,truncated:a.truncated,entries:d}),!0}const b=w.match(/^\/projects\/(\d+)\/file$/);if(b&&r.method==="GET"){const i=x.projects.getById(Number(b[1]));if(!i)return n(t,404,{error:"Project not found"}),!0;const a=f.searchParams.get("path");if(!a)return n(t,400,{error:'Missing "path" query parameter'}),!0;let u;try{u=v(i.path,a)}catch{return n(t,403,{error:"Path escapes the project"}),!0}let c;try{c=await j(u)}catch{return n(t,404,{error:"File not found"}),!0}if(!c.isFile())return n(t,404,{error:"Not a file"}),!0;if(c.size>N)return n(t,413,{error:"File too large to preview"}),!0;const m=B(a),p=M(a),d=L(a);let e=await T(u);if(!m&&!p&&!d){if(e.subarray(0,_).includes(0))return n(t,415,{error:"Binary file"}),!0;if(e.length>P){const o=e.subarray(0,P),l=o.lastIndexOf(10);e=l>0?o.subarray(0,l):o,t.setHeader("x-weave-truncated","1")}}return p&&t.setHeader("content-security-policy","sandbox"),d&&t.setHeader("content-disposition",`attachment; filename*=UTF-8''${encodeURI(I.basename(a))}`),t.writeHead(200,{"content-type":m??p??d??"text/plain; charset=utf-8","content-length":String(e.length),"cache-control":"private, max-age=60"}),t.end(e),!0}return!1}
@@ -1 +1 @@
1
- import g from"node:fs";import E from"node:path";import{isHarness as $}from"@weavecode/core";import{messagingSurfaceFor as J}from"../../surfaces.js";import{readBody as l,sendJson as s}from"../http.js";import{readDaemonSettings as j}from"../settings.js";import{closeTerminalsIn as A,defaultProjectOpener as f,readTerminalCounts as D,terminalBackendFor as R}from"../opener.js";import{purgeProjectPipeline as x}from"../hook-pipeline.js";import{hooksRoot as G}from"../../hooks/mirror.js";import{projectHarnesses as H,withProjectHarnesses as k}from"../project-harnesses.js";import{scheduleBootstrapInjection as C}from"../session-open.js";import{getUploadsDir as U}from"../../db/paths.js";export async function handleProjectRoutes(c,r,t,p){const w=p.match(/^\/projects\/(\d+)\/open$/);if(w&&c.method==="POST"){const e=t.projects.getById(Number(w[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;let o;try{o=JSON.parse(await l(c))}catch{return s(r,400,{error:"Invalid JSON body"}),!0}if(o.target!=="explorer"&&o.target!=="terminal")return s(r,400,{error:'Invalid "target" (explorer|terminal)'}),!0;const a=t.opener??f;try{if(!(await g.promises.stat(e.path)).isDirectory())throw new Error(`Not a directory: ${e.path}`);if(o.target==="explorer")await a.openExplorer(e.path);else{const n=await j();await a.openTerminal(e.path,n.terminal),setTimeout(()=>{t.terminalRefresher?.refreshNow()},600)}s(r,200,{ok:!0,target:o.target,path:e.path})}catch(n){s(r,400,{error:n instanceof Error?n.message:"Open failed"})}return!0}const I=p.match(/^\/projects\/(\d+)\/close-terminal$/);if(I&&c.method==="POST"){const e=t.projects.getById(Number(I[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;let o;try{o=JSON.parse(await l(c)||"{}")}catch{return s(r,400,{error:"Invalid JSON body"}),!0}if(!Array.isArray(o.paneIds)||o.paneIds.length===0||o.paneIds.some(i=>typeof i!="string"))return s(r,400,{error:"paneIds must be a non-empty array of strings"}),!0;const a=t.opener??f,n=await j();try{const i=await(a.closeTerminals??A)(e.path,n.terminal,o.paneIds);setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),s(r,200,{ok:!0,closed:i})}catch(i){s(r,400,{error:i instanceof Error?i.message:"Close failed"})}return!0}const P=p.match(/^\/projects\/(\d+)\/focus-terminal$/);if(P&&c.method==="POST"){const e=t.projects.getById(Number(P[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;let o;try{o=JSON.parse(await l(c)||"{}")}catch{return s(r,400,{error:"Invalid JSON body"}),!0}if(typeof o.targetId!="string"||!o.targetId)return s(r,400,{error:"targetId must be a non-empty string"}),!0;const a=t.opener??f,n=await j();try{await(a.focusTerminal??f.focusTerminal)(e.path,o.targetId,n.terminal),s(r,200,{ok:!0,targetId:o.targetId})}catch(i){s(r,409,{error:i instanceof Error?i.message:"Cannot focus terminal"})}return!0}const v=p.match(/^\/projects\/(\d+)\/new-session$/);if(v&&c.method==="POST"){const e=t.projects.getById(Number(v[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;let o;try{o=JSON.parse(await l(c)||"{}")}catch{return s(r,400,{error:"Invalid JSON body"}),!0}const a=await H(e.path,t.harnesses);if(o.harness!==void 0&&!$(o.harness))return s(r,400,{error:'Invalid "harness"'}),!0;const n=o.harness;if(n&&!a.some(d=>d.id===n))return s(r,409,{error:`Harness "${n}" is not integrated in this project`}),!0;const i=n?[n]:a.map(d=>d.id),m=a.find(d=>i.includes(d.id)&&d.canStartSession),u=m?t.harnesses?.get(m.id)?.resume:void 0;if(!u?.bin)return s(r,501,{error:`Harness "${i[0]}" cannot start an interactive session`}),!0;const h=t.opener??f;try{if(!(await g.promises.stat(e.path)).isDirectory())throw new Error(`Not a directory: ${e.path}`);const d=await j(),O=[u.bin,...u.launchArgs??[]],y=await h.runInTerminal(e.path,O,d.terminal);y&&m&&J(m.id).paneEnvSource==="launch"&&t.messageDeliverer?.notePendingOrigin({harness:m.id,projectId:e.id,env:y.env}),y&&m&&u?.bootstrapText&&C(t,y,u.bootstrapText(e.name)),setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),s(r,200,{ok:!0,command:O.join(" "),cwd:e.path})}catch(d){s(r,400,{error:d instanceof Error?d.message:"Open failed"})}return!0}if(p==="/projects"&&c.method==="GET")return s(r,200,{projects:await k(t.projects.list(),t.harnesses)}),!0;if(p==="/projects/archived"&&c.method==="GET")return s(r,200,{projects:await k(t.projects.listArchived(),t.harnesses)}),!0;const b=p.match(/^\/projects\/(\d+)\/archive$/);if(b&&c.method==="POST"){const e=t.projects.getById(Number(b[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;if(e.archivedAt)return s(r,200,{project:e,purged:{events:0,dispatches:0,sessions:0,messages:0}}),!0;const o=t.hookDispatches?.deleteByProject(e.id)??0,a=t.hookEvents?.deleteByProject(e.id)??0;t.uploads?.pruneUnreferenced();const n=t.messageDeliverer?.forgetProject(e.id)??0;t.sessionWatches?.deleteByProject(e.id),t.orchestrations?.deleteByProject(e.id),t.orchestrationRuns?.clear("all",e.id),t.sideQuestions?.repo.deleteByProject(e.id);const i=t.hookSessions?.removeByProject(e.id)??0;return t.projects.setArchived(e.id,!0),x(t.hooksDir??G(),e.token),t.watch?.reconcile(),t.dataBus?.emit({key:"projects"}),s(r,200,{project:t.projects.getById(e.id),purged:{events:a,dispatches:o,sessions:i,messages:n}}),!0}const S=p.match(/^\/projects\/(\d+)\/restore$/);if(S&&c.method==="POST"){const e=t.projects.getById(Number(S[1]));return e?e.archivedAt?(t.projects.setArchived(e.id,!1),t.hookMirror?.syncProject(e.id),t.watch?.reconcile(),t.dataBus?.emit({key:"projects"}),s(r,200,{project:t.projects.getById(e.id)}),!0):(s(r,200,{project:e}),!0):(s(r,404,{error:"Project not found"}),!0)}if(p==="/projects/order"&&c.method==="PUT"){let e;try{e=JSON.parse(await l(c))}catch{return s(r,400,{error:"Invalid JSON body"}),!0}return!Array.isArray(e.ids)||!e.ids.every(o=>Number.isInteger(o))?(s(r,400,{error:'Invalid "ids" (integer array expected)'}),!0):(t.projects.setOrder(e.ids),t.dataBus?.emit({key:"projects"}),s(r,200,{projects:t.projects.list()}),!0)}const T=p.match(/^\/projects\/(\d+)\/panes$/);if(T&&c.method==="GET"){const e=t.projects.getById(Number(T[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;const o=await j(),a=t.opener?.listPanes??f.listPanes;try{s(r,200,{projectId:e.id,panes:await a(e.path,o.terminal)})}catch(n){s(r,409,{error:n instanceof Error?n.message:"Cannot list panes"})}return!0}const N=p.match(/^\/projects\/(\d+)\/terminals$/);if(N&&c.method==="GET"){const e=t.projects.getById(Number(N[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;const o=await j(),a=t.opener?.listTerminals??f.listTerminals,n=R(o.terminal).enumerable?await a(e.path,o.terminal):[];return s(r,200,{projectId:e.id,terminals:n}),!0}if(p==="/terminals/counts"&&c.method==="GET"){if(t.terminalRefresher)s(r,200,{counts:t.terminalRefresher.lastSnapshot?.counts??{}}),t.terminalRefresher.tick(!0);else{const e=t.opener??f;s(r,200,{counts:await D(t.projects.list(),e)})}return!0}const B=p.match(/^\/projects\/(\d+)\/storage$/);if(B){const e=t.projects.getById(Number(B[1]));if(!e)return s(r,404,{error:"Project not found"}),!0;const o=t.projects.getMeta(e.id)?.storage??{},a=t.uploads?.defaultDir??U();if(c.method==="GET")return s(r,200,{storage:o,effective:{images:o.images||a,files:o.files||a}}),!0;if(c.method==="PUT"){let n;try{n=JSON.parse(await l(c))}catch{return s(r,400,{error:"Invalid JSON body"}),!0}const i={};for(const m of["images","files"]){const u=n[m];if(u==null||u===""){i[m]=null;continue}if(typeof u!="string")return s(r,400,{error:`"${m}" must be a string or null`}),!0;const h=u.trim();if(!E.isAbsolute(h))return s(r,400,{error:`"${m}" must be an absolute path`}),!0;try{g.mkdirSync(h,{recursive:!0}),g.accessSync(h,g.constants.W_OK)}catch(d){return s(r,400,{error:`"${m}" is not writable: ${d instanceof Error?d.message:String(d)}`}),!0}i[m]=h}return t.projects.setMeta(e.id,{storage:i}),t.dataBus?.emit({key:"projects"}),s(r,200,{storage:i,effective:{images:i.images||a,files:i.files||a}}),!0}return!1}return!1}
1
+ import y from"node:fs";import $ from"node:path";import{isHarness as J}from"@weavecode/core";import{messagingSurfaceFor as M}from"../../surfaces.js";import{readBody as p,sendJson as o}from"../http.js";import{readDaemonSettings as j}from"../settings.js";import{closeTerminalsIn as A,defaultProjectOpener as d,readTerminalCounts as x,terminalBackendFor as D}from"../opener.js";import{purgeProjectPipeline as R}from"../hook-pipeline.js";import{hooksRoot as G}from"../../hooks/mirror.js";import{projectHarnesses as H,withProjectHarnesses as E}from"../project-harnesses.js";import{scheduleBootstrapInjection as C}from"../session-open.js";import{getUploadsDir as U}from"../../db/paths.js";export async function handleProjectRoutes(a,e,r,l){const I=l.match(/^\/projects\/(\d+)\/open$/);if(I&&a.method==="POST"){const t=r.projects.getById(Number(I[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;let n;try{n=JSON.parse(await p(a))}catch{return o(e,400,{error:"Invalid JSON body"}),!0}if(n.target!=="explorer"&&n.target!=="terminal")return o(e,400,{error:'Invalid "target" (explorer|terminal)'}),!0;const s=r.opener??d;try{if(!(await y.promises.stat(t.path)).isDirectory())throw new Error(`Not a directory: ${t.path}`);if(n.target==="explorer")await s.openExplorer(t.path);else{const c=await j();await s.openTerminal(t.path,c.terminal),setTimeout(()=>{r.terminalRefresher?.refreshNow()},600)}o(e,200,{ok:!0,target:n.target,path:t.path})}catch(i){o(e,400,{error:i instanceof Error?i.message:"Open failed"})}return!0}const v=l.match(/^\/projects\/(\d+)\/close-terminal$/);if(v&&a.method==="POST"){const t=r.projects.getById(Number(v[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;let n;try{n=JSON.parse(await p(a)||"{}")}catch{return o(e,400,{error:"Invalid JSON body"}),!0}if(!Array.isArray(n.paneIds)||n.paneIds.length===0||n.paneIds.some(c=>typeof c!="string"))return o(e,400,{error:"paneIds must be a non-empty array of strings"}),!0;const s=r.opener??d,i=await j();try{const u=await(s.closeTerminals??A)(t.path,i.terminal,n.paneIds);setTimeout(()=>{r.terminalRefresher?.refreshNow()},600),o(e,200,{ok:!0,closed:u})}catch(c){o(e,400,{error:c instanceof Error?c.message:"Close failed"})}return!0}const b=l.match(/^\/projects\/(\d+)\/focus-terminal$/);if(b&&a.method==="POST"){const t=r.projects.getById(Number(b[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;let n;try{n=JSON.parse(await p(a)||"{}")}catch{return o(e,400,{error:"Invalid JSON body"}),!0}if(typeof n.targetId!="string"||!n.targetId)return o(e,400,{error:"targetId must be a non-empty string"}),!0;const s=r.opener??d,i=await j();try{await(s.focusTerminal??d.focusTerminal)(t.path,n.targetId,i.terminal),o(e,200,{ok:!0,targetId:n.targetId})}catch(c){o(e,409,{error:c instanceof Error?c.message:"Cannot focus terminal"})}return!0}const P=l.match(/^\/projects\/(\d+)\/new-session$/);if(P&&a.method==="POST"){const t=r.projects.getById(Number(P[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;let n;try{n=JSON.parse(await p(a)||"{}")}catch{return o(e,400,{error:"Invalid JSON body"}),!0}const s=await H(t.path,r.harnesses);if(n.harness!==void 0&&!J(n.harness))return o(e,400,{error:'Invalid "harness"'}),!0;const i=n.harness;if(i&&!s.some(m=>m.id===i))return o(e,409,{error:`Harness "${i}" is not integrated in this project`}),!0;const c=i?[i]:s.map(m=>m.id),u=s.find(m=>c.includes(m.id)&&m.canStartSession),f=u?r.harnesses?.get(u.id)?.resume:void 0;if(!f?.bin)return o(e,501,{error:`Harness "${c[0]}" cannot start an interactive session`}),!0;const h=r.opener??d;try{if(!(await y.promises.stat(t.path)).isDirectory())throw new Error(`Not a directory: ${t.path}`);const g=await j(),k=[f.bin,...f.launchArgs??[]],w=await h.runInTerminal(t.path,k,g.terminal);w&&u&&M(u.id).paneEnvSource==="launch"&&r.messageDeliverer?.notePendingOrigin({harness:u.id,projectId:t.id,env:w.env}),w&&u&&f?.bootstrapText&&C(r,w,f.bootstrapText(t.name)),setTimeout(()=>{r.terminalRefresher?.refreshNow()},600),o(e,200,{ok:!0,command:k.join(" "),cwd:t.path})}catch(m){o(e,400,{error:m instanceof Error?m.message:"Open failed"})}return!0}if(l==="/projects"&&a.method==="GET")return o(e,200,{projects:await E(r.projects.list(),r.harnesses)}),!0;if(l==="/projects/archived"&&a.method==="GET")return o(e,200,{projects:await E(r.projects.listArchived(),r.harnesses)}),!0;const T=l.match(/^\/projects\/(\d+)\/archive$/);if(T&&a.method==="POST"){const t=r.projects.getById(Number(T[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;if(t.archivedAt)return o(e,200,{project:t,purged:{events:0,dispatches:0,sessions:0,messages:0}}),!0;const n=r.hookDispatches?.deleteByProject(t.id)??0,s=r.hookEvents?.deleteByProject(t.id)??0;r.uploads?.pruneUnreferenced();const i=r.messageDeliverer?.forgetProject(t.id)??0;r.sessionWatches?.deleteByProject(t.id),r.orchestrations?.deleteByProject(t.id),r.orchestrationRuns?.clear("all",t.id),r.sideQuestions?.repo.deleteByProject(t.id);const c=r.hookSessions?.removeByProject(t.id)??0;return r.projects.setArchived(t.id,!0),R(r.hooksDir??G(),t.token),r.watch?.reconcile(),r.dataBus?.emit({key:"projects"}),o(e,200,{project:r.projects.getById(t.id),purged:{events:s,dispatches:n,sessions:c,messages:i}}),!0}const S=l.match(/^\/projects\/(\d+)\/restore$/);if(S&&a.method==="POST"){const t=r.projects.getById(Number(S[1]));return t?t.archivedAt?(r.projects.setArchived(t.id,!1),r.hookMirror?.syncProject(t.id),r.watch?.reconcile(),r.dataBus?.emit({key:"projects"}),o(e,200,{project:r.projects.getById(t.id)}),!0):(o(e,200,{project:t}),!0):(o(e,404,{error:"Project not found"}),!0)}if(l==="/projects/order"&&a.method==="PUT"){let t;try{t=JSON.parse(await p(a))}catch{return o(e,400,{error:"Invalid JSON body"}),!0}return!Array.isArray(t.ids)||!t.ids.every(n=>Number.isInteger(n))?(o(e,400,{error:'Invalid "ids" (integer array expected)'}),!0):(r.projects.setOrder(t.ids),r.dataBus?.emit({key:"projects"}),o(e,200,{projects:r.projects.list()}),!0)}const N=l.match(/^\/projects\/(\d+)\/panes$/);if(N&&a.method==="GET"){const t=r.projects.getById(Number(N[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;const n=await j(),s=r.opener?.listPanes??d.listPanes;try{o(e,200,{projectId:t.id,panes:await s(t.path,n.terminal)})}catch(i){o(e,409,{error:i instanceof Error?i.message:"Cannot list panes"})}return!0}const B=l.match(/^\/projects\/(\d+)\/terminals$/);if(B&&a.method==="GET"){const t=r.projects.getById(Number(B[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;const n=await j(),s=r.opener?.listTerminals??d.listTerminals,i=D(n.terminal).enumerable?await s(t.path,n.terminal):[];return o(e,200,{projectId:t.id,terminals:i}),!0}if(l==="/terminals/counts"&&a.method==="GET"){if(r.terminalRefresher)o(e,200,{counts:r.terminalRefresher.lastSnapshot?.counts??{}}),r.terminalRefresher.tick(!0);else{const t=r.opener??d;o(e,200,{counts:await x(r.projects.list(),t)})}return!0}const O=l.match(/^\/projects\/(\d+)\/storage$/);if(O){const t=r.projects.getById(Number(O[1]));if(!t)return o(e,404,{error:"Project not found"}),!0;const s=r.projects.getMeta(t.id)?.storage??{},i=r.uploads?.defaultDir??U();if(a.method==="GET")return o(e,200,{storage:s,effective:{images:s.images||i,files:s.files||i}}),!0;if(a.method==="PUT"){let c;try{c=JSON.parse(await p(a))}catch{return o(e,400,{error:"Invalid JSON body"}),!0}const u={};for(const f of["images","files"]){const h=c[f];if(h==null||h===""){u[f]=null;continue}if(typeof h!="string")return o(e,400,{error:`"${f}" must be a string or null`}),!0;const m=h.trim();if(!$.isAbsolute(m))return o(e,400,{error:`"${f}" must be an absolute path`}),!0;try{y.mkdirSync(m,{recursive:!0}),y.accessSync(m,y.constants.W_OK)}catch(g){return o(e,400,{error:`"${f}" is not writable: ${g instanceof Error?g.message:String(g)}`}),!0}u[f]=m}return r.projects.setMeta(t.id,{storage:u}),r.dataBus?.emit({key:"projects"}),o(e,200,{storage:u,effective:{images:u.images||i,files:u.files||i}}),!0}return!1}return!1}
@@ -1 +1 @@
1
- import{sendJson as c}from"../http.js";import{matchPaths as g,peekCachedIndex as v}from"../project-files.js";const j=8,m=12,k=6,f=18,y=1440*6e4,d=80;export async function handleSearchRoutes(e,n,t,a,r){if(a!=="/search"||e.method!=="GET")return!1;if(!t.hookEvents||!t.hookSessions)return c(n,503,{error:"Hooks subsystem unavailable"}),!0;const o=(r.searchParams.get("q")??"").trim();if(!o)return c(n,200,{q:o,sessions:[],messages:[],files:[],truncated:{messages:!1,files:!1}}),!0;const[u,l]=await Promise.all([t.hookSessions.searchByTitle(o,j),t.hookEvents.searchConversationTexts(o,m)]),I=t.projects.list().filter(s=>!s.archivedAt),h=(await Promise.all(I.map(async s=>{const p=await v(s.id,s.path,{maxStaleMs:y});if(!p)return[];const{hits:x}=await g(p,o,k,"");return x.map(i=>({projectId:s.id,path:i.path,kind:i.kind,ranges:i.ranges}))}))).flat().slice(0,f);return c(n,200,{q:o,sessions:u.map(s=>({sessionId:s.sessionId,projectId:s.projectId,title:s.title})),messages:l.map(s=>T(s,o)),files:h,truncated:{messages:l.length>=m,files:h.length>=f}}),!0}function T(e,n){const t=e.text.toLowerCase().indexOf(n.toLowerCase());if(t<0||e.text.length<=d*2)return{eventId:e.eventId,sessionId:e.sessionId,projectId:e.projectId,source:e.source,eventType:e.eventType,at:e.at,text:e.text,offset:Math.max(t,0),clipped:!1};const a=Math.max(0,t-d),r=Math.min(e.text.length,t+n.length+d);return{eventId:e.eventId,sessionId:e.sessionId,projectId:e.projectId,source:e.source,eventType:e.eventType,at:e.at,text:e.text.slice(a,r),offset:t-a,clipped:a>0||r<e.text.length}}
1
+ import{sendJson as i}from"../http.js";import{matchPaths as T,peekCachedIndex as E}from"../project-files.js";const _=8,p=12,g=6,m=18,v=1440*6e4,l=80;export async function handleSearchRoutes(e,n,a,o,r){if(o!=="/search"||e.method!=="GET")return!1;if(!a.hookEvents||!a.hookSessions)return i(n,503,{error:"Hooks subsystem unavailable"}),!0;const s=(r.searchParams.get("q")??"").trim();if(!s)return i(n,200,{q:s,sessions:[],messages:[],files:[],truncated:{messages:!1,files:!1}}),!0;const[u,d]=await Promise.all([a.hookSessions.searchByTitle(s,_),a.hookEvents.searchConversationTexts(s,p)]),S=a.projects.list().filter(t=>!t.archivedAt),I=(await Promise.all(S.map(async t=>{const f=await E(t.id,t.path,{maxStaleMs:v});if(!f)return[];const{hits:x}=await T(f,s,g,"");return x.map(c=>({projectId:t.id,path:c.path,kind:c.kind,ranges:c.ranges}))}))).flat().slice(0,m);return i(n,200,{q:s,sessions:u.map(t=>({sessionId:t.sessionId,projectId:t.projectId,title:t.title})),messages:d.map(t=>M(t,s)),files:I,truncated:{messages:d.length>=p,files:I.length>=m}}),!0}function M(e,n){const o=e.text.toLowerCase().indexOf(n.toLowerCase());if(o<0||e.text.length<=l*2)return{eventId:e.eventId,sessionId:e.sessionId,projectId:e.projectId,source:e.source,eventType:e.eventType,at:e.at,text:e.text,offset:Math.max(o,0),clipped:!1};const r=Math.max(0,o-l),s=Math.min(e.text.length,o+n.length+l);return{eventId:e.eventId,sessionId:e.sessionId,projectId:e.projectId,source:e.source,eventType:e.eventType,at:e.at,text:e.text.slice(r,s),offset:o-r,clipped:r>0||s<e.text.length}}
@@ -1 +1 @@
1
- import{z as a}from"zod";import{readJson as d,sendJson as r}from"../http.js";import{composeAnswerAtoms as D}from"../../hooks/answer-keys.js";import{readSideQuestions as R}from"../../hooks/side-questions.js";const q=a.object({question:a.string().min(1).max(4e3)}),S=a.object({model:a.string().min(1).max(128)}),C=a.object({level:a.string().min(1).max(32)}),M=a.object({answers:a.array(a.object({questionKey:a.string().min(1),options:a.array(a.number().int().min(0)).max(32),text:a.string().max(2e3).optional()})).min(1)});export async function handleSessionControlRoutes(i,e,o,m,l){const g=m.match(/^\/sessions\/([^/]+)\/interrupt$/);if(g&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(g[1]),s=await o.messageDeliverer.interrupt(t);return s.ok?(setTimeout(()=>o.interruptRefresher?.tick(),1500),setTimeout(()=>o.interruptRefresher?.tick(),12e3),r(e,200,{ok:!0,sessionId:t,confirmed:s.confirmed}),!0):(r(e,s.status,{error:s.error}),!0)}const f=m.match(/^\/sessions\/([^/]+)\/close-pane$/);if(f&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(f[1]),s=await o.messageDeliverer.closePane(t);return s.ok?(setTimeout(()=>{o.livenessRefresher?.tick(),o.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:t}),!0):(r(e,s.status,{error:s.error}),!0)}const h=m.match(/^\/sessions\/([^/]+)\/mode$/);if(h&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(h[1]),s=await o.messageDeliverer.cycleMode(t);return s.ok?(r(e,200,{ok:!0,sessionId:t}),!0):(r(e,s.status,{error:s.error}),!0)}const v=m.match(/^\/sessions\/([^/]+)\/enter$/);if(v&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(v[1]),s=await o.messageDeliverer.pressEnter(t);return s.ok?(r(e,200,{ok:!0,sessionId:t}),!0):(r(e,s.status,{error:s.error}),!0)}const b=m.match(/^\/sessions\/([^/]+)\/ctrl-c$/);if(b&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(b[1]),s=await o.messageDeliverer.pressCtrlC(t);return s.ok?(r(e,200,{ok:!0,sessionId:t}),!0):(r(e,s.status,{error:s.error}),!0)}const p=m.match(/^\/sessions\/([^/]+)\/model$/);if(p&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(p[1]),s=S.parse(await d(i)),n=await o.messageDeliverer.setModel(t,s.model);return n.ok?(setTimeout(()=>o.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:t}),!0):(r(e,n.status,{error:n.error}),!0)}const k=m.match(/^\/sessions\/([^/]+)\/effort$/);if(k&&i.method==="POST"){if(!o.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(k[1]),s=C.parse(await d(i)),n=await o.messageDeliverer.setEffort(t,s.level);return n.ok?(r(e,200,{ok:!0,sessionId:t}),!0):(r(e,n.status,{error:n.error}),!0)}if(m==="/messaging/questions"&&i.method==="GET")return o.questionTracker?(r(e,200,{questions:o.questionTracker.snapshot()}),!0):(r(e,503,{error:"Question tracking unavailable"}),!0);const I=m.match(/^\/sessions\/([^/]+)\/answer$/);if(I&&i.method==="POST"){if(!o.questionTracker||!o.messageDeliverer)return r(e,503,{error:"Question tracking unavailable"}),!0;const t=decodeURIComponent(I[1]);let s;try{s=M.parse(await d(i))}catch(y){return r(e,400,{error:y instanceof Error?y.message:"Invalid body"}),!0}const n=o.questionTracker.get(t);if(!n)return r(e,409,{error:"Session has no pending question"}),!0;const u=D(n.questions,s.answers);if(!u.ok)return r(e,400,{error:u.error}),!0;const c=await o.messageDeliverer.answer(t,u.atoms);return c.ok?(o.questionTracker.markAnswered(t),r(e,200,{ok:!0,sessionId:t}),!0):(r(e,c.status,{error:c.error}),!0)}const w=m.match(/^\/sessions\/([^/]+)\/side-question$/);if(w&&i.method==="POST"){if(!o.messageDeliverer||!o.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(w[1]);let s;try{s=q.parse(await d(i))}catch(c){return r(e,400,{error:c instanceof Error?c.message:"Invalid body"}),!0}const n=await o.messageDeliverer.askSideQuestion(t,s.question);if(!n.ok)return r(e,n.status,{error:n.error}),!0;const u=o.sideQuestions.repo.insert({sessionId:t,projectId:o.hookSessions?.getBySessionId(t)?.projectId??null,question:n.question});return r(e,200,{ok:!0,sideQuestion:u}),!0}const T=m.match(/^\/sessions\/([^/]+)\/side-questions$/);if(T&&i.method==="GET"){if(!o.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const t=decodeURIComponent(T[1]),s=Number(l.searchParams.get("limit")),n=Number(l.searchParams.get("beforeId")),u=R(o.sideQuestions,t,{limit:Number.isFinite(s)&&s>0?Math.min(s,100):20,beforeId:Number.isFinite(n)&&n>0?n:void 0});return r(e,200,{sideQuestions:u}),!0}return!1}
1
+ import{z as u}from"zod";import{readJson as l,sendJson as r}from"../http.js";import{composeAnswerAtoms as D}from"../../hooks/answer-keys.js";import{readSideQuestions as R}from"../../hooks/side-questions.js";const S=u.object({question:u.string().min(1).max(4e3)}),C=u.object({model:u.string().min(1).max(128)}),P=u.object({level:u.string().min(1).max(32)}),Q=u.object({answers:u.array(u.object({questionKey:u.string().min(1),options:u.array(u.number().int().min(0)).max(32),text:u.string().max(2e3).optional()})).min(1)});export async function handleSessionControlRoutes(i,e,s,a,f){const d=a.match(/^\/sessions\/([^/]+)\/interrupt$/);if(d&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(d[1]),t=await s.messageDeliverer.interrupt(o);return t.ok?(setTimeout(()=>s.interruptRefresher?.tick(),1500),setTimeout(()=>s.interruptRefresher?.tick(),12e3),r(e,200,{ok:!0,sessionId:o,confirmed:t.confirmed}),!0):(r(e,t.status,{error:t.error}),!0)}const g=a.match(/^\/sessions\/([^/]+)\/close-pane$/);if(g&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(g[1]),t=await s.messageDeliverer.closePane(o);return t.ok?(setTimeout(()=>{s.livenessRefresher?.tick(),s.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,t.status,{error:t.error}),!0)}const b=a.match(/^\/sessions\/([^/]+)\/mode$/);if(b&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(b[1]),t=await s.messageDeliverer.cycleMode(o);return t.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,t.status,{error:t.error}),!0)}const h=a.match(/^\/sessions\/([^/]+)\/enter$/);if(h&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(h[1]),t=await s.messageDeliverer.pressEnter(o);return t.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,t.status,{error:t.error}),!0)}const v=a.match(/^\/sessions\/([^/]+)\/ctrl-c$/);if(v&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(v[1]),t=await s.messageDeliverer.pressCtrlC(o);return t.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,t.status,{error:t.error}),!0)}const k=a.match(/^\/sessions\/([^/]+)\/model$/);if(k&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(k[1]),t=C.parse(await l(i)),n=await s.messageDeliverer.setModel(o,t.model);return n.ok?(setTimeout(()=>s.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const y=a.match(/^\/sessions\/([^/]+)\/effort$/);if(y&&i.method==="POST"){if(!s.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(y[1]),t=P.parse(await l(i)),n=await s.messageDeliverer.setEffort(o,t.level);return n.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}if(a==="/messaging/questions"&&i.method==="GET")return s.questionTracker?(r(e,200,{questions:s.questionTracker.snapshot()}),!0):(r(e,503,{error:"Question tracking unavailable"}),!0);const I=a.match(/^\/sessions\/([^/]+)\/answer$/);if(I&&i.method==="POST"){if(!s.questionTracker||!s.messageDeliverer)return r(e,503,{error:"Question tracking unavailable"}),!0;const o=decodeURIComponent(I[1]);let t;try{t=Q.parse(await l(i))}catch(T){return r(e,400,{error:T instanceof Error?T.message:"Invalid body"}),!0}const n=s.questionTracker.get(o);if(!n)return r(e,409,{error:"Session has no pending question"}),!0;const c=D(n.questions,t.answers);if(!c.ok)return r(e,400,{error:c.error}),!0;const m=await s.messageDeliverer.answer(o,c.atoms);return m.ok?(s.questionTracker.markAnswered(o),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,m.status,{error:m.error}),!0)}const w=a.match(/^\/sessions\/([^/]+)\/side-question$/);if(w&&i.method==="POST"){if(!s.messageDeliverer||!s.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(w[1]);let t;try{t=S.parse(await l(i))}catch(m){return r(e,400,{error:m instanceof Error?m.message:"Invalid body"}),!0}const n=await s.messageDeliverer.askSideQuestion(o,t.question);if(!n.ok)return r(e,n.status,{error:n.error}),!0;const c=s.sideQuestions.repo.insert({sessionId:o,projectId:s.hookSessions?.getBySessionId(o)?.projectId??null,question:n.question});return r(e,200,{ok:!0,sideQuestion:c}),!0}const M=a.match(/^\/sessions\/([^/]+)\/side-questions$/);if(M&&i.method==="GET"){if(!s.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(M[1]),t=Number(f.searchParams.get("limit")),n=Number(f.searchParams.get("beforeId")),c=R(s.sideQuestions,o,{limit:Number.isFinite(t)&&t>0?Math.min(t,100):20,beforeId:Number.isFinite(n)&&n>0?n:void 0});return r(e,200,{sideQuestions:c}),!0}return!1}
@@ -1 +1 @@
1
- import{readFileSync as M}from"node:fs";import F from"node:path";import{isHarness as O}from"@weavecode/core";import{sendJson as i}from"../http.js";import{blockingPromptFor as U,commandsSurfaceFor as $,editSurfaceFor as D,narrationSurfaceFor as J,rewindSurfaceFor as Q}from"../../surfaces.js";function w(s,n,t){if(!n.hookSessions||!n.hookEvents)return i(s,503,{error:"Hooks subsystem unavailable"}),null;const o=n.hookSessions.getBySessionId(t);return o?o.projectId==null?(i(s,400,{error:"Session is not bound to a project"}),null):n.projects.getById(o.projectId)||(i(s,404,{error:"Project not found"}),null):(i(s,404,{error:"Session not found"}),null)}function I(s,n){if(!s.hookEvents)return null;const t=s.hookEvents.listBySession(n,1),o=t[t.length-1]?.source;return O(o)?o:null}const B=20,z=2e3,W=200,x=new Map,q=2e5;function K(s){try{const n=JSON.parse(s);return[typeof n.toolName=="string"?n.toolName:null,n.toolInput??null,n.toolResponse??null]}catch{return[null,null,null]}}function N(s){if(!s)return null;try{const n=M(s,"utf8");return n.trim()?n:null}catch{return null}}const H=2e5,L=4e6;function V(s,n){const t=F.relative(n,s);return(t&&!t.startsWith("..")&&!F.isAbsolute(t)?t:s).split(F.sep).join("/")}function A(s){if(!s)return null;const n=Date.parse(s);return Number.isFinite(n)?n:null}function X(s,n,t){if(n===null&&t===null)return!0;if(!s)return!1;const o=Date.parse(s);return!(!Number.isFinite(o)||n!==null&&o<=n||t!==null&&o>t)}function Y(s,n){const t=[],o=new Map;let f=L,P=0,d=!1;for(const a of s){const p=a.hunk.before.slice(0,H),h=a.hunk.after.slice(0,H),b=p.length<a.hunk.before.length||h.length<a.hunk.after.length;b&&(d=!0);const E=p.length+h.length;if(E>f){d=!0;continue}f-=E;const e=V(a.path,n);let r=o.get(e);r||(r={path:e,hunks:[]},o.set(e,r),t.push(r)),r.hunks.push({before:p,after:h,at:a.at,...b?{clamped:!0}:{}}),P++}return{files:t,hunks:P,truncated:d}}export async function handleSessionInsightRoutes(s,n,t,o,f){const P=o.match(/^\/sessions\/([^/]+)\/plan$/);if(P&&s.method==="GET"){const e=decodeURIComponent(P[1]);if(!t.hookEvents)return i(n,503,{error:"Hook ingestion unavailable"}),!0;const r=t.hookEvents.listBySession(e,1),u=r[r.length-1]?.source,l=O(u)?U(u)?.plan??null:null;if(!l)return i(n,200,{plan:null}),!0;const m=c=>c.flatMap(v=>{const R=l.draftOf(...K(v.payload));return R?[{row:v,draft:R}]:[]}),g=r[r.length-1]?.id??0,S=t.hookEvents,y=x.get(e);if(y&&y.latestId===g)return i(n,200,{plan:y.plan}),!0;const T=c=>(x.size>=W&&x.clear(),x.set(e,{latestId:g,plan:c}),i(n,200,{plan:c}),!0),j=(c,v)=>{const R=S.listByTools(e,c,v,B,g-z);return R.length>0?R:S.listByTools(e,c,v,B)},[k]=m(j([l.tool],null));if(!k)return T(null);const[C]=m(j(l.writeTools,l.fileHint)).filter(c=>c.row.id<k.row.id),G=k.draft.text??N(k.draft.filePath)??C?.draft.text??N(C?.draft.filePath??null);return T(G?{eventId:k.row.id,at:k.row.createdAt,text:G.slice(0,q)}:null)}const d=o.match(/^\/sessions\/([^/]+)\/pre-question$/);if(d&&s.method==="GET"){const e=decodeURIComponent(d[1]);if(!w(n,t,e))return!0;const r=I(t,e),u=await(r?U(r):null)?.preQuestion?.(t.sessionProbe?.transcriptPathOf(e)??null);return i(n,200,{preQuestion:u??null}),!0}const a=o.match(/^\/sessions\/([^/]+)\/narration$/);if(a&&s.method==="GET"){const e=decodeURIComponent(a[1]);if(!w(n,t,e))return!0;const r=I(t,e),u=r?J(r):null;if(!u)return i(n,200,{supported:!1,narration:null}),!0;const l=await u.sessionNarration({sessionId:e,transcriptPath:t.sessionProbe?.transcriptPathOf(e)??null});return i(n,200,{supported:l!==null,narration:l}),!0}const p=o.match(/^\/sessions\/([^/]+)\/rewinds$/);if(p&&s.method==="GET"){const e=decodeURIComponent(p[1]);if(!w(n,t,e))return!0;const r=I(t,e),u=r?Q(r):null;if(!u)return i(n,200,{supported:!1,rewinds:null}),!0;const l=await u.sessionRewinds({sessionId:e,transcriptPath:t.sessionProbe?.transcriptPathOf(e)??null});return i(n,200,{supported:l!==null,rewinds:l}),!0}const h=o.match(/^\/sessions\/([^/]+)\/commands$/);if(h&&s.method==="GET"){const e=decodeURIComponent(h[1]),r=w(n,t,e);if(!r)return!0;const u=I(t,e),l=u?$(u):null;return l?(i(n,200,{supported:!0,commands:await l.list({projectPath:r.path}),inputModes:l.inputModes}),!0):(i(n,200,{supported:!1,commands:[],inputModes:[]}),!0)}const b=o.match(/^\/sessions\/([^/]+)\/command-executions$/);if(b&&s.method==="GET"){const e=decodeURIComponent(b[1]);if(!w(n,t,e))return!0;const r=I(t,e),u=r?$(r):null;if(!u)return i(n,200,{supported:!1,executions:null}),!0;const l=await u.executions(t.sessionProbe?.transcriptPathOf(e)??null);return i(n,200,{supported:l!==null,executions:l}),!0}const E=o.match(/^\/sessions\/([^/]+)\/edits$/);if(E&&s.method==="GET"){const e=decodeURIComponent(E[1]),r=w(n,t,e);if(!r)return!0;const u=I(t,e),l=u?D(u):null;if(!l)return i(n,200,{files:null,hunks:0,truncated:!1,reason:"unsupported"}),!0;const m=await l.sessionEdits({sessionId:e,transcriptPath:t.sessionProbe?.transcriptPathOf(e)??null});if(!m)return i(n,200,{files:null,hunks:0,truncated:!1,reason:"unreadable"}),!0;const g=A(f.searchParams.get("since")),S=A(f.searchParams.get("until")),y=g!==null||S!==null?m.filter(T=>X(T.at,g,S)):m;return i(n,200,Y(y,r.path)),!0}return!1}
1
+ import{readFileSync as U}from"node:fs";import T from"node:path";import{isHarness as j}from"@weavecode/core";import{sendJson as c}from"../http.js";import{blockingPromptFor as v,commandsSurfaceFor as x,editSurfaceFor as $,narrationSurfaceFor as D,rewindSurfaceFor as L}from"../../surfaces.js";function g(o,t,n){if(!t.hookSessions||!t.hookEvents)return c(o,503,{error:"Hooks subsystem unavailable"}),null;const u=t.hookSessions.getBySessionId(n);if(!u)return c(o,404,{error:"Session not found"}),null;if(u.projectId==null)return c(o,400,{error:"Session is not bound to a project"}),null;const f=t.projects.getById(u.projectId);return f||(c(o,404,{error:"Project not found"}),null)}function k(o,t){if(!o.hookEvents)return null;const n=o.hookEvents.listBySession(t,1),u=n[n.length-1]?.source;return j(u)?u:null}const F=20,X=2e3,Q=200,C=new Map,W=2e5;function z(o){try{const t=JSON.parse(o);return[typeof t.toolName=="string"?t.toolName:null,t.toolInput??null,t.toolResponse??null]}catch{return[null,null,null]}}function H(o){if(!o)return null;try{const t=U(o,"utf8");return t.trim()?t:null}catch{return null}}const B=2e5,J=4e6;function K(o,t){const n=T.relative(t,o);return(!!n&&!n.startsWith("..")&&!T.isAbsolute(n)?n:o).split(T.sep).join("/")}function G(o){if(!o)return null;const t=Date.parse(o);return Number.isFinite(t)?t:null}function V(o,t,n){if(t===null&&n===null)return!0;if(!o)return!1;const u=Date.parse(o);return!(!Number.isFinite(u)||t!==null&&u<=t||n!==null&&u>n)}function Y(o,t){const n=[],u=new Map;let f=J,w=0,d=!1;for(const l of o){const h=l.hunk.before.slice(0,B),p=l.hunk.after.slice(0,B),E=h.length<l.hunk.before.length||p.length<l.hunk.after.length;E&&(d=!0);const S=h.length+p.length;if(S>f){d=!0;continue}f-=S;const e=K(l.path,t);let s=u.get(e);s||(s={path:e,hunks:[]},u.set(e,s),n.push(s)),s.hunks.push({before:h,after:p,at:l.at,...E?{clamped:!0}:{}}),w++}return{files:n,hunks:w,truncated:d}}export async function handleSessionInsightRoutes(o,t,n,u,f){const w=u.match(/^\/sessions\/([^/]+)\/plan$/);if(w&&o.method==="GET"){const e=decodeURIComponent(w[1]);if(!n.hookEvents)return c(t,503,{error:"Hook ingestion unavailable"}),!0;const s=n.hookEvents.listBySession(e,1),i=s[s.length-1]?.source,r=j(i)?v(i)?.plan??null:null;if(!r)return c(t,200,{plan:null}),!0;const m=a=>a.flatMap(M=>{const y=r.draftOf(...z(M.payload));return y?[{row:M,draft:y}]:[]}),I=s[s.length-1]?.id??0,b=n.hookEvents,A=C.get(e);if(A&&A.latestId===I)return c(t,200,{plan:A.plan}),!0;const _=a=>(C.size>=Q&&C.clear(),C.set(e,{latestId:I,plan:a}),c(t,200,{plan:a}),!0),R=(a,M)=>{const y=b.listByTools(e,a,M,F,I-X);return y.length>0?y:b.listByTools(e,a,M,F)},[P]=m(R([r.tool],null));if(!P)return _(null);const[N]=m(R(r.writeTools,r.fileHint)).filter(a=>a.row.id<P.row.id),O=P.draft.text??H(P.draft.filePath)??N?.draft.text??H(N?.draft.filePath??null);return _(O?{eventId:P.row.id,at:P.row.createdAt,text:O.slice(0,W)}:null)}const d=u.match(/^\/sessions\/([^/]+)\/pre-question$/);if(d&&o.method==="GET"){const e=decodeURIComponent(d[1]);if(!g(t,n,e))return!0;const s=k(n,e),r=await(s?v(s):null)?.preQuestion?.(n.sessionProbe?.transcriptPathOf(e)??null);return c(t,200,{preQuestion:r??null}),!0}const l=u.match(/^\/sessions\/([^/]+)\/narration$/);if(l&&o.method==="GET"){const e=decodeURIComponent(l[1]);if(!g(t,n,e))return!0;const s=k(n,e),i=s?D(s):null;if(!i)return c(t,200,{supported:!1,narration:null}),!0;const r=await i.sessionNarration({sessionId:e,transcriptPath:n.sessionProbe?.transcriptPathOf(e)??null});return c(t,200,{supported:r!==null,narration:r}),!0}const h=u.match(/^\/sessions\/([^/]+)\/rewinds$/);if(h&&o.method==="GET"){const e=decodeURIComponent(h[1]);if(!g(t,n,e))return!0;const s=k(n,e),i=s?L(s):null;if(!i)return c(t,200,{supported:!1,rewinds:null}),!0;const r=await i.sessionRewinds({sessionId:e,transcriptPath:n.sessionProbe?.transcriptPathOf(e)??null});return c(t,200,{supported:r!==null,rewinds:r}),!0}const p=u.match(/^\/sessions\/([^/]+)\/commands$/);if(p&&o.method==="GET"){const e=decodeURIComponent(p[1]),s=g(t,n,e);if(!s)return!0;const i=k(n,e),r=i?x(i):null;return r?(c(t,200,{supported:!0,commands:await r.list({projectPath:s.path}),inputModes:r.inputModes}),!0):(c(t,200,{supported:!1,commands:[],inputModes:[]}),!0)}const E=u.match(/^\/sessions\/([^/]+)\/command-executions$/);if(E&&o.method==="GET"){const e=decodeURIComponent(E[1]);if(!g(t,n,e))return!0;const s=k(n,e),i=s?x(s):null;if(!i)return c(t,200,{supported:!1,executions:null}),!0;const r=await i.executions(n.sessionProbe?.transcriptPathOf(e)??null);return c(t,200,{supported:r!==null,executions:r}),!0}const S=u.match(/^\/sessions\/([^/]+)\/edits$/);if(S&&o.method==="GET"){const e=decodeURIComponent(S[1]),s=g(t,n,e);if(!s)return!0;const i=k(n,e),r=i?$(i):null;if(!r)return c(t,200,{files:null,hunks:0,truncated:!1,reason:"unsupported"}),!0;const m=await r.sessionEdits({sessionId:e,transcriptPath:n.sessionProbe?.transcriptPathOf(e)??null});if(!m)return c(t,200,{files:null,hunks:0,truncated:!1,reason:"unreadable"}),!0;const I=G(f.searchParams.get("since")),b=G(f.searchParams.get("until")),A=I!==null||b!==null?m.filter(_=>V(_.at,I,b)):m;return c(t,200,Y(A,s.path)),!0}return!1}