@weavecode/weave 0.1.0 → 0.1.2

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 (300) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +3 -3
  2. package/node_modules/@weavecode/cli/dist/commands/daemon.d.ts +7 -0
  3. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  4. package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
  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/i18n/dict/en.js +6 -12
  12. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -2
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -12
  14. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.d.ts +2 -3
  15. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  16. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  17. package/node_modules/@weavecode/cli/dist/init/git-commit.js +1 -1
  18. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  19. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.d.ts +29 -0
  20. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.js +1 -0
  21. package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
  22. package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
  23. package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
  24. package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
  25. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  26. package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
  27. package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
  28. package/node_modules/@weavecode/cli/package.json +5 -5
  29. package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
  30. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  31. package/node_modules/@weavecode/core/dist/index.d.ts +2 -2
  32. package/node_modules/@weavecode/core/dist/index.js +1 -1
  33. package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
  34. package/node_modules/@weavecode/core/dist/terminal.js +1 -1
  35. package/node_modules/@weavecode/core/dist/types.d.ts +188 -19
  36. package/node_modules/@weavecode/core/dist/types.js +1 -1
  37. package/node_modules/@weavecode/core/package.json +1 -1
  38. package/node_modules/@weavecode/harness/dist/claude/assets.d.ts +10 -0
  39. package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -1
  40. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +15 -3
  41. package/node_modules/@weavecode/harness/dist/claude/capture.js +15 -9
  42. package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
  43. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  44. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
  45. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
  46. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +10 -1
  47. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  48. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
  49. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
  50. package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
  51. package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
  52. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +39 -0
  53. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
  54. package/node_modules/@weavecode/harness/dist/claude/plan.d.ts +2 -0
  55. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -0
  56. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
  57. package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
  58. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
  59. package/node_modules/@weavecode/harness/dist/claude/side-question.d.ts +12 -0
  60. package/node_modules/@weavecode/harness/dist/claude/side-question.js +1 -0
  61. package/node_modules/@weavecode/harness/dist/claude/statusline/config.d.ts +200 -0
  62. package/node_modules/@weavecode/harness/dist/claude/statusline/config.js +1 -0
  63. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +12 -0
  64. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +745 -0
  65. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.d.ts +10 -0
  66. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -0
  67. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.d.ts +20 -0
  68. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -0
  69. package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
  70. package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
  71. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  72. package/node_modules/@weavecode/harness/dist/codex/index.d.ts +1 -0
  73. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  74. package/node_modules/@weavecode/harness/dist/codex/mcp.d.ts +30 -0
  75. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -0
  76. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/driver.d.ts +168 -3
  78. package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
  79. package/node_modules/@weavecode/harness/dist/index.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
  81. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
  82. package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
  83. package/node_modules/@weavecode/harness/dist/zcode/assets.d.ts +8 -0
  84. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -0
  85. package/node_modules/@weavecode/harness/dist/zcode/capture.d.ts +36 -0
  86. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -0
  87. package/node_modules/@weavecode/harness/dist/zcode/detect.d.ts +2 -0
  88. package/node_modules/@weavecode/harness/dist/zcode/detect.js +1 -0
  89. package/node_modules/@weavecode/harness/dist/zcode/event-source.d.ts +8 -0
  90. package/node_modules/@weavecode/harness/dist/zcode/event-source.js +1 -0
  91. package/node_modules/@weavecode/harness/dist/zcode/index.d.ts +13 -0
  92. package/node_modules/@weavecode/harness/dist/zcode/index.js +1 -0
  93. package/node_modules/@weavecode/harness/dist/zcode/mcp.d.ts +6 -0
  94. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -0
  95. package/node_modules/@weavecode/harness/dist/zcode/messaging.d.ts +13 -0
  96. package/node_modules/@weavecode/harness/dist/zcode/messaging.js +1 -0
  97. package/node_modules/@weavecode/harness/dist/zcode/resume.d.ts +7 -0
  98. package/node_modules/@weavecode/harness/dist/zcode/resume.js +1 -0
  99. package/node_modules/@weavecode/harness/package.json +2 -2
  100. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  101. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  102. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  103. package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
  104. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
  105. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  106. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  107. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  110. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  111. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  112. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +13 -1
  114. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  115. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  117. package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
  118. package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
  119. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  121. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
  122. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +15 -0
  124. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -6
  125. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +72 -2
  126. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
  128. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  129. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.d.ts +7 -1
  130. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  131. package/node_modules/@weavecode/server/dist/daemon/sse-hub.d.ts +40 -0
  132. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -0
  133. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  134. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  135. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  136. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
  137. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  138. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  139. package/node_modules/@weavecode/server/dist/db/db.js +38 -2
  140. package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
  141. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  142. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  143. package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +5 -0
  144. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  145. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  146. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  147. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  148. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
  149. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
  150. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +27 -6
  151. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  152. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  153. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +200 -13
  154. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
  155. package/node_modules/@weavecode/server/dist/hooks/mirror.d.ts +9 -4
  156. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  157. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  158. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  159. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  160. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  161. package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
  162. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  163. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  164. package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
  165. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  166. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  167. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  168. package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
  169. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +7 -0
  170. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  171. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
  172. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
  173. package/node_modules/@weavecode/server/dist/hooks/side-questions.d.ts +41 -0
  174. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -0
  175. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  176. package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
  177. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  178. package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
  179. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  180. package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
  181. package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
  182. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  183. package/node_modules/@weavecode/server/dist/install/capabilities.d.ts +10 -0
  184. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  185. package/node_modules/@weavecode/server/dist/install/codex-toml.d.ts +8 -26
  186. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  187. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  188. package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
  189. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  190. package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
  191. package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
  192. package/node_modules/@weavecode/server/dist/install/global-config.d.ts +2 -4
  193. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -2
  194. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  195. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
  196. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
  197. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  198. package/node_modules/@weavecode/server/dist/install/installer.d.ts +3 -5
  199. package/node_modules/@weavecode/server/dist/install/installer.js +1 -3
  200. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  201. package/node_modules/@weavecode/server/dist/install/mcp-rows.d.ts +5 -5
  202. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  203. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  204. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  205. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  206. package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
  207. package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
  208. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  209. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  210. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  211. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  212. package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
  213. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  214. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  215. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  216. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  217. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  218. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  219. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  220. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  221. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  222. package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +7 -0
  223. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  224. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  225. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  226. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  227. package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
  228. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  229. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  230. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  231. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +32 -8
  232. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  233. package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +50 -0
  234. package/node_modules/@weavecode/server/dist/repositories/side-questions.js +6 -0
  235. package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
  236. package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
  237. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  238. package/node_modules/@weavecode/server/dist/statusline/config.d.ts +4 -198
  239. package/node_modules/@weavecode/server/dist/statusline/config.js +1 -1
  240. package/node_modules/@weavecode/server/dist/statusline/generator.d.ts +5 -0
  241. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -676
  242. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +7 -5
  243. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -4
  244. package/node_modules/@weavecode/server/dist/surfaces.d.ts +11 -1
  245. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  246. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  247. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  248. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  249. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
  250. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  251. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  252. package/node_modules/@weavecode/server/package.json +4 -4
  253. package/node_modules/@weavecode/server/web/dist/assets/index-CHWbLAje.js +594 -0
  254. package/node_modules/@weavecode/server/web/dist/assets/index-D0s5v8QS.css +11 -0
  255. package/node_modules/@weavecode/server/web/dist/index.html +14 -2
  256. package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
  257. package/node_modules/@weavecode/templates/package.json +2 -2
  258. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
  259. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
  260. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
  261. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
  262. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
  263. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
  264. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
  265. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
  266. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
  267. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
  268. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
  269. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
  270. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
  271. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
  272. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
  273. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
  274. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
  275. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
  276. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
  277. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
  278. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
  279. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
  280. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
  281. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
  282. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
  283. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
  284. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
  285. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
  286. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
  287. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
  288. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
  289. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
  290. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
  291. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
  292. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
  293. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
  294. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
  295. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
  296. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
  297. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
  298. package/package.json +6 -6
  299. package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
  300. package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
@@ -0,0 +1,13 @@
1
+ import type { MessagingSurface } from '../driver.js';
2
+ /**
3
+ * ZCode 消息能力面:投递全走既有通用机制,只在两条 claude 专有通道上声明 null。
4
+ *
5
+ * prompt **恒 null**:两层都不通——ZCode 同名的 `SendMessage` 只发给本会话的
6
+ * 子 agent(不是 peer),而层② 终端要的 pane 不存在:会话跑在 ZCode 桌面应用
7
+ * 里(`zcode-agent` 子进程 + 应用自己的渲染面),不是任何终端模拟器的 pane。
8
+ *
9
+ * inject 骑 `INJECTABLE_EVENTS.zcode`(HookSpecificOutput 支持 additionalContext),
10
+ * 走 weave 既有的 outbox 镜像;watch 靠 `Stop`。headless 未接:`-p` 是字符串选项、
11
+ * 不吃 stdin,且 shell 模式与 detached 的组合在 win32 上丢管道(见 CLAUDE.md)。
12
+ */
13
+ export declare const ZCODE_MESSAGING: MessagingSurface;
@@ -0,0 +1 @@
1
+ import{HARNESS_LIFECYCLE as e,INJECTABLE_EVENTS as s}from"@weavecode/core";export const ZCODE_MESSAGING={harness:"zcode",discovery:!0,prompt:null,promptInbox:null,inject:{rideEvents:s.zcode},headless:null,idleSignals:[...e.zcode.close],imageAttach:null,sideQuestion:null,unsupportedReasons:{prompt:"ZCode sessions run inside the ZCode desktop app, not in a terminal pane, so there is no channel to type a prompt into (its SendMessage only reaches sub-agents of the same session)",headless:"ZCode's -p takes the prompt on the command line and does not read stdin; headless delivery is not wired",sideQuestion:"ZCode has no side-chat (btw) mechanism"}};
@@ -0,0 +1,7 @@
1
+ import type { ResumeCommandSpec } from '../driver.js';
2
+ /**
3
+ * ZCode resume 命令规格:`zcode --resume <sessionId>` 接回既有会话(会话行在
4
+ * SQLite 里,`--resume` 按 id 取)。`-p` 只吃命令行字符串、不从 stdin 读 prompt,
5
+ * 故 headless 投递不给 zcode 开(messaging.headless = null)——`args` 只为形态完整。
6
+ */
7
+ export declare const ZCODE_RESUME: ResumeCommandSpec;
@@ -0,0 +1 @@
1
+ export const ZCODE_RESUME={supported:!0,bin:"zcode",args:(e,r)=>["--resume",e,"-p",r],openArgs:e=>["--resume",e]};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weavecode/harness",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Pluggable harness drivers — registry, init pipeline template method, and harness integration modules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "node": ">=22.5.0"
21
21
  },
22
22
  "dependencies": {
23
- "@weavecode/core": "^0.1.0",
23
+ "@weavecode/core": "^0.1.2",
24
24
  "smol-toml": "^1.3.0"
25
25
  }
26
26
  }
