@weavecode/weave 0.1.0 → 0.1.1

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 (273) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +4 -4
  2. package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
  3. package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
  4. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
  6. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
  7. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  9. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  10. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  11. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  12. package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +5 -3
  14. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -1
  15. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -4
  16. package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
  17. package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
  18. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  19. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  20. package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
  21. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  22. package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
  23. package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
  24. package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
  25. package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
  26. package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
  27. package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
  28. package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
  29. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  30. package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
  31. package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
  32. package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
  33. package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
  34. package/node_modules/@weavecode/cli/dist/parser.js +1 -1
  35. package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
  36. package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
  37. package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
  38. package/node_modules/@weavecode/cli/package.json +5 -5
  39. package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
  40. package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
  41. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  42. package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
  43. package/node_modules/@weavecode/core/dist/index.js +1 -1
  44. package/node_modules/@weavecode/core/dist/platform.js +1 -1
  45. package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
  46. package/node_modules/@weavecode/core/dist/terminal.js +1 -1
  47. package/node_modules/@weavecode/core/dist/types.d.ts +188 -11
  48. package/node_modules/@weavecode/core/dist/types.js +1 -1
  49. package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
  50. package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
  51. package/node_modules/@weavecode/core/package.json +1 -1
  52. package/node_modules/@weavecode/harness/dist/claude/assets.js +1 -1
  53. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +11 -1
  54. package/node_modules/@weavecode/harness/dist/claude/capture.js +5 -5
  55. package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
  56. package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
  57. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  58. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
  59. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
  60. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +5 -1
  61. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  62. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
  63. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
  64. package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
  65. package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
  66. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +25 -0
  67. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
  68. package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
  69. package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
  70. package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
  71. package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
  72. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
  73. package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
  74. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
  75. package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
  76. package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
  77. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  78. package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
  79. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
  81. package/node_modules/@weavecode/harness/dist/codex/toml.js +9 -9
  82. package/node_modules/@weavecode/harness/dist/driver.d.ts +58 -1
  83. package/node_modules/@weavecode/harness/dist/driver.js +1 -1
  84. package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
  85. package/node_modules/@weavecode/harness/dist/index.js +1 -1
  86. package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
  87. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
  88. package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
  89. package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
  90. package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
  91. package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
  92. package/node_modules/@weavecode/harness/package.json +2 -2
  93. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  94. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  95. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  96. package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
  97. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
  98. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  99. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  100. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  101. package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
  102. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  103. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  104. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  105. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  106. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +6 -1
  107. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  110. package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
  111. package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
  112. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  114. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
  115. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +8 -0
  117. package/node_modules/@weavecode/server/dist/daemon/server.js +6 -6
  118. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +59 -2
  119. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
  121. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  122. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  124. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  125. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
  126. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  128. package/node_modules/@weavecode/server/dist/db/db.js +20 -2
  129. package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
  130. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  131. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  132. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  133. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  134. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  135. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  136. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
  137. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
  138. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +20 -6
  139. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  140. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  141. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +171 -13
  142. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
  143. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  144. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  145. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  146. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  147. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  148. package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
  149. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  150. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  151. package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
  152. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  153. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  154. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  155. package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
  156. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +4 -0
  157. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  158. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
  159. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
  160. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  161. package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
  162. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  163. package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
  164. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  165. package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
  166. package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
  167. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  168. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  169. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  170. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  171. package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
  172. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  173. package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
  174. package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
  175. package/node_modules/@weavecode/server/dist/install/global-config.js +2 -2
  176. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  177. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
  178. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
  179. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  180. package/node_modules/@weavecode/server/dist/install/installer.js +3 -3
  181. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  182. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  183. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  184. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  185. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  186. package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
  187. package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
  188. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  189. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  190. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  191. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  192. package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
  193. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  194. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  195. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  196. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  197. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  198. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  199. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  200. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  201. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  202. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  203. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  204. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  205. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  206. package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
  207. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  208. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  209. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  210. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +17 -4
  211. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  212. package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
  213. package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
  214. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  215. package/node_modules/@weavecode/server/dist/statusline/generator.js +81 -40
  216. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +2 -0
  217. package/node_modules/@weavecode/server/dist/statusline/manager.js +4 -4
  218. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  219. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  220. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  221. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  222. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
  223. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  224. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  225. package/node_modules/@weavecode/server/package.json +4 -4
  226. package/node_modules/@weavecode/server/web/dist/assets/index-D5WFh77i.css +11 -0
  227. package/node_modules/@weavecode/server/web/dist/assets/index-DJibaGnJ.js +585 -0
  228. package/node_modules/@weavecode/server/web/dist/index.html +14 -2
  229. package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
  230. package/node_modules/@weavecode/templates/package.json +2 -2
  231. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
  232. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
  233. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
  234. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
  235. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
  236. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
  237. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
  238. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
  239. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
  240. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
  241. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
  242. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
  243. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
  244. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
  245. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
  246. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
  247. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
  248. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
  249. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
  250. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
  251. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
  252. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
  253. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
  254. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
  255. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
  256. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
  257. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
  258. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
  259. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
  260. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
  261. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
  262. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
  263. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
  264. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
  265. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
  266. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
  267. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
  268. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
  269. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
  270. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
  271. package/package.json +6 -6
  272. package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
  273. package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