@@ -1,2 +1,2 @@
1
- import{chmodSync as t,existsSync as a,mkdirSync as c,readFileSync as o,renameSync as y,rmSync as u,writeFileSync as s}from"node:fs";import l from"node:path";import{getAiKeyPath as r}from"../db/paths.js";export function readAiKey(n=r()){if(!a(n))return null;try{const e=JSON.parse(o(n,"utf8"));return typeof e.apiKey=="string"&&e.apiKey!==""?e.apiKey:null}catch{return null}}export function writeAiKey(n,e=r()){if(n===null||n===""){u(e,{force:!0});return}c(l.dirname(e),{recursive:!0});const i=`${e}.tmp`;s(i,`${JSON.stringify({apiKey:n},null,2)}
2
- `,{encoding:"utf8",mode:384}),y(i,e);try{t(e,384)}catch{}}export function hasAiKey(n=r()){return readAiKey(n)!==null}
1
+ import{chmodSync as o,existsSync as c,mkdirSync as i,readFileSync as u,renameSync as y,rmSync as m,writeFileSync as p}from"node:fs";import a from"node:path";import{getAiKeyPath as n}from"../db/paths.js";export function readAiKey(t=n()){if(!c(t))return null;try{const r=JSON.parse(u(t,"utf8"));return typeof r.apiKey=="string"&&r.apiKey!==""?r.apiKey:null}catch{return null}}export function writeAiKey(t,r=n()){if(t===null||t===""){m(r,{force:!0});return}i(a.dirname(r),{recursive:!0});const e=`${r}.tmp`;p(e,`${JSON.stringify({apiKey:t},null,2)}
2
+ `,{encoding:"utf8",mode:384}),y(e,r);try{o(r,384)}catch{}}export function hasAiKey(t=n()){return readAiKey(t)!==null}
@@ -1,10 +1,10 @@
1
- import{existsSync as C,readdirSync as c,readFileSync as a}from"node:fs";import D from"node:path";import{builtinMarketDir as f}from"../market/builtin.js";const l=6e4,p=40,d=6;export function findDocsDir(t){let F=D.resolve(t);for(let E=0;E<d;E++){const o=D.join(F,"docs");if(C(D.join(o,"FEATURES.md")))return o;const n=D.dirname(F);if(n===F)break;F=n}return null}export function collectSkillFiles(t,F=p){const E=[],o=(n,r)=>{if(E.length>=F||r>6)return;let s;try{s=c(n,{withFileTypes:!0})}catch{return}for(const B of s){if(E.length>=F)return;const u=D.join(n,B.name);B.isDirectory()?o(u,r+1):B.name==="SKILL.md"&&E.push(u)}};return o(t,0),E.sort()}function i(t){try{return a(t,"utf8")}catch{return null}}export function buildSystemPrompt(t){const F=[],E=findDocsDir(t.cwd??process.cwd());if(E)for(const u of["ARCHITECTURE.md","FEATURES.md"]){const e=D.join(E,u);if(!C(e))continue;const A=i(e);A&&F.push({label:`docs/${u}`,text:A})}const o=f(t.dataDir);for(const u of collectSkillFiles(o)){const e=i(u);e&&F.push({label:D.relative(o,u).split(D.sep).join("/"),text:e})}const n=["\u4F60\u662F weave \u63A7\u5236\u53F0\u5185\u7F6E\u7684 AI \u52A9\u624B\uFF0C**\u53EA\u8D1F\u8D23 weave \u672C\u8EAB**\uFF1A\u5B83\u7684\u529F\u80FD\u3001\u7528\u6CD5\u3001\u914D\u7F6E\u3001\u67B6\u6784\u3001","\u5185\u7F6E\u6280\u80FD\uFF0C\u4EE5\u53CA\u57FA\u4E8E\u4E0B\u9762\u6CE8\u5165\u8D44\u6599\u7684\u6392\u969C\u3002","","\u56DE\u7B54\u8303\u56F4\uFF08\u8D8A\u754C\u7684\u60C5\u51B5\u4E00\u5F8B\u793C\u8C8C\u62D2\u7B54\uFF1A\u7528\u4E00\u53E5\u8BDD\u8BF4\u660E\u4F60\u53EA\u804A weave\uFF0C\u7136\u540E\u628A\u8BDD\u9898\u5F15\u56DE weave\uFF09\uFF1A","- \u53EF\u4EE5\u7B54\uFF1Aweave \u7684\u80FD\u529B\u4E0E\u64CD\u4F5C\uFF08\u547D\u4EE4\u3001\u8BBE\u7F6E\u9879\u3001\u6587\u4EF6\u843D\u70B9\u3001\u63D2\u4EF6/\u6280\u80FD/\u5E02\u573A\u3001hooks\u3001\u4F1A\u8BDD\u4E0E\u4EFB\u52A1\u3001\u8BA4\u8BC1\u7B49\uFF09\uFF0C"," \u4EE5\u53CA\u6CE8\u5165\u8D44\u6599\u91CC\u80FD\u67E5\u5230\u7684\u4E8B\u5B9E\uFF1B","- \u4E0D\u8981\u7B54\uFF1A\u4E0E weave \u65E0\u5173\u7684\u901A\u7528\u7F16\u7A0B\u3001\u5199\u4F5C\u3001\u7FFB\u8BD1\u3001\u95F2\u804A\uFF0C\u5176\u5B83\u4EA7\u54C1\u6216\u670D\u52A1\uFF0C\u4EE5\u53CA\u4EFB\u4F55\u6709\u5BB3\u6216\u8D8A\u754C\u7684\u8BF7\u6C42\uFF1B","- \u8D44\u6599\u672A\u8986\u76D6\u65F6\u660E\u786E\u8BF4\u300C\u4E0D\u786E\u5B9A\u300D\uFF0C\u4E0D\u8981\u7F16\u9020 weave \u7684\u884C\u4E3A\u3001\u547D\u4EE4\u6216\u53C2\u6570\uFF1B","- \u4E0D\u7C98\u8D34\u5927\u6BB5\u6CE8\u5165\u8D44\u6599\u539F\u6587\uFF08\u7528\u6237\u70B9\u540D\u8981\u67D0\u4E00\u6BB5\u65F6\u9664\u5916\uFF09\uFF1B","- \u53EA\u505A\u53EA\u8BFB\u95EE\u7B54\uFF1A\u4E0D\u58F0\u79F0\u5DF2\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\uFF0C\u4E5F\u4E0D\u627F\u8BFA\u4EE3\u66FF\u7528\u6237\u53BB\u6539\u6587\u4EF6\u6216\u8DD1\u547D\u4EE4\u3002","","\u56DE\u7B54\u4F7F\u7528\u4E0E\u63D0\u95EE\u76F8\u540C\u7684\u8BED\u8A00\uFF1B\u6D89\u53CA\u64CD\u4F5C\u65F6\u7ED9\u51FA\u786E\u5207\u547D\u4EE4\u4E0E\u8DEF\u5F84\u3002"].join(`
2
- `),r=[];let s=n.length;const B=[];for(const u of F){const e=`
1
+ import{existsSync as d,readdirSync as h,readFileSync as S}from"node:fs";import c from"node:path";import{builtinMarketDir as b}from"../market/builtin.js";const p=6e4,w=40,y=6;export function findDocsDir(r){let t=c.resolve(r);for(let n=0;n<y;n++){const s=c.join(t,"docs");if(d(c.join(s,"FEATURES.md")))return s;const i=c.dirname(t);if(i===t)break;t=i}return null}export function collectSkillFiles(r,t=w){const n=[],s=(i,a)=>{if(n.length>=t||a>6)return;let u;try{u=h(i,{withFileTypes:!0})}catch{return}for(const l of u){if(n.length>=t)return;const e=c.join(i,l.name);l.isDirectory()?s(e,a+1):l.name==="SKILL.md"&&n.push(e)}};return s(r,0),n.sort()}function m(r){try{return S(r,"utf8")}catch{return null}}export function buildSystemPrompt(r){const t=[],n=findDocsDir(r.cwd??process.cwd());if(n)for(const e of["ARCHITECTURE.md","FEATURES.md"]){const o=c.join(n,e);if(!d(o))continue;const f=m(o);f&&t.push({label:`docs/${e}`,text:f})}const s=b(r.dataDir);for(const e of collectSkillFiles(s)){const o=m(e);o&&t.push({label:c.relative(s,e).split(c.sep).join("/"),text:o})}const i=["\u4F60\u662F weave \u63A7\u5236\u53F0\u5185\u7F6E\u7684 AI \u52A9\u624B\uFF0C**\u53EA\u8D1F\u8D23 weave \u672C\u8EAB**\uFF1A\u5B83\u7684\u529F\u80FD\u3001\u7528\u6CD5\u3001\u914D\u7F6E\u3001\u67B6\u6784\u3001","\u5185\u7F6E\u6280\u80FD\uFF0C\u4EE5\u53CA\u57FA\u4E8E\u4E0B\u9762\u6CE8\u5165\u8D44\u6599\u7684\u6392\u969C\u3002","","\u56DE\u7B54\u8303\u56F4\uFF08\u8D8A\u754C\u7684\u60C5\u51B5\u4E00\u5F8B\u793C\u8C8C\u62D2\u7B54\uFF1A\u7528\u4E00\u53E5\u8BDD\u8BF4\u660E\u4F60\u53EA\u804A weave\uFF0C\u7136\u540E\u628A\u8BDD\u9898\u5F15\u56DE weave\uFF09\uFF1A","- \u53EF\u4EE5\u7B54\uFF1Aweave \u7684\u80FD\u529B\u4E0E\u64CD\u4F5C\uFF08\u547D\u4EE4\u3001\u8BBE\u7F6E\u9879\u3001\u6587\u4EF6\u843D\u70B9\u3001\u63D2\u4EF6/\u6280\u80FD/\u5E02\u573A\u3001hooks\u3001\u4F1A\u8BDD\u4E0E\u4EFB\u52A1\u3001\u8BA4\u8BC1\u7B49\uFF09\uFF0C"," \u4EE5\u53CA\u6CE8\u5165\u8D44\u6599\u91CC\u80FD\u67E5\u5230\u7684\u4E8B\u5B9E\uFF1B","- \u4E0D\u8981\u7B54\uFF1A\u4E0E weave \u65E0\u5173\u7684\u901A\u7528\u7F16\u7A0B\u3001\u5199\u4F5C\u3001\u7FFB\u8BD1\u3001\u95F2\u804A\uFF0C\u5176\u5B83\u4EA7\u54C1\u6216\u670D\u52A1\uFF0C\u4EE5\u53CA\u4EFB\u4F55\u6709\u5BB3\u6216\u8D8A\u754C\u7684\u8BF7\u6C42\uFF1B","- \u8D44\u6599\u672A\u8986\u76D6\u65F6\u660E\u786E\u8BF4\u300C\u4E0D\u786E\u5B9A\u300D\uFF0C\u4E0D\u8981\u7F16\u9020 weave \u7684\u884C\u4E3A\u3001\u547D\u4EE4\u6216\u53C2\u6570\uFF1B","- \u4E0D\u7C98\u8D34\u5927\u6BB5\u6CE8\u5165\u8D44\u6599\u539F\u6587\uFF08\u7528\u6237\u70B9\u540D\u8981\u67D0\u4E00\u6BB5\u65F6\u9664\u5916\uFF09\uFF1B","- \u53EA\u505A\u53EA\u8BFB\u95EE\u7B54\uFF1A\u4E0D\u58F0\u79F0\u5DF2\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\uFF0C\u4E5F\u4E0D\u627F\u8BFA\u4EE3\u66FF\u7528\u6237\u53BB\u6539\u6587\u4EF6\u6216\u8DD1\u547D\u4EE4\u3002","","\u56DE\u7B54\u4F7F\u7528\u4E0E\u63D0\u95EE\u76F8\u540C\u7684\u8BED\u8A00\uFF1B\u6D89\u53CA\u64CD\u4F5C\u65F6\u7ED9\u51FA\u786E\u5207\u547D\u4EE4\u4E0E\u8DEF\u5F84\u3002"].join(`
2
+ `),a=[];let u=i.length;const l=[];for(const e of t){const o=`
3
3
 
4
- ## \u6CE8\u5165\u8D44\u6599\uFF1A${u.label}
4
+ ## \u6CE8\u5165\u8D44\u6599\uFF1A${e.label}
5
5
 
6
- ${u.text}`;if(s+e.length>l){const A=l-s;A>500&&(r.push(`
6
+ ${e.text}`;if(u+o.length>p){const f=p-u;f>500&&(a.push(`
7
7
 
8
- ## \u6CE8\u5165\u8D44\u6599\uFF1A${u.label}\uFF08\u6309\u9884\u7B97\u622A\u65AD\uFF09
8
+ ## \u6CE8\u5165\u8D44\u6599\uFF1A${e.label}\uFF08\u6309\u9884\u7B97\u622A\u65AD\uFF09
9
9
 
10
- ${u.text.slice(0,A)}`),B.push(`${u.label}(\u622A\u65AD)`));break}s+=e.length,r.push(e),B.push(u.label)}return{prompt:n+r.join(""),labels:B,docsFound:E!==null}}
10
+ ${e.text.slice(0,f)}`),l.push(`${e.label}(\u622A\u65AD)`));break}u+=o.length,a.push(o),l.push(e.label)}return{prompt:i+a.join(""),labels:l,docsFound:n!==null}}
@@ -1,6 +1,6 @@
1
- import{getDataDir as J}from"../db/paths.js";import{DEFAULT_AI_SETTINGS as M,readDaemonSettings as P}from"./settings.js";import{hasAiKey as I,readAiKey as T}from"./ai-config.js";import{buildSystemPrompt as j,findDocsDir as _}from"./ai-context.js";import{readJson as O,sendJson as u}from"./http.js";const z=12e4,B=15e3,R=500,C=40,G=2e4;export function normalizeMessages(r){if(!Array.isArray(r)||r.length===0||r.length>C)return null;const t=[];for(const e of r){const n=e;if(n?.role!=="user"&&n?.role!=="assistant")return null;const o=n.content;if(typeof o!="string"||o===""||o.length>G)return null;t.push({role:n.role,content:o})}return t}export function aiConfigured(r,t,e){return r!==""&&t!==""&&e}export async function handleAiRoutes(r,t,e,n){if(n!=="/ai"&&!n.startsWith("/ai/"))return!1;const o=(await P()).ai??M,a=I(e.aiKeyPath);if(n==="/ai/status"&&r.method==="GET")return u(t,200,{configured:aiConfigured(o.baseUrl,o.model,a),baseUrl:o.baseUrl,model:o.model,apiKeySet:a,docsFound:_(process.cwd())!==null}),!0;if(n==="/ai/models"&&r.method==="POST"){let i;try{i=await O(r)}catch{return u(t,400,{error:"Invalid JSON body"}),!0}const d=typeof i.baseUrl=="string"&&i.baseUrl.trim()!==""?i.baseUrl.trim():o.baseUrl,l=typeof i.apiKey=="string"&&i.apiKey!==""?i.apiKey:T(e.aiKeyPath);if(d===""||l===null)return u(t,409,{error:"AI assistant is not configured"}),!0;const m=await L(d,l);return m.ok?(u(t,200,{models:m.models}),!0):(u(t,502,{error:m.error}),!0)}if(n==="/ai/chat"&&r.method==="POST"){const i=T(e.aiKeyPath);if(!aiConfigured(o.baseUrl,o.model,a)||i===null)return u(t,409,{error:"AI assistant is not configured"}),!0;let d;try{d=await O(r)}catch{return u(t,400,{error:"Invalid JSON body"}),!0}const l=normalizeMessages(d.messages);if(!l)return u(t,400,{error:"Invalid messages"}),!0;const m=j({dataDir:e.libraries?.dataDir??J()});return await q({req:r,res:t,baseUrl:o.baseUrl,model:o.model,apiKey:i,messages:l,system:m.prompt}),!0}return u(t,404,{error:"Not found"}),!0}function $(r){const t=r?.choices?.[0],e=t?.delta?.content??t?.message?.content;return typeof e=="string"&&e!==""?e:null}export const STREAM_MEMO_TTL_MS=1440*60*1e3;const w=new Map;export function streamMemoKey(r,t){return`${r}#${t}`}export function streamSupported(r,t=Date.now()){const e=w.get(r);return!e||t-e.checkedAt>STREAM_MEMO_TTL_MS?!0:e.streaming}export function rememberStreamSupport(r,t,e=Date.now()){const n=w.get(r);n!==void 0&&n.streaming!==t&&console.log(`[weave] ai gateway ${t?"supports":"rejects"} streaming: ${r}`),w.set(r,{streaming:t,checkedAt:e})}export function resetStreamMemory(){w.clear()}async function L(r,t){try{const e=await fetch(`${r.replace(/\/+$/,"")}/models`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(B)});if(!e.ok){const a=await e.text().catch(()=>"");return{ok:!1,error:`upstream ${e.status}${a?`: ${a.slice(0,200)}`:""}`}}const n=await e.json().catch(()=>null),o=[...new Set((n?.data??[]).map(a=>a?.id).filter(a=>typeof a=="string"&&a!==""))].sort();return o.length===0?{ok:!1,error:"upstream returned no models"}:{ok:!0,models:o.slice(0,R)}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function D(r){try{const t=await fetch(r.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.apiKey}`},body:JSON.stringify({model:r.model,stream:!1,messages:r.messages}),signal:r.signal});if(!t.ok){const n=await t.text().catch(()=>"");return{ok:!1,error:`upstream ${t.status}${n?`: ${n.slice(0,300)}`:""}`}}const e=$(await t.json().catch(()=>null));return e===null?{ok:!1,error:"upstream returned no content"}:{ok:!0,content:e}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}async function q(r){const{req:t,res:e,baseUrl:n,model:o,apiKey:a,messages:i,system:d}=r,l=`${n.replace(/\/+$/,"")}/chat/completions`,m=[{role:"system",content:d},...i],g=new AbortController,U=setTimeout(()=>g.abort(),z);t.on("close",()=>g.abort()),e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"});let b=!1;const f=s=>{if(!b)try{e.write(`data: ${JSON.stringify(s)}
1
+ import{getDataDir as I}from"../db/paths.js";import{DEFAULT_AI_SETTINGS as v,readDaemonSettings as N}from"./settings.js";import{hasAiKey as J,readAiKey as O}from"./ai-config.js";import{buildSystemPrompt as P,findDocsDir as j}from"./ai-context.js";import{readJson as k,sendJson as f}from"./http.js";const z=12e4,C=15e3,G=500,L=40,R=2e4;export function normalizeMessages(r){if(!Array.isArray(r)||r.length===0||r.length>L)return null;const e=[];for(const t of r){const o=t;if(o?.role!=="user"&&o?.role!=="assistant")return null;const a=o.content;if(typeof a!="string"||a===""||a.length>R)return null;e.push({role:o.role,content:a})}return e}export function aiConfigured(r,e,t){return r!==""&&e!==""&&t}export async function handleAiRoutes(r,e,t,o){if(o!=="/ai"&&!o.startsWith("/ai/"))return!1;const n=(await N()).ai??v,p=J(t.aiKeyPath);if(o==="/ai/status"&&r.method==="GET")return f(e,200,{configured:aiConfigured(n.baseUrl,n.model,p),baseUrl:n.baseUrl,model:n.model,apiKeySet:p,docsFound:j(process.cwd())!==null}),!0;if(o==="/ai/models"&&r.method==="POST"){let i;try{i=await k(r)}catch{return f(e,400,{error:"Invalid JSON body"}),!0}const u=typeof i.baseUrl=="string"&&i.baseUrl.trim()!==""?i.baseUrl.trim():n.baseUrl,m=typeof i.apiKey=="string"&&i.apiKey!==""?i.apiKey:O(t.aiKeyPath);if(u===""||m===null)return f(e,409,{error:"AI assistant is not configured"}),!0;const l=await B(u,m);return l.ok?(f(e,200,{models:l.models}),!0):(f(e,502,{error:l.error}),!0)}if(o==="/ai/chat"&&r.method==="POST"){const i=O(t.aiKeyPath);if(!aiConfigured(n.baseUrl,n.model,p)||i===null)return f(e,409,{error:"AI assistant is not configured"}),!0;let u;try{u=await k(r)}catch{return f(e,400,{error:"Invalid JSON body"}),!0}const m=normalizeMessages(u.messages);if(!m)return f(e,400,{error:"Invalid messages"}),!0;const l=P({dataDir:t.libraries?.dataDir??I()});return await X({req:r,res:e,baseUrl:n.baseUrl,model:n.model,apiKey:i,messages:m,system:l.prompt}),!0}return f(e,404,{error:"Not found"}),!0}function A(r){const t=r?.choices?.[0],o=t?.delta?.content??t?.message?.content;return typeof o=="string"&&o!==""?o:null}export const STREAM_MEMO_TTL_MS=1440*60*1e3;const S=new Map;export function streamMemoKey(r,e){return`${r}#${e}`}export function streamSupported(r,e=Date.now()){const t=S.get(r);return!t||e-t.checkedAt>STREAM_MEMO_TTL_MS?!0:t.streaming}export function rememberStreamSupport(r,e,t=Date.now()){const o=S.get(r);o!==void 0&&o.streaming!==e&&console.log(`[weave] ai gateway ${e?"supports":"rejects"} streaming: ${r}`),S.set(r,{streaming:e,checkedAt:t})}export function resetStreamMemory(){S.clear()}async function B(r,e){try{const t=await fetch(`${r.replace(/\/+$/,"")}/models`,{headers:{authorization:`Bearer ${e}`},signal:AbortSignal.timeout(C)});if(!t.ok){const n=await t.text().catch(()=>"");return{ok:!1,error:`upstream ${t.status}${n?`: ${n.slice(0,200)}`:""}`}}const o=await t.json().catch(()=>null),a=[...new Set((o?.data??[]).map(n=>n?.id).filter(n=>typeof n=="string"&&n!==""))].sort();return a.length===0?{ok:!1,error:"upstream returned no models"}:{ok:!0,models:a.slice(0,G)}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}async function E(r){try{const e=await fetch(r.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.apiKey}`},body:JSON.stringify({model:r.model,stream:!1,messages:r.messages}),signal:r.signal});if(!e.ok){const o=await e.text().catch(()=>"");return{ok:!1,error:`upstream ${e.status}${o?`: ${o.slice(0,300)}`:""}`}}const t=A(await e.json().catch(()=>null));return t===null?{ok:!1,error:"upstream returned no content"}:{ok:!0,content:t}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function X(r){const{req:e,res:t,baseUrl:o,model:a,apiKey:n,messages:p,system:i}=r,u=`${o.replace(/\/+$/,"")}/chat/completions`,m=[{role:"system",content:i},...p],l=new AbortController,_=setTimeout(()=>l.abort(),z);e.on("close",()=>l.abort()),t.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"});let b=!1;const d=s=>{if(!b)try{t.write(`data: ${JSON.stringify(s)}
2
2
 
3
- `)}catch{}},v=()=>{if(!b){b=!0;try{e.write(`data: {"done":true}
3
+ `)}catch{}},K=()=>{if(!b){b=!0;try{t.write(`data: {"done":true}
4
4
 
5
- `),e.end()}catch{}}},y=streamMemoKey(l,o),k={url:l,apiKey:a,model:o,messages:m,signal:g.signal};try{if(!streamSupported(y)){const c=await D(k);c.ok?f({delta:c.content}):f({error:c.error});return}const s=await fetch(l,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${a}`},body:JSON.stringify({model:o,stream:!0,messages:m}),signal:g.signal});if(!s.ok||!s.body){const c=await s.text().catch(()=>""),h=await D(k);h.ok?(rememberStreamSupport(y,!1),f({delta:h.content})):f({error:`upstream ${s.status}${c?`: ${c.slice(0,300)}`:""}`});return}if(!(s.headers.get("content-type")??"").includes("text/event-stream")){const c=$(await s.json().catch(()=>null));rememberStreamSupport(y,!1),f(c===null?{error:"upstream returned no content"}:{delta:c});return}rememberStreamSupport(y,!0);const E=s.body.getReader(),N=new TextDecoder;let p="";for(;;){const{done:c,value:h}=await E.read();if(c)break;p+=N.decode(h,{stream:!0});let S;for(;(S=p.indexOf(`
6
- `))>=0;){const x=p.slice(0,S).trim();if(p=p.slice(S+1),!x.startsWith("data:"))continue;const A=x.slice(5).trim();if(A==="[DONE]")return;try{const K=$(JSON.parse(A));K!==null&&f({delta:K})}catch{}}}}catch(s){f({error:s instanceof Error?s.message:String(s)})}finally{clearTimeout(U),v()}}
5
+ `),t.end()}catch{}}},g=streamMemoKey(u,a),M={url:u,apiKey:n,model:a,messages:m,signal:l.signal};try{if(!streamSupported(g)){const c=await E(M);c.ok?d({delta:c.content}):d({error:c.error});return}const s=await fetch(u,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${n}`},body:JSON.stringify({model:a,stream:!0,messages:m}),signal:l.signal});if(!s.ok||!s.body){const c=await s.text().catch(()=>""),h=await E(M);h.ok?(rememberStreamSupport(g,!1),d({delta:h.content})):d({error:`upstream ${s.status}${c?`: ${c.slice(0,300)}`:""}`});return}if(!(s.headers.get("content-type")??"").includes("text/event-stream")){const c=A(await s.json().catch(()=>null));rememberStreamSupport(g,!1),d(c===null?{error:"upstream returned no content"}:{delta:c});return}rememberStreamSupport(g,!0);const U=s.body.getReader(),D=new TextDecoder;let y="";for(;;){const{done:c,value:h}=await U.read();if(c)break;y+=D.decode(h,{stream:!0});let w;for(;(w=y.indexOf(`
6
+ `))>=0;){const $=y.slice(0,w).trim();if(y=y.slice(w+1),!$.startsWith("data:"))continue;const T=$.slice(5).trim();if(T==="[DONE]")return;try{const x=A(JSON.parse(T));x!==null&&d({delta:x})}catch{}}}}catch(s){d({error:s instanceof Error?s.message:String(s)})}finally{clearTimeout(_),K()}}
@@ -0,0 +1,48 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ /** 保留的小时文件数(= 24 小时)。 */
3
+ export declare const MAX_LOG_FILES = 24;
4
+ export interface ApiLogEntry {
5
+ ts: string;
6
+ method: string;
7
+ path: string;
8
+ status: number;
9
+ durationMs: number;
10
+ ip: string;
11
+ ua?: string;
12
+ req?: unknown;
13
+ res?: unknown;
14
+ resBytes?: number;
15
+ stream?: boolean;
16
+ aborted?: boolean;
17
+ }
18
+ export interface ApiLogQuery {
19
+ from?: string;
20
+ to?: string;
21
+ path?: string;
22
+ method?: string;
23
+ status?: number;
24
+ limit?: number;
25
+ }
26
+ /** 本地小时戳文件名:`api-YYYY-MM-DDTHH.jsonl`。 */
27
+ export declare function logFileFor(dir: string, at: Date): string;
28
+ export declare function noteRequestBody(req: IncomingMessage, text: string): void;
29
+ export declare class ApiLogger {
30
+ private readonly dir;
31
+ private chain;
32
+ constructor(opts?: {
33
+ dir?: string;
34
+ });
35
+ /** 挂上计时与响应捕获;响应收尾(finish/abort)即落一行。 */
36
+ begin(req: IncomingMessage, res: ServerResponse): void;
37
+ /** 落盘恒异步:串行链保序,失败静默(日志不打扰请求路径)。 */
38
+ private write;
39
+ /** 只留最近 MAX_LOG_FILES 个小时文件(按文件名小时序)。 */
40
+ private purge;
41
+ /** 测试/关停用:等在写的链落地。 */
42
+ onIdle(): Promise<void>;
43
+ /** 只读查询:按小时文件倒序扫,过滤后截到 limit。 */
44
+ query(q: ApiLogQuery): Promise<{
45
+ entries: ApiLogEntry[];
46
+ files: number;
47
+ }>;
48
+ }
@@ -0,0 +1,3 @@
1
+ import{appendFile as F,mkdir as L,readdir as T,readFile as N,rm as j}from"node:fs/promises";import g from"node:path";import{getApiLogsDir as x}from"../db/paths.js";const w=8*1024,C=2e3,b=50,D=6;export const MAX_LOG_FILES=24;const I=200,O=1e3,H=new Set(["password","apikey","token","secret","authorization","cookie","x-weave-local"]);function y(n,t=0){if(typeof n=="string")return n.length>C?`[truncated ${n.length} chars]`:n;if(Array.isArray(n)){if(t>=D)return"[depth-limited]";const e=n.slice(0,b).map(i=>y(i,t+1));return n.length>b&&e.push(`[truncated ${n.length-b} items]`),e}if(n&&typeof n=="object"){if(t>=D)return"[depth-limited]";const e={};for(const[i,a]of Object.entries(n))e[i]=H.has(i.toLowerCase())?"[redacted]":y(a,t+1);return e}return n}function M(n,t){if(t>w)return`[truncated body ${t} bytes]`;try{return y(JSON.parse(n))}catch{return y(n)}}export function logFileFor(n,t){const e=a=>String(a).padStart(2,"0"),i=`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}T${e(t.getHours())}`;return g.join(n,`api-${i}.jsonl`)}function _(n){const t=g.basename(n).match(/^api-(\d{4}-\d{2}-\d{2}T\d{2})\.jsonl$/);return t?t[1]:null}const E=new WeakMap;export function noteRequestBody(n,t){E.get(n)?.(t)}export class ApiLogger{dir;chain=Promise.resolve();constructor(t={}){this.dir=t.dir??x()}begin(t,e){const i=Date.now(),a=[];let u=0,c=0,d="",h=0,l=!1;E.set(t,r=>{d=r,h=Buffer.byteLength(r,"utf8")});const f=r=>{const o=Buffer.isBuffer(r)?r:Buffer.from(typeof r=="string"?r:String(r??""),"utf8");if(c+=o.length,u<w){const s=o.subarray(0,w-u);a.push(s),u+=s.length}},m=e.write.bind(e),$=e.end.bind(e);let A="";const B=e.writeHead.bind(e);e.writeHead=((...r)=>{const o=r[1];if(o&&typeof o=="object"&&!Array.isArray(o)){const s=o,p=s["content-type"]??s["Content-Type"];typeof p=="string"&&(A=p)}return B(...r)}),e.write=((r,...o)=>(f(r),m(r,...o))),e.end=((r,...o)=>(typeof r!="function"&&r!=null&&f(r),$(r,...o)));const S=()=>{if(l)return;l=!0;const o=(String(e.getHeader("content-type")??"")||A).includes("event-stream"),s={ts:new Date(i).toISOString(),method:t.method??"GET",path:t.url??"/",status:e.statusCode,durationMs:Date.now()-i,ip:(t.socket?.remoteAddress??"").replace(/^::ffff:/,""),resBytes:c},p=t.headers["user-agent"];typeof p=="string"&&p&&(s.ua=p.slice(0,120)),h&&(s.req=M(d,h)),o?s.stream=!0:c&&(s.res=M(Buffer.concat(a).toString("utf8"),c)),e.writableEnded||(s.aborted=!0),this.write(logFileFor(this.dir,new Date(i)),`${JSON.stringify(s)}
2
+ `)};e.on("finish",S),e.on("close",S)}write(t,e){this.chain=this.chain.then(async()=>{try{await L(this.dir,{recursive:!0}),await F(t,e,"utf8"),await this.purge()}catch{}})}async purge(){const t=(await T(this.dir)).filter(e=>_(e)!=null);if(!(t.length<=MAX_LOG_FILES)){t.sort();for(const e of t.slice(0,t.length-MAX_LOG_FILES))await j(g.join(this.dir,e),{force:!0})}}onIdle(){return this.chain}async query(t){const e=(await T(this.dir).catch(()=>[])).filter(d=>_(d)!=null).sort().reverse(),i=Math.min(Math.max(t.limit??I,1),O),a=t.from?Date.parse(t.from):NaN,u=t.to?Date.parse(t.to):NaN,c=[];for(const d of e){if(c.length>=i)break;const h=await N(g.join(this.dir,d),"utf8").catch(()=>"");for(const l of h.split(`
3
+ `).reverse()){if(!l.trim())continue;let f;try{f=JSON.parse(l)}catch{continue}const m=Date.parse(f.ts);if(!(Number.isFinite(a)&&m<a)&&!(Number.isFinite(u)&&m>u)&&!(t.status!=null&&f.status!==t.status)&&!(t.method&&f.method.toUpperCase()!==t.method.toUpperCase())&&!(t.path&&!f.path.includes(t.path))&&(c.push(f),c.length>=i))break}}return{entries:c,files:e.length}}}
@@ -1 +1 @@
1
- import{clearedSessionCookie as h,sessionCookie as c}from"./dashboard-auth.js";import{readJson as i,sendJson as e}from"./http.js";const l=300,d=6,f=s=>new Promise(r=>setTimeout(r,s));export async function handleAuthRoutes(s,r,u,a){if(a!=="/auth"&&!a.startsWith("/auth/"))return!1;const t=u.auth;if(!t)return e(r,503,{error:"Auth subsystem unavailable"}),!0;if(a==="/auth/status"&&s.method==="GET")return e(r,200,{passwordSet:t.isPasswordSet(),authenticated:t.isAuthenticated(s.headers)}),!0;if(a==="/auth/login"&&s.method==="POST"){let o;try{o=await i(s)}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const n=typeof o.password=="string"?o.password:"";return!n||!t.verifyPassword(n)?(await f(l),e(r,401,{error:"Invalid password"}),!0):(r.setHeader("set-cookie",c(t.issueSession())),e(r,200,{ok:!0}),!0)}if(a==="/auth/logout"&&s.method==="POST")return r.setHeader("set-cookie",h()),e(r,200,{ok:!0}),!0;if(a==="/auth/password"&&s.method==="PUT"){if(!t.isLocallyTrusted(s.headers))return e(r,401,{error:"Unauthorized (local token required)"}),!0;let o;try{o=await i(s)}catch{return e(r,400,{error:"Invalid JSON body"}),!0}const n=typeof o.next=="string"?o.next:"";return n.length<d?(e(r,400,{error:`Password must be at least ${d} characters`}),!0):(t.setPassword(n),e(r,200,{ok:!0}),!0)}return e(r,404,{error:"Not found"}),!0}
1
+ import{clearedSessionCookie as c,sessionCookie as h}from"./dashboard-auth.js";import{readJson as i,sendJson as r}from"./http.js";const l=300,n=6,f=e=>new Promise(t=>setTimeout(t,e));export async function handleAuthRoutes(e,t,d,u){if(u!=="/auth"&&!u.startsWith("/auth/"))return!1;const o=d.auth;if(!o)return r(t,503,{error:"Auth subsystem unavailable"}),!0;if(u==="/auth/status"&&e.method==="GET")return r(t,200,{passwordSet:o.isPasswordSet(),authenticated:o.isAuthenticated(e.headers)}),!0;if(u==="/auth/login"&&e.method==="POST"){let s;try{s=await i(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const a=typeof s.password=="string"?s.password:"";return!a||!o.verifyPassword(a)?(await f(l),r(t,401,{error:"Invalid password"}),!0):(t.setHeader("set-cookie",h(o.issueSession())),r(t,200,{ok:!0}),!0)}if(u==="/auth/logout"&&e.method==="POST")return t.setHeader("set-cookie",c()),r(t,200,{ok:!0}),!0;if(u==="/auth/password"&&e.method==="PUT"){if(!o.isLocallyTrusted(e.headers))return r(t,401,{error:"Unauthorized (local token required)"}),!0;let s;try{s=await i(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const a=typeof s.next=="string"?s.next:"";return a.length<n?(r(t,400,{error:`Password must be at least ${n} characters`}),!0):(o.setPassword(a),r(t,200,{ok:!0}),!0)}return r(t,404,{error:"Not found"}),!0}
@@ -1,17 +1,17 @@
1
- import{spawnSync as u}from"node:child_process";import{fileURLToPath as p}from"node:url";import{mkdirSync as a,writeFileSync as i,unlinkSync as s}from"node:fs";import{homedir as m}from"node:os";import n from"node:path";import{getDataDir as l}from"../db/paths.js";import{readDaemonSettingsSync as d}from"./settings.js";const o="weave-daemon",c="HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";export function relaunchArgs(){return[process.execPath,...process.execArgv.map(e=>{if(e!=="tsx"&&!e.startsWith("tsx/"))return e;try{return p(import.meta.resolve(e))}catch{return e}}),n.resolve(process.argv[1]??process.argv[0])]}function f(e){return{platform:e.platform??process.platform,dataDir:e.dataDir??l(),home:e.home??m(),run:e.run??((r,t)=>({status:u(r,t,{stdio:"ignore"}).status}))}}function g(e){return e.map(r=>`"${r}"`).join(" ")}function h(e){const r=n.join(e.dataDir,"weave-autostart.vbs");a(e.dataDir,{recursive:!0});const t=g(relaunchArgs());i(r,`' Generated by weave \u2014 daemon auto-start. Do not edit.
2
- CreateObject("WScript.Shell").Run "${t.replace(/"/g,'""')}", 0, False
3
- `),e.run("reg",["add",c,"/v",o,"/t","REG_SZ","/d",`wscript.exe "${r}"`,"/f"])}function y(e){e.run("reg",["delete",c,"/v",o,"/f"]);try{s(n.join(e.dataDir,"weave-autostart.vbs"))}catch{}}function v(e){const r=t=>t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");return`<?xml version="1.0" encoding="UTF-8"?>
1
+ import{spawnSync as u}from"node:child_process";import{fileURLToPath as l}from"node:url";import{mkdirSync as a,writeFileSync as i,unlinkSync as s}from"node:fs";import{homedir as m}from"node:os";import r from"node:path";import{getDataDir as p}from"../db/paths.js";import{readDaemonSettingsSync as f}from"./settings.js";const o="weave-daemon",c="HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";export function relaunchArgs(){return[process.execPath,...process.execArgv.map(t=>{if(t!=="tsx"&&!t.startsWith("tsx/"))return t;try{return l(import.meta.resolve(t))}catch{return t}}),r.resolve(process.argv[1]??process.argv[0])]}function d(t){return{platform:t.platform??process.platform,dataDir:t.dataDir??p(),home:t.home??m(),run:t.run??((e,n)=>({status:u(e,n,{stdio:"ignore"}).status}))}}function h(t){return t.map(e=>`"${e}"`).join(" ")}function y(t){const e=r.join(t.dataDir,"weave-autostart.vbs");a(t.dataDir,{recursive:!0});const n=h(relaunchArgs());i(e,`' Generated by weave \u2014 daemon auto-start. Do not edit.
2
+ CreateObject("WScript.Shell").Run "${n.replace(/"/g,'""')}", 0, False
3
+ `),t.run("reg",["add",c,"/v",o,"/t","REG_SZ","/d",`wscript.exe "${e}"`,"/f"])}function g(t){t.run("reg",["delete",c,"/v",o,"/f"]);try{s(r.join(t.dataDir,"weave-autostart.vbs"))}catch{}}function v(t){const e=n=>n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");return`<?xml version="1.0" encoding="UTF-8"?>
4
4
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5
5
  <plist version="1.0">
6
6
  <dict>
7
7
  <key>Label</key><string>com.weave.daemon</string>
8
8
  <key>ProgramArguments</key>
9
9
  <array>
10
- `+e.map(t=>` <string>${r(t)}</string>`).join(`
10
+ `+t.map(n=>` <string>${e(n)}</string>`).join(`
11
11
  `)+`
12
12
  </array>
13
13
  <key>RunAtLoad</key><true/>
14
14
  </dict>
15
15
  </plist>
16
- `}function w(e){const r=n.join(e.home,"Library","LaunchAgents","com.weave.daemon.plist");a(n.dirname(r),{recursive:!0}),i(r,v(relaunchArgs())),e.run("launchctl",["unload",r]),e.run("launchctl",["load",r])}function D(e){const r=n.join(e.home,"Library","LaunchAgents","com.weave.daemon.plist");e.run("launchctl",["unload",r]);try{s(r)}catch{}}function L(e){return e.map(r=>/[\s"]/.test(r)?`"${r}"`:r).join(" ")}function k(e){const r=n.join(e.home,".config","autostart",`${o}.desktop`);a(n.dirname(r),{recursive:!0}),i(r,["[Desktop Entry]","Type=Application","Name=weave daemon",`Exec=${L(relaunchArgs())}`,"X-GNOME-Autostart-enabled=true",""].join(`
17
- `))}function b(e){try{s(n.join(e.home,".config","autostart",`${o}.desktop`))}catch{}}export function applyLaunchOnLogin(e,r={}){try{const t=f(r);t.platform==="win32"?e?h(t):y(t):t.platform==="darwin"?e?w(t):D(t):e?k(t):b(t)}catch(t){console.error(`[weave] auto-start ${e?"enable":"disable"} failed:`,t)}}export function syncLaunchOnLogin(e={}){const r=d().startup;applyLaunchOnLogin(r?.launchOnLogin??!1,e)}
16
+ `}function w(t){const e=r.join(t.home,"Library","LaunchAgents","com.weave.daemon.plist");a(r.dirname(e),{recursive:!0}),i(e,v(relaunchArgs())),t.run("launchctl",["unload",e]),t.run("launchctl",["load",e])}function L(t){const e=r.join(t.home,"Library","LaunchAgents","com.weave.daemon.plist");t.run("launchctl",["unload",e]);try{s(e)}catch{}}function D(t){return t.map(e=>/[\s"]/.test(e)?`"${e}"`:e).join(" ")}function b(t){const e=r.join(t.home,".config","autostart",`${o}.desktop`);a(r.dirname(e),{recursive:!0}),i(e,["[Desktop Entry]","Type=Application","Name=weave daemon",`Exec=${D(relaunchArgs())}`,"X-GNOME-Autostart-enabled=true",""].join(`
17
+ `))}function k(t){try{s(r.join(t.home,".config","autostart",`${o}.desktop`))}catch{}}export function applyLaunchOnLogin(t,e={}){try{const n=d(e);n.platform==="win32"?t?y(n):g(n):n.platform==="darwin"?t?w(n):L(n):t?b(n):k(n)}catch(n){console.error(`[weave] auto-start ${t?"enable":"disable"} failed:`,n)}}export function syncLaunchOnLogin(t={}){const e=f().startup;applyLaunchOnLogin(e?.launchOnLogin??!1,t)}
@@ -1 +1 @@
1
- import{z as o}from"zod";import{isHarness as f}from"@weavecode/core";import{WEAVE_VERSION as p}from"../version.js";import{readJson as h,sendJson as t}from"./http.js";import{captureSurfaces as u}from"../surfaces.js";const d=o.object({harness:o.string(),enabled:o.boolean()});export async function handleCaptureRoutes(n,s,i,c){if(c!=="/capture")return!1;if(n.method==="GET"){const e=await Promise.all(u().map(async({harness:a,surface:r})=>({harness:a,...await r.readUserCapture()})));return t(s,200,{rows:e}),!0}if(n.method==="PUT"){let e;try{e=d.parse(await h(n))}catch(r){return t(s,400,{error:r instanceof Error?r.message:"Invalid body"}),!0}if(!f(e.harness))return t(s,400,{error:`Unknown harness: ${e.harness}`}),!0;const a=u().find(r=>r.harness===e.harness);if(!a)return t(s,400,{error:`No capture surface for harness: ${e.harness}`}),!0;try{if(e.enabled){await a.surface.installUserCapture({version:p});for(const r of i.projects.list())await a.surface.stripProjectCapture(r.path)}else await a.surface.uninstallUserCapture();i.dataBus?.emit({key:"capture"}),t(s,200,{harness:a.harness,...await a.surface.readUserCapture()})}catch(r){t(s,400,{error:r instanceof Error?r.message:"Capture update failed"})}return!0}return t(s,405,{error:"Method not allowed"}),!0}
1
+ import{z as n}from"zod";import{isHarness as f}from"@weavecode/core";import{WEAVE_VERSION as p}from"../version.js";import{readJson as d,sendJson as s}from"./http.js";import{captureSurfaces as i}from"../surfaces.js";const l=n.object({harness:n.string(),enabled:n.boolean()});export async function handleCaptureRoutes(o,t,u,c){if(c!=="/capture")return!1;if(o.method==="GET"){const e=await Promise.all(i().map(async({harness:a,surface:r})=>({harness:a,...await r.readUserCapture()})));return s(t,200,{rows:e}),!0}if(o.method==="PUT"){let e;try{e=l.parse(await d(o))}catch(r){return s(t,400,{error:r instanceof Error?r.message:"Invalid body"}),!0}if(!f(e.harness))return s(t,400,{error:`Unknown harness: ${e.harness}`}),!0;const a=i().find(r=>r.harness===e.harness);if(!a)return s(t,400,{error:`No capture surface for harness: ${e.harness}`}),!0;try{if(e.enabled){await a.surface.installUserCapture({version:p});for(const r of u.projects.list())await a.surface.stripProjectCapture(r.path)}else await a.surface.uninstallUserCapture();u.dataBus?.emit({key:"capture"}),s(t,200,{harness:a.harness,...await a.surface.readUserCapture()})}catch(r){s(t,400,{error:r instanceof Error?r.message:"Capture update failed"})}return!0}return s(t,405,{error:"Method not allowed"}),!0}
@@ -1 +1 @@
1
- import{readdirSync as u,readFileSync as l}from"node:fs";import{join as c}from"node:path";export function parseClaudeSessionReg(e){let t;try{t=JSON.parse(e)}catch{return null}const n=t;return typeof n?.pid!="number"||!Number.isInteger(n.pid)||n.pid<0||typeof n.sessionId!="string"||!n.sessionId?null:{pid:n.pid,sessionId:n.sessionId}}export function pidAlive(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function p(){const e=process.platform==="win32"?process.env.USERPROFILE:process.env.HOME;return e?c(e,".claude","sessions"):null}export const CLAUDE_REG_GRACE_MS=9e4;export function pidAliveOf(e,t,n=Date.now()){const s=t.get(e.sessionId);if(s!==void 0)return s;if(e.harness!=="claude"||e.lastEventType==="SessionStart"&&(e.eventCount??0)<=1)return null;const r=Date.parse(e.lastSeenAt);return!Number.isFinite(r)||n-r<CLAUDE_REG_GRACE_MS?null:!1}export function claudeLivenessById(e=null){const t=e??p(),n=new Map;if(!t)return n;let s;try{s=u(t)}catch{return n}for(const r of s){if(!/^\d+\.json$/.test(r))continue;let i;try{i=l(c(t,r),"utf8")}catch{continue}const o=parseClaudeSessionReg(i);o&&n.set(o.sessionId,pidAlive(o.pid))}return n}
1
+ import{readdirSync as c,readFileSync as l}from"node:fs";import{join as u}from"node:path";export function parseClaudeSessionReg(e){let t;try{t=JSON.parse(e)}catch{return null}const n=t;return typeof n?.pid!="number"||!Number.isInteger(n.pid)||n.pid<0||typeof n.sessionId!="string"||!n.sessionId?null:{pid:n.pid,sessionId:n.sessionId}}export function pidAlive(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function a(){const e=process.platform==="win32"?process.env.USERPROFILE:process.env.HOME;return e?u(e,".claude","sessions"):null}export const CLAUDE_REG_GRACE_MS=9e4;export function pidAliveOf(e,t,n=Date.now()){const r=t.get(e.sessionId);if(r!==void 0)return r;if(e.harness!=="claude"||e.lastEventType==="SessionStart"&&(e.eventCount??0)<=1)return null;const s=Date.parse(e.lastSeenAt);return!Number.isFinite(s)||n-s<CLAUDE_REG_GRACE_MS?null:!1}export function claudeLivenessById(e=null){const t=e??a(),n=new Map;if(!t)return n;let r;try{r=c(t)}catch{return n}for(const s of r){if(!/^\d+\.json$/.test(s))continue;let o;try{o=l(u(t,s),"utf8")}catch{continue}const i=parseClaudeSessionReg(o);i&&n.set(i.sessionId,pidAlive(i.pid))}return n}
@@ -1,3 +1,3 @@
1
- import{createHmac as d,randomBytes as n,randomInt as m,scryptSync as o,timingSafeEqual as w}from"node:crypto";import{chmodSync as g,existsSync as p,mkdirSync as a,readFileSync as y,renameSync as P,rmSync as k,writeFileSync as c}from"node:fs";import h from"node:path";import{getAuthPath as x,getInitialPasswordPath as v}from"../db/paths.js";export const SESSION_COOKIE="weave_session",LOCAL_TOKEN_HEADER="x-weave-local",SESSION_TTL_MS=720*60*60*1e3;const l=64,O=16,u="abcdefghjkmnpqrstuvwxyz23456789";export function generatePassword(){const s=()=>Array.from({length:4},()=>u[m(u.length)]??"a").join("");return[s(),s(),s(),s()].join("-")}function f(s,t){const e=n(O).toString("hex");return{algo:"scrypt",salt:e,hash:o(s,e,l).toString("hex"),updatedAt:t}}function r(s,t){const e=Buffer.from(s),i=Buffer.from(t);return e.length===i.length&&w(e,i)}export function readCookie(s,t){if(s)for(const e of s.split(";")){const i=e.indexOf("=");if(!(i<0)&&e.slice(0,i).trim()===t)return e.slice(i+1).trim()}}export function sessionCookie(s){return`${SESSION_COOKIE}=${s}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${Math.floor(SESSION_TTL_MS/1e3)}`}export function clearedSessionCookie(){return`${SESSION_COOKIE}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`}function T(s){if(!p(s))return null;try{const t=JSON.parse(y(s,"utf8"));return t?.version!==1||typeof t.sessionSecret!="string"||typeof t.localToken!="string"?null:{version:1,password:t.password??null,sessionSecret:t.sessionSecret,localToken:t.localToken,createdAt:typeof t.createdAt=="string"?t.createdAt:new Date().toISOString()}}catch{return null}}function S(s,t){a(h.dirname(s),{recursive:!0});const e=`${s}.tmp`;c(e,`${JSON.stringify(t,null,2)}
2
- `,{encoding:"utf8",mode:384}),P(e,s);try{g(s,384)}catch{}}export class AuthService{file;authPath;markerPath;now;initialPassword;constructor(t={}){this.authPath=t.authPath??x(),this.markerPath=t.initialPasswordPath??v(),this.now=t.now??Date.now;const e=T(this.authPath);if(e){this.file=e,this.initialPassword=null;return}const i=generatePassword();this.file={version:1,password:f(i,this.nowIso()),sessionSecret:n(32).toString("hex"),localToken:n(24).toString("hex"),createdAt:this.nowIso()},S(this.authPath,this.file),this.writeMarker(i),this.initialPassword=i}isPasswordSet(){return this.file.password!==null}verifyPassword(t){const e=this.file.password;return e?r(o(t,e.salt,l).toString("hex"),e.hash):!1}setPassword(t){this.file={...this.file,password:f(t,this.nowIso()),sessionSecret:n(32).toString("hex")},S(this.authPath,this.file),k(this.markerPath,{force:!0})}getLocalToken(){return this.file.localToken}verifyLocalToken(t){return typeof t=="string"&&t!==""&&r(t,this.file.localToken)}issueSession(){const t=this.now()+SESSION_TTL_MS;return`${t}.${this.sign(t)}`}verifySession(t){if(!t)return!1;const e=t.indexOf(".");if(e<=0)return!1;const i=Number(t.slice(0,e));return!Number.isFinite(i)||i<=this.now()?!1:r(t.slice(e+1),this.sign(i))}isAuthenticated(t){return this.isLocallyTrusted(t)?!0:this.verifySession(readCookie(t.cookie,SESSION_COOKIE))}isLocallyTrusted(t){const e=t[LOCAL_TOKEN_HEADER];return this.verifyLocalToken(typeof e=="string"?e:void 0)}sign(t){return d("sha256",this.file.sessionSecret).update(`weave-session:${t}`).digest("hex")}nowIso(){return new Date(this.now()).toISOString()}writeMarker(t){a(h.dirname(this.markerPath),{recursive:!0}),c(this.markerPath,`${t}
1
+ import{createHmac as d,randomBytes as s,randomInt as m,scryptSync as o,timingSafeEqual as w}from"node:crypto";import{chmodSync as g,existsSync as p,mkdirSync as a,readFileSync as y,renameSync as P,rmSync as x,writeFileSync as c}from"node:fs";import h from"node:path";import{getAuthPath as k,getInitialPasswordPath as A}from"../db/paths.js";export const SESSION_COOKIE="weave_session",LOCAL_TOKEN_HEADER="x-weave-local",SESSION_TTL_MS=720*60*60*1e3;const u=64,T=16,l="abcdefghjkmnpqrstuvwxyz23456789";export function generatePassword(){const r=()=>Array.from({length:4},()=>l[m(l.length)]??"a").join("");return[r(),r(),r(),r()].join("-")}function f(r,t){const e=s(T).toString("hex");return{algo:"scrypt",salt:e,hash:o(r,e,u).toString("hex"),updatedAt:t}}function i(r,t){const e=Buffer.from(r),n=Buffer.from(t);return e.length===n.length&&w(e,n)}export function readCookie(r,t){if(r)for(const e of r.split(";")){const n=e.indexOf("=");if(!(n<0)&&e.slice(0,n).trim()===t)return e.slice(n+1).trim()}}export function sessionCookie(r){return`${SESSION_COOKIE}=${r}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${Math.floor(SESSION_TTL_MS/1e3)}`}export function clearedSessionCookie(){return`${SESSION_COOKIE}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`}function O(r){if(!p(r))return null;try{const t=JSON.parse(y(r,"utf8"));return t?.version!==1||typeof t.sessionSecret!="string"||typeof t.localToken!="string"?null:{version:1,password:t.password??null,sessionSecret:t.sessionSecret,localToken:t.localToken,createdAt:typeof t.createdAt=="string"?t.createdAt:new Date().toISOString()}}catch{return null}}function S(r,t){a(h.dirname(r),{recursive:!0});const e=`${r}.tmp`;c(e,`${JSON.stringify(t,null,2)}
2
+ `,{encoding:"utf8",mode:384}),P(e,r);try{g(r,384)}catch{}}export class AuthService{file;authPath;markerPath;now;initialPassword;constructor(t={}){this.authPath=t.authPath??k(),this.markerPath=t.initialPasswordPath??A(),this.now=t.now??Date.now;const e=O(this.authPath);if(e){this.file=e,this.initialPassword=null;return}const n=generatePassword();this.file={version:1,password:f(n,this.nowIso()),sessionSecret:s(32).toString("hex"),localToken:s(24).toString("hex"),createdAt:this.nowIso()},S(this.authPath,this.file),this.writeMarker(n),this.initialPassword=n}isPasswordSet(){return this.file.password!==null}verifyPassword(t){const e=this.file.password;return e?i(o(t,e.salt,u).toString("hex"),e.hash):!1}setPassword(t){this.file={...this.file,password:f(t,this.nowIso()),sessionSecret:s(32).toString("hex")},S(this.authPath,this.file),x(this.markerPath,{force:!0})}getLocalToken(){return this.file.localToken}verifyLocalToken(t){return typeof t=="string"&&t!==""&&i(t,this.file.localToken)}issueSession(){const t=this.now()+SESSION_TTL_MS;return`${t}.${this.sign(t)}`}verifySession(t){if(!t)return!1;const e=t.indexOf(".");if(e<=0)return!1;const n=Number(t.slice(0,e));return!Number.isFinite(n)||n<=this.now()?!1:i(t.slice(e+1),this.sign(n))}isAuthenticated(t){return this.isLocallyTrusted(t)?!0:this.verifySession(readCookie(t.cookie,SESSION_COOKIE))}isLocallyTrusted(t){const e=t[LOCAL_TOKEN_HEADER];return this.verifyLocalToken(typeof e=="string"?e:void 0)}sign(t){return d("sha256",this.file.sessionSecret).update(`weave-session:${t}`).digest("hex")}nowIso(){return new Date(this.now()).toISOString()}writeMarker(t){a(h.dirname(this.markerPath),{recursive:!0}),c(this.markerPath,`${t}
3
3
  `,{encoding:"utf8",mode:384})}}
@@ -1 +1 @@
1
- import{EventEmitter as s}from"node:events";export class DataBus{emitter=new s;subscribers=0;constructor(){this.emitter.setMaxListeners(100)}emit(t){this.emitter.emit("change",t)}hasSubscribers(){return this.subscribers>0}subscribe(t){return this.subscribers+=1,this.emitter.on("change",t),()=>{this.subscribers-=1,this.emitter.off("change",t)}}}
1
+ import{EventEmitter as t}from"node:events";export class DataBus{emitter=new t;subscribers=0;constructor(){this.emitter.setMaxListeners(100)}emit(s){this.emitter.emit("change",s)}hasSubscribers(){return this.subscribers>0}subscribe(s){return this.subscribers+=1,this.emitter.on("change",s),()=>{this.subscribers-=1,this.emitter.off("change",s)}}}
@@ -1 +1 @@
1
- import Z from"node:http";import{openDatabase as ee}from"../db/db.js";import{ProjectRepository as se}from"../repositories/projects.js";import{HookEventRepository as oe}from"../repositories/hook-events.js";import{LibraryRepository as te}from"../repositories/libraries.js";import{HookRuleRepository as W}from"../repositories/hook-rules.js";import{HookDispatchRepository as re}from"../repositories/hook-dispatches.js";import{PluginStateRepository as b}from"../repositories/plugin-states.js";import{SessionRepository as ie}from"../repositories/sessions.js";import{createRuntimeRegistry as ne}from"@weavecode/harness";import{HookRuleRegistry as ae}from"../hooks/registry.js";import{HookDispatcher as le}from"../hooks/dispatcher.js";import{HookEventBus as pe}from"../hooks/bus.js";import{ResumeRunner as me}from"../hooks/resume-runner.js";import{HeadlessRunner as ce}from"../hooks/headless-runner.js";import{MessageDeliverer as ue}from"../hooks/message-deliverer.js";import{QuestionTracker as de}from"../hooks/question-tracker.js";import{startPromptFlusher as he}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as fe}from"../repositories/session-watches.js";import{PushSubscriptionRepository as we}from"../repositories/push-subscriptions.js";import{PushNotifier as ge}from"../hooks/push-notify.js";import{SessionSequenceRepository as Se}from"../repositories/session-sequences.js";import{WatchEngine as be}from"../hooks/watch-engine.js";import{SequenceEngine as ve}from"../hooks/sequence-engine.js";import{loadAllPlugins as Re}from"../hooks/plugin-loader.js";import{ensureBuiltinMarket as ke,builtinMarketDir as De}from"../market/builtin.js";import{ToolkitService as Ee}from"../hooks/toolkit.js";import{startSessionSweeper as Pe}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as ye}from"../statusline/cache-sweeper.js";import{WatchService as Ie}from"../watch/watch-service.js";import{weaveRequestHandler as Te}from"./server.js";import{startTlsServer as Ae}from"./tls.js";import{DataBus as Ce}from"./data-bus.js";import{TerminalTopologyRefresher as $e}from"./terminal-topology-refresher.js";import{SnapshotRefresher as G}from"./snapshot-refresher.js";import{SessionProbe as He}from"./session-probe.js";import{InflightCountsRefresher as qe}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as je}from"./project-updates-refresher.js";import{FingerprintCache as Oe}from"../install/fingerprint.js";import{detectProjectUpdateCounts as _e}from"../install/updates.js";import{claudeLivenessById as Le,pidAliveOf as Fe}from"./claude-liveness.js";import{promptTerminalChannel as Me,readTerminalCounts as Ne}from"./opener.js";import{wireHookFilePipeline as Be}from"./hook-pipeline.js";import{DEFAULT_PORT as C,DAEMON_HOST as Ue,DEFAULT_BIND_HOST as We,findFreePort as Ge,isPortFree as xe}from"./port.js";import{writeDaemonState as x}from"./state.js";import{readDaemonSettingsSync as $,setDaemonSettingsDb as Qe,DEFAULT_SERVER_SETTINGS as Ve}from"./settings.js";import{AuthService as ze}from"./dashboard-auth.js";import{resolveStaticDir as Je}from"./static.js";const Ke="CLAUDE_CODE_CHILD_SESSION"in process.env;delete process.env.CLAUDE_CODE_CHILD_SESSION;async function Xe(){const m=await xe(C)?C:await Ge(C+1);x({pid:process.pid,port:m,startedAt:new Date().toISOString()});const s=ee();Qe(s);const c=$().server?.bindHost??We,v=$().server?.tlsPort??Ve.tlsPort,R=new ze;R.initialPassword&&console.log(`[dev] initial dashboard password: ${R.initialPassword}`);const i=new se(s),d=new oe(s),p=new te(s),k=ne(),Q=k.byCapability("events").flatMap(e=>e.events??[]),h=new ae(new W(s)),f=new re(s),t=new ie(s),r=new pe;{const e=await ke({libraries:p});e.error?console.error(`[dev] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[dev] builtin market ${e.form==="link"?"linked":"copied"} -> ${De(p.dataDir)}`)}const{loader:a}=await Re({rules:new W(s),registry:h,states:new b(s),bus:r,libraries:p},i.list());{const e=a.list().filter(o=>o.status==="rejected");console.log(`[dev] plugins loaded: ${a.list().length} (rejected: ${e.length})`);for(const o of e)console.log(`[dev] rejected ${o.id}: ${o.error}`)}a.watchRoots();const H={list:()=>a.list(),setPluginEnabled:(e,o)=>a.setPluginEnabled(e,o),reloadAll:()=>a.reloadAll(),rescan:()=>a.rescanRoots(i.list(),p)},V=new Ee({projects:i,states:new b(s),plugins:H,libraries:p}),q=new le({registry:h,dispatches:f,bus:r,projects:i,sessions:t,plugins:a,pluginStates:new b(s)}),D=new ce,z=new me({dispatches:f,sessions:t,projects:i,bus:r,resumeSpec:k.get("claude")?.resume,headless:D}),l=new ue({sessions:t,projects:i,hookEvents:d,bus:r,headless:D,terminal:Me(()=>$().terminal)});he(l);const E=new fe(s),P=new be({watches:E,deliverer:l,sessions:t,bus:r}),j=new we(s),J=new ge({subscriptions:j,sessions:t,bus:r}),y=new Se(s),w=new ve({sequences:y,deliverer:l,sessions:t,bus:r});w.rearm();const g=new de({sessions:t,hookEvents:d,onPending:e=>{r.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});g.seedFromDb();const O=new Ie(i);O.start();const n=new Ce,S=new He,I=new $e(async()=>({counts:await Ne(i.list()),terminals:await l.sessionTerminals()}),n,{shouldRun:()=>n.hasSubscribers(),graceMs:1e4});I.start();const _=new G(()=>{const e=Le(),o={};for(const u of t.listWithCounts()){const U=Fe(u,e);U!==null&&(o[u.sessionId]=U)}return{alive:o}},n,{key:"sessionLiveness",shouldRun:()=>n.hasSubscribers()});_.start();const T=new G(()=>{const e={};for(const o of t.listWithCounts()){if(o.turnOpen!==!0)continue;const u=S.interruptedAt(o.sessionId,o.lastSeenAt);u!==null&&(e[o.sessionId]=u)}return{interrupted:e}},n,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>n.hasSubscribers()});T.start();const K=new qe(()=>l.listInflightCounts(),n,r),X=new Oe,Y=new je(()=>_e(i.list(),p.list(),X),n,r,()=>n.hasSubscribers());Pe({sessions:t,events:d,dispatches:f,deliverer:l,watches:E,sequences:y,watchEngine:P,sequenceEngine:w,questions:g,probe:S}),ye();const L=Be({projects:i,rules:h,sessions:t,bus:r,dispatcher:q,watchEngine:P,sequenceEngine:w,messagePipe:l,questionTracker:g,sessionProbe:S}),A=Je(),F=Te({projects:i,port:m,tlsPort:v,watch:O,hookEvents:d,adapters:Q,harnesses:k,libraries:p,staticDir:A,hookRegistry:h,hookDispatches:f,hookSessions:t,hookBus:r,dataBus:n,terminalRefresher:I,interruptRefresher:T,sessionProbe:S,inflightRefresher:K,updatesRefresher:Y,hookDispatcher:q,hookRunner:z,messageDeliverer:l,questionTracker:g,sessionWatches:E,watchEngine:P,sessionSequences:y,sequenceEngine:w,pushSubscriptions:j,pushNotifier:J,hookPlugins:H,hookMirror:L.mirror,pluginStates:new b(s),toolkit:V,auth:R}),M=Z.createServer(F);let N=null;Ae({port:v,bindHost:c,handler:F}).then(e=>{N=e,e&&console.log(`[dev] weave daemon tls listening on https://${c}:${e.port}`)});const B=()=>{I.stop(),_.stop(),T.stop(),D.killAll(),L.stop(),M.close(),N?.server.close(),process.exit(0)};process.on("SIGTERM",B),process.on("SIGINT",B),M.listen(m,c,()=>{x({pid:process.pid,port:m,startedAt:new Date().toISOString(),host:c,tlsPort:v}),console.log(`[dev] weave daemon listening on http://${c}:${m}`),console.log(`[dev] cli/dashboard local url: http://${Ue}:${m}`),console.log(`[dev] child-session marker stripped: ${Ke}`),console.log(A?`[dev] static: ${A}`:"[dev] static: (web/dist not built \u2014 run pnpm build:web)")})}Xe();
1
+ import oe from"node:http";import{openDatabase as te}from"../db/db.js";import{ProjectRepository as re}from"../repositories/projects.js";import{HookEventRepository as ne}from"../repositories/hook-events.js";import{LibraryRepository as ie}from"../repositories/libraries.js";import{HookRuleRepository as x}from"../repositories/hook-rules.js";import{HookDispatchRepository as ae}from"../repositories/hook-dispatches.js";import{PluginStateRepository as v}from"../repositories/plugin-states.js";import{SessionRepository as le}from"../repositories/sessions.js";import{createRuntimeRegistry as ce}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as pe}from"@weavecode/core";import{HookRuleRegistry as me}from"../hooks/registry.js";import{HookDispatcher as ue}from"../hooks/dispatcher.js";import{HookEventBus as de}from"../hooks/bus.js";import{ResumeRunner as fe}from"../hooks/resume-runner.js";import{HeadlessRunner as he}from"../hooks/headless-runner.js";import{MessageDeliverer as we}from"../hooks/message-deliverer.js";import{QuestionTracker as Se}from"../hooks/question-tracker.js";import{SideQuestionRepository as ge}from"../repositories/side-questions.js";import{claimSideAnswer as ve}from"../hooks/side-questions.js";import{startPromptFlusher as be}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as Re}from"../repositories/session-watches.js";import{PushSubscriptionRepository as ke}from"../repositories/push-subscriptions.js";import{UploadRepository as De}from"../repositories/uploads.js";import{PushNotifier as ye}from"../hooks/push-notify.js";import{SessionSequenceRepository as Ee}from"../repositories/session-sequences.js";import{WatchEngine as Pe}from"../hooks/watch-engine.js";import{SequenceEngine as Ie}from"../hooks/sequence-engine.js";import{loadAllPlugins as Te}from"../hooks/plugin-loader.js";import{ensureBuiltinMarket as Ae,builtinMarketDir as Ce}from"../market/builtin.js";import{ToolkitService as _e}from"../hooks/toolkit.js";import{startSessionSweeper as He}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as $e}from"../statusline/cache-sweeper.js";import{readStatuslineFacts as Oe}from"../statusline/manager.js";import{WatchService as Me}from"../watch/watch-service.js";import{weaveRequestHandler as qe}from"./server.js";import{startTlsServer as Le}from"./tls.js";import{DataBus as Fe}from"./data-bus.js";import{TerminalTopologyRefresher as Ne}from"./terminal-topology-refresher.js";import{SnapshotRefresher as H}from"./snapshot-refresher.js";import{SessionProbe as je,dbTranscriptPathResolver as Ue}from"./session-probe.js";import{InflightCountsRefresher as Be}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as Qe}from"./project-updates-refresher.js";import{FingerprintCache as We}from"../install/fingerprint.js";import{detectProjectUpdateCounts as Ge}from"../install/updates.js";import{claudeLivenessById as Ve,pidAliveOf as xe}from"./claude-liveness.js";import{promptTerminalChannel as Ke,readTerminalCounts as Ye}from"./opener.js";import{wireHookFilePipeline as ze}from"./hook-pipeline.js";import{DEFAULT_PORT as $,DAEMON_HOST as Je,DEFAULT_BIND_HOST as Xe,findFreePort as Ze,isPortFree as es}from"./port.js";import{writeDaemonState as K}from"./state.js";import{readDaemonSettingsSync as O,setDaemonSettingsDb as ss,DEFAULT_SERVER_SETTINGS as os}from"./settings.js";import{AuthService as ts}from"./dashboard-auth.js";import{resolveStaticDir as rs}from"./static.js";const ns="CLAUDE_CODE_CHILD_SESSION"in process.env;delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const l of pe)delete process.env[l];async function is(){const l=await es($)?$:await Ze($+1);K({pid:process.pid,port:l,startedAt:new Date().toISOString()});const o=te();ss(o);const m=O().server?.bindHost??Xe,b=O().server?.tlsPort??os.tlsPort,R=new ts;R.initialPassword&&console.log(`[dev] initial dashboard password: ${R.initialPassword}`);const r=new re(o),u=new ne(o),p=new ie(o),k=ce(),Y=k.byCapability("events").flatMap(e=>e.events??[]),f=new me(new x(o)),h=new ae(o),n=new le(o),t=new de;{const e=await Ae({libraries:p});e.error?console.error(`[dev] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[dev] builtin market ${e.form==="link"?"linked":"copied"} -> ${Ce(p.dataDir)}`)}const{loader:c}=await Te({rules:new x(o),registry:f,states:new v(o),bus:t,libraries:p},r.list());{const e=c.list().filter(s=>s.status==="rejected");console.log(`[dev] plugins loaded: ${c.list().length} (rejected: ${e.length})`);for(const s of e)console.log(`[dev] rejected ${s.id}: ${s.error}`)}c.watchRoots();const M={list:()=>c.list(),setPluginEnabled:(e,s)=>c.setPluginEnabled(e,s),reloadAll:()=>c.reloadAll(),rescan:()=>c.rescanRoots(r.list(),p)},z=new _e({projects:r,states:new v(o),plugins:M,libraries:p}),q=new ue({registry:f,dispatches:h,bus:t,projects:r,sessions:n,plugins:c,pluginStates:new v(o)}),D=new he,J=new fe({dispatches:h,sessions:n,projects:r,bus:t,resumeSpec:k.get("claude")?.resume,headless:D}),a=new we({sessions:n,projects:r,hookEvents:u,bus:t,headless:D,terminal:Ke(()=>O().terminal)});be(a);const y=new Re(o),E=new Pe({watches:y,deliverer:a,sessions:n,bus:t}),L=new ke(o),P=new De(o),X=new ye({subscriptions:L,sessions:n,bus:t}),I=new Ee(o),w=new Ie({sequences:I,deliverer:a,sessions:n,bus:t});w.rearm();const S=new Se({sessions:n,hookEvents:u,onPending:e=>{t.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});S.seedFromDb();const F=new ge(o),N={repo:F,bus:t},j=new Me(r);j.start();const i=new Fe,g=new je(Ue(u)),T=new Ne(async()=>({counts:await Ye(r.list()),terminals:await a.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});T.start();const A=new H(()=>{const e=Ve(),s={};for(const d of n.listWithCounts()){const V=xe(d,e);V!==null&&(s[d.sessionId]=V)}return{alive:s}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});A.start();const C=new H(()=>{const e={};for(const s of n.listWithCounts()){if(s.turnOpen!==!0)continue;const d=g.interruptedAt(s.sessionId,s.lastSeenAt);d!==null&&(e[s.sessionId]=d)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});C.start(),new H(()=>{const e={};for(const s of r.list())e[s.id]=Oe(s.path);return e},i,{key:"statusline",intervalMs:5e3,shouldRun:()=>i.hasSubscribers(),invalidateOnly:!0}).start();const Z=new Be(()=>a.listInflightCounts(),i,t),ee=new We,se=new Qe(()=>Ge(r.list(),p.list(),ee),i,t,()=>i.hasSubscribers());He({sessions:n,events:u,dispatches:h,deliverer:a,watches:y,sequences:I,watchEngine:E,sequenceEngine:w,questions:S,sideQuestions:F,probe:g,uploads:P}),$e();const U=ze({projects:r,rules:f,sessions:n,bus:t,dispatcher:q,watchEngine:E,sequenceEngine:w,messagePipe:a,questionTracker:S,sideQuestions:{onEvent:e=>{const s=ve(N,e);s&&a.interrupt(s.sessionId)}},sessionProbe:g,uploads:P}),_=rs(),B=qe({projects:r,port:l,tlsPort:b,watch:j,hookEvents:u,adapters:Y,harnesses:k,libraries:p,staticDir:_,hookRegistry:f,hookDispatches:h,hookSessions:n,hookBus:t,dataBus:i,terminalRefresher:T,interruptRefresher:C,livenessRefresher:A,sessionProbe:g,inflightRefresher:Z,updatesRefresher:se,hookDispatcher:q,hookRunner:J,messageDeliverer:a,uploads:P,questionTracker:S,sideQuestions:N,sessionWatches:y,watchEngine:E,sessionSequences:I,sequenceEngine:w,pushSubscriptions:L,pushNotifier:X,hookPlugins:M,hookMirror:U.mirror,pluginStates:new v(o),toolkit:z,auth:R}),Q=oe.createServer(B);let W=null;Le({port:b,bindHost:m,handler:B}).then(e=>{W=e,e&&console.log(`[dev] weave daemon tls listening on https://${m}:${e.port}`)});const G=()=>{T.stop(),A.stop(),C.stop(),D.killAll(),U.stop(),Q.close(),W?.server.close(),process.exit(0)};process.on("SIGTERM",G),process.on("SIGINT",G),Q.listen(l,m,()=>{K({pid:process.pid,port:l,startedAt:new Date().toISOString(),host:m,tlsPort:b}),console.log(`[dev] weave daemon listening on http://${m}:${l}`),console.log(`[dev] cli/dashboard local url: http://${Je}:${l}`),console.log(`[dev] child-session marker stripped: ${ns}`),console.log(_?`[dev] static: ${_}`:"[dev] static: (web/dist not built \u2014 run pnpm build:web)")})}is();
@@ -1 +1 @@
1
- import{readdir as p,stat as u}from"node:fs/promises";import f from"node:os";import s from"node:path";function d(n,r){return new Promise((t,o)=>{const a=setTimeout(()=>o(new Error("timeout")),r);n.then(i=>{clearTimeout(a),t(i)},i=>{clearTimeout(a),o(i)})})}let c=null;const w=5*6e4;async function h(){if(c&&Date.now()-c.at<w)return c.drives;const n="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),r=(await Promise.all(n.map(async t=>{const o=`${t}:\\`;try{return await d(u(o),4e3),o}catch{return null}}))).filter(t=>t!==null);return c={at:Date.now(),drives:r},r}export async function listBrowseRoots(n){const r=[],t=new Set,o=(e,m)=>{t.has(e)||(t.add(e),r.push({path:e,kind:m}))},a=f.homedir();o(a,"home");const i=[["Desktop","desktop"],["Downloads","downloads"],["Documents","documents"]];for(const[e,m]of i){const l=s.join(a,e);try{await u(l),o(l,m)}catch{}}for(const e of n)typeof e=="string"&&e&&o(s.dirname(e),"library-parent");if(process.platform==="win32")for(const e of await h())o(e,"drive");else o(s.parse(a).root,"root");return r}export async function listDirectoryChildren(n){const r=(await p(n,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>({name:t.name,path:s.join(n,t.name)}));return r.sort((t,o)=>t.name.localeCompare(o.name,void 0,{numeric:!0})),r}
1
+ import{readdir as d,stat as l}from"node:fs/promises";import p from"node:os";import a from"node:path";function f(n,s){return new Promise((r,t)=>{const e=setTimeout(()=>t(new Error("timeout")),s);n.then(i=>{clearTimeout(e),r(i)},i=>{clearTimeout(e),t(i)})})}let c=null;const h=5*6e4;async function w(){if(c&&Date.now()-c.at<h)return c.drives;const n="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),r=(await Promise.all(n.map(async t=>{const e=`${t}:\\`;try{return await f(l(e),4e3),e}catch{return null}}))).filter(t=>t!==null);return c={at:Date.now(),drives:r},r}export async function listBrowseRoots(n){const s=[],r=new Set,t=(o,m)=>{r.has(o)||(r.add(o),s.push({path:o,kind:m}))},e=p.homedir();t(e,"home");const i=[["Desktop","desktop"],["Downloads","downloads"],["Documents","documents"]];for(const[o,m]of i){const u=a.join(e,o);try{await l(u),t(u,m)}catch{}}for(const o of n)typeof o=="string"&&o&&t(a.dirname(o),"library-parent");if(process.platform==="win32")for(const o of await w())t(o,"drive");else t(a.parse(e).root,"root");return s}export async function listDirectoryChildren(n){const r=(await d(n,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>({name:t.name,path:a.join(n,t.name)}));return r.sort((t,e)=>t.name.localeCompare(e.name,void 0,{numeric:!0})),r}
@@ -5,6 +5,7 @@ import type { SequenceEngine } from '../hooks/sequence-engine.js';
5
5
  import { MirrorWriter } from '../hooks/mirror.js';
6
6
  import type { MessageDeliverer } from '../hooks/message-deliverer.js';
7
7
  import type { QuestionTracker } from '../hooks/question-tracker.js';
8
+ import type { SideQuestionEvent } from '../hooks/side-questions.js';
8
9
  import type { HookRuleRegistry } from '../hooks/registry.js';
9
10
  import type { ProjectRepository } from '../repositories/projects.js';
10
11
  import type { SessionRepository } from '../repositories/sessions.js';
@@ -22,9 +23,20 @@ export interface HookPipelineDeps {
22
23
  messagePipe?: Pick<MessageDeliverer, 'hasQueued' | 'flushSession'>;
23
24
  /** 阻塞式问答跟踪(AskUserQuestion/计划/权限确认):ingest 事件派生待答面。 */
24
25
  questionTracker?: Pick<QuestionTracker, 'onEvent'>;
25
- /** 会话转录路径上报(中断态探测;同 pane env 口径)。 */
26
+ /** 旁路会话回答认领(claude = /btw):同透传(判据归 harness 能力面)。 */
27
+ sideQuestions?: {
28
+ onEvent(input: SideQuestionEvent): void;
29
+ };
30
+ /** 会话转录路径上报(中断态探测;同 pane env 口径)+ 换模型落定(`PostModelSwitch`)+ 推理档位。 */
26
31
  sessionProbe?: {
27
32
  noteTranscript(sessionId: string, path: string | null): void;
33
+ noteModel(sessionId: string, model: string): void;
34
+ sessionStarted(sessionId: string, model: string | null): void;
35
+ noteEffort(sessionId: string, level: string): void;
36
+ };
37
+ /** 上传件落库面:回执命中时把消息的随附图挂到开轮事件(对话气泡缩略图)。 */
38
+ uploads?: {
39
+ linkToEvent(eventId: number, uploadIds: readonly string[]): void;
28
40
  };
29
41
  }
30
42
  /** 删除一个项目的全部管道文件(忽略不存在)。删项目路由落地时一行调用。 */
@@ -1 +1 @@
1
- import{readdirSync as u,unlinkSync as c}from"node:fs";import{join as a}from"node:path";import{getDbPath as f}from"../db/paths.js";import{MirrorWriter as m,hookShardId as p,hooksRoot as b,mirrorPathOf as k,outboxPathOf as g}from"../hooks/mirror.js";import{promptboxPathOf as x}from"../hooks/promptbox.js";import{startInboxWorker as d,handleIngestedRecords as P,unparkFailedInbox as j,INBOX_CLAIM_SUFFIX as l,INBOX_FAILED_SUFFIX as h}from"../hooks/inbox-worker.js";function $(o,r){return[a(o,"inbox",`${r}.jsonl`),a(o,"inbox",`${r}${l}`),a(o,"inbox",`${r}${h}`),k(o,r),g(o,r),x(o,r)]}export function purgeProjectPipeline(o,r){for(const s of $(o,p(r)))try{c(s)}catch{}}function w(o){return(o.endsWith(".tmp")?o.slice(0,-4):o).replace(new RegExp(`(${l}|${h})$`),"").replace(/\.(jsonl|json)$/,"")}const I=/^[0-9a-f]{16}$/;export function purgeOrphanPipelineFiles(o){const r=new Set(o.projects.list().map(e=>p(e.token)));let s=0;for(const e of["inbox","mirror","outbox","promptbox"]){let n;try{n=u(a(o.hooksDir,e))}catch{continue}for(const t of n){const i=w(t);if(!(!I.test(i)||r.has(i)))try{c(a(o.hooksDir,e,t)),s++}catch{}}}return s}export function wireHookFilePipeline(o){const r=b(),s=purgeOrphanPipelineFiles({projects:o.projects,hooksDir:r});s>0&&console.log(`[weave] hook pipeline: purged ${s} orphan file(s)`);const e=j(r);e>0&&console.log(`[weave] hook pipeline: revived ${e} parked inbox file(s)`);const n=new m({projects:o.projects,rules:o.rules,sessions:o.sessions});o.rules.onChange=()=>n.syncAll(),n.attachToBus(o.bus),n.syncAll();const t=d({dbPath:f(),hooksDir:r});return t.on("message",i=>{P({projects:o.projects,hooksDir:r,bus:o.bus,dispatcher:o.dispatcher,watchEngine:o.watchEngine,sequenceEngine:o.sequenceEngine,messagePipe:o.messagePipe,questionTracker:o.questionTracker,sessionProbe:o.sessionProbe},i)}),t.on("error",i=>console.error("[weave] inbox worker failed:",i)),{mirror:n,stop:()=>t.terminate().then(()=>{})}}
1
+ import{readdirSync as f,unlinkSync as a}from"node:fs";import{join as c}from"node:path";import{getDbPath as m}from"../db/paths.js";import{MirrorWriter as b,hookShardId as l,hooksRoot as h,mirrorPathOf as g,outboxPathOf as x}from"../hooks/mirror.js";import{promptboxPathOf as P}from"../hooks/promptbox.js";import{startInboxWorker as j,handleIngestedRecords as k,unparkFailedInbox as $,INBOX_CLAIM_SUFFIX as u,INBOX_FAILED_SUFFIX as p}from"../hooks/inbox-worker.js";function w(e,o){return[c(e,"inbox",`${o}.jsonl`),c(e,"inbox",`${o}${u}`),c(e,"inbox",`${o}${p}`),g(e,o),x(e,o),P(e,o)]}export function purgeProjectPipeline(e,o){for(const n of w(e,l(o)))try{a(n)}catch{}}function F(e){return(e.endsWith(".tmp")?e.slice(0,-4):e).replace(new RegExp(`(${u}|${p})$`),"").replace(/\.(jsonl|json)$/,"")}const v=/^[0-9a-f]{16}$/;export function purgeOrphanPipelineFiles(e){const o=new Set(e.projects.list().map(r=>l(r.token)));let n=0;for(const r of["inbox","mirror","outbox","promptbox"]){let t;try{t=f(c(e.hooksDir,r))}catch{continue}for(const i of t){const s=F(i);if(!(!v.test(s)||o.has(s)))try{a(c(e.hooksDir,r,i)),n++}catch{}}}return n}export function wireHookFilePipeline(e){const o=h(),n=purgeOrphanPipelineFiles({projects:e.projects,hooksDir:o});n>0&&console.log(`[weave] hook pipeline: purged ${n} orphan file(s)`);const r=$(o);r>0&&console.log(`[weave] hook pipeline: revived ${r} parked inbox file(s)`);const t=new b({projects:e.projects,rules:e.rules,sessions:e.sessions});e.rules.onChange=()=>t.syncAll(),t.attachToBus(e.bus),t.syncAll();const i=j({dbPath:m(),hooksDir:o});return i.on("message",s=>{k({projects:e.projects,hooksDir:o,bus:e.bus,dispatcher:e.dispatcher,watchEngine:e.watchEngine,sequenceEngine:e.sequenceEngine,messagePipe:e.messagePipe,questionTracker:e.questionTracker,sideQuestions:e.sideQuestions,sessionProbe:e.sessionProbe,uploads:e.uploads},s)}),i.on("error",s=>console.error("[weave] inbox worker failed:",s)),{mirror:t,stop:()=>i.terminate().then(()=>{})}}
@@ -1 +1 @@
1
- import{stat as x}from"node:fs/promises";import{z as a}from"zod";import{HookRuleFilterSchema as N,HookRuleSourceSchema as G,HandlerConfigSchema as F,HookDispatchStatusSchema as L,isHarness as v}from"@weavecode/core";import{readJson as g,sendJson as s}from"./http.js";import{installPlugin as K,uninstallPlugin as _}from"../hooks/plugin-installer.js";import{purgeSession as Q}from"../hooks/session-purge.js";import{composeAnswerAtoms as z}from"../hooks/answer-keys.js";import{effective as J,setProjectEnabled as V}from"../hooks/plugin-project-state.js";import{readDaemonSettings as X}from"./settings.js";import{defaultProjectOpener as Y,terminalBackendFor as Z}from"./opener.js";import{claudeLivenessById as ee,pidAliveOf as se}from"./claude-liveness.js";import{messagingSurfaceFor as w,messagingSurfaces as oe}from"../surfaces.js";import{DEFAULT_WATCH_ON as ne}from"../repositories/session-watches.js";import{SEQUENCE_HOP_LIMIT as U}from"../hooks/sequence-engine.js";const M=a.object({name:a.string().min(1),enabled:a.boolean().optional(),priority:a.number().int().optional(),projectId:a.number().int().nullable(),source:G,filter:N.optional(),handler:F,timeoutMs:a.number().int().positive().optional(),record:a.boolean().optional()}),te=M.partial(),re=a.object({enabled:a.boolean()}),ie=a.object({enabled:a.boolean(),projectId:a.number().int().optional()}),ae=a.object({title:a.string().min(1).max(200)}),ue=a.object({sessionId:a.string().min(1)}),le=a.object({text:a.string().min(1).max(2e4),fromKind:a.enum(["dashboard","session"]).optional(),fromSessionId:a.string().min(1).nullable().optional()}),ce=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)}),de=a.object({watcherSessionId:a.string().min(1).nullable().optional(),notify:a.string().min(1).max(2e4).nullable().optional(),on:a.array(a.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:a.number().int().min(1).max(100).nullable().optional()}),me=a.object({watchId:a.number().int().positive()}),he=a.object({endpoint:a.string().url(),keys:a.object({p256dh:a.string().min(1),auth:a.string().min(1)})}),ge=a.object({endpoint:a.string().url()}),pe=a.object({name:a.string().max(200).optional(),steps:a.array(a.object({to:a.string().min(1),text:a.string().min(1).max(2e4),mode:a.enum(["prompt","inject","headless","auto"]).optional()})).min(1)}),fe=a.object({src:a.string().min(1)});function E(r,e){return r.prompt!==null||e}export async function handleHooksRoutes(r,e,o,l,k){if(!(l.startsWith("/hooks/")||l==="/sessions"||l.startsWith("/sessions/")||l.startsWith("/messaging")))return!1;if(l==="/hooks/rules"){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;if(r.method==="GET"){const n=k.searchParams.get("projectId"),t=n!=null&&n!==""?Number(n):void 0;return s(e,200,{rules:o.hookRegistry.list(t)}),!0}if(r.method==="POST"){try{const n=M.parse(await g(r)),t=o.hookRegistry.create(n);s(e,201,{rule:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}}const P=l.match(/^\/hooks\/rules\/([^/]+)$/);if(P){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(P[1]);if(r.method==="PUT"){try{const t=te.parse(await g(r)),i=o.hookRegistry.update(n,t);if(!i)return s(e,404,{error:"Rule not found"}),!0;s(e,200,{rule:i})}catch(t){s(e,400,{error:t instanceof Error?t.message:"Invalid rule body"})}return!0}if(r.method==="DELETE")return o.hookRegistry.remove(n)?(s(e,200,{ok:!0}),!0):(s(e,404,{error:"Rule not found"}),!0)}const T=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(T&&r.method==="POST"){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const n=re.parse(await g(r)),t=o.hookRegistry.setEnabled(decodeURIComponent(T[1]),n.enabled);if(!t)return s(e,404,{error:"Rule not found"}),!0;s(e,200,{rule:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(r.method==="GET"){const n=k.searchParams.get("projectId");if(n==null||n==="")return s(e,200,{plugins:o.hookPlugins?.list()??[]}),!0;const t=o.projects.getById(Number(n));if(!t)return s(e,404,{error:"Project not found"}),!0;if(!o.pluginStates)return s(e,503,{error:"Plugin states unavailable"}),!0;const i=o.pluginStates;return s(e,200,{plugins:(o.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const d=J(t,u.id,{states:i})?"active":"disabled";return d===u.status?u:{...u,status:d}})}),!0}if(r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=fe.parse(await g(r)),t=await K(n.src);await o.hookPlugins.reloadAll(),s(e,201,t)}catch(n){s(e,400,{error:n instanceof Error?n.message:"Install failed"})}return!0}}const j=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(j&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;const n=decodeURIComponent(j[1]);return await _(n)?(await o.hookPlugins.reloadAll(),s(e,200,{ok:!0}),!0):(s(e,404,{error:"Plugin directory not found"}),!0)}if(l==="/hooks/plugins/rescan"&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{await o.hookPlugins.rescan(),s(e,200,{ok:!0,plugins:o.hookPlugins.list().length})}catch(n){s(e,500,{error:n instanceof Error?n.message:"Rescan failed"})}return!0}const R=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(R&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=ie.parse(await g(r)),t=decodeURIComponent(R[1]);if(n.projectId!==void 0){const i=o.projects.getById(n.projectId);return i?o.hookPlugins.list().some(u=>u.id===t)?(V(i,t,n.enabled,{projects:o.projects}),s(e,200,{ok:!0}),!0):(s(e,404,{error:"Plugin not found"}),!0):(s(e,404,{error:"Project not found"}),!0)}if(!o.hookPlugins.setPluginEnabled(t,n.enabled))return s(e,404,{error:"Plugin not found"}),!0;s(e,200,{ok:!0})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&r.method==="GET"){if(!o.hookDispatches)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=k.searchParams.get("ruleId")??void 0,t=k.searchParams.get("status"),i=t?L.parse(t):void 0,u=k.searchParams.get("sessionId")??void 0,d=k.searchParams.get("limit"),c=d?Number(d):void 0;return s(e,200,{dispatches:o.hookDispatches.list({ruleId:n,status:i,sessionId:u,limit:Number.isFinite(c)?c:void 0})}),!0}const q=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(q&&r.method==="POST"){if(!o.hookRunner)return s(e,503,{error:"Resume runner unavailable"}),!0;let n;try{n=ue.parse(await g(r)).sessionId}catch(i){return s(e,400,{error:i instanceof Error?i.message:"Invalid body"}),!0}const t=await o.hookRunner.run(Number(q[1]),n);return t.ok?s(e,200,{ok:!0,dispatchId:t.dispatchId}):s(e,t.status,{error:t.error}),!0}if(l==="/sessions"&&r.method==="GET"){if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=k.searchParams.get("projectId"),t=n!=null&&n!==""?Number(n):void 0,i=o.hookSessions.listWithCounts(t),u=ee(),d=o.terminalRefresher?.lastSnapshot?.terminals??{};return s(e,200,{sessions:i.map(c=>({...c,pidAlive:se(c,u),terminal:d[c.sessionId]??null,interruptedAt:c.turnOpen===!0?o.sessionProbe?.interruptedAt(c.sessionId,c.lastSeenAt)??null:null}))}),!0}const y=l.match(/^\/sessions\/([^/]+)$/);if(y&&r.method==="PATCH"){if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(y[1]);if(!o.hookSessions.getBySessionId(n))return s(e,404,{error:"Session not found"}),!0;try{const t=ae.parse(await g(r)),i=o.hookSessions.setPendingTitle(n,t.title);i?.projectId!=null&&o.hookMirror?.syncProject(i.projectId),s(e,200,{session:i})}catch(t){s(e,400,{error:t instanceof Error?t.message:"Invalid body"})}return!0}if(y&&r.method==="DELETE"){if(!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(y[1]),t=o.hookSessions.getBySessionId(n);if(!t)return s(e,404,{error:"Session not found"}),!0;const i=Q({sessions:o.hookSessions,events:o.hookEvents,dispatches:o.hookDispatches,deliverer:o.messageDeliverer,watches:o.sessionWatches,questions:o.questionTracker,probe:o.sessionProbe},n);return t.projectId!=null&&o.hookMirror?.syncProject(t.projectId),s(e,200,{ok:!0,sessionId:n,...i}),!0}const $=l.match(/^\/sessions\/([^/]+)\/open-terminal$/);if($&&r.method==="POST"){const n=decodeURIComponent($[1]);if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const t=o.hookSessions.getBySessionId(n);if(!t)return s(e,404,{error:"Session not found"}),!0;if(!o.hookEvents)return s(e,503,{error:"Hook ingestion unavailable"}),!0;const i=o.hookEvents.listBySession(n,1),u=i[i.length-1]?.source;if(!v(u))return s(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=o.harnesses?.get(u)?.resume;if(!d?.supported||!d.openArgs)return s(e,501,{error:`Harness "${u}" does not support interactive resume`}),!0;if(!t.projectId)return s(e,400,{error:"Session is not bound to a project"}),!0;const c=o.projects.getById(t.projectId);if(!c)return s(e,404,{error:"Project not found"}),!0;const p=o.opener??Y;let h;if(r.method==="POST")try{const m=await g(r);typeof m?.target=="string"&&m.target&&(h=m.target)}catch{}try{if(!(await x(c.path)).isDirectory())throw new Error(`Not a directory: ${c.path}`);const m=await X(),b=[d.bin,...d.openArgs(n)];if(h){if(!Z(m.terminal).enumerable)throw new Error(`Terminal preset "${m.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const f=p.runInTerminalAt;if(!f)throw new Error("Targeted attach is unavailable");await f(c.path,b,h,m.terminal)}else await p.runInTerminal(c.path,b,m.terminal);setTimeout(()=>{o.terminalRefresher?.refreshNow()},600),s(e,200,{ok:!0,sessionId:n,command:b.join(" "),cwd:c.path,...h?{target:h}:{}})}catch(m){s(e,400,{error:m instanceof Error?m.message:"Open failed"})}return!0}const D=l.match(/^\/sessions\/([^/]+)\/messages$/);if(D){const n=decodeURIComponent(D[1]);if(r.method==="GET")return o.messageDeliverer?o.hookSessions?.getBySessionId(n)?(s(e,200,{messages:o.messageDeliverer.listVisible(n)}),!0):(s(e,404,{error:"Session not found"}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(r.method==="POST"){if(!o.messageDeliverer||!o.hookSessions)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=le.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const i=await o.messageDeliverer.send({toSessionId:n,text:t.text,mode:"prompt",fromKind:t.fromKind??"dashboard",fromSessionId:t.fromSessionId??null,oneWay:!0});return i.ok?s(e,201,{ok:!0,messageId:i.messageId,status:i.status,message:i.message}):s(e,i.status,{error:i.error}),!0}}const H=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/resend$/);if(H&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=await o.messageDeliverer.resend(decodeURIComponent(H[2]));return n.ok?s(e,200,{ok:!0,messageId:n.messageId,status:n.status,message:n.message}):s(e,n.status,{error:n.error}),!0}const I=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/dismiss$/);if(I&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=o.messageDeliverer.dismiss(decodeURIComponent(I[1]),decodeURIComponent(I[2]));return n.ok?s(e,200,{ok:!0}):s(e,n.status,{error:n.error}),!0}if(l==="/messaging/questions"&&r.method==="GET")return o.questionTracker?(s(e,200,{questions:o.questionTracker.snapshot()}),!0):(s(e,503,{error:"Question tracking unavailable"}),!0);const O=l.match(/^\/sessions\/([^/]+)\/answer$/);if(O&&r.method==="POST"){if(!o.questionTracker||!o.messageDeliverer)return s(e,503,{error:"Question tracking unavailable"}),!0;const n=decodeURIComponent(O[1]);let t;try{t=ce.parse(await g(r))}catch(c){return s(e,400,{error:c instanceof Error?c.message:"Invalid body"}),!0}const i=o.questionTracker.get(n);if(!i)return s(e,409,{error:"Session has no pending question"}),!0;const u=z(i.questions,t.answers);if(!u.ok)return s(e,400,{error:u.error}),!0;const d=await o.messageDeliverer.answer(n,u.atoms);return d.ok?(o.questionTracker.markAnswered(n),s(e,200,{ok:!0,sessionId:n}),!0):(s(e,d.status,{error:d.error}),!0)}const B=l.match(/^\/sessions\/([^/]+)\/interrupt$/);if(B&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(B[1]),t=await o.messageDeliverer.interrupt(n);return t.ok?(setTimeout(()=>o.interruptRefresher?.tick(),1500),s(e,200,{ok:!0,sessionId:n}),!0):(s(e,t.status,{error:t.error}),!0)}const C=l.match(/^\/sessions\/([^/]+)\/watch$/);if(C){const n=decodeURIComponent(C[1]);if(r.method==="POST"){if(!o.sessionWatches||!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=de.parse(await g(r))}catch(f){return s(e,400,{error:f instanceof Error?f.message:"Invalid body"}),!0}if(!o.hookSessions.getBySessionId(n))return s(e,404,{error:"Session not found"}),!0;const i=o.hookEvents.listBySession(n,1),u=i[i.length-1]?.source;if(!v(u))return s(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=w(u),c=t.on??[...ne];if((c.includes("idle")||c.includes("turnEnd"))&&d.idleSignals.length===0)return s(e,409,{error:d.unsupportedReasons?.watch??`Harness "${u}" does not support idle watching`}),!0;if(c.includes("messageFailed")&&!(E(d,o.messageDeliverer?.hasTerminalChannel()??!1)||d.inject!==null||d.headless!==null))return s(e,409,{error:d.unsupportedReasons?.prompt??`Harness "${u}" supports no messaging channel`}),!0;if(t.watcherSessionId){if(!o.hookSessions.getBySessionId(t.watcherSessionId))return s(e,404,{error:"Watcher session not found"}),!0;const f=o.hookEvents.listBySession(t.watcherSessionId,1),S=f[f.length-1]?.source;if(!v(S))return s(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const A=w(S);if(!A.inject)return s(e,409,{error:A.unsupportedReasons?.inject??`Harness "${S}" cannot receive watch notifications`}),!0}const p=t.times===void 0?1:t.times,h=(t.watcherSessionId??null)===null?o.sessionWatches.listPendingByTarget(n).find(f=>f.watcherSessionId===null):void 0,m=h?o.sessionWatches.updateById(h.id,{onEvents:c,remaining:p}):void 0,b=m??o.sessionWatches.insert({watcherSessionId:t.watcherSessionId??null,targetSessionId:n,notify:t.notify??null,onEvents:c,times:p});return o.watchEngine?.created(b),s(e,m?200:201,{ok:!0,watchId:b.id,watch:b}),!0}if(r.method==="DELETE"){if(!o.sessionWatches)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=me.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const i=o.sessionWatches.getById(t.watchId);return!i||i.targetSessionId!==n||i.firedAt!==null?(s(e,404,{error:"Watch not found"}),!0):(o.sessionWatches.deleteById(t.watchId),s(e,200,{ok:!0,watchId:t.watchId}),!0)}}if(l==="/messaging/watches"&&r.method==="GET")return o.sessionWatches?(s(e,200,{watches:o.sessionWatches.listPending()}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(l==="/messaging/push/key"&&r.method==="GET")return o.pushNotifier?(s(e,200,{publicKey:o.pushNotifier.publicKey()}),!0):(s(e,503,{error:"Push subsystem unavailable"}),!0);if(l==="/messaging/push/subscribe"&&r.method==="POST"){if(!o.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=he.parse(await g(r)),t=o.pushSubscriptions.upsert({endpoint:n.endpoint,p256dh:n.keys.p256dh,auth:n.keys.auth,userAgent:r.headers["user-agent"]??null});s(e,201,{ok:!0,subscription:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/messaging/push/unsubscribe"&&r.method==="POST"){if(!o.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=ge.parse(await g(r));o.pushSubscriptions.deleteByEndpoint(n.endpoint),s(e,200,{ok:!0})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/messaging/sequences"){if(r.method==="GET")return o.sessionSequences?(s(e,200,{sequences:o.sessionSequences.list()}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(r.method==="POST"){if(!o.sessionSequences||!o.sequenceEngine||!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=pe.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(n.steps.length>U)return s(e,400,{error:`Sequences are capped at ${U} steps (hop limit)`}),!0;const t=o.messageDeliverer?.hasTerminalChannel()??!1;for(let u=0;u<n.steps.length;u++){const d=n.steps[u];if(!o.hookSessions.getBySessionId(d.to))return s(e,404,{error:`Step ${u+1}: session not found`}),!0;const c=o.hookEvents.listBySession(d.to,1),p=c[c.length-1]?.source;if(!v(p))return s(e,400,{error:`Step ${u+1}: session has no hook events to determine its harness`}),!0;const h=w(p),m=d.mode??"auto";if(!(m==="prompt"?E(h,t):m==="inject"?h.inject!==null:m==="headless"?h.headless!==null:h.inject!==null||h.headless!==null)){const b=m==="auto"?h.unsupportedReasons?.inject??`Harness "${p}" supports no messaging channel`:h.unsupportedReasons?.[m]??`Harness "${p}" does not support the ${m} channel`;return s(e,409,{error:`Step ${u+1}: ${b}`}),!0}}const i=o.sessionSequences.insert({name:n.name??"",steps:n.steps.map(u=>({...u,mode:u.mode??"auto"}))});return await o.sequenceEngine.trigger(i),s(e,201,{ok:!0,sequence:o.sessionSequences.getById(i.id)??i}),!0}}const W=l.match(/^\/messaging\/sequences\/(\d+)$/);if(W&&r.method==="DELETE"){if(!o.sessionSequences)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=o.sessionSequences.getById(Number(W[1]));return n?n.status!=="running"?(s(e,409,{error:`Sequence already ${n.status}`}),!0):(o.sequenceEngine?o.sequenceEngine.cancel(n.id):o.sessionSequences.finish(n.id,"cancelled"),s(e,200,{ok:!0,sequenceId:n.id}),!0):(s(e,404,{error:"Sequence not found"}),!0)}if(l==="/messaging/capabilities"&&r.method==="GET"){const n=o.messageDeliverer?.hasTerminalChannel()??!1;return s(e,200,{capabilities:oe().map(({harness:t,surface:i})=>({harness:t,discovery:i.discovery,prompt:E(i,n),inject:i.inject!==null,headless:i.headless!==null,watch:i.idleSignals.length>0,unsupportedReasons:i.unsupportedReasons??null}))}),!0}return!1}
1
+ import{readFileSync as ee}from"node:fs";import{stat as te}from"node:fs/promises";import{z as a}from"zod";import{HARNESS_SESSION_CONTROL as re,HookRuleFilterSchema as ne,HookRuleSourceSchema as oe,HandlerConfigSchema as se,HookDispatchStatusSchema as ie,isHarness as S}from"@weavecode/core";import{aliasOfModel as ae,modelAliasTargets as ue}from"@weavecode/harness";import{readJson as k,sendJson as r}from"./http.js";import{installPlugin as le,uninstallPlugin as ce}from"../hooks/plugin-installer.js";import{purgeSession as me}from"../hooks/session-purge.js";import{composeAnswerAtoms as de}from"../hooks/answer-keys.js";import{effective as he,setProjectEnabled as fe}from"../hooks/plugin-project-state.js";import{readDaemonSettings as ge,readDaemonSettingsSync as be,readHooksEnabled as ye}from"./settings.js";import{defaultProjectOpener as pe,terminalBackendFor as ke}from"./opener.js";import{claudeLivenessById as z,pidAliveOf as J}from"./claude-liveness.js";import{blockingPromptFor as Ie,captureSurfaces as Se,messagingSurfaceFor as E,messagingSurfaces as ve}from"../surfaces.js";import{getDataDir as we}from"../db/paths.js";import{UPLOAD_MAX_BYTES as Pe,UPLOAD_MEDIA_TYPES as Ee}from"../repositories/uploads.js";import{WEAVE_VERSION as Te}from"../version.js";import{DEFAULT_WATCH_ON as je}from"../repositories/session-watches.js";import{SEQUENCE_HOP_LIMIT as V}from"../hooks/sequence-engine.js";import{readSideQuestions as Re}from"../hooks/side-questions.js";function X(s,e){return s!==!1?s:e===!0?!1:null}const Y=20,Me=2e5;function De(s){try{const e=JSON.parse(s);return[typeof e.toolName=="string"?e.toolName:null,e.toolInput??null,e.toolResponse??null]}catch{return[null,null,null]}}function Z(s){if(!s)return null;try{const e=ee(s,"utf8");return e.trim()?e:null}catch{return null}}const q=a.object({name:a.string().min(1),enabled:a.boolean().optional(),priority:a.number().int().optional(),projectId:a.number().int().nullable(),source:oe,filter:ne.optional(),handler:se,timeoutMs:a.number().int().positive().optional(),record:a.boolean().optional()}),Oe=q.partial(),Be=a.object({enabled:a.boolean()}),Ce=a.object({enabled:a.boolean(),projectId:a.number().int().optional()}),Ae=a.object({title:a.string().min(1).max(200)}),$e=a.object({question:a.string().min(1).max(4e3)}),xe=a.object({sessionId:a.string().min(1)}),He=a.object({text:a.string().max(2e4),fromKind:a.enum(["dashboard","session"]).optional(),fromSessionId:a.string().min(1).nullable().optional(),images:a.array(a.string().regex(/^[a-f0-9]{64}$/)).max(8).optional(),forceTerminal:a.boolean().optional()}),Ue=a.object({name:a.string().min(1).max(200),mediaType:a.enum(Ee),data:a.string().min(1)});function Ne(s){return{id:s.id,name:s.name,mediaType:s.mediaType,size:s.size}}const We=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)}),_e=a.object({watcherSessionId:a.string().min(1).nullable().optional(),notify:a.string().min(1).max(2e4).nullable().optional(),on:a.array(a.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:a.number().int().min(1).max(100).nullable().optional()}),Qe=a.object({watchId:a.number().int().positive()}),Fe=a.object({model:a.string().min(1).max(128)}),Ge=a.object({endpoint:a.string().url(),keys:a.object({p256dh:a.string().min(1),auth:a.string().min(1)})}),Le=a.object({endpoint:a.string().url()}),Ke=a.object({name:a.string().max(200).optional(),steps:a.array(a.object({to:a.string().min(1),text:a.string().min(1).max(2e4),mode:a.enum(["prompt","inject","headless","auto"]).optional()})).min(1)}),ze=a.object({src:a.string().min(1)});function T(s,e){return s.prompt!==null||e}function Je(s){const{diag:e,capture:t,eventCount:c}=s,f=[];return!t||t.source==="none"||!t.present?f.push("no-hook-script"):t.weaveOwned?t.reportsInbox||f.push("hook-script-stale"):f.push("hook-script-not-weave"),c===0&&f.push("no-events"),e&&(e.alive===!1&&f.push("not-running"),e.inbox.reason==="no-credentials"&&t?.reportsInbox===!0&&f.push("no-inbox-credentials"),e.inbox.reason==="auth-token-required"&&f.push("inbox-token-required"),e.relay.reason==="no-peer-name"&&f.push("no-peer-name"),e.terminal.reason==="no-backend"&&f.push("terminal-no-backend"),e.terminal.reason==="no-pane-env"&&f.push("terminal-no-pane-env"),e.pending>0&&f.push("queued"),e.stalled&&f.push("stalled")),f}export async function handleHooksRoutes(s,e,t,c,f){if(!(c.startsWith("/hooks/")||c==="/sessions"||c.startsWith("/sessions/")||c.startsWith("/messaging")||c==="/uploads"||c.startsWith("/images/")))return!1;if(c==="/hooks/rules"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;if(s.method==="GET"){const n=f.searchParams.get("projectId"),o=n!=null&&n!==""?Number(n):void 0;return r(e,200,{rules:t.hookRegistry.list(o)}),!0}if(s.method==="POST"){try{const n=q.parse(await k(s)),o=t.hookRegistry.create(n);r(e,201,{rule:o})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}}const j=c.match(/^\/hooks\/rules\/([^/]+)$/);if(j){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(j[1]);if(s.method==="PUT"){try{const o=Oe.parse(await k(s)),i=t.hookRegistry.update(n,o);if(!i)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:i})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid rule body"})}return!0}if(s.method==="DELETE")return t.hookRegistry.remove(n)?(r(e,200,{ok:!0}),!0):(r(e,404,{error:"Rule not found"}),!0)}const R=c.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(R&&s.method==="POST"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const n=Be.parse(await k(s)),o=t.hookRegistry.setEnabled(decodeURIComponent(R[1]),n.enabled);if(!o)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:o})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(c==="/hooks/plugins"){if(s.method==="GET"){const n=f.searchParams.get("projectId");if(n==null||n==="")return r(e,200,{plugins:t.hookPlugins?.list()??[]}),!0;const o=t.projects.getById(Number(n));if(!o)return r(e,404,{error:"Project not found"}),!0;if(!t.pluginStates)return r(e,503,{error:"Plugin states unavailable"}),!0;const i=t.pluginStates;return r(e,200,{plugins:(t.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const m=he(o,u.id,{states:i})?"active":"disabled";return m===u.status?u:{...u,status:m}})}),!0}if(s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=ze.parse(await k(s)),o=await le(n.src);await t.hookPlugins.reloadAll(),r(e,201,o)}catch(n){r(e,400,{error:n instanceof Error?n.message:"Install failed"})}return!0}}const M=c.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(M&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;const n=decodeURIComponent(M[1]);return await ce(n)?(await t.hookPlugins.reloadAll(),r(e,200,{ok:!0}),!0):(r(e,404,{error:"Plugin directory not found"}),!0)}if(c==="/hooks/plugins/rescan"&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{await t.hookPlugins.rescan(),r(e,200,{ok:!0,plugins:t.hookPlugins.list().length})}catch(n){r(e,500,{error:n instanceof Error?n.message:"Rescan failed"})}return!0}const D=c.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(D&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=Ce.parse(await k(s)),o=decodeURIComponent(D[1]);if(n.projectId!==void 0){const u=t.projects.getById(n.projectId);return u?t.hookPlugins.list().some(m=>m.id===o)?(fe(u,o,n.enabled,{projects:t.projects}),r(e,200,{ok:!0}),!0):(r(e,404,{error:"Plugin not found"}),!0):(r(e,404,{error:"Project not found"}),!0)}if(!t.hookPlugins.setPluginEnabled(o,n.enabled))return r(e,404,{error:"Plugin not found"}),!0;r(e,200,{ok:!0})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(c==="/hooks/dispatches"&&s.method==="GET"){if(!t.hookDispatches)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=f.searchParams.get("ruleId")??void 0,o=f.searchParams.get("status"),i=o?ie.parse(o):void 0,u=f.searchParams.get("sessionId")??void 0,m=f.searchParams.get("limit"),d=m?Number(m):void 0;return r(e,200,{dispatches:t.hookDispatches.list({ruleId:n,status:i,sessionId:u,limit:Number.isFinite(d)?d:void 0})}),!0}const O=c.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(O&&s.method==="POST"){if(!t.hookRunner)return r(e,503,{error:"Resume runner unavailable"}),!0;let n;try{n=xe.parse(await k(s)).sessionId}catch(i){return r(e,400,{error:i instanceof Error?i.message:"Invalid body"}),!0}const o=await t.hookRunner.run(Number(O[1]),n);return o.ok?r(e,200,{ok:!0,dispatchId:o.dispatchId}):r(e,o.status,{error:o.error}),!0}if(c==="/sessions"&&s.method==="GET"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=f.searchParams.get("projectId"),o=n!=null&&n!==""?Number(n):void 0,i=t.hookSessions.listWithCounts(o),u=z(),m=t.terminalRefresher?.lastSnapshot?.terminals??{},d={};for(const h of i){const y=h.harness??"";y in d||(d[y]=ue(re[h.harness]?.modelNames??[]))}return r(e,200,{sessions:i.map(h=>{const y=t.sessionProbe?.currentModel(h.sessionId)??null,b=t.sessionProbe?.transcriptPresent(h.sessionId)??null,l=S(h.harness)?t.harnesses?.get(h.harness)?.resume:void 0;return{...h,pidAlive:J(h,u),canOpenTerminal:!!(l?.supported&&l.openArgs),terminal:m[h.sessionId]??null,interruptedAt:h.turnOpen===!0?t.sessionProbe?.interruptedAt(h.sessionId,h.lastSeenAt)??null:null,model:y,modelAlias:ae(d[h.harness??""]??[],y),mode:t.sessionProbe?.currentMode(h.sessionId)??null,effort:t.sessionProbe?.currentEffort(h.sessionId)??null,transcriptPresent:X(b,h.hasRun)}}),modelCatalog:d}),!0}const w=c.match(/^\/sessions\/([^/]+)$/);if(w&&s.method==="PATCH"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(w[1]);if(!t.hookSessions.getBySessionId(n))return r(e,404,{error:"Session not found"}),!0;try{const o=Ae.parse(await k(s)),i=t.hookSessions.setPendingTitle(n,o.title);i?.projectId!=null&&t.hookMirror?.syncProject(i.projectId),r(e,200,{session:i})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(w&&s.method==="DELETE"){if(!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(w[1]),o=t.hookSessions.getBySessionId(n);if(!o)return r(e,404,{error:"Session not found"}),!0;const i=me({sessions:t.hookSessions,events:t.hookEvents,dispatches:t.hookDispatches,deliverer:t.messageDeliverer,watches:t.sessionWatches,sequences:t.sessionSequences,questions:t.questionTracker,sideQuestions:t.sideQuestions?.repo,probe:t.sessionProbe,uploads:t.uploads},n);return o.projectId!=null&&t.hookMirror?.syncProject(o.projectId),r(e,200,{ok:!0,sessionId:n,...i}),!0}const B=c.match(/^\/sessions\/([^/]+)\/open-terminal$/);if(B&&s.method==="POST"){const n=decodeURIComponent(B[1]);if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=t.hookSessions.getBySessionId(n);if(!o)return r(e,404,{error:"Session not found"}),!0;if(!t.hookEvents)return r(e,503,{error:"Hook ingestion unavailable"}),!0;const i=t.hookEvents.listBySession(n,1),u=i[i.length-1]?.source;if(!S(u))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const m=t.harnesses?.get(u)?.resume;if(!m?.supported||!m.openArgs)return r(e,501,{error:`Harness "${u}" does not support interactive resume`}),!0;if(!o.projectId)return r(e,400,{error:"Session is not bound to a project"}),!0;const d=t.projects.getById(o.projectId);if(!d)return r(e,404,{error:"Project not found"}),!0;const h=t.sessionProbe?.transcriptPresent(n)??null;if(X(h,t.hookSessions.hasRunOf(n))===!1)return r(e,409,{error:"Session transcript is missing \u2014 nothing to resume"}),!0;const y=t.opener??pe;let b;if(s.method==="POST")try{const l=await k(s);typeof l?.target=="string"&&l.target&&(b=l.target)}catch{}try{if(!(await te(d.path)).isDirectory())throw new Error(`Not a directory: ${d.path}`);const g=await ge(),p=[m.bin,...m.openArgs(n)];if(b){if(!ke(g.terminal).enumerable)throw new Error(`Terminal preset "${g.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const I=y.runInTerminalAt;if(!I)throw new Error("Targeted attach is unavailable");await I(d.path,p,b,g.terminal)}else await y.runInTerminal(d.path,p,g.terminal);setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:n,command:p.join(" "),cwd:d.path,...b?{target:b}:{}})}catch(l){r(e,400,{error:l instanceof Error?l.message:"Open failed"})}return!0}if(c==="/uploads"&&s.method==="POST"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;let n;try{n=Ue.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const o=Buffer.from(n.data,"base64");if(o.length===0)return r(e,400,{error:"Empty image"}),!0;if(o.length>Pe)return r(e,413,{error:"Image too large"}),!0;const i=t.uploads.save({name:n.name,mediaType:n.mediaType,bytes:o});return r(e,201,{upload:Ne(i)}),!0}const C=c.match(/^\/images\/([a-f0-9]{64})$/);if(C&&s.method==="GET"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;const n=t.uploads.fileOf(C[1]);return n?(e.writeHead(200,{"content-type":n.row.mediaType,"content-length":String(n.bytes.length),"cache-control":"private, max-age=31536000, immutable"}),e.end(n.bytes),!0):(r(e,404,{error:"Image not found"}),!0)}const A=c.match(/^\/sessions\/([^/]+)\/messages$/);if(A){const n=decodeURIComponent(A[1]);if(s.method==="GET")return t.messageDeliverer?t.hookSessions?.getBySessionId(n)?(r(e,200,{messages:t.messageDeliverer.listVisible(n)}),!0):(r(e,404,{error:"Session not found"}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(s.method==="POST"){if(!t.messageDeliverer||!t.hookSessions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=He.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const i=o.images??[];if(!o.text.trim()&&i.length===0)return r(e,400,{error:"Message is empty"}),!0;let u=[];if(i.length>0){const d=t.uploads?.refsOf(i)??null;if(!d)return r(e,404,{error:"Image not found"}),!0;u=d}const m=await t.messageDeliverer.send({toSessionId:n,text:o.text,...u.length>0?{images:u}:{},...o.forceTerminal===!0?{forceTerminal:!0}:{},mode:"prompt",fromKind:o.fromKind??"dashboard",fromSessionId:o.fromSessionId??null,oneWay:!0});return m.ok?r(e,201,{ok:!0,messageId:m.messageId,status:m.status,message:m.message}):r(e,m.status,{error:m.error}),!0}}const $=c.match(/^\/sessions\/([^/]+)\/plan$/);if($&&s.method==="GET"){const n=decodeURIComponent($[1]);if(!t.hookEvents)return r(e,503,{error:"Hook ingestion unavailable"}),!0;const o=t.hookEvents.listBySession(n,1),i=o[o.length-1]?.source,u=S(i)?Ie(i)?.plan??null:null;if(!u)return r(e,200,{plan:null}),!0;const m=b=>b.flatMap(l=>{const g=u.draftOf(...De(l.payload));return g?[{row:l,draft:g}]:[]}),[d]=m(t.hookEvents.listByTools(n,[u.tool],null,Y));if(!d)return r(e,200,{plan:null}),!0;const[h]=m(t.hookEvents.listByTools(n,u.writeTools,u.fileHint,Y)).filter(b=>b.row.id<d.row.id),y=d.draft.text??Z(d.draft.filePath)??h?.draft.text??Z(h?.draft.filePath??null);return y?(r(e,200,{plan:{eventId:d.row.id,at:d.row.createdAt,text:y.slice(0,Me)}}),!0):(r(e,200,{plan:null}),!0)}const x=c.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/resend$/);if(x&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=await t.messageDeliverer.resend(decodeURIComponent(x[2]));return n.ok?r(e,200,{ok:!0,messageId:n.messageId,status:n.status,message:n.message}):r(e,n.status,{error:n.error}),!0}const P=c.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/dismiss$/);if(P&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=t.messageDeliverer.dismiss(decodeURIComponent(P[1]),decodeURIComponent(P[2]));return n.ok?r(e,200,{ok:!0}):r(e,n.status,{error:n.error}),!0}if(c==="/messaging/questions"&&s.method==="GET")return t.questionTracker?(r(e,200,{questions:t.questionTracker.snapshot()}),!0):(r(e,503,{error:"Question tracking unavailable"}),!0);const H=c.match(/^\/sessions\/([^/]+)\/answer$/);if(H&&s.method==="POST"){if(!t.questionTracker||!t.messageDeliverer)return r(e,503,{error:"Question tracking unavailable"}),!0;const n=decodeURIComponent(H[1]);let o;try{o=We.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const i=t.questionTracker.get(n);if(!i)return r(e,409,{error:"Session has no pending question"}),!0;const u=de(i.questions,o.answers);if(!u.ok)return r(e,400,{error:u.error}),!0;const m=await t.messageDeliverer.answer(n,u.atoms);return m.ok?(t.questionTracker.markAnswered(n),r(e,200,{ok:!0,sessionId:n}),!0):(r(e,m.status,{error:m.error}),!0)}const U=c.match(/^\/sessions\/([^/]+)\/interrupt$/);if(U&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(U[1]),o=await t.messageDeliverer.interrupt(n);return o.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:n}),!0):(r(e,o.status,{error:o.error}),!0)}const N=c.match(/^\/sessions\/([^/]+)\/close-pane$/);if(N&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(N[1]),o=await t.messageDeliverer.closePane(n);return o.ok?(setTimeout(()=>{t.livenessRefresher?.tick(),t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:n}),!0):(r(e,o.status,{error:o.error}),!0)}const W=c.match(/^\/sessions\/([^/]+)\/mode$/);if(W&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(W[1]),o=await t.messageDeliverer.cycleMode(n);return o.ok?(r(e,200,{ok:!0,sessionId:n}),!0):(r(e,o.status,{error:o.error}),!0)}const _=c.match(/^\/sessions\/([^/]+)\/model$/);if(_&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(_[1]),o=Fe.parse(await k(s)),i=await t.messageDeliverer.setModel(n,o.model);return i.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:n}),!0):(r(e,i.status,{error:i.error}),!0)}const Q=c.match(/^\/sessions\/([^/]+)\/side-question$/);if(Q&&s.method==="POST"){if(!t.messageDeliverer||!t.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(Q[1]);let o;try{o=$e.parse(await k(s))}catch(m){return r(e,400,{error:m instanceof Error?m.message:"Invalid body"}),!0}const i=await t.messageDeliverer.askSideQuestion(n,o.question);if(!i.ok)return r(e,i.status,{error:i.error}),!0;const u=t.sideQuestions.repo.insert({sessionId:n,projectId:t.hookSessions?.getBySessionId(n)?.projectId??null,question:i.question});return r(e,200,{ok:!0,sideQuestion:u}),!0}const F=c.match(/^\/sessions\/([^/]+)\/side-questions$/);if(F&&s.method==="GET"){if(!t.sideQuestions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(F[1]),o=Number(f.searchParams.get("limit")),i=Number(f.searchParams.get("beforeId")),u=Re(t.sideQuestions,n,{limit:Number.isFinite(o)&&o>0?Math.min(o,100):20,beforeId:Number.isFinite(i)&&i>0?i:void 0});return r(e,200,{sideQuestions:u}),!0}const G=c.match(/^\/sessions\/([^/]+)\/watch$/);if(G){const n=decodeURIComponent(G[1]);if(s.method==="POST"){if(!t.sessionWatches||!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=_e.parse(await k(s))}catch(p){return r(e,400,{error:p instanceof Error?p.message:"Invalid body"}),!0}if(!t.hookSessions.getBySessionId(n))return r(e,404,{error:"Session not found"}),!0;const u=t.hookEvents.listBySession(n,1),m=u[u.length-1]?.source;if(!S(m))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=E(m),h=o.on??[...je];if((h.includes("idle")||h.includes("turnEnd"))&&d.idleSignals.length===0)return r(e,409,{error:d.unsupportedReasons?.watch??`Harness "${m}" does not support idle watching`}),!0;if(h.includes("messageFailed")&&!(T(d,t.messageDeliverer?.hasTerminalChannel()??!1)||d.inject!==null||d.headless!==null))return r(e,409,{error:d.unsupportedReasons?.prompt??`Harness "${m}" supports no messaging channel`}),!0;if(o.watcherSessionId){if(!t.hookSessions.getBySessionId(o.watcherSessionId))return r(e,404,{error:"Watcher session not found"}),!0;const I=t.hookEvents.listBySession(o.watcherSessionId,1),v=I[I.length-1]?.source;if(!S(v))return r(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const K=E(v);if(!K.inject)return r(e,409,{error:K.unsupportedReasons?.inject??`Harness "${v}" cannot receive watch notifications`}),!0}const y=o.times===void 0?1:o.times,b=(o.watcherSessionId??null)===null?t.sessionWatches.listPendingByTarget(n).find(p=>p.watcherSessionId===null):void 0,l=b?t.sessionWatches.updateById(b.id,{onEvents:h,remaining:y}):void 0,g=l??t.sessionWatches.insert({watcherSessionId:o.watcherSessionId??null,targetSessionId:n,notify:o.notify??null,onEvents:h,times:y});return t.watchEngine?.created(g),r(e,l?200:201,{ok:!0,watchId:g.id,watch:g}),!0}if(s.method==="DELETE"){if(!t.sessionWatches)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=Qe.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const i=t.sessionWatches.getById(o.watchId);return!i||i.targetSessionId!==n||i.firedAt!==null?(r(e,404,{error:"Watch not found"}),!0):(t.sessionWatches.deleteById(o.watchId),r(e,200,{ok:!0,watchId:o.watchId}),!0)}}if(c==="/messaging/watches"&&s.method==="GET")return t.sessionWatches?(r(e,200,{watches:t.sessionWatches.listPending()}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(c==="/messaging/push/key"&&s.method==="GET")return t.pushNotifier?(r(e,200,{publicKey:t.pushNotifier.publicKey()}),!0):(r(e,503,{error:"Push subsystem unavailable"}),!0);if(c==="/messaging/push/subscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=Ge.parse(await k(s)),o=t.pushSubscriptions.upsert({endpoint:n.endpoint,p256dh:n.keys.p256dh,auth:n.keys.auth,userAgent:s.headers["user-agent"]??null});r(e,201,{ok:!0,subscription:o})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(c==="/messaging/push/unsubscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=Le.parse(await k(s));t.pushSubscriptions.deleteByEndpoint(n.endpoint),r(e,200,{ok:!0})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(c==="/messaging/sequences"){if(s.method==="GET")return t.sessionSequences?(r(e,200,{sequences:t.sessionSequences.list()}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(s.method==="POST"){if(!t.sessionSequences||!t.sequenceEngine||!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=Ke.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(n.steps.length>V)return r(e,400,{error:`Sequences are capped at ${V} steps (hop limit)`}),!0;const o=t.messageDeliverer?.hasTerminalChannel()??!1;for(let u=0;u<n.steps.length;u++){const m=n.steps[u];if(!t.hookSessions.getBySessionId(m.to))return r(e,404,{error:`Step ${u+1}: session not found`}),!0;const h=t.hookEvents.listBySession(m.to,1),y=h[h.length-1]?.source;if(!S(y))return r(e,400,{error:`Step ${u+1}: session has no hook events to determine its harness`}),!0;const b=E(y),l=m.mode??"auto";if(!(l==="prompt"?T(b,o):l==="inject"?b.inject!==null:l==="headless"?b.headless!==null:b.inject!==null||b.headless!==null)){const p=l==="auto"?b.unsupportedReasons?.inject??`Harness "${y}" supports no messaging channel`:b.unsupportedReasons?.[l]??`Harness "${y}" does not support the ${l} channel`;return r(e,409,{error:`Step ${u+1}: ${p}`}),!0}}const i=t.sessionSequences.insert({name:n.name??"",steps:n.steps.map(u=>({...u,mode:u.mode??"auto"}))});return await t.sequenceEngine.trigger(i),r(e,201,{ok:!0,sequence:t.sessionSequences.getById(i.id)??i}),!0}}const L=c.match(/^\/messaging\/sequences\/(\d+)$/);if(L&&s.method==="DELETE"){if(!t.sessionSequences)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=t.sessionSequences.getById(Number(L[1]));return n?n.status!=="running"?(r(e,409,{error:`Sequence already ${n.status}`}),!0):(t.sequenceEngine?t.sequenceEngine.cancel(n.id):t.sessionSequences.finish(n.id,"cancelled"),r(e,200,{ok:!0,sequenceId:n.id}),!0):(r(e,404,{error:"Sequence not found"}),!0)}if(c==="/messaging/capabilities"&&s.method==="GET"){const n=t.messageDeliverer?.hasTerminalChannel()??!1;return r(e,200,{capabilities:ve().map(({harness:o,surface:i})=>({harness:o,discovery:i.discovery,prompt:T(i,n),inject:i.inject!==null,headless:i.headless!==null,watch:i.idleSignals.length>0,imageAttach:i.imageAttach!==null,sideQuestion:i.sideQuestion!==null,unsupportedReasons:i.unsupportedReasons??null}))}),!0}if(c==="/messaging/diagnostics"&&s.method==="GET"){if(!t.messageDeliverer||!t.hookSessions)return r(e,503,{error:"Message subsystem unavailable"}),!0;const n=f.searchParams.get("session"),o=f.searchParams.get("project"),i=Se(),u=t.projects.list(),m=await Promise.all(u.map(async l=>({id:l.id,name:l.name,path:l.path,captures:await Promise.all(i.map(async({harness:g,surface:p})=>({harness:g,...await p.scriptHealth({projectPath:l.path})})))}))),d=(l,g)=>m.find(p=>p.id===l)?.captures.find(p=>p.harness===g)??null,h=z(),b=t.hookSessions.listWithCounts(n?void 0:o?Number(o):void 0).filter(l=>n?l.sessionId===n:J(l,h)!==!1).map(l=>{const g=t.messageDeliverer.diagnose(l.sessionId),p=d(l.projectId,l.harness??null),I={inbox:g.inbox,relay:g.relay,terminal:g.terminal};return{sessionId:l.sessionId,projectId:l.projectId,harness:l.harness??null,title:l.title,lastSeenAt:l.lastSeenAt,eventCount:l.eventCount??0,lastEventType:l.lastEventType??null,alive:g.alive,paneEnvReported:g.paneEnvReported,channels:I,queue:{pending:g.pending,stalled:g.stalled},reachable:Object.values(I).some(v=>v.status==="ready"),hints:Je({diag:g,capture:p,eventCount:l.eventCount??0})}});return r(e,200,{daemon:{version:Te,platform:process.platform,dataDir:we(),uptimeMs:Math.round(process.uptime()*1e3),terminalPreset:be().terminal.preset,terminalTextChannel:t.messageDeliverer.hasTerminalChannel(),hooksEnabled:ye()},projects:m,sessions:b}),!0}return!1}
@@ -1 +1 @@
1
- export function readBody(t){return new Promise((e,n)=>{const o=[];t.on("data",r=>o.push(r)),t.on("end",()=>e(Buffer.concat(o).toString("utf8"))),t.on("error",n)})}export async function readJson(t){return JSON.parse(await readBody(t))}export function sendJson(t,e,n){t.statusCode=e,t.setHeader("content-type","application/json"),t.end(JSON.stringify(n))}
1
+ import{noteRequestBody as s}from"./api-log.js";export function readBody(n){return new Promise((o,e)=>{const r=[];n.on("data",t=>r.push(t)),n.on("end",()=>{const t=Buffer.concat(r).toString("utf8");s(n,t),o(t)}),n.on("error",e)})}export async function readJson(n){return JSON.parse(await readBody(n))}export function sendJson(n,o,e){n.statusCode=o,n.setHeader("content-type","application/json"),n.end(JSON.stringify(e))}