@@ -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 ee from"node:http";import{openDatabase as se}from"../db/db.js";import{ProjectRepository as oe}from"../repositories/projects.js";import{HookEventRepository as te}from"../repositories/hook-events.js";import{LibraryRepository as re}from"../repositories/libraries.js";import{HookRuleRepository as G}from"../repositories/hook-rules.js";import{HookDispatchRepository as ne}from"../repositories/hook-dispatches.js";import{PluginStateRepository as v}from"../repositories/plugin-states.js";import{SessionRepository as ie}from"../repositories/sessions.js";import{createRuntimeRegistry as ae}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as le}from"@weavecode/core";import{HookRuleRegistry as ce}from"../hooks/registry.js";import{HookDispatcher as pe}from"../hooks/dispatcher.js";import{HookEventBus as me}from"../hooks/bus.js";import{ResumeRunner as ue}from"../hooks/resume-runner.js";import{HeadlessRunner as de}from"../hooks/headless-runner.js";import{MessageDeliverer as fe}from"../hooks/message-deliverer.js";import{QuestionTracker as he}from"../hooks/question-tracker.js";import{startPromptFlusher as we}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as ge}from"../repositories/session-watches.js";import{PushSubscriptionRepository as Se}from"../repositories/push-subscriptions.js";import{UploadRepository as ve}from"../repositories/uploads.js";import{PushNotifier as be}from"../hooks/push-notify.js";import{SessionSequenceRepository as Re}from"../repositories/session-sequences.js";import{WatchEngine as ke}from"../hooks/watch-engine.js";import{SequenceEngine as De}from"../hooks/sequence-engine.js";import{loadAllPlugins as Pe}from"../hooks/plugin-loader.js";import{ensureBuiltinMarket as Ee,builtinMarketDir as ye}from"../market/builtin.js";import{ToolkitService as Te}from"../hooks/toolkit.js";import{startSessionSweeper as Ie}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as Ae}from"../statusline/cache-sweeper.js";import{WatchService as Ce}from"../watch/watch-service.js";import{weaveRequestHandler as _e}from"./server.js";import{startTlsServer as He}from"./tls.js";import{DataBus as $e}from"./data-bus.js";import{TerminalTopologyRefresher as Oe}from"./terminal-topology-refresher.js";import{SnapshotRefresher as V}from"./snapshot-refresher.js";import{SessionProbe as qe,dbTranscriptPathResolver as Le}from"./session-probe.js";import{InflightCountsRefresher as Me}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as Fe}from"./project-updates-refresher.js";import{FingerprintCache as Ne}from"../install/fingerprint.js";import{detectProjectUpdateCounts as je}from"../install/updates.js";import{claudeLivenessById as Ue,pidAliveOf as Be}from"./claude-liveness.js";import{promptTerminalChannel as We,readTerminalCounts as Ge}from"./opener.js";import{wireHookFilePipeline as Ve}from"./hook-pipeline.js";import{DEFAULT_PORT as H,DAEMON_HOST as xe,DEFAULT_BIND_HOST as Ke,findFreePort as Qe,isPortFree as Ye}from"./port.js";import{writeDaemonState as x}from"./state.js";import{readDaemonSettingsSync as $,setDaemonSettingsDb as ze,DEFAULT_SERVER_SETTINGS as Je}from"./settings.js";import{AuthService as Xe}from"./dashboard-auth.js";import{resolveStaticDir as Ze}from"./static.js";const es="CLAUDE_CODE_CHILD_SESSION"in process.env;delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const a of le)delete process.env[a];async function ss(){const a=await Ye(H)?H:await Qe(H+1);x({pid:process.pid,port:a,startedAt:new Date().toISOString()});const s=se();ze(s);const m=$().server?.bindHost??Ke,b=$().server?.tlsPort??Je.tlsPort,R=new Xe;R.initialPassword&&console.log(`[dev] initial dashboard password: ${R.initialPassword}`);const n=new oe(s),u=new te(s),p=new re(s),k=ae(),K=k.byCapability("events").flatMap(e=>e.events??[]),f=new ce(new G(s)),h=new ne(s),t=new ie(s),r=new me;{const e=await Ee({libraries:p});e.error?console.error(`[dev] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[dev] builtin market ${e.form==="link"?"linked":"copied"} -> ${ye(p.dataDir)}`)}const{loader:l}=await Pe({rules:new G(s),registry:f,states:new v(s),bus:r,libraries:p},n.list());{const e=l.list().filter(o=>o.status==="rejected");console.log(`[dev] plugins loaded: ${l.list().length} (rejected: ${e.length})`);for(const o of e)console.log(`[dev] rejected ${o.id}: ${o.error}`)}l.watchRoots();const O={list:()=>l.list(),setPluginEnabled:(e,o)=>l.setPluginEnabled(e,o),reloadAll:()=>l.reloadAll(),rescan:()=>l.rescanRoots(n.list(),p)},Q=new Te({projects:n,states:new v(s),plugins:O,libraries:p}),q=new pe({registry:f,dispatches:h,bus:r,projects:n,sessions:t,plugins:l,pluginStates:new v(s)}),D=new de,Y=new ue({dispatches:h,sessions:t,projects:n,bus:r,resumeSpec:k.get("claude")?.resume,headless:D}),c=new fe({sessions:t,projects:n,hookEvents:u,bus:r,headless:D,terminal:We(()=>$().terminal)});we(c);const P=new ge(s),E=new ke({watches:P,deliverer:c,sessions:t,bus:r}),L=new Se(s),y=new ve(s),z=new be({subscriptions:L,sessions:t,bus:r}),T=new Re(s),w=new De({sequences:T,deliverer:c,sessions:t,bus:r});w.rearm();const g=new he({sessions:t,hookEvents:u,onPending:e=>{r.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});g.seedFromDb();const M=new Ce(n);M.start();const i=new $e,S=new qe(Le(u)),I=new Oe(async()=>({counts:await Ge(n.list()),terminals:await c.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});I.start();const A=new V(()=>{const e=Ue(),o={};for(const d of t.listWithCounts()){const W=Be(d,e);W!==null&&(o[d.sessionId]=W)}return{alive:o}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});A.start();const C=new V(()=>{const e={};for(const o of t.listWithCounts()){if(o.turnOpen!==!0)continue;const d=S.interruptedAt(o.sessionId,o.lastSeenAt);d!==null&&(e[o.sessionId]=d)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});C.start();const J=new Me(()=>c.listInflightCounts(),i,r),X=new Ne,Z=new Fe(()=>je(n.list(),p.list(),X),i,r,()=>i.hasSubscribers());Ie({sessions:t,events:u,dispatches:h,deliverer:c,watches:P,sequences:T,watchEngine:E,sequenceEngine:w,questions:g,probe:S,uploads:y}),Ae();const F=Ve({projects:n,rules:f,sessions:t,bus:r,dispatcher:q,watchEngine:E,sequenceEngine:w,messagePipe:c,questionTracker:g,sessionProbe:S,uploads:y}),_=Ze(),N=_e({projects:n,port:a,tlsPort:b,watch:M,hookEvents:u,adapters:K,harnesses:k,libraries:p,staticDir:_,hookRegistry:f,hookDispatches:h,hookSessions:t,hookBus:r,dataBus:i,terminalRefresher:I,interruptRefresher:C,livenessRefresher:A,sessionProbe:S,inflightRefresher:J,updatesRefresher:Z,hookDispatcher:q,hookRunner:Y,messageDeliverer:c,uploads:y,questionTracker:g,sessionWatches:P,watchEngine:E,sessionSequences:T,sequenceEngine:w,pushSubscriptions:L,pushNotifier:z,hookPlugins:O,hookMirror:F.mirror,pluginStates:new v(s),toolkit:Q,auth:R}),j=ee.createServer(N);let U=null;He({port:b,bindHost:m,handler:N}).then(e=>{U=e,e&&console.log(`[dev] weave daemon tls listening on https://${m}:${e.port}`)});const B=()=>{I.stop(),A.stop(),C.stop(),D.killAll(),F.stop(),j.close(),U?.server.close(),process.exit(0)};process.on("SIGTERM",B),process.on("SIGINT",B),j.listen(a,m,()=>{x({pid:process.pid,port:a,startedAt:new Date().toISOString(),host:m,tlsPort:b}),console.log(`[dev] weave daemon listening on http://${m}:${a}`),console.log(`[dev] cli/dashboard local url: http://${xe}:${a}`),console.log(`[dev] child-session marker stripped: ${es}`),console.log(_?`[dev] static: ${_}`:"[dev] static: (web/dist not built \u2014 run pnpm build:web)")})}ss();
@@ -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}
@@ -22,9 +22,14 @@ export interface HookPipelineDeps {
22
22
  messagePipe?: Pick<MessageDeliverer, 'hasQueued' | 'flushSession'>;
23
23
  /** 阻塞式问答跟踪(AskUserQuestion/计划/权限确认):ingest 事件派生待答面。 */
24
24
  questionTracker?: Pick<QuestionTracker, 'onEvent'>;
25
- /** 会话转录路径上报(中断态探测;同 pane env 口径)。 */
25
+ /** 会话转录路径上报(中断态探测;同 pane env 口径)+ 换模型落定(`PostModelSwitch`)。 */
26
26
  sessionProbe?: {
27
27
  noteTranscript(sessionId: string, path: string | null): void;
28
+ noteModel(sessionId: string, model: string): void;
29
+ };
30
+ /** 上传件落库面:回执命中时把消息的随附图挂到开轮事件(对话气泡缩略图)。 */
31
+ uploads?: {
32
+ linkToEvent(eventId: number, uploadIds: readonly string[]): void;
28
33
  };
29
34
  }
30
35
  /** 删除一个项目的全部管道文件(忽略不存在)。删项目路由落地时一行调用。 */
@@ -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 p,INBOX_FAILED_SUFFIX as u}from"../hooks/inbox-worker.js";function w(e,o){return[c(e,"inbox",`${o}.jsonl`),c(e,"inbox",`${o}${p}`),c(e,"inbox",`${o}${u}`),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(`(${p}|${u})$`),"").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,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{stat as V}from"node:fs/promises";import{z as i}from"zod";import{HARNESS_SESSION_CONTROL as J,HookRuleFilterSchema as Y,HookRuleSourceSchema as X,HandlerConfigSchema as Z,HookDispatchStatusSchema as q,isHarness as w}from"@weavecode/core";import{aliasOfModel as ee,modelAliasTargets as te}from"@weavecode/harness";import{readJson as k,sendJson as r}from"./http.js";import{installPlugin as re,uninstallPlugin as oe}from"../hooks/plugin-installer.js";import{purgeSession as ne}from"../hooks/session-purge.js";import{composeAnswerAtoms as se}from"../hooks/answer-keys.js";import{effective as ie,setProjectEnabled as ae}from"../hooks/plugin-project-state.js";import{readDaemonSettings as ue,readDaemonSettingsSync as le,readHooksEnabled as ce}from"./settings.js";import{defaultProjectOpener as me,terminalBackendFor as de}from"./opener.js";import{claudeLivenessById as F,pidAliveOf as K}from"./claude-liveness.js";import{captureSurfaces as he,messagingSurfaceFor as E,messagingSurfaces as ge}from"../surfaces.js";import{getDataDir as fe}from"../db/paths.js";import{UPLOAD_MAX_BYTES as be,UPLOAD_MEDIA_TYPES as ye}from"../repositories/uploads.js";import{WEAVE_VERSION as pe}from"../version.js";import{DEFAULT_WATCH_ON as ke}from"../repositories/session-watches.js";import{SEQUENCE_HOP_LIMIT as z}from"../hooks/sequence-engine.js";const Q=i.object({name:i.string().min(1),enabled:i.boolean().optional(),priority:i.number().int().optional(),projectId:i.number().int().nullable(),source:X,filter:Y.optional(),handler:Z,timeoutMs:i.number().int().positive().optional(),record:i.boolean().optional()}),ve=Q.partial(),Ie=i.object({enabled:i.boolean()}),Se=i.object({enabled:i.boolean(),projectId:i.number().int().optional()}),we=i.object({title:i.string().min(1).max(200)}),Pe=i.object({sessionId:i.string().min(1)}),Ee=i.object({text:i.string().max(2e4),fromKind:i.enum(["dashboard","session"]).optional(),fromSessionId:i.string().min(1).nullable().optional(),images:i.array(i.string().regex(/^[a-f0-9]{64}$/)).max(8).optional(),forceTerminal:i.boolean().optional()}),Te=i.object({name:i.string().min(1).max(200),mediaType:i.enum(ye),data:i.string().min(1)});function je(s){return{id:s.id,name:s.name,mediaType:s.mediaType,size:s.size}}const Re=i.object({answers:i.array(i.object({questionKey:i.string().min(1),options:i.array(i.number().int().min(0)).max(32),text:i.string().max(2e3).optional()})).min(1)}),Me=i.object({watcherSessionId:i.string().min(1).nullable().optional(),notify:i.string().min(1).max(2e4).nullable().optional(),on:i.array(i.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:i.number().int().min(1).max(100).nullable().optional()}),De=i.object({watchId:i.number().int().positive()}),Oe=i.object({model:i.string().min(1).max(128)}),Be=i.object({endpoint:i.string().url(),keys:i.object({p256dh:i.string().min(1),auth:i.string().min(1)})}),Ce=i.object({endpoint:i.string().url()}),$e=i.object({name:i.string().max(200).optional(),steps:i.array(i.object({to:i.string().min(1),text:i.string().min(1).max(2e4),mode:i.enum(["prompt","inject","headless","auto"]).optional()})).min(1)}),Ae=i.object({src:i.string().min(1)});function T(s,e){return s.prompt!==null||e}function xe(s){const{diag:e,capture:t,eventCount:l}=s,g=[];return!t||t.source==="none"||!t.present?g.push("no-hook-script"):t.weaveOwned?t.reportsInbox||g.push("hook-script-stale"):g.push("hook-script-not-weave"),l===0&&g.push("no-events"),e&&(e.alive===!1&&g.push("not-running"),e.inbox.reason==="no-credentials"&&t?.reportsInbox===!0&&g.push("no-inbox-credentials"),e.inbox.reason==="auth-token-required"&&g.push("inbox-token-required"),e.relay.reason==="no-peer-name"&&g.push("no-peer-name"),e.terminal.reason==="no-backend"&&g.push("terminal-no-backend"),e.terminal.reason==="no-pane-env"&&g.push("terminal-no-pane-env"),e.pending>0&&g.push("queued"),e.stalled&&g.push("stalled")),g}export async function handleHooksRoutes(s,e,t,l,g){if(!(l.startsWith("/hooks/")||l==="/sessions"||l.startsWith("/sessions/")||l.startsWith("/messaging")||l==="/uploads"||l.startsWith("/images/")))return!1;if(l==="/hooks/rules"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;if(s.method==="GET"){const o=g.searchParams.get("projectId"),n=o!=null&&o!==""?Number(o):void 0;return r(e,200,{rules:t.hookRegistry.list(n)}),!0}if(s.method==="POST"){try{const o=Q.parse(await k(s)),n=t.hookRegistry.create(o);r(e,201,{rule:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid rule body"})}return!0}}const j=l.match(/^\/hooks\/rules\/([^/]+)$/);if(j){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(j[1]);if(s.method==="PUT"){try{const n=ve.parse(await k(s)),a=t.hookRegistry.update(o,n);if(!a)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:a})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}if(s.method==="DELETE")return t.hookRegistry.remove(o)?(r(e,200,{ok:!0}),!0):(r(e,404,{error:"Rule not found"}),!0)}const R=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(R&&s.method==="POST"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const o=Ie.parse(await k(s)),n=t.hookRegistry.setEnabled(decodeURIComponent(R[1]),o.enabled);if(!n)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(s.method==="GET"){const o=g.searchParams.get("projectId");if(o==null||o==="")return r(e,200,{plugins:t.hookPlugins?.list()??[]}),!0;const n=t.projects.getById(Number(o));if(!n)return r(e,404,{error:"Project not found"}),!0;if(!t.pluginStates)return r(e,503,{error:"Plugin states unavailable"}),!0;const a=t.pluginStates;return r(e,200,{plugins:(t.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const c=ie(n,u.id,{states:a})?"active":"disabled";return c===u.status?u:{...u,status:c}})}),!0}if(s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const o=Ae.parse(await k(s)),n=await re(o.src);await t.hookPlugins.reloadAll(),r(e,201,n)}catch(o){r(e,400,{error:o instanceof Error?o.message:"Install failed"})}return!0}}const M=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(M&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;const o=decodeURIComponent(M[1]);return await oe(o)?(await t.hookPlugins.reloadAll(),r(e,200,{ok:!0}),!0):(r(e,404,{error:"Plugin directory not found"}),!0)}if(l==="/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(o){r(e,500,{error:o instanceof Error?o.message:"Rescan failed"})}return!0}const D=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(D&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const o=Se.parse(await k(s)),n=decodeURIComponent(D[1]);if(o.projectId!==void 0){const u=t.projects.getById(o.projectId);return u?t.hookPlugins.list().some(c=>c.id===n)?(ae(u,n,o.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(n,o.enabled))return r(e,404,{error:"Plugin not found"}),!0;r(e,200,{ok:!0})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&s.method==="GET"){if(!t.hookDispatches)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=g.searchParams.get("ruleId")??void 0,n=g.searchParams.get("status"),a=n?q.parse(n):void 0,u=g.searchParams.get("sessionId")??void 0,c=g.searchParams.get("limit"),d=c?Number(c):void 0;return r(e,200,{dispatches:t.hookDispatches.list({ruleId:o,status:a,sessionId:u,limit:Number.isFinite(d)?d:void 0})}),!0}const O=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(O&&s.method==="POST"){if(!t.hookRunner)return r(e,503,{error:"Resume runner unavailable"}),!0;let o;try{o=Pe.parse(await k(s)).sessionId}catch(a){return r(e,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const n=await t.hookRunner.run(Number(O[1]),o);return n.ok?r(e,200,{ok:!0,dispatchId:n.dispatchId}):r(e,n.status,{error:n.error}),!0}if(l==="/sessions"&&s.method==="GET"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=g.searchParams.get("projectId"),n=o!=null&&o!==""?Number(o):void 0,a=t.hookSessions.listWithCounts(n),u=F(),c=t.terminalRefresher?.lastSnapshot?.terminals??{},d={};for(const h of a){const b=h.harness??"";b in d||(d[b]=te(J[h.harness]?.modelNames??[]))}return r(e,200,{sessions:a.map(h=>{const b=t.sessionProbe?.currentModel(h.sessionId)??null;return{...h,pidAlive:K(h,u),terminal:c[h.sessionId]??null,interruptedAt:h.turnOpen===!0?t.sessionProbe?.interruptedAt(h.sessionId,h.lastSeenAt)??null:null,model:b,modelAlias:ee(d[h.harness??""]??[],b),mode:t.sessionProbe?.currentMode(h.sessionId)??null,transcriptPresent:t.sessionProbe?.transcriptPresent(h.sessionId)??null}}),modelCatalog:d}),!0}const S=l.match(/^\/sessions\/([^/]+)$/);if(S&&s.method==="PATCH"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(S[1]);if(!t.hookSessions.getBySessionId(o))return r(e,404,{error:"Session not found"}),!0;try{const n=we.parse(await k(s)),a=t.hookSessions.setPendingTitle(o,n.title);a?.projectId!=null&&t.hookMirror?.syncProject(a.projectId),r(e,200,{session:a})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(S&&s.method==="DELETE"){if(!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(S[1]),n=t.hookSessions.getBySessionId(o);if(!n)return r(e,404,{error:"Session not found"}),!0;const a=ne({sessions:t.hookSessions,events:t.hookEvents,dispatches:t.hookDispatches,deliverer:t.messageDeliverer,watches:t.sessionWatches,questions:t.questionTracker,probe:t.sessionProbe,uploads:t.uploads},o);return n.projectId!=null&&t.hookMirror?.syncProject(n.projectId),r(e,200,{ok:!0,sessionId:o,...a}),!0}const B=l.match(/^\/sessions\/([^/]+)\/open-terminal$/);if(B&&s.method==="POST"){const o=decodeURIComponent(B[1]);if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=t.hookSessions.getBySessionId(o);if(!n)return r(e,404,{error:"Session not found"}),!0;if(!t.hookEvents)return r(e,503,{error:"Hook ingestion unavailable"}),!0;const a=t.hookEvents.listBySession(o,1),u=a[a.length-1]?.source;if(!w(u))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const c=t.harnesses?.get(u)?.resume;if(!c?.supported||!c.openArgs)return r(e,501,{error:`Harness "${u}" does not support interactive resume`}),!0;if(!n.projectId)return r(e,400,{error:"Session is not bound to a project"}),!0;const d=t.projects.getById(n.projectId);if(!d)return r(e,404,{error:"Project not found"}),!0;if(t.sessionProbe?.transcriptPresent(o)===!1)return r(e,409,{error:"Session transcript is missing \u2014 nothing to resume"}),!0;const h=t.opener??me;let b;if(s.method==="POST")try{const y=await k(s);typeof y?.target=="string"&&y.target&&(b=y.target)}catch{}try{if(!(await V(d.path)).isDirectory())throw new Error(`Not a directory: ${d.path}`);const m=await ue(),f=[c.bin,...c.openArgs(o)];if(b){if(!de(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 p=h.runInTerminalAt;if(!p)throw new Error("Targeted attach is unavailable");await p(d.path,f,b,m.terminal)}else await h.runInTerminal(d.path,f,m.terminal);setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:o,command:f.join(" "),cwd:d.path,...b?{target:b}:{}})}catch(y){r(e,400,{error:y instanceof Error?y.message:"Open failed"})}return!0}if(l==="/uploads"&&s.method==="POST"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;let o;try{o=Te.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const n=Buffer.from(o.data,"base64");if(n.length===0)return r(e,400,{error:"Empty image"}),!0;if(n.length>be)return r(e,413,{error:"Image too large"}),!0;const a=t.uploads.save({name:o.name,mediaType:o.mediaType,bytes:n});return r(e,201,{upload:je(a)}),!0}const C=l.match(/^\/images\/([a-f0-9]{64})$/);if(C&&s.method==="GET"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;const o=t.uploads.fileOf(C[1]);return o?(e.writeHead(200,{"content-type":o.row.mediaType,"content-length":String(o.bytes.length),"cache-control":"private, max-age=31536000, immutable"}),e.end(o.bytes),!0):(r(e,404,{error:"Image not found"}),!0)}const $=l.match(/^\/sessions\/([^/]+)\/messages$/);if($){const o=decodeURIComponent($[1]);if(s.method==="GET")return t.messageDeliverer?t.hookSessions?.getBySessionId(o)?(r(e,200,{messages:t.messageDeliverer.listVisible(o)}),!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 n;try{n=Ee.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const a=n.images??[];if(!n.text.trim()&&a.length===0)return r(e,400,{error:"Message is empty"}),!0;let u=[];if(a.length>0){const d=t.uploads?.refsOf(a)??null;if(!d)return r(e,404,{error:"Image not found"}),!0;u=d}const c=await t.messageDeliverer.send({toSessionId:o,text:n.text,...u.length>0?{images:u}:{},...n.forceTerminal===!0?{forceTerminal:!0}:{},mode:"prompt",fromKind:n.fromKind??"dashboard",fromSessionId:n.fromSessionId??null,oneWay:!0});return c.ok?r(e,201,{ok:!0,messageId:c.messageId,status:c.status,message:c.message}):r(e,c.status,{error:c.error}),!0}}const A=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/resend$/);if(A&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=await t.messageDeliverer.resend(decodeURIComponent(A[2]));return o.ok?r(e,200,{ok:!0,messageId:o.messageId,status:o.status,message:o.message}):r(e,o.status,{error:o.error}),!0}const P=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/dismiss$/);if(P&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=t.messageDeliverer.dismiss(decodeURIComponent(P[1]),decodeURIComponent(P[2]));return o.ok?r(e,200,{ok:!0}):r(e,o.status,{error:o.error}),!0}if(l==="/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 x=l.match(/^\/sessions\/([^/]+)\/answer$/);if(x&&s.method==="POST"){if(!t.questionTracker||!t.messageDeliverer)return r(e,503,{error:"Question tracking unavailable"}),!0;const o=decodeURIComponent(x[1]);let n;try{n=Re.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const a=t.questionTracker.get(o);if(!a)return r(e,409,{error:"Session has no pending question"}),!0;const u=se(a.questions,n.answers);if(!u.ok)return r(e,400,{error:u.error}),!0;const c=await t.messageDeliverer.answer(o,u.atoms);return c.ok?(t.questionTracker.markAnswered(o),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,c.status,{error:c.error}),!0)}const H=l.match(/^\/sessions\/([^/]+)\/interrupt$/);if(H&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(H[1]),n=await t.messageDeliverer.interrupt(o);return n.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const U=l.match(/^\/sessions\/([^/]+)\/close-pane$/);if(U&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(U[1]),n=await t.messageDeliverer.closePane(o);return n.ok?(setTimeout(()=>{t.livenessRefresher?.tick(),t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const W=l.match(/^\/sessions\/([^/]+)\/mode$/);if(W&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(W[1]),n=await t.messageDeliverer.cycleMode(o);return n.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const N=l.match(/^\/sessions\/([^/]+)\/model$/);if(N&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(N[1]),n=Oe.parse(await k(s)),a=await t.messageDeliverer.setModel(o,n.model);return a.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,a.status,{error:a.error}),!0)}const _=l.match(/^\/sessions\/([^/]+)\/watch$/);if(_){const o=decodeURIComponent(_[1]);if(s.method==="POST"){if(!t.sessionWatches||!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=Me.parse(await k(s))}catch(p){return r(e,400,{error:p instanceof Error?p.message:"Invalid body"}),!0}if(!t.hookSessions.getBySessionId(o))return r(e,404,{error:"Session not found"}),!0;const u=t.hookEvents.listBySession(o,1),c=u[u.length-1]?.source;if(!w(c))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=E(c),h=n.on??[...ke];if((h.includes("idle")||h.includes("turnEnd"))&&d.idleSignals.length===0)return r(e,409,{error:d.unsupportedReasons?.watch??`Harness "${c}" 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 "${c}" supports no messaging channel`}),!0;if(n.watcherSessionId){if(!t.hookSessions.getBySessionId(n.watcherSessionId))return r(e,404,{error:"Watcher session not found"}),!0;const v=t.hookEvents.listBySession(n.watcherSessionId,1),I=v[v.length-1]?.source;if(!w(I))return r(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const L=E(I);if(!L.inject)return r(e,409,{error:L.unsupportedReasons?.inject??`Harness "${I}" cannot receive watch notifications`}),!0}const b=n.times===void 0?1:n.times,y=(n.watcherSessionId??null)===null?t.sessionWatches.listPendingByTarget(o).find(p=>p.watcherSessionId===null):void 0,m=y?t.sessionWatches.updateById(y.id,{onEvents:h,remaining:b}):void 0,f=m??t.sessionWatches.insert({watcherSessionId:n.watcherSessionId??null,targetSessionId:o,notify:n.notify??null,onEvents:h,times:b});return t.watchEngine?.created(f),r(e,m?200:201,{ok:!0,watchId:f.id,watch:f}),!0}if(s.method==="DELETE"){if(!t.sessionWatches)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=De.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const a=t.sessionWatches.getById(n.watchId);return!a||a.targetSessionId!==o||a.firedAt!==null?(r(e,404,{error:"Watch not found"}),!0):(t.sessionWatches.deleteById(n.watchId),r(e,200,{ok:!0,watchId:n.watchId}),!0)}}if(l==="/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(l==="/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(l==="/messaging/push/subscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const o=Be.parse(await k(s)),n=t.pushSubscriptions.upsert({endpoint:o.endpoint,p256dh:o.keys.p256dh,auth:o.keys.auth,userAgent:s.headers["user-agent"]??null});r(e,201,{ok:!0,subscription:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/messaging/push/unsubscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const o=Ce.parse(await k(s));t.pushSubscriptions.deleteByEndpoint(o.endpoint),r(e,200,{ok:!0})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/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 o;try{o=$e.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(o.steps.length>z)return r(e,400,{error:`Sequences are capped at ${z} steps (hop limit)`}),!0;const n=t.messageDeliverer?.hasTerminalChannel()??!1;for(let u=0;u<o.steps.length;u++){const c=o.steps[u];if(!t.hookSessions.getBySessionId(c.to))return r(e,404,{error:`Step ${u+1}: session not found`}),!0;const h=t.hookEvents.listBySession(c.to,1),b=h[h.length-1]?.source;if(!w(b))return r(e,400,{error:`Step ${u+1}: session has no hook events to determine its harness`}),!0;const y=E(b),m=c.mode??"auto";if(!(m==="prompt"?T(y,n):m==="inject"?y.inject!==null:m==="headless"?y.headless!==null:y.inject!==null||y.headless!==null)){const p=m==="auto"?y.unsupportedReasons?.inject??`Harness "${b}" supports no messaging channel`:y.unsupportedReasons?.[m]??`Harness "${b}" does not support the ${m} channel`;return r(e,409,{error:`Step ${u+1}: ${p}`}),!0}}const a=t.sessionSequences.insert({name:o.name??"",steps:o.steps.map(u=>({...u,mode:u.mode??"auto"}))});return await t.sequenceEngine.trigger(a),r(e,201,{ok:!0,sequence:t.sessionSequences.getById(a.id)??a}),!0}}const G=l.match(/^\/messaging\/sequences\/(\d+)$/);if(G&&s.method==="DELETE"){if(!t.sessionSequences)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=t.sessionSequences.getById(Number(G[1]));return o?o.status!=="running"?(r(e,409,{error:`Sequence already ${o.status}`}),!0):(t.sequenceEngine?t.sequenceEngine.cancel(o.id):t.sessionSequences.finish(o.id,"cancelled"),r(e,200,{ok:!0,sequenceId:o.id}),!0):(r(e,404,{error:"Sequence not found"}),!0)}if(l==="/messaging/capabilities"&&s.method==="GET"){const o=t.messageDeliverer?.hasTerminalChannel()??!1;return r(e,200,{capabilities:ge().map(({harness:n,surface:a})=>({harness:n,discovery:a.discovery,prompt:T(a,o),inject:a.inject!==null,headless:a.headless!==null,watch:a.idleSignals.length>0,imageAttach:a.imageAttach!==null,unsupportedReasons:a.unsupportedReasons??null}))}),!0}if(l==="/messaging/diagnostics"&&s.method==="GET"){if(!t.messageDeliverer||!t.hookSessions)return r(e,503,{error:"Message subsystem unavailable"}),!0;const o=g.searchParams.get("session"),n=g.searchParams.get("project"),a=he(),u=t.projects.list(),c=await Promise.all(u.map(async m=>({id:m.id,name:m.name,path:m.path,captures:await Promise.all(a.map(async({harness:f,surface:p})=>({harness:f,...await p.scriptHealth({projectPath:m.path})})))}))),d=(m,f)=>c.find(p=>p.id===m)?.captures.find(p=>p.harness===f)??null,h=F(),y=t.hookSessions.listWithCounts(o?void 0:n?Number(n):void 0).filter(m=>o?m.sessionId===o:K(m,h)!==!1).map(m=>{const f=t.messageDeliverer.diagnose(m.sessionId),p=d(m.projectId,m.harness??null),v={inbox:f.inbox,relay:f.relay,terminal:f.terminal};return{sessionId:m.sessionId,projectId:m.projectId,harness:m.harness??null,title:m.title,lastSeenAt:m.lastSeenAt,eventCount:m.eventCount??0,lastEventType:m.lastEventType??null,alive:f.alive,paneEnvReported:f.paneEnvReported,channels:v,queue:{pending:f.pending,stalled:f.stalled},reachable:Object.values(v).some(I=>I.status==="ready"),hints:xe({diag:f,capture:p,eventCount:m.eventCount??0})}});return r(e,200,{daemon:{version:pe,platform:process.platform,dataDir:fe(),uptimeMs:Math.round(process.uptime()*1e3),terminalPreset:le().terminal.preset,terminalTextChannel:t.messageDeliverer.hasTerminalChannel(),hooksEnabled:ce()},projects:c,sessions:y}),!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))}