@weavecode/weave 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +3 -3
  2. package/node_modules/@weavecode/cli/dist/commands/daemon.d.ts +7 -0
  3. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  4. package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
  6. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  7. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  9. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  10. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  11. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +6 -12
  12. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -2
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -12
  14. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.d.ts +2 -3
  15. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  16. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  17. package/node_modules/@weavecode/cli/dist/init/git-commit.js +1 -1
  18. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  19. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.d.ts +29 -0
  20. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.js +1 -0
  21. package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
  22. package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
  23. package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
  24. package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
  25. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  26. package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
  27. package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
  28. package/node_modules/@weavecode/cli/package.json +5 -5
  29. package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
  30. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  31. package/node_modules/@weavecode/core/dist/index.d.ts +2 -2
  32. package/node_modules/@weavecode/core/dist/index.js +1 -1
  33. package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
  34. package/node_modules/@weavecode/core/dist/terminal.js +1 -1
  35. package/node_modules/@weavecode/core/dist/types.d.ts +188 -19
  36. package/node_modules/@weavecode/core/dist/types.js +1 -1
  37. package/node_modules/@weavecode/core/package.json +1 -1
  38. package/node_modules/@weavecode/harness/dist/claude/assets.d.ts +10 -0
  39. package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -1
  40. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +15 -3
  41. package/node_modules/@weavecode/harness/dist/claude/capture.js +15 -9
  42. package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
  43. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  44. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
  45. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
  46. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +10 -1
  47. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  48. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
  49. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
  50. package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
  51. package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
  52. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +39 -0
  53. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
  54. package/node_modules/@weavecode/harness/dist/claude/plan.d.ts +2 -0
  55. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -0
  56. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
  57. package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
  58. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
  59. package/node_modules/@weavecode/harness/dist/claude/side-question.d.ts +12 -0
  60. package/node_modules/@weavecode/harness/dist/claude/side-question.js +1 -0
  61. package/node_modules/@weavecode/harness/dist/claude/statusline/config.d.ts +200 -0
  62. package/node_modules/@weavecode/harness/dist/claude/statusline/config.js +1 -0
  63. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +12 -0
  64. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +745 -0
  65. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.d.ts +10 -0
  66. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -0
  67. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.d.ts +20 -0
  68. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -0
  69. package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
  70. package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
  71. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  72. package/node_modules/@weavecode/harness/dist/codex/index.d.ts +1 -0
  73. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  74. package/node_modules/@weavecode/harness/dist/codex/mcp.d.ts +30 -0
  75. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -0
  76. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/driver.d.ts +168 -3
  78. package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
  79. package/node_modules/@weavecode/harness/dist/index.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
  81. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
  82. package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
  83. package/node_modules/@weavecode/harness/dist/zcode/assets.d.ts +8 -0
  84. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -0
  85. package/node_modules/@weavecode/harness/dist/zcode/capture.d.ts +36 -0
  86. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -0
  87. package/node_modules/@weavecode/harness/dist/zcode/detect.d.ts +2 -0
  88. package/node_modules/@weavecode/harness/dist/zcode/detect.js +1 -0
  89. package/node_modules/@weavecode/harness/dist/zcode/event-source.d.ts +8 -0
  90. package/node_modules/@weavecode/harness/dist/zcode/event-source.js +1 -0
  91. package/node_modules/@weavecode/harness/dist/zcode/index.d.ts +13 -0
  92. package/node_modules/@weavecode/harness/dist/zcode/index.js +1 -0
  93. package/node_modules/@weavecode/harness/dist/zcode/mcp.d.ts +6 -0
  94. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -0
  95. package/node_modules/@weavecode/harness/dist/zcode/messaging.d.ts +13 -0
  96. package/node_modules/@weavecode/harness/dist/zcode/messaging.js +1 -0
  97. package/node_modules/@weavecode/harness/dist/zcode/resume.d.ts +7 -0
  98. package/node_modules/@weavecode/harness/dist/zcode/resume.js +1 -0
  99. package/node_modules/@weavecode/harness/package.json +2 -2
  100. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  101. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  102. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  103. package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
  104. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
  105. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  106. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  107. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  110. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  111. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  112. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +13 -1
  114. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  115. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  117. package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
  118. package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
  119. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  121. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
  122. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +15 -0
  124. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -6
  125. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +72 -2
  126. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
  128. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  129. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.d.ts +7 -1
  130. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  131. package/node_modules/@weavecode/server/dist/daemon/sse-hub.d.ts +40 -0
  132. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -0
  133. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  134. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  135. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  136. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
  137. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  138. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  139. package/node_modules/@weavecode/server/dist/db/db.js +38 -2
  140. package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
  141. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  142. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  143. package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +5 -0
  144. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  145. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  146. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  147. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  148. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
  149. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
  150. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +27 -6
  151. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  152. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  153. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +200 -13
  154. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
  155. package/node_modules/@weavecode/server/dist/hooks/mirror.d.ts +9 -4
  156. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  157. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  158. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  159. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  160. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  161. package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
  162. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  163. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  164. package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
  165. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  166. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  167. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  168. package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
  169. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +7 -0
  170. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  171. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
  172. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
  173. package/node_modules/@weavecode/server/dist/hooks/side-questions.d.ts +41 -0
  174. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -0
  175. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  176. package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
  177. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  178. package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
  179. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  180. package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
  181. package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
  182. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  183. package/node_modules/@weavecode/server/dist/install/capabilities.d.ts +10 -0
  184. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  185. package/node_modules/@weavecode/server/dist/install/codex-toml.d.ts +8 -26
  186. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  187. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  188. package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
  189. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  190. package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
  191. package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
  192. package/node_modules/@weavecode/server/dist/install/global-config.d.ts +2 -4
  193. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -2
  194. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  195. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
  196. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
  197. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  198. package/node_modules/@weavecode/server/dist/install/installer.d.ts +3 -5
  199. package/node_modules/@weavecode/server/dist/install/installer.js +1 -3
  200. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  201. package/node_modules/@weavecode/server/dist/install/mcp-rows.d.ts +5 -5
  202. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  203. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  204. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  205. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  206. package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
  207. package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
  208. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  209. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  210. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  211. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  212. package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
  213. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  214. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  215. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  216. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  217. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  218. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  219. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  220. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  221. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  222. package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +7 -0
  223. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  224. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  225. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  226. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  227. package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
  228. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  229. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  230. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  231. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +32 -8
  232. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  233. package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +50 -0
  234. package/node_modules/@weavecode/server/dist/repositories/side-questions.js +6 -0
  235. package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
  236. package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
  237. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  238. package/node_modules/@weavecode/server/dist/statusline/config.d.ts +4 -198
  239. package/node_modules/@weavecode/server/dist/statusline/config.js +1 -1
  240. package/node_modules/@weavecode/server/dist/statusline/generator.d.ts +5 -0
  241. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -676
  242. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +7 -5
  243. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -4
  244. package/node_modules/@weavecode/server/dist/surfaces.d.ts +11 -1
  245. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  246. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  247. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  248. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  249. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
  250. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  251. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  252. package/node_modules/@weavecode/server/package.json +4 -4
  253. package/node_modules/@weavecode/server/web/dist/assets/index-CHWbLAje.js +594 -0
  254. package/node_modules/@weavecode/server/web/dist/assets/index-D0s5v8QS.css +11 -0
  255. package/node_modules/@weavecode/server/web/dist/index.html +14 -2
  256. package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
  257. package/node_modules/@weavecode/templates/package.json +2 -2
  258. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
  259. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
  260. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
  261. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
  262. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
  263. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
  264. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
  265. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
  266. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
  267. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
  268. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
  269. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
  270. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
  271. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
  272. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
  273. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
  274. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
  275. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
  276. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
  277. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
  278. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
  279. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
  280. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
  281. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
  282. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
  283. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
  284. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
  285. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
  286. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
  287. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
  288. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
  289. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
  290. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
  291. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
  292. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
  293. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
  294. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
  295. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
  296. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
  297. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
  298. package/package.json +6 -6
  299. package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
  300. package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
@@ -1,11 +1,13 @@
1
- import ur from"node:http";import{WEAVE_VERSION as dr}from"../version.js";import{checkHarness as mr,isHarness as T}from"@weavecode/core";import j from"node:fs";import S from"node:path";import{hooksRoot as pr}from"../hooks/mirror.js";import{syncPlugins as fr}from"../hooks/plugin-project-state.js";import{getLibraryScan as Y,invalidateScan as k}from"../install/scan-cache.js";import{installSkill as hr,uninstallSkill as gr,installMcp as yr,uninstallMcp as br,installFileAsset as wr,uninstallFileAsset as kr,InstallConflictError as Z,AssetNotFoundError as O}from"../install/installer.js";import{isFileAssetCategory as rr}from"../install/file-assets.js";import{installCapabilities as jr}from"../install/capabilities.js";import{readMcpRows as Sr}from"../install/mcp-rows.js";import{writeGlobalMcpServer as vr,removeGlobalMcpServer as Pr,installGlobalSkill as Nr,uninstallGlobalSkill as Er,readGlobalSkillGroups as Ir,resolveGlobalSkillDir as er,listGlobalSkillFiles as Tr,readGlobalSkillFile as Or,ClaudeJsonCorruptError as Br}from"../install/global-config.js";import{writeCodexMcpServer as Cr,removeCodexMcpServer as Gr,codexMcpExists as Dr,CodexTomlCorruptError as Jr}from"../install/codex-toml.js";import{setMcpEnableOverride as Mr}from"../install/settings-mcp.js";import{readProjectConfig as tr,writeProjectConfig as $r}from"../install/project-config.js";import{applyUpdate as Ar,syncAll as xr}from"../install/apply-update.js";import{buildLibraryIndex as Fr}from"../install/library-index.js";import{importFromDir as Lr,importFromGit as Rr,importLibraryIntoMarket as Ur}from"../market/import.js";import{marketDir as B,readManifest as Hr}from"../market/manifest.js";import{marketIdOf as Kr}from"../market/identity.js";import{isInsideDir as C,toRelPosix as Wr}from"../market/resolve.js";import{checkMarketUpdates as zr}from"../market/updates.js";import{refreshMarketItems as qr}from"../market/refresh.js";import{ensureBuiltinMarket as _r,isBuiltinMarketDir as v}from"../market/builtin.js";import{removeInstalled as Vr}from"../market/install-link.js";import{readProjectFile as Qr,readGlobalFile as Xr,PathEscapeError as Yr,FileTooLargeError as Zr}from"../install/reader.js";import{listGlobalFileAssets as re}from"../install/global-file-assets.js";import{readStatuslineConfig as ar,readStatuslineScript as ee,applyStatuslineConfig as ir,readGlobalStatuslineConfig as sr,writeGlobalStatuslineConfig as te}from"../statusline/manager.js";import{DEFAULT_STATUSLINE_CONFIG as ae}from"../statusline/config.js";import{FingerprintCache as G}from"../install/fingerprint.js";import{detectUpdates as ie}from"../install/updates.js";import{detectPluginTemplateUpdates as se}from"../install/plugin-templates.js";import{readBody as f,sendJson as i}from"./http.js";import{handleHooksRoutes as ne}from"./hooks-routes.js";import{handleToolkitRoutes as oe}from"./toolkit-routes.js";import{handleCaptureRoutes as ce}from"./capture-routes.js";import{purgeProjectPipeline as le}from"./hook-pipeline.js";import{projectFileNamespaces as ue}from"../hooks/toolkit.js";import{listBrowseRoots as de,listDirectoryChildren as me}from"./fs-browser.js";import{DEFAULT_AI_SETTINGS as pe,readDaemonSettings as P,writeDaemonSettings as fe,terminalPresetsFor as he}from"./settings.js";import{defaultProjectOpener as N,readTerminalCounts as ge,terminalBackendFor as ye}from"./opener.js";import{applyLaunchOnLogin as be}from"./auto-start.js";import{DAEMON_HOST as we}from"./port.js";import{pluginStateSurfaces as ke,pluginSurfaces as nr,pluginSurfaceFor as or}from"../surfaces.js";import{readPluginRows as je}from"../install/plugin-rows.js";import{installPluginPack as Se}from"../install/plugin-install.js";import{handleAuthRoutes as ve}from"./auth-routes.js";import{handleAiRoutes as Pe}from"./ai-routes.js";import{hasAiKey as Ne,writeAiKey as Ee}from"./ai-config.js";import{accessUrls as Ie}from"./tls.js";import{projectHarnesses as Te,withProjectHarnesses as cr}from"./project-harnesses.js";export const DAEMON_VERSION=dr;export function weaveRequestHandler(s){const r=s.fingerprintCache??new G,t={...s,fingerprintCache:r};return(u,o)=>{Oe(u,o,t)}}export function createWeaveServer(s){return ur.createServer(weaveRequestHandler(s))}async function Oe(s,r,t){const u=new URL(s.url??"/",`http://${we}`);let o=u.pathname;if(o.startsWith("/api/")?o=o.slice(4):o==="/api"&&(o="/"),o==="/health"&&s.method==="GET"){i(r,200,{service:"weave-daemon",version:DAEMON_VERSION,pid:process.pid,port:t.port,uptimeMs:Math.round(process.uptime()*1e3)});return}if(await ve(s,r,t,o)||await Pe(s,r,t,o))return;if(t.auth&&!Ce(s,o,t)&&!t.auth.isAuthenticated(s.headers)){i(r,401,{error:"Unauthorized"});return}if(await ne(s,r,t,o,u)||await oe(s,r,t,o,u)||await ce(s,r,t,o))return;const y=o.match(/^\/projects\/(\d+)\/hooks$/);if(y&&s.method==="GET"){if(!t.hookEvents){i(r,503,{error:"Hook ingestion unavailable"});return}const a=Number(y[1]),e=Me(u.searchParams.get("limit")),n=u.searchParams.get("sessionId"),c=u.searchParams.get("beforeId"),l=c?Number(c):void 0,d=(u.searchParams.get("types")??"").split(",").map(h=>h.trim()).filter(Boolean);if(n){i(r,200,{events:t.hookEvents.listBySession(n,e??300,l,d)});return}i(r,200,{events:t.hookEvents.listByProject(a,e)});return}if(o==="/settings"){if(s.method==="GET"){i(r,200,{settings:lr(await P(),t.aiKeyPath),presets:he(process.platform),platform:process.platform,urls:Ie(t.port,t.tlsPort??0)});return}if(s.method==="PUT"){let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}const e=a.ai?.apiKey;e!==void 0&&Ee(typeof e=="string"?e:null,t.aiKeyPath);const n=await fe({...a,ai:De(a.ai)});t.hookEvents?.resetPrune(),(t.autoStart??be)(n.startup?.launchOnLogin??!1),t.dataBus?.emit({key:"settings"}),i(r,200,lr(n,t.aiKeyPath));return}}const b=o.match(/^\/projects\/(\d+)\/open$/);if(b&&s.method==="POST"){const a=t.projects.getById(Number(b[1]));if(!a){i(r,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(e.target!=="explorer"&&e.target!=="terminal"){i(r,400,{error:'Invalid "target" (explorer|terminal)'});return}const n=t.opener??N;try{if(!(await j.promises.stat(a.path)).isDirectory())throw new Error(`Not a directory: ${a.path}`);if(e.target==="explorer")await n.openExplorer(a.path);else{const c=await P();await n.openTerminal(a.path,c.terminal),setTimeout(()=>{t.terminalRefresher?.refreshNow()},600)}i(r,200,{ok:!0,target:e.target,path:a.path})}catch(c){i(r,400,{error:c instanceof Error?c.message:"Open failed"})}return}const g=o.match(/^\/projects\/(\d+)\/new-session$/);if(g&&s.method==="POST"){const a=t.projects.getById(Number(g[1]));if(!a){i(r,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await f(s)||"{}")}catch{i(r,400,{error:"Invalid JSON body"});return}const n=await Te(a.path,t.harnesses);if(e.harness!==void 0&&!T(e.harness)){i(r,400,{error:'Invalid "harness"'});return}const c=e.harness;if(c&&!n.some(m=>m.id===c)){i(r,409,{error:`Harness "${c}" is not integrated in this project`});return}const l=c?[c]:n.map(m=>m.id),d=l.map(m=>({id:m,spec:t.harnesses?.get(m)?.resume})).find(m=>m.spec?.bin);if(!d){i(r,501,{error:`Harness "${l[0]}" cannot start an interactive session`});return}const h=d.spec,p=t.opener??N;try{if(!(await j.promises.stat(a.path)).isDirectory())throw new Error(`Not a directory: ${a.path}`);const m=await P();await p.runInTerminal(a.path,[h.bin],m.terminal),setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),i(r,200,{ok:!0,command:h.bin,cwd:a.path})}catch(m){i(r,400,{error:m instanceof Error?m.message:"Open failed"})}return}if(o==="/fs/roots"&&s.method==="GET"){const a=t.libraries?t.libraries.list().map(n=>n.path):[],e=await de(a);i(r,200,{roots:e});return}if(o==="/fs/children"&&s.method==="GET"){const a=u.searchParams.get("path");if(!a){i(r,400,{error:'Missing "path" query parameter'});return}try{const e=await me(a);i(r,200,{children:e})}catch(e){i(r,400,{error:`Cannot list directory: ${String(e)}`})}return}if(o==="/capabilities"&&s.method==="GET"){i(r,200,jr());return}if(o==="/libraries"&&s.method==="GET"){i(r,200,{libraries:t.libraries?t.libraries.list():[]});return}if(o==="/libraries"&&s.method==="POST"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!a.path||!a.kind){i(r,400,{error:'Missing "path" or "kind"'});return}if(!["skill","mcp","both"].includes(a.kind)){i(r,400,{error:'Invalid "kind" (skill|mcp|both)'});return}const e=t.libraries.add({path:a.path,kind:a.kind});t.dataBus?.emit({key:"libraries"}),i(r,201,e);return}const w=o.match(/^\/libraries\/(\d+)\/assets$/);if(w&&s.method==="GET"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}const a=t.libraries.getById(Number(w[1]));if(!a){i(r,404,{error:"Library not found"});return}const{plugins:e,skills:n,mcp:c,files:l}=await Y(a.path),d=a.kind==="skill"||a.kind==="both"?e:[],h=a.kind==="mcp"||a.kind==="both"?c:[],p=a.kind==="skill"||a.kind==="both"?Object.values(l).flat():null;i(r,200,{library:a,skills:n,mcp:h,files:p,plugins:d});return}const J=o.match(/^\/libraries\/(\d+)$/);if(J&&s.method==="DELETE"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}const a=Number(J[1]),e=t.libraries.getById(a);e&&await k(e.path),t.libraries.remove(a),t.dataBus?.emit({key:"libraries"}),t.dataBus?.emit({key:"market"}),i(r,200,{ok:!0});return}if(o==="/market"&&s.method==="GET"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}const a=await Promise.all(t.libraries.list().map(e=>I(e,t.libraries.dataDir)));i(r,200,{items:a});return}if(o==="/market"&&s.method==="POST"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}const e={libraries:t.libraries,dataDir:t.libraries.dataDir};try{if(a.kind==="dir"&&a.path){const n=await Lr(a.path,e);n.refreshed&&t.fingerprintCache?.invalidate(n.dir),await k(n.dir),t.dataBus?.emit({key:"market"}),i(r,201,{item:await I(t.libraries.getById(n.libraryId),t.libraries.dataDir)})}else if(a.kind==="git"&&a.url){const n=await Rr(a.url,e);n.refreshed&&t.fingerprintCache?.invalidate(n.dir),await k(n.dir),t.dataBus?.emit({key:"market"}),i(r,201,{item:await I(t.libraries.getById(n.libraryId),t.libraries.dataDir)})}else i(r,400,{error:'Invalid body (kind: "dir" + path | "git" + url)'})}catch(n){i(r,400,{error:n instanceof Error?n.message:"Import failed"})}return}if(o==="/market/check-updates"&&s.method==="POST"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}let a={};const e=(await f(s)).trim();if(e)try{a=JSON.parse(e)}catch{i(r,400,{error:"Invalid JSON body"});return}const n=t.libraries.list().filter(l=>!v(l.path,t.libraries.dataDir)).filter(l=>!a.ids?.length||a.ids.includes(l.id));for(const l of n)await k(l.path);const c=await zr(n.map(l=>({id:l.id,dir:l.path})));t.dataBus?.emit({key:"market"}),i(r,200,{results:c});return}if(o==="/market/refresh"&&s.method==="POST"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}let a={};const e=(await f(s)).trim();if(e)try{a=JSON.parse(e)}catch{i(r,400,{error:"Invalid JSON body"});return}const n=t.libraries.list().filter(p=>!a.ids?.length||a.ids.includes(p.id)),c=[];for(const p of n.filter(m=>v(m.path,t.libraries.dataDir))){const m=await _r({libraries:t.libraries});c.push({id:p.id,status:m.error?"failed":"refreshed"})}const l=n.filter(p=>!v(p.path,t.libraries.dataDir)).map(p=>({id:p.id,dir:p.path})),d=[...await qr(l,{libraries:t.libraries,dataDir:t.libraries.dataDir}),...c],h=new Map(l.map(p=>[p.id,p.dir]));for(const p of d)if(p.status==="refreshed"){const m=h.get(p.id);m&&(t.fingerprintCache?.invalidate(m),await k(m))}t.dataBus?.emit({key:"market"}),i(r,200,{results:d});return}const M=o.match(/^\/market\/(\d+)$/);if(M&&s.method==="DELETE"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}const a=t.libraries.getById(Number(M[1]));if(!a){i(r,404,{error:"Library not found"});return}if(v(a.path,t.libraries.dataDir)){i(r,409,{error:"Built-in market is owned by weave and cannot be deleted",note:"It is re-materialized from @weavecode/templates on every daemon start."});return}if(!C(a.path,B(t.libraries.dataDir))){i(r,400,{error:"Not a market resource (legacy row \u2014 use DELETE /libraries/:id)"});return}let e;try{await(t.pluginSurface??or("claude")).removeMarketplace(a.path)}catch(n){e=`Host marketplace deregistration failed: ${n instanceof Error?n.message:String(n)}`}await Vr(a.path),t.libraries.remove(a.id),await k(a.path),t.dataBus?.emit({key:"market"}),t.dataBus?.emit({key:"libraries"}),i(r,200,{ok:!0,removed:a.path,installedCopiesKept:!0,...e?{warning:e}:{},note:"The host cascade-uninstalls plugins installed from this market; other installed copies are kept."});return}const $=o.match(/^\/libraries\/(\d+)\/market-import$/);if($&&s.method==="POST"){if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}const a=t.libraries.getById(Number($[1]));if(!a){i(r,404,{error:"Library not found"});return}try{const e=a.path,n=await Ur(a,{libraries:t.libraries,dataDir:t.libraries.dataDir});await k(e),await k(n.dir),i(r,200,{item:await I(t.libraries.getById(n.libraryId),t.libraries.dataDir)})}catch(e){i(r,400,{error:e instanceof Error?e.message:"Import failed"})}return}const A=o.match(/^\/projects\/(\d+)\/install$/);if(A&&s.method==="POST"){const a=t.projects.getById(Number(A[1]));if(!a){i(r,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}try{if(e.category==="skill"){if(!e.name||!e.sourceDir){i(r,400,{error:'Missing "name" or "sourceDir"'});return}const n=e.agent??"claude",c=e.scope==="user"?await Nr(e.sourceDir,e.name,n):await hr(a.path,e.sourceDir,e.name,n);i(r,201,{category:"skill",name:e.name,scope:e.scope??"project",agent:n,path:c})}else if(e.category&&rr(e.category)){if(!e.name||!e.sourceFile){i(r,400,{error:'Missing "name" or "sourceFile"'});return}const n=e.agent??"claude",c=e.scope??"project",l=await wr(a.path,e.category,e.name,e.sourceFile,n,c);i(r,201,{category:e.category,name:e.name,scope:c,agent:n,path:l})}else if(e.category==="mcp"){if(!e.name||!e.mcpConfig){i(r,400,{error:'Missing "name" or "mcpConfig"'});return}if(e.agent==="codex"){if(e.scope==="project"){i(r,400,{error:'Codex MCP servers are user-level (~/.codex/config.toml) \u2014 use scope "user"'});return}if(await Dr(e.name)){E(r,new Z(`MCP server "${e.name}" is already configured in ~/.codex/config.toml`));return}await Cr(e.name,e.mcpConfig)}else e.scope==="user"?await vr(e.name,e.mcpConfig):await yr(a.path,e.name,e.mcpConfig);i(r,201,{category:"mcp",name:e.name,scope:e.agent==="codex"?"user":e.scope??"project",agent:e.agent??"claude"})}else if(e.category==="plugin"){if(!e.name||!e.sourceDir){i(r,400,{error:'Missing "name" or "sourceDir"'});return}if(e.scope&&e.scope!=="user"){i(r,400,{error:'Plugin install currently only supports scope "user"'});return}const n=e.agent??"claude",c=nr().find(h=>h.harness===n);if(!c){i(r,400,{error:`No plugin install surface for runtime: ${n}`});return}const l=n==="claude"&&t.pluginSurface?t.pluginSurface:c.surface,d=await Se(l,{dir:e.sourceDir,name:e.name,version:e.version,description:e.description});t.dataBus?.emit({key:"toolkit"}),i(r,201,{category:"plugin",key:d.key,scope:"user",agent:n,alreadyInstalled:d.alreadyInstalled})}else i(r,400,{error:'Invalid "category" (skill|mcp|plugin|command|agent|workflow|rule|output-style)'})}catch(n){E(r,n)}return}const x=o.match(/^\/projects\/(\d+)\/uninstall$/);if(x&&s.method==="POST"){const a=t.projects.getById(Number(x[1]));if(!a){i(r,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}try{if(e.category==="skill"){if(!e.name){i(r,400,{error:'Missing "name"'});return}const n=e.agent??"claude";e.scope==="user"?await Er(e.name,n):await gr(a.path,e.name,n)}else if(e.category&&rr(e.category)){if(!e.name){i(r,400,{error:'Missing "name"'});return}await kr(a.path,e.category,e.name,e.agent??"claude",e.scope??"project")}else if(e.category==="mcp"){if(!e.name){i(r,400,{error:'Missing "name"'});return}if(e.agent==="codex"){if(!await Gr(e.name)){E(r,new O(`MCP server "${e.name}" is not configured in ~/.codex/config.toml`));return}}else e.scope==="user"?await Pr(e.name):await br(a.path,e.name)}else{i(r,400,{error:'Invalid "category" (skill|mcp|command|agent|workflow|rule|output-style)'});return}i(r,200,{ok:!0})}catch(n){E(r,n)}return}const F=o.match(/^\/projects\/(\d+)\/file$/);if(F&&s.method==="GET"){const a=t.projects.getById(Number(F[1]));if(!a){i(r,404,{error:"Project not found"});return}const e=u.searchParams.get("path");if(!e){i(r,400,{error:'Missing "path" query parameter'});return}try{const n=await Qr(a.path,e);i(r,200,{path:e,content:n.content,size:n.size})}catch(n){D(r,n)}return}if(o==="/global-file"&&s.method==="GET"){const a=u.searchParams.get("path");if(!a){i(r,400,{error:'Missing "path" query parameter'});return}try{const e=await Xr(a);i(r,200,{path:a,content:e.content,size:e.size})}catch(e){D(r,e)}return}const L=o.match(/^\/projects\/(\d+)\/mcp$/);if(L&&s.method==="GET"){const a=t.projects.getById(Number(L[1]));if(!a){i(r,404,{error:"Project not found"});return}i(r,200,{rows:await Sr(a.path)});return}const R=o.match(/^\/projects\/(\d+)\/harness-checks$/);if(R&&s.method==="GET"){const a=t.projects.getById(Number(R[1]));if(!a){i(r,404,{error:"Project not found"});return}i(r,200,{checks:await mr(a.path)});return}if(o.match(/^\/projects\/(\d+)\/skills\/global$/)&&s.method==="GET"){i(r,200,{groups:await Ir()});return}if(o.match(/^\/projects\/(\d+)\/skills\/global\/files$/)&&s.method==="GET"){const a=u.searchParams.get("source"),e=u.searchParams.get("name"),n=u.searchParams.get("pluginKey")??void 0;if(!a||!e){i(r,400,{error:'Missing "source" or "name" query parameter'});return}const c=await er(a,e,n);if(!c){i(r,404,{error:"Skill not found"});return}i(r,200,{files:await Tr(c)});return}if(o.match(/^\/projects\/(\d+)\/skills\/global\/file$/)&&s.method==="GET"){const a=u.searchParams.get("source"),e=u.searchParams.get("name"),n=u.searchParams.get("pluginKey")??void 0,c=u.searchParams.get("path");if(!a||!e||!c){i(r,400,{error:'Missing "source", "name" or "path" query parameter'});return}const l=await er(a,e,n);if(!l){i(r,404,{error:"Skill not found"});return}try{const d=await Or(l,c);i(r,200,{path:c,content:d.content,size:d.size})}catch(d){D(r,d)}return}const U=o.match(/^\/projects\/(\d+)\/plugins\/state$/);if(U){const a=t.projects.getById(Number(U[1]));if(!a){i(r,404,{error:"Project not found"});return}if(s.method==="GET"){i(r,200,{rows:await je(a.path)});return}if(s.method==="PUT"){let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!T(e.runtime)||!e.key||!e.scope||!["user","project","local"].includes(e.scope)||!e.state||!["on","off","inherit"].includes(e.state)){i(r,400,{error:'Missing or invalid "runtime"/"key"/"scope" (user|project|local)/"state" (on|off|inherit)'});return}const n=e.scope,c=e.state;try{const l=nr().find(d=>d.harness===e.runtime);if(l)await(e.runtime==="claude"&&t.pluginSurface?t.pluginSurface:l.surface).setEnabledOverride(a.path,n,e.key,c);else{const d=ke().find(h=>h.harness===e.runtime);if(!d||n!=="user"||c==="inherit"){i(r,400,{error:"This runtime only supports user-scope on/off overrides"});return}await d.state.writeGlobalEnabled(e.key,c==="on")}t.dataBus?.emit({key:"toolkit"}),i(r,200,{ok:!0})}catch(l){i(r,400,{error:l instanceof Error?l.message:"Plugin state write failed"})}return}}if(o.match(/^\/projects\/(\d+)\/plugins\/uninstall$/)&&s.method==="POST"){let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!T(a.runtime)||!a.key){i(r,400,{error:'Missing or invalid "runtime"/"key"'});return}try{const e=a.runtime==="claude"&&t.pluginSurface?t.pluginSurface:or(a.runtime),{name:n,market:c}=e.parsePluginKey(a.key);await e.uninstall(n,c),i(r,200,{ok:!0})}catch(e){i(r,400,{error:e instanceof Error?e.message:"Plugin uninstall failed"})}return}const H=o.match(/^\/projects\/(\d+)\/mcp\/enable$/);if(H){const a=t.projects.getById(Number(H[1]));if(!a){i(r,404,{error:"Project not found"});return}if(s.method==="PUT"){let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!e.name||!e.state){i(r,400,{error:'Missing "name" or "state"'});return}if(!["on","off","inherit"].includes(e.state)){i(r,400,{error:'Invalid "state" (on|off|inherit)'});return}await Mr(a.path,e.name,e.state),i(r,200,{ok:!0});return}}const K=o.match(/^\/projects\/(\d+)\/updates$/);if(K&&s.method==="GET"){const a=t.projects.getById(Number(K[1]));if(!a){i(r,404,{error:"Project not found"});return}const e=t.fingerprintCache??new G;if(!t.libraries){const c=await se(a.path,e);i(r,200,{skills:[],mcp:[],files:[],pluginTemplates:c,available:c.filter(l=>l.outdated).length});return}const n=await ie(a.path,t.libraries.list(),e);i(r,200,n);return}const W=o.match(/^\/projects\/(\d+)\/update$/);if(W&&s.method==="POST"){const a=t.projects.getById(Number(W[1]));if(!a){i(r,404,{error:"Project not found"});return}if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!e.category||!e.name||!e.scope){i(r,400,{error:'Missing "category", "name", or "scope"'});return}if(!["skill","mcp","command","agent","workflow","rule","output-style"].includes(e.category)){i(r,400,{error:'Invalid "category"'});return}try{const n=await Fr(t.libraries.list());await Ar(a.path,{category:e.category,name:e.name,scope:e.scope,agent:e.agent},n),i(r,200,{ok:!0,category:e.category,name:e.name,scope:e.scope})}catch(n){i(r,400,{error:n instanceof Error?n.message:"Update failed"})}return}const z=o.match(/^\/projects\/(\d+)\/sync-all$/);if(z&&s.method==="POST"){const a=t.projects.getById(Number(z[1]));if(!a){i(r,404,{error:"Project not found"});return}if(!t.libraries){i(r,503,{error:"Libraries unavailable"});return}try{const e=t.fingerprintCache??new G,n=await xr(a.path,t.libraries.list(),e);let c=n;try{const l=t.hookPlugins?.list().map(h=>h.id)??[],d=fr(a,l,{projects:t.projects});c={...n,pluginSync:{syncedAt:d}}}catch{}i(r,200,c),t.updatesRefresher?.refreshNow(!0)}catch(e){i(r,400,{error:e instanceof Error?e.message:"Sync failed"})}return}const q=o.match(/^\/projects\/(\d+)\/config$/);if(q){const a=t.projects.getById(Number(q[1]));if(!a){i(r,404,{error:"Project not found"});return}if(s.method==="GET"){i(r,200,await tr(a.path));return}if(s.method==="PUT"){let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}const n=await tr(a.path),c={autoSync:e.autoSync??n.autoSync,lastSyncAt:e.lastSyncAt??n.lastSyncAt};await $r(a.path,c),i(r,200,c);return}}if(o==="/statusline/global"){if(s.method==="GET"){i(r,200,{config:await sr()});return}if(s.method==="PUT"){let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}try{await te(a);for(const e of t.projects.list()){const n=await ar(e.path);n.source==="global"&&await ir(e.path,n)}t.dataBus?.emit({key:"statusline"}),i(r,200,{ok:!0})}catch(e){i(r,400,{error:e instanceof Error?e.message:"Global statusline update failed"})}return}}if(o==="/statusline/default"&&s.method==="GET"){i(r,200,{config:ae});return}const _=o.match(/^\/projects\/(\d+)\/statusline$/);if(_){const a=t.projects.getById(Number(_[1]));if(!a){i(r,404,{error:"Project not found"});return}if(s.method==="GET"){const[e,n,c]=await Promise.all([ar(a.path),ee(a.path),sr()]);i(r,200,{config:e,script:n,globalConfig:c});return}if(s.method==="PUT"){let e;try{e=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}try{await ir(a.path,e),t.dataBus?.emit({key:"statusline",projectPath:a.path}),i(r,200,{ok:!0})}catch(n){i(r,400,{error:n instanceof Error?n.message:"Statusline update failed"})}return}}if(o==="/events"&&s.method==="GET"){Be(s,r,t);return}if(o==="/assets"&&s.method==="GET"){const a=u.searchParams.get("path");if(!a){i(r,400,{error:'Missing "path" query parameter'});return}if(!t.watch){i(r,503,{error:"Watch service unavailable"});return}const e=await ue(a),n=t.watch.getAssets(a).map(c=>{const l=e.get(c.relPath);return l?{...c,namespace:l}:c});i(r,200,{projectPath:a,assets:n});return}if(o==="/global-file-assets"&&s.method==="GET"){i(r,200,{assets:await re()});return}if(o==="/projects"&&s.method==="GET"){i(r,200,{projects:await cr(t.projects.list(),t.harnesses)});return}if(o==="/projects/archived"&&s.method==="GET"){i(r,200,{projects:await cr(t.projects.listArchived(),t.harnesses)});return}const V=o.match(/^\/projects\/(\d+)\/archive$/);if(V&&s.method==="POST"){const a=t.projects.getById(Number(V[1]));if(!a){i(r,404,{error:"Project not found"});return}if(a.archivedAt){i(r,200,{project:a,purged:{events:0,dispatches:0,sessions:0,messages:0}});return}const e=t.hookDispatches?.deleteByProject(a.id)??0,n=t.hookEvents?.deleteByProject(a.id)??0,c=t.messageDeliverer?.forgetProject(a.id)??0;t.sessionWatches?.deleteByProject(a.id),t.sessionSequences?.deleteByProject(a.id);const l=t.hookSessions?.removeByProject(a.id)??0;t.projects.setArchived(a.id,!0),le(t.hooksDir??pr(),a.token),t.watch?.reconcile(),t.dataBus?.emit({key:"projects"}),i(r,200,{project:t.projects.getById(a.id),purged:{events:n,dispatches:e,sessions:l,messages:c}});return}const Q=o.match(/^\/projects\/(\d+)\/restore$/);if(Q&&s.method==="POST"){const a=t.projects.getById(Number(Q[1]));if(!a){i(r,404,{error:"Project not found"});return}if(!a.archivedAt){i(r,200,{project:a});return}t.projects.setArchived(a.id,!1),t.hookMirror?.syncProject(a.id),t.watch?.reconcile(),t.dataBus?.emit({key:"projects"}),i(r,200,{project:t.projects.getById(a.id)});return}if(o==="/projects/order"&&s.method==="PUT"){let a;try{a=JSON.parse(await f(s))}catch{i(r,400,{error:"Invalid JSON body"});return}if(!Array.isArray(a.ids)||!a.ids.every(e=>Number.isInteger(e))){i(r,400,{error:'Invalid "ids" (integer array expected)'});return}t.projects.setOrder(a.ids),t.dataBus?.emit({key:"projects"}),i(r,200,{projects:t.projects.list()});return}const X=o.match(/^\/projects\/(\d+)\/terminals$/);if(X&&s.method==="GET"){const a=t.projects.getById(Number(X[1]));if(!a){i(r,404,{error:"Project not found"});return}const e=await P(),n=t.opener?.listTerminals??N.listTerminals,c=ye(e.terminal).enumerable?await n(a.path,e.terminal):[];i(r,200,{projectId:a.id,terminals:c});return}if(o==="/terminals/counts"&&s.method==="GET"){if(t.terminalRefresher)i(r,200,{counts:t.terminalRefresher.lastSnapshot?.counts??{}}),t.terminalRefresher.tick(!0);else{const a=t.opener??N;i(r,200,{counts:await ge(t.projects.list(),a)})}return}if(s.method==="GET"&&t.staticDir){Ge(r,o,t.staticDir);return}i(r,404,{error:"Not found"})}function Be(s,r,t){if(!t.watch&&!t.hookBus&&!t.dataBus){r.statusCode=503,r.setHeader("content-type","application/json"),r.end(JSON.stringify({error:"Event stream unavailable"}));return}r.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),r.write(`: connected
1
+ import yt from"node:http";import{WEAVE_VERSION as bt}from"../version.js";import{checkHarness as wt,isHarness as C}from"@weavecode/core";import S from"node:fs";import{homedir as $}from"node:os";import v from"node:path";import{hooksRoot as jt}from"../hooks/mirror.js";import{SseHub as kt}from"./sse-hub.js";import{syncPlugins as St}from"../hooks/plugin-project-state.js";import{getLibraryScan as it,invalidateScan as k}from"../install/scan-cache.js";import{installSkill as vt,uninstallSkill as Pt,installFileAsset as It,uninstallFileAsset as Et,InstallConflictError as ot,AssetNotFoundError as G}from"../install/installer.js";import{isFileAssetCategory as nt}from"../install/file-assets.js";import{installCapabilities as Nt}from"../install/capabilities.js";import{readMcpRows as Tt}from"../install/mcp-rows.js";import{installGlobalSkill as Ot,uninstallGlobalSkill as Mt,readGlobalSkillGroups as Bt,resolveGlobalSkillDir as st,listGlobalSkillFiles as Ct,readGlobalSkillFile as $t,ClaudeJsonCorruptError as Gt}from"../install/global-config.js";import{CodexTomlCorruptError as At}from"../install/codex-toml.js";import{forgetInstalled as Jt,recordInstalled as Dt}from"../install/install-ledger.js";import{setMcpEnableOverride as Ft}from"../install/settings-mcp.js";import{readProjectConfig as ct,writeProjectConfig as Rt}from"../install/project-config.js";import{applyUpdate as Lt,syncAll as Ht}from"../install/apply-update.js";import{buildLibraryIndex as Ut}from"../install/library-index.js";import{importFromDir as xt,importFromGit as Kt,importLibraryIntoMarket as Wt}from"../market/import.js";import{marketDir as A,readManifest as _t}from"../market/manifest.js";import{marketIdOf as zt}from"../market/identity.js";import{isInsideDir as J,toRelPosix as Vt}from"../market/resolve.js";import{checkMarketUpdates as Qt}from"../market/updates.js";import{refreshMarketItems as Xt}from"../market/refresh.js";import{ensureBuiltinMarket as Yt,isBuiltinMarketDir as E}from"../market/builtin.js";import{removeInstalled as Zt}from"../market/install-link.js";import{readProjectFile as qt,readGlobalFile as te,PathEscapeError as ee,FileTooLargeError as re}from"../install/reader.js";import{listGlobalFileAssets as ae}from"../install/global-file-assets.js";import{readStatuslineConfig as lt,readStatuslineScript as ie,readStatuslineFacts as oe,applyStatuslineConfig as ut,readGlobalStatuslineConfig as mt,writeGlobalStatuslineConfig as ne}from"../statusline/manager.js";import{DEFAULT_STATUSLINE_CONFIG as se}from"../statusline/config.js";import{FingerprintCache as D}from"../install/fingerprint.js";import{detectUpdates as ce}from"../install/updates.js";import{detectPluginTemplateUpdates as le}from"../install/plugin-templates.js";import{detectInitFileUpdates as ue,needsInit as me}from"../install/init-files.js";import{readBody as p,sendJson as i}from"./http.js";import{ApiLogger as fe}from"./api-log.js";import{handleHooksRoutes as de}from"./hooks-routes.js";import{handleToolkitRoutes as he}from"./toolkit-routes.js";import{handleCaptureRoutes as pe}from"./capture-routes.js";import{purgeProjectPipeline as ge}from"./hook-pipeline.js";import{projectFileNamespaces as ye}from"../hooks/toolkit.js";import{listBrowseRoots as be,listDirectoryChildren as we}from"./fs-browser.js";import{DEFAULT_AI_SETTINGS as je,readDaemonSettings as P,writeDaemonSettings as ke,terminalPresetsFor as Se}from"./settings.js";import{closeTerminalsIn as ve,defaultProjectOpener as I,readTerminalCounts as Pe,terminalBackendFor as Ie}from"./opener.js";import{applyLaunchOnLogin as Ee}from"./auto-start.js";import{DAEMON_HOST as Ne}from"./port.js";import{assetSurfaces as Te,pluginStateSurfaces as Oe,pluginSurfaces as ft,pluginSurfaceFor as dt}from"../surfaces.js";import{readPluginRows as Me}from"../install/plugin-rows.js";import{installPluginPack as Be}from"../install/plugin-install.js";import{handleAuthRoutes as Ce}from"./auth-routes.js";import{handleAiRoutes as $e}from"./ai-routes.js";import{hasAiKey as Ge,writeAiKey as Ae}from"./ai-config.js";import{accessUrls as Je}from"./tls.js";import{projectHarnesses as De,withProjectHarnesses as ht}from"./project-harnesses.js";export const DAEMON_VERSION=bt;export function weaveRequestHandler(o){const t=o.fingerprintCache??new D,r=o.apiLog??new fe,u=o.sseHub??new kt(o),c={...o,fingerprintCache:t,apiLog:r,sseHub:u};return(b,g)=>{r.begin(b,g),Fe(b,g,c)}}export function createWeaveServer(o){return yt.createServer(weaveRequestHandler(o))}async function Fe(o,t,r){const u=new URL(o.url??"/",`http://${Ne}`);let c=u.pathname;if(c.startsWith("/api/")?c=c.slice(4):c==="/api"&&(c="/"),c==="/health"&&o.method==="GET"){i(t,200,{service:"weave-daemon",version:DAEMON_VERSION,pid:process.pid,port:r.port,uptimeMs:Math.round(process.uptime()*1e3)});return}if(await Ce(o,t,r,c)||await $e(o,t,r,c))return;if(r.auth&&!He(o,c,r)&&!r.auth.isAuthenticated(o.headers)){i(t,401,{error:"Unauthorized"});return}if(c==="/api-logs"&&o.method==="GET"){if(!r.apiLog){i(t,503,{error:"API log unavailable"});return}const a=u.searchParams.get("status"),e=u.searchParams.get("limit"),n=await r.apiLog.query({from:u.searchParams.get("from")??void 0,to:u.searchParams.get("to")??void 0,path:u.searchParams.get("path")??void 0,method:u.searchParams.get("method")??void 0,status:a==null?void 0:Number(a),limit:e==null?void 0:Number(e)});i(t,200,n);return}if(await de(o,t,r,c,u)||await he(o,t,r,c,u)||await pe(o,t,r,c))return;const b=c.match(/^\/projects\/(\d+)\/hooks$/);if(b&&o.method==="GET"){if(!r.hookEvents){i(t,503,{error:"Hook ingestion unavailable"});return}const a=Number(b[1]),e=_e(u.searchParams.get("limit")),n=u.searchParams.get("sessionId"),s=u.searchParams.get("beforeId"),l=s?Number(s):void 0,m=(u.searchParams.get("types")??"").split(",").map(f=>f.trim()).filter(Boolean);if(n){const f=r.hookEvents.listBySession(n,e??300,l,m),h=r.uploads?.imagesBySession(n);i(t,200,{events:f.map(d=>{const T=h?.get(d.id);return T?.length?{...d,images:T.map(B=>({id:B.id,name:B.name,mediaType:B.mediaType}))}:d})});return}i(t,200,{events:r.hookEvents.listByProject(a,e)});return}if(c==="/settings"){if(o.method==="GET"){i(t,200,{settings:pt(await P(),r.aiKeyPath),presets:Se(process.platform),platform:process.platform,urls:Je(r.port,r.tlsPort??0)});return}if(o.method==="PUT"){let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}const e=a.ai?.apiKey;e!==void 0&&Ae(typeof e=="string"?e:null,r.aiKeyPath);const n=await ke({...a,ai:Ke(a.ai)});r.hookEvents?.resetPrune(),(r.autoStart??Ee)(n.startup?.launchOnLogin??!1),r.dataBus?.emit({key:"settings"}),i(t,200,pt(n,r.aiKeyPath));return}}const g=c.match(/^\/projects\/(\d+)\/open$/);if(g&&o.method==="POST"){const a=r.projects.getById(Number(g[1]));if(!a){i(t,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(e.target!=="explorer"&&e.target!=="terminal"){i(t,400,{error:'Invalid "target" (explorer|terminal)'});return}const n=r.opener??I;try{if(!(await S.promises.stat(a.path)).isDirectory())throw new Error(`Not a directory: ${a.path}`);if(e.target==="explorer")await n.openExplorer(a.path);else{const l=await P();await n.openTerminal(a.path,l.terminal),setTimeout(()=>{r.terminalRefresher?.refreshNow()},600)}i(t,200,{ok:!0,target:e.target,path:a.path})}catch(s){i(t,400,{error:s instanceof Error?s.message:"Open failed"})}return}const y=c.match(/^\/projects\/(\d+)\/close-terminal$/);if(y&&o.method==="POST"){const a=r.projects.getById(Number(y[1]));if(!a){i(t,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await p(o)||"{}")}catch{i(t,400,{error:"Invalid JSON body"});return}if(!Array.isArray(e.paneIds)||e.paneIds.length===0||e.paneIds.some(l=>typeof l!="string")){i(t,400,{error:"paneIds must be a non-empty array of strings"});return}const n=r.opener??I,s=await P();try{const m=await(n.closeTerminals??ve)(a.path,s.terminal,e.paneIds);setTimeout(()=>{r.terminalRefresher?.refreshNow()},600),i(t,200,{ok:!0,closed:m})}catch(l){i(t,400,{error:l instanceof Error?l.message:"Close failed"})}return}const w=c.match(/^\/projects\/(\d+)\/new-session$/);if(w&&o.method==="POST"){const a=r.projects.getById(Number(w[1]));if(!a){i(t,404,{error:"Project not found"});return}let e;try{e=JSON.parse(await p(o)||"{}")}catch{i(t,400,{error:"Invalid JSON body"});return}const n=await De(a.path,r.harnesses);if(e.harness!==void 0&&!C(e.harness)){i(t,400,{error:'Invalid "harness"'});return}const s=e.harness;if(s&&!n.some(d=>d.id===s)){i(t,409,{error:`Harness "${s}" is not integrated in this project`});return}const l=s?[s]:n.map(d=>d.id),m=l.map(d=>({id:d,spec:r.harnesses?.get(d)?.resume})).find(d=>d.spec?.bin);if(!m){i(t,501,{error:`Harness "${l[0]}" cannot start an interactive session`});return}const f=m.spec,h=r.opener??I;try{if(!(await S.promises.stat(a.path)).isDirectory())throw new Error(`Not a directory: ${a.path}`);const T=await P();await h.runInTerminal(a.path,[f.bin],T.terminal),setTimeout(()=>{r.terminalRefresher?.refreshNow()},600),i(t,200,{ok:!0,command:f.bin,cwd:a.path})}catch(d){i(t,400,{error:d instanceof Error?d.message:"Open failed"})}return}if(c==="/fs/roots"&&o.method==="GET"){const a=r.libraries?r.libraries.list().map(n=>n.path):[],e=await be(a);i(t,200,{roots:e});return}if(c==="/fs/children"&&o.method==="GET"){const a=u.searchParams.get("path");if(!a){i(t,400,{error:'Missing "path" query parameter'});return}try{const e=await we(a);i(t,200,{children:e})}catch(e){i(t,400,{error:`Cannot list directory: ${String(e)}`})}return}if(c==="/capabilities"&&o.method==="GET"){i(t,200,Nt());return}if(c==="/libraries"&&o.method==="GET"){i(t,200,{libraries:r.libraries?r.libraries.list():[]});return}if(c==="/libraries"&&o.method==="POST"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!a.path||!a.kind){i(t,400,{error:'Missing "path" or "kind"'});return}if(!["skill","mcp","both"].includes(a.kind)){i(t,400,{error:'Invalid "kind" (skill|mcp|both)'});return}const e=r.libraries.add({path:a.path,kind:a.kind});r.dataBus?.emit({key:"libraries"}),i(t,201,e);return}const N=c.match(/^\/libraries\/(\d+)\/assets$/);if(N&&o.method==="GET"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}const a=r.libraries.getById(Number(N[1]));if(!a){i(t,404,{error:"Library not found"});return}const{plugins:e,skills:n,mcp:s,files:l}=await it(a.path),m=a.kind==="skill"||a.kind==="both"?e:[],f=a.kind==="mcp"||a.kind==="both"?s:[],h=a.kind==="skill"||a.kind==="both"?Object.values(l).flat():null;i(t,200,{library:a,skills:n,mcp:f,files:h,plugins:m});return}const j=c.match(/^\/libraries\/(\d+)$/);if(j&&o.method==="DELETE"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}const a=Number(j[1]),e=r.libraries.getById(a);e&&await k(e.path),r.libraries.remove(a),r.dataBus?.emit({key:"libraries"}),r.dataBus?.emit({key:"market"}),i(t,200,{ok:!0});return}if(c==="/market"&&o.method==="GET"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}const a=await Promise.all(r.libraries.list().map(e=>M(e,r.libraries.dataDir)));i(t,200,{items:a});return}if(c==="/market"&&o.method==="POST"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}const e={libraries:r.libraries,dataDir:r.libraries.dataDir};try{if(a.kind==="dir"&&a.path){const n=await xt(a.path,e);n.refreshed&&r.fingerprintCache?.invalidate(n.dir),await k(n.dir),r.dataBus?.emit({key:"market"}),i(t,201,{item:await M(r.libraries.getById(n.libraryId),r.libraries.dataDir)})}else if(a.kind==="git"&&a.url){const n=await Kt(a.url,e);n.refreshed&&r.fingerprintCache?.invalidate(n.dir),await k(n.dir),r.dataBus?.emit({key:"market"}),i(t,201,{item:await M(r.libraries.getById(n.libraryId),r.libraries.dataDir)})}else i(t,400,{error:'Invalid body (kind: "dir" + path | "git" + url)'})}catch(n){i(t,400,{error:n instanceof Error?n.message:"Import failed"})}return}if(c==="/market/check-updates"&&o.method==="POST"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}let a={};const e=(await p(o)).trim();if(e)try{a=JSON.parse(e)}catch{i(t,400,{error:"Invalid JSON body"});return}const n=r.libraries.list().filter(l=>!E(l.path,r.libraries.dataDir)).filter(l=>!a.ids?.length||a.ids.includes(l.id));for(const l of n)await k(l.path);const s=await Qt(n.map(l=>({id:l.id,dir:l.path})));r.dataBus?.emit({key:"market"}),i(t,200,{results:s});return}if(c==="/market/refresh"&&o.method==="POST"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}let a={};const e=(await p(o)).trim();if(e)try{a=JSON.parse(e)}catch{i(t,400,{error:"Invalid JSON body"});return}const n=r.libraries.list().filter(h=>!a.ids?.length||a.ids.includes(h.id)),s=[];for(const h of n.filter(d=>E(d.path,r.libraries.dataDir))){const d=await Yt({libraries:r.libraries});s.push({id:h.id,status:d.error?"failed":"refreshed"})}const l=n.filter(h=>!E(h.path,r.libraries.dataDir)).map(h=>({id:h.id,dir:h.path})),m=[...await Xt(l,{libraries:r.libraries,dataDir:r.libraries.dataDir}),...s],f=new Map(l.map(h=>[h.id,h.dir]));for(const h of m)if(h.status==="refreshed"){const d=f.get(h.id);d&&(r.fingerprintCache?.invalidate(d),await k(d))}r.dataBus?.emit({key:"market"}),i(t,200,{results:m});return}const L=c.match(/^\/market\/(\d+)$/);if(L&&o.method==="DELETE"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}const a=r.libraries.getById(Number(L[1]));if(!a){i(t,404,{error:"Library not found"});return}if(E(a.path,r.libraries.dataDir)){i(t,409,{error:"Built-in market is owned by weave and cannot be deleted",note:"It is re-materialized from @weavecode/templates on every daemon start."});return}if(!J(a.path,A(r.libraries.dataDir))){i(t,400,{error:"Not a market resource (legacy row \u2014 use DELETE /libraries/:id)"});return}let e;try{await(r.pluginSurface??dt("claude")).removeMarketplace(a.path)}catch(n){e=`Host marketplace deregistration failed: ${n instanceof Error?n.message:String(n)}`}await Zt(a.path),r.libraries.remove(a.id),await k(a.path),r.dataBus?.emit({key:"market"}),r.dataBus?.emit({key:"libraries"}),i(t,200,{ok:!0,removed:a.path,installedCopiesKept:!0,...e?{warning:e}:{},note:"The host cascade-uninstalls plugins installed from this market; other installed copies are kept."});return}const H=c.match(/^\/libraries\/(\d+)\/market-import$/);if(H&&o.method==="POST"){if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}const a=r.libraries.getById(Number(H[1]));if(!a){i(t,404,{error:"Library not found"});return}try{const e=a.path,n=await Wt(a,{libraries:r.libraries,dataDir:r.libraries.dataDir});await k(e),await k(n.dir),i(t,200,{item:await M(r.libraries.getById(n.libraryId),r.libraries.dataDir)})}catch(e){i(t,400,{error:e instanceof Error?e.message:"Import failed"})}return}const U=c.match(/^\/projects\/(\d+)\/install$/);if(U&&o.method==="POST"){const a=r.projects.getById(Number(U[1]));let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!a&&gt(e)){i(t,404,{error:"Project not found"});return}const n=a?.path??"";try{if(e.category==="skill"){if(!e.name||!e.sourceDir){i(t,400,{error:'Missing "name" or "sourceDir"'});return}const s=e.agent??"claude",l=e.scope==="user"?await Ot(e.sourceDir,e.name,s):await vt(n,e.sourceDir,e.name,s);i(t,201,{category:"skill",name:e.name,scope:e.scope??"project",agent:s,path:l})}else if(e.category&&nt(e.category)){if(!e.name||!e.sourceFile){i(t,400,{error:'Missing "name" or "sourceFile"'});return}const s=e.agent??"claude",l=e.scope??"project",m=await It(n,e.category,e.name,e.sourceFile,s,l);i(t,201,{category:e.category,name:e.name,scope:l,agent:s,path:m})}else if(e.category==="mcp"){if(!e.name||!e.mcpConfig){i(t,400,{error:'Missing "name" or "mcpConfig"'});return}const s=e.agent??"claude",l=F(s);if(!l){i(t,400,{error:`Unsupported agent: ${s}`});return}const m=l.mcpScopes(),f=e.scope??m[0];if(!f||!m.includes(f)){i(t,400,{error:`MCP servers for ${s} are ${m.join("/")}-level only \u2014 scope "${e.scope}" is not available`});return}if(e.name in await l.mcpRead(f,n,$())){O(t,new ot(`MCP server "${e.name}" is already configured`));return}await l.mcpWrite(f,n,$(),e.name,e.mcpConfig),f==="project"&&await Dt(n,{category:"mcp",name:e.name,agent:s}),i(t,201,{category:"mcp",name:e.name,scope:f,agent:s})}else if(e.category==="plugin"){if(!e.name||!e.sourceDir){i(t,400,{error:'Missing "name" or "sourceDir"'});return}if(e.scope&&e.scope!=="user"){i(t,400,{error:'Plugin install currently only supports scope "user"'});return}const s=e.agent??"claude",l=ft().find(h=>h.harness===s);if(!l){i(t,400,{error:`No plugin install surface for runtime: ${s}`});return}const m=s==="claude"&&r.pluginSurface?r.pluginSurface:l.surface,f=await Be(m,{dir:e.sourceDir,name:e.name,version:e.version,description:e.description});r.dataBus?.emit({key:"toolkit"}),i(t,201,{category:"plugin",key:f.key,scope:"user",agent:s,alreadyInstalled:f.alreadyInstalled})}else i(t,400,{error:'Invalid "category" (skill|mcp|plugin|command|agent|workflow|rule|output-style)'})}catch(s){O(t,s)}return}const x=c.match(/^\/projects\/(\d+)\/uninstall$/);if(x&&o.method==="POST"){const a=r.projects.getById(Number(x[1]));let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!a&&gt(e)){i(t,404,{error:"Project not found"});return}const n=a?.path??"";try{if(e.category==="skill"){if(!e.name){i(t,400,{error:'Missing "name"'});return}const s=e.agent??"claude";e.scope==="user"?await Mt(e.name,s):await Pt(n,e.name,s)}else if(e.category&&nt(e.category)){if(!e.name){i(t,400,{error:'Missing "name"'});return}await Et(n,e.category,e.name,e.agent??"claude",e.scope??"project")}else if(e.category==="mcp"){if(!e.name){i(t,400,{error:'Missing "name"'});return}const s=e.agent??"claude",l=F(s);if(!l){i(t,400,{error:`Unsupported agent: ${s}`});return}const m=l.mcpScopes(),f=e.scope??m[0];if(!f||!m.includes(f)){i(t,400,{error:`MCP servers for ${s} are ${m.join("/")}-level only \u2014 scope "${e.scope}" is not available`});return}if(!await l.mcpRemove(f,n,$(),e.name)){O(t,new G(`MCP server "${e.name}" is not configured`));return}f==="project"&&await Jt(n,{category:"mcp",name:e.name,agent:s})}else{i(t,400,{error:'Invalid "category" (skill|mcp|command|agent|workflow|rule|output-style)'});return}i(t,200,{ok:!0})}catch(s){O(t,s)}return}const K=c.match(/^\/projects\/(\d+)\/file$/);if(K&&o.method==="GET"){const a=r.projects.getById(Number(K[1]));if(!a){i(t,404,{error:"Project not found"});return}const e=u.searchParams.get("path");if(!e){i(t,400,{error:'Missing "path" query parameter'});return}try{const n=await qt(a.path,e);i(t,200,{path:e,content:n.content,size:n.size})}catch(n){R(t,n)}return}if(c==="/global-file"&&o.method==="GET"){const a=u.searchParams.get("path");if(!a){i(t,400,{error:'Missing "path" query parameter'});return}try{const e=await te(a);i(t,200,{path:a,content:e.content,size:e.size})}catch(e){R(t,e)}return}const W=c.match(/^\/projects\/(\d+)\/mcp$/);if(W&&o.method==="GET"){const a=r.projects.getById(Number(W[1]));if(!a){i(t,404,{error:"Project not found"});return}i(t,200,{rows:await Tt(a.path)});return}const _=c.match(/^\/projects\/(\d+)\/harness-checks$/);if(_&&o.method==="GET"){const a=r.projects.getById(Number(_[1]));if(!a){i(t,404,{error:"Project not found"});return}i(t,200,{checks:await wt(a.path)});return}if(c.match(/^\/projects\/(\d+)\/skills\/global$/)&&o.method==="GET"){i(t,200,{groups:await Bt()});return}if(c.match(/^\/projects\/(\d+)\/skills\/global\/files$/)&&o.method==="GET"){const a=u.searchParams.get("source"),e=u.searchParams.get("name"),n=u.searchParams.get("pluginKey")??void 0;if(!a||!e){i(t,400,{error:'Missing "source" or "name" query parameter'});return}const s=await st(a,e,n);if(!s){i(t,404,{error:"Skill not found"});return}i(t,200,{files:await Ct(s)});return}if(c.match(/^\/projects\/(\d+)\/skills\/global\/file$/)&&o.method==="GET"){const a=u.searchParams.get("source"),e=u.searchParams.get("name"),n=u.searchParams.get("pluginKey")??void 0,s=u.searchParams.get("path");if(!a||!e||!s){i(t,400,{error:'Missing "source", "name" or "path" query parameter'});return}const l=await st(a,e,n);if(!l){i(t,404,{error:"Skill not found"});return}try{const m=await $t(l,s);i(t,200,{path:s,content:m.content,size:m.size})}catch(m){R(t,m)}return}const z=c.match(/^\/projects\/(\d+)\/plugins\/state$/);if(z){const a=r.projects.getById(Number(z[1]));if(!a){i(t,404,{error:"Project not found"});return}if(o.method==="GET"){i(t,200,{rows:await Me(a.path)});return}if(o.method==="PUT"){let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!C(e.runtime)||!e.key||!e.scope||!["user","project","local"].includes(e.scope)||!e.state||!["on","off","inherit"].includes(e.state)){i(t,400,{error:'Missing or invalid "runtime"/"key"/"scope" (user|project|local)/"state" (on|off|inherit)'});return}const n=e.scope,s=e.state;try{const l=ft().find(m=>m.harness===e.runtime);if(l)await(e.runtime==="claude"&&r.pluginSurface?r.pluginSurface:l.surface).setEnabledOverride(a.path,n,e.key,s);else{const m=Oe().find(f=>f.harness===e.runtime);if(!m||n!=="user"||s==="inherit"){i(t,400,{error:"This runtime only supports user-scope on/off overrides"});return}await m.state.writeGlobalEnabled(e.key,s==="on")}r.dataBus?.emit({key:"toolkit"}),i(t,200,{ok:!0})}catch(l){i(t,400,{error:l instanceof Error?l.message:"Plugin state write failed"})}return}}if(c.match(/^\/projects\/(\d+)\/plugins\/uninstall$/)&&o.method==="POST"){let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!C(a.runtime)||!a.key){i(t,400,{error:'Missing or invalid "runtime"/"key"'});return}try{const e=a.runtime==="claude"&&r.pluginSurface?r.pluginSurface:dt(a.runtime),{name:n,market:s}=e.parsePluginKey(a.key);await e.uninstall(n,s),i(t,200,{ok:!0})}catch(e){i(t,400,{error:e instanceof Error?e.message:"Plugin uninstall failed"})}return}const V=c.match(/^\/projects\/(\d+)\/mcp\/enable$/);if(V){const a=r.projects.getById(Number(V[1]));if(!a){i(t,404,{error:"Project not found"});return}if(o.method==="PUT"){let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!e.name||!e.state){i(t,400,{error:'Missing "name" or "state"'});return}if(!["on","off","inherit"].includes(e.state)){i(t,400,{error:'Invalid "state" (on|off|inherit)'});return}await Ft(a.path,e.name,e.state),i(t,200,{ok:!0});return}}const Q=c.match(/^\/projects\/(\d+)\/updates$/);if(Q&&o.method==="GET"){const a=r.projects.getById(Number(Q[1]));if(!a){i(t,404,{error:"Project not found"});return}const e=r.fingerprintCache??new D;if(!r.libraries){const s=await le(a.path,e),l=await ue(a.path);i(t,200,{skills:[],mcp:[],files:[],pluginTemplates:s,initFiles:l,available:s.filter(m=>m.outdated).length+l.filter(m=>m.outdated&&m.syncClass==="auto").length,needsInit:me(l)});return}const n=await ce(a.path,r.libraries.list(),e);i(t,200,n);return}const X=c.match(/^\/projects\/(\d+)\/update$/);if(X&&o.method==="POST"){const a=r.projects.getById(Number(X[1]));if(!a){i(t,404,{error:"Project not found"});return}if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!e.category||!e.name||!e.scope){i(t,400,{error:'Missing "category", "name", or "scope"'});return}if(!["skill","mcp","command","agent","workflow","rule","output-style"].includes(e.category)){i(t,400,{error:'Invalid "category"'});return}try{const s=await Ut(r.libraries.list());await Lt(a.path,{category:e.category,name:e.name,scope:e.scope,agent:e.agent},s),i(t,200,{ok:!0,category:e.category,name:e.name,scope:e.scope})}catch(s){i(t,400,{error:s instanceof Error?s.message:"Update failed"})}return}const Y=c.match(/^\/projects\/(\d+)\/sync-all$/);if(Y&&o.method==="POST"){const a=r.projects.getById(Number(Y[1]));if(!a){i(t,404,{error:"Project not found"});return}if(!r.libraries){i(t,503,{error:"Libraries unavailable"});return}try{const e=r.fingerprintCache??new D,n=await Ht(a.path,r.libraries.list(),e);let s=n;try{const l=r.hookPlugins?.list().map(f=>f.id)??[],m=St(a,l,{projects:r.projects});s={...n,pluginSync:{syncedAt:m}}}catch{}i(t,200,s),r.updatesRefresher?.refreshNow(!0)}catch(e){i(t,400,{error:e instanceof Error?e.message:"Sync failed"})}return}const Z=c.match(/^\/projects\/(\d+)\/config$/);if(Z){const a=r.projects.getById(Number(Z[1]));if(!a){i(t,404,{error:"Project not found"});return}if(o.method==="GET"){i(t,200,await ct(a.path));return}if(o.method==="PUT"){let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}const n=await ct(a.path),s={lastSyncAt:e.lastSyncAt??n.lastSyncAt};await Rt(a.path,s),i(t,200,s);return}}if(c==="/statusline/global"){if(o.method==="GET"){i(t,200,{config:await mt()});return}if(o.method==="PUT"){let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}try{await ne(a);for(const e of r.projects.list()){const n=await lt(e.path);n.source==="global"&&await ut(e.path,n)}r.dataBus?.emit({key:"statusline"}),i(t,200,{ok:!0})}catch(e){i(t,400,{error:e instanceof Error?e.message:"Global statusline update failed"})}return}}if(c==="/statusline/default"&&o.method==="GET"){i(t,200,{config:se});return}const q=c.match(/^\/projects\/(\d+)\/statusline$/);if(q){const a=r.projects.getById(Number(q[1]));if(!a){i(t,404,{error:"Project not found"});return}if(o.method==="GET"){const[e,n,s]=await Promise.all([lt(a.path),ie(a.path),mt()]);i(t,200,{config:e,script:n,globalConfig:s,facts:oe(a.path)});return}if(o.method==="PUT"){let e;try{e=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}try{await ut(a.path,e),r.dataBus?.emit({key:"statusline",projectPath:a.path}),i(t,200,{ok:!0})}catch(n){i(t,400,{error:n instanceof Error?n.message:"Statusline update failed"})}return}}if(c==="/events"&&o.method==="GET"){Le(o,t,r,u);return}if(c==="/assets"&&o.method==="GET"){const a=u.searchParams.get("path");if(!a){i(t,400,{error:'Missing "path" query parameter'});return}if(!r.watch){i(t,503,{error:"Watch service unavailable"});return}const e=await ye(a),n=r.watch.getAssets(a).map(s=>{const l=e.get(s.relPath);return l?{...s,namespace:l}:s});i(t,200,{projectPath:a,assets:n});return}if(c==="/global-file-assets"&&o.method==="GET"){i(t,200,{assets:await ae()});return}if(c==="/projects"&&o.method==="GET"){i(t,200,{projects:await ht(r.projects.list(),r.harnesses)});return}if(c==="/projects/archived"&&o.method==="GET"){i(t,200,{projects:await ht(r.projects.listArchived(),r.harnesses)});return}const tt=c.match(/^\/projects\/(\d+)\/archive$/);if(tt&&o.method==="POST"){const a=r.projects.getById(Number(tt[1]));if(!a){i(t,404,{error:"Project not found"});return}if(a.archivedAt){i(t,200,{project:a,purged:{events:0,dispatches:0,sessions:0,messages:0}});return}const e=r.hookDispatches?.deleteByProject(a.id)??0,n=r.hookEvents?.deleteByProject(a.id)??0;r.uploads?.pruneUnreferenced();const s=r.messageDeliverer?.forgetProject(a.id)??0;r.sessionWatches?.deleteByProject(a.id),r.sessionSequences?.deleteByProject(a.id),r.sideQuestions?.repo.deleteByProject(a.id);const l=r.hookSessions?.removeByProject(a.id)??0;r.projects.setArchived(a.id,!0),ge(r.hooksDir??jt(),a.token),r.watch?.reconcile(),r.dataBus?.emit({key:"projects"}),i(t,200,{project:r.projects.getById(a.id),purged:{events:n,dispatches:e,sessions:l,messages:s}});return}const et=c.match(/^\/projects\/(\d+)\/restore$/);if(et&&o.method==="POST"){const a=r.projects.getById(Number(et[1]));if(!a){i(t,404,{error:"Project not found"});return}if(!a.archivedAt){i(t,200,{project:a});return}r.projects.setArchived(a.id,!1),r.hookMirror?.syncProject(a.id),r.watch?.reconcile(),r.dataBus?.emit({key:"projects"}),i(t,200,{project:r.projects.getById(a.id)});return}if(c==="/projects/order"&&o.method==="PUT"){let a;try{a=JSON.parse(await p(o))}catch{i(t,400,{error:"Invalid JSON body"});return}if(!Array.isArray(a.ids)||!a.ids.every(e=>Number.isInteger(e))){i(t,400,{error:'Invalid "ids" (integer array expected)'});return}r.projects.setOrder(a.ids),r.dataBus?.emit({key:"projects"}),i(t,200,{projects:r.projects.list()});return}const rt=c.match(/^\/projects\/(\d+)\/panes$/);if(rt&&o.method==="GET"){const a=r.projects.getById(Number(rt[1]));if(!a){i(t,404,{error:"Project not found"});return}const e=await P(),n=r.opener?.listPanes??I.listPanes;try{i(t,200,{projectId:a.id,panes:await n(a.path,e.terminal)})}catch(s){i(t,409,{error:s instanceof Error?s.message:"Cannot list panes"})}return}const at=c.match(/^\/projects\/(\d+)\/terminals$/);if(at&&o.method==="GET"){const a=r.projects.getById(Number(at[1]));if(!a){i(t,404,{error:"Project not found"});return}const e=await P(),n=r.opener?.listTerminals??I.listTerminals,s=Ie(e.terminal).enumerable?await n(a.path,e.terminal):[];i(t,200,{projectId:a.id,terminals:s});return}if(c==="/terminals/counts"&&o.method==="GET"){if(r.terminalRefresher)i(t,200,{counts:r.terminalRefresher.lastSnapshot?.counts??{}}),r.terminalRefresher.tick(!0);else{const a=r.opener??I;i(t,200,{counts:await Pe(r.projects.list(),a)})}return}if(o.method==="GET"&&r.staticDir){xe(t,c,r.staticDir);return}i(t,404,{error:"Not found"})}const Re=25e3;function Le(o,t,r,u){const c=r.sseHub;if(!c||!r.watch&&!r.hookBus&&!r.dataBus){t.statusCode=503,t.setHeader("content-type","application/json"),t.end(JSON.stringify({error:"Event stream unavailable"}));return}const b=o.headers["last-event-id"],g=(Array.isArray(b)?b[0]:b)??u.searchParams.get("since")??null,y=c.replay(g);t.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.write(`: connected
2
2
 
3
- `);const u=[];t.watch&&(u.push(t.watch.subscribe(o=>{r.write(`data: ${JSON.stringify({type:"asset",...o})}
3
+ `);const w=setInterval(()=>{t.writableEnded||t.write(`data: ${JSON.stringify({type:"ping"})}
4
4
 
5
- `)})),u.push(t.watch.subscribeProjects(o=>{r.write(`data: ${JSON.stringify({type:"project",...o})}
5
+ `)},Re);w.unref?.(),y.gap&&t.write(`data: ${JSON.stringify({type:"resync"})}
6
6
 
7
- `)}))),t.hookBus&&u.push(t.hookBus.subscribe(o=>{r.write(`data: ${JSON.stringify({type:"hook",...o})}
7
+ `);for(const j of y.frames)t.write(`id: ${j.id}
8
+ data: ${j.data}
8
9
 
9
- `)})),t.dataBus&&u.push(t.dataBus.subscribe(o=>{const y=o.payload===void 0?"invalidate":"push";r.write(`data: ${JSON.stringify({type:y,...o})}
10
+ `);const N=c.subscribe(j=>{t.write(`id: ${j.id}
11
+ data: ${j.data}
10
12
 
11
- `)})),t.inflightRefresher?.refreshNow(),t.terminalRefresher?.onSubscriberJoin(),t.updatesRefresher?.onSubscriberJoin(),s.on("close",()=>{for(const o of u)o()})}function Ce(s,r,t){if(r==="/health")return!0;if(s.method!=="GET")return!1;if((s.headers.accept??"").includes("text/html"))return!0;if(!t.staticDir)return!1;const u=S.normalize(r).replace(/^([/\\]\.\.[/\\])+/,""),o=S.join(t.staticDir,u);return o.startsWith(t.staticDir)&&j.existsSync(o)&&j.statSync(o).isFile()}function Ge(s,r,t){const u=S.normalize(r).replace(/^([/\\]\.\.[/\\])+/,""),o=S.join(t,u);if(!o.startsWith(t)){s.statusCode=403,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:"Forbidden"}));return}j.stat(o,(y,b)=>{if(!y&&b.isFile()){s.setHeader("content-type",Je(o)),j.createReadStream(o).pipe(s);return}j.readFile(S.join(t,"index.html"),(g,w)=>{if(g){s.statusCode=404,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:"Not found"}));return}s.setHeader("content-type","text/html"),s.end(w)})})}function lr(s,r){const t=s.ai??pe;return{...s,ai:{baseUrl:t.baseUrl,model:t.model,apiKeySet:Ne(r)}}}function De(s){if(!s)return;const{apiKey:r,...t}=s;return t}function Je(s){return s.endsWith(".js")?"text/javascript":s.endsWith(".css")?"text/css":s.endsWith(".html")?"text/html":s.endsWith(".svg")?"image/svg+xml":s.endsWith(".json")?"application/json":"application/octet-stream"}function Me(s){const r=Number(s??"100");return!Number.isFinite(r)||r<=0?100:Math.min(Math.floor(r),500)}function E(s,r){r instanceof Z?s.statusCode=409:r instanceof O?s.statusCode=404:r instanceof Br||r instanceof Jr?s.statusCode=500:s.statusCode=400,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:r instanceof Error?r.message:"Install failed"}))}async function I(s,r){const t=C(s.path,B(r)),u=t?await Hr(s.path):null,o=v(s.path,r);return{id:s.id,kind:s.kind,addedAt:s.addedAt,path:s.path,relPath:C(s.path,r)?Wr(s.path,r):null,resourceId:t?S.basename(s.path):null,managed:t,builtin:o,namespace:t?Kr(s.path,B(r)):void 0,legacy:!u&&!o,source:o?"builtin":u?.source??"legacy",origin:u?.origin??null,importedAt:u?.importedAt??null,commit:u?.commit??null,tags:await xe(s.path)}}const $e={command:"command",agent:"agent",workflow:"workflow",rule:"rules","output-style":"output-style"};async function Ae(s){const{plugins:r,skills:t,mcp:u,files:o}=await Y(s),y={},b=(g,w)=>{w>0&&(y[g]=(y[g]??0)+w)};b("skill",t.length),b("mcp",u.length);for(const[g,w]of Object.entries(o))b($e[g]??g,w.length);return b("plugin",r.length),b("mods",r.filter(g=>g.kind==="mod"||g.components.includes("mod")).length),y}async function xe(s){try{return await Ae(s)}catch{return{}}}function D(s,r){r instanceof Yr?s.statusCode=403:r instanceof Zr?s.statusCode=413:r instanceof O?s.statusCode=404:s.statusCode=400,s.setHeader("content-type","application/json"),s.end(JSON.stringify({error:r instanceof Error?r.message:"Read failed"}))}
13
+ `)});r.inflightRefresher?.refreshNow(),r.terminalRefresher?.onSubscriberJoin(),r.updatesRefresher?.onSubscriberJoin(),o.on("close",()=>{clearInterval(w),N()})}function He(o,t,r){if(t==="/health")return!0;if(o.method!=="GET")return!1;if((o.headers.accept??"").includes("text/html"))return!0;if(!r.staticDir)return!1;const u=v.normalize(t).replace(/^([/\\]\.\.[/\\])+/,""),c=v.join(r.staticDir,u);return c.startsWith(r.staticDir)&&S.existsSync(c)&&S.statSync(c).isFile()}function Ue(o,t){o.setHeader("cache-control",t.startsWith("/assets/")?"public, max-age=31536000, immutable":"no-cache")}function xe(o,t,r){const u=v.normalize(t).replace(/^([/\\]\.\.[/\\])+/,""),c=v.join(r,u);if(!c.startsWith(r)){o.statusCode=403,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:"Forbidden"}));return}S.stat(c,(b,g)=>{if(!b&&g.isFile()){o.setHeader("content-type",We(c)),Ue(o,t),o.setHeader("content-length",String(g.size)),S.createReadStream(c).pipe(o);return}S.readFile(v.join(r,"index.html"),(y,w)=>{if(y){o.statusCode=404,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:"Not found"}));return}o.setHeader("content-type","text/html"),o.setHeader("cache-control","no-cache"),o.end(w)})})}function pt(o,t){const r=o.ai??je;return{...o,ai:{baseUrl:r.baseUrl,model:r.model,apiKeySet:Ge(t)}}}function Ke(o){if(!o)return;const{apiKey:t,...r}=o;return r}function We(o){return o.endsWith(".js")?"text/javascript":o.endsWith(".css")?"text/css":o.endsWith(".html")?"text/html":o.endsWith(".svg")?"image/svg+xml":o.endsWith(".json")?"application/json":"application/octet-stream"}function _e(o){const t=Number(o??"100");return!Number.isFinite(t)||t<=0?100:Math.min(Math.floor(t),500)}function gt(o){return o.scope==="user"||o.category==="plugin"?!1:o.category==="mcp"?!!F(o.agent)?.mcpScopes().includes("project"):!0}function F(o){const t=o??"claude";return Te().find(r=>r.harness===t)}function O(o,t){t instanceof ot?o.statusCode=409:t instanceof G?o.statusCode=404:t instanceof Gt||t instanceof At?o.statusCode=500:o.statusCode=400,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:t instanceof Error?t.message:"Install failed"}))}async function M(o,t){const r=J(o.path,A(t)),u=r?await _t(o.path):null,c=E(o.path,t);return{id:o.id,kind:o.kind,addedAt:o.addedAt,path:o.path,relPath:J(o.path,t)?Vt(o.path,t):null,resourceId:r?v.basename(o.path):null,managed:r,builtin:c,namespace:r?zt(o.path,A(t)):void 0,legacy:!u&&!c,source:c?"builtin":u?.source??"legacy",origin:u?.origin??null,importedAt:u?.importedAt??null,commit:u?.commit??null,tags:await Qe(o.path)}}const ze={command:"command",agent:"agent",workflow:"workflow",rule:"rules","output-style":"output-style"};async function Ve(o){const{plugins:t,skills:r,mcp:u,files:c}=await it(o),b={},g=(y,w)=>{w>0&&(b[y]=(b[y]??0)+w)};g("skill",r.length),g("mcp",u.length);for(const[y,w]of Object.entries(c))g(ze[y]??y,w.length);return g("plugin",t.length),g("mods",t.filter(y=>y.kind==="mod"||y.components.includes("mod")).length),b}async function Qe(o){try{return await Ve(o)}catch{return{}}}function R(o,t){t instanceof ee?o.statusCode=403:t instanceof re?o.statusCode=413:t instanceof G?o.statusCode=404:o.statusCode=400,o.setHeader("content-type","application/json"),o.end(JSON.stringify({error:t instanceof Error?t.message:"Read failed"}))}
@@ -1,17 +1,87 @@
1
1
  /** 读文件尾部(读不到 → null,不猜)。 */
2
2
  export declare function readTail(path: string, bytes?: number): string | null;
3
+ /**
4
+ * 装配用兜底:路径从库里该会话最近一条事件的旁路字段补回(与入站侧读同一个
5
+ * `transcriptPath`)。每个会话在 daemon 生命周期里最多查一次——查到即写回内存。
6
+ */
7
+ export declare function dbTranscriptPathResolver(events: {
8
+ listBySession(sessionId: string, limit?: number): Array<{
9
+ payload: string;
10
+ }>;
11
+ }): (sessionId: string) => string | null;
3
12
  export declare class SessionProbe {
13
+ /**
14
+ * 路径的内存副本没了以后的兜底(daemon 重启后第一拍):不补的话,重启后**没有
15
+ * 新事件**的会话(已收尾 / 闲置中的那些)模型与模式会一直显示「未知」。
16
+ */
17
+ private readonly fallbackPath?;
18
+ constructor(
19
+ /**
20
+ * 路径的内存副本没了以后的兜底(daemon 重启后第一拍):不补的话,重启后**没有
21
+ * 新事件**的会话(已收尾 / 闲置中的那些)模型与模式会一直显示「未知」。
22
+ */
23
+ fallbackPath?: ((sessionId: string) => string | null) | undefined);
4
24
  /** sessionId → 转录路径(内存态;hook 事件每次上报都覆盖刷新)。 */
5
25
  private readonly paths;
6
- /** 路径 → 上次读到的标记(按文件大小缓存:没长过就不重读)。 */
26
+ /** 路径 → 上次读到的事实(按文件大小缓存:没长过就不重读)。 */
7
27
  private readonly marks;
28
+ /** sessionId → 最后已知的模型/模式(读到就记;见 `latched`)。 */
29
+ private readonly known;
30
+ /**
31
+ * sessionId → 宿主落定的换模型(`PostModelSwitch`)+ 记下的那一刻转录里还是哪个
32
+ * 模型。转录只在 assistant 消息上照会模型,切完不跑一轮就永远读不到新值——故
33
+ * 换模型这件事得由事件先说,等转录自己跟上(照会的值不再是 `stale`)才交还给它。
34
+ */
35
+ private readonly switched;
36
+ /** sessionId → 推理档位(每次带 `effort` 的事件覆盖):状态栏 `thinking` 块的事实在 hook 里。 */
37
+ private readonly efforts;
8
38
  noteTranscript(sessionId: string, path: string | null): void;
39
+ private pathOf;
9
40
  forget(sessionId: string): void;
41
+ /** 推理档位(`effort.level`,事件自带):逐条覆盖,与模型/模式同口径只放内存。 */
42
+ noteEffort(sessionId: string, level: string): void;
43
+ /** 最后已知的推理档位;没上报过即 null(不猜)。 */
44
+ currentEffort(sessionId: string): string | null;
45
+ /** 宿主落定的换模型(`PostModelSwitch` 的 `to_model`):立刻生效,见 `switched`。 */
46
+ noteModel(sessionId: string, model: string): void;
47
+ /**
48
+ * 宿主开 / 恢复会话(`SessionStart`):模型由宿主重新决定,此前的「最后已知」与
49
+ * 换模型闩一律作废、下一次问重新读——`--resume` 起来会落回默认模型,而转录里还
50
+ * 只有上一轮的照会,旧答案既可能不是此刻的模型、也会让 `switched` 的 stale 对照
51
+ * 永远对不上(新照会恰好等于 stale 时标签就再也改不回来)。带了真名就以它为准。
52
+ */
53
+ sessionStarted(sessionId: string, model: string | null): void;
54
+ /**
55
+ * 转录还在不在:true/false;路径都不知道 → null(不猜)。
56
+ *
57
+ * 会话行是采集出来的、与转录那份文件同生不同死——转录被清理/删掉后列表照旧
58
+ * 有行,`claude --resume <id>` 却在 pane 里当场报 "No conversation found"。
59
+ * 故「打开」前与列表渲染前都得先问这一句。空文件也算没有(没有可接的对话)。
60
+ */
61
+ transcriptPresent(sessionId: string): boolean | null;
10
62
  /**
11
63
  * 单会话的中断时刻(ms):转录最后一条中断标记**晚于**最后一条 hook 事件才算
12
64
  * ——之后任何事件(用户又发了一条、工具收尾)都会把它盖过去,故是自愈的;
13
65
  * 未知路径/读不到/没标记一律 null(不猜)。
14
66
  */
15
67
  interruptedAt(sessionId: string, lastSeenAt: string): number | null;
16
- private markerOf;
68
+ /** 最近一轮真跑过的模型(转录 `message.model`);未知/读不到一律 null(不猜)。 */
69
+ currentModel(sessionId: string): string | null;
70
+ /** 最后一次活动时的执行模式(转录 `permissionMode`);Shift+Tab 不留痕,故是「最后已知」。 */
71
+ currentMode(sessionId: string): string | null;
72
+ /**
73
+ * 模型/模式在 UI 上承诺的是**最后已知**,不是「此刻尾窗里有没有」:尾窗只有 64KB,
74
+ * 一轮的尾巴若被一条大记录占满、或刚压缩完还没有 assistant 条目,这一拍就什么
75
+ * 都读不到。更要命的是读空的那一拍会按文件大小被缓存住——会话一完成文件不再
76
+ * 增长,那口 null 就钉死了,界面上直接掉回「未知」。故读到就记住,读空沿用:
77
+ * 值只会被**更新的值**替换,不会被读空擦掉。中断标记不参与闩(它按「晚于最后
78
+ * 一条事件」判,陈旧标记必须能被新事件盖过)。
79
+ */
80
+ private latched;
81
+ /**
82
+ * 换模型事件压过转录:只要转录照会的还是切换前那个模型(切完还没真跑一轮),
83
+ * 就答事件说的新值;转录自己跟上(照会别的值)即交还给它。
84
+ */
85
+ private switchedModel;
86
+ private factsOf;
17
87
  }
@@ -1 +1 @@
1
- import{closeSync as i,openSync as o,readSync as u,statSync as l}from"node:fs";import{interruptMarkerAt as c}from"@weavecode/harness";const p=64*1024;export function readTail(a,t=p){try{const r=l(a).size,e=Math.max(0,r-t),n=o(a,"r");try{const s=Buffer.alloc(r-e);return u(n,s,0,s.length,e),s.toString("utf8")}finally{i(n)}}catch{return null}}export class SessionProbe{paths=new Map;marks=new Map;noteTranscript(t,r){r&&this.paths.set(t,r)}forget(t){this.paths.delete(t)}interruptedAt(t,r){const e=this.paths.get(t);if(!e)return null;const n=this.markerOf(e);if(n===null)return null;const s=Date.parse(r);return Number.isFinite(s)&&n>s?n:null}markerOf(t){let r;try{r=l(t).size}catch{return null}const e=this.marks.get(t);if(e&&e.size===r)return e.markerAt;const n=readTail(t),s=n===null?null:c(n);return this.marks.set(t,{size:r,markerAt:s}),s}}
1
+ import{closeSync as a,openSync as c,readSync as i,statSync as o}from"node:fs";import{currentModelAt as h,currentModeAt as u,interruptMarkerAt as f}from"@weavecode/harness";const d=64*1024,m={model:null,mode:null};export function readTail(s,t=d){try{const e=o(s).size,r=Math.max(0,e-t),n=c(s,"r");try{const l=Buffer.alloc(e-r);return i(n,l,0,l.length,r),l.toString("utf8")}finally{a(n)}}catch{return null}}export function dbTranscriptPathResolver(s){return t=>{try{const e=JSON.parse(s.listBySession(t,1)[0]?.payload??"");return typeof e.transcriptPath=="string"&&e.transcriptPath?e.transcriptPath:null}catch{return null}}}export class SessionProbe{fallbackPath;constructor(t){this.fallbackPath=t}paths=new Map;marks=new Map;known=new Map;switched=new Map;efforts=new Map;noteTranscript(t,e){e&&this.paths.set(t,e)}pathOf(t){const e=this.paths.get(t);if(e)return e;const r=this.fallbackPath?.(t)??null;return r&&this.paths.set(t,r),r}forget(t){this.paths.delete(t),this.known.delete(t),this.switched.delete(t),this.efforts.delete(t)}noteEffort(t,e){this.efforts.set(t,e)}currentEffort(t){return this.efforts.get(t)??null}noteModel(t,e){const r=this.pathOf(t);this.switched.set(t,{stale:r?this.factsOf(r).model:null,model:e})}sessionStarted(t,e){this.known.delete(t),this.switched.delete(t),e&&this.noteModel(t,e)}transcriptPresent(t){const e=this.pathOf(t);return e?this.factsOf(e).size>0:null}interruptedAt(t,e){const r=this.pathOf(t);if(!r)return null;const n=this.factsOf(r).markerAt;if(n===null)return null;const l=Date.parse(e);return Number.isFinite(l)&&n>l?n:null}currentModel(t){return this.latched(t).model}currentMode(t){return this.latched(t).mode}latched(t){const e=this.pathOf(t),r=e?this.factsOf(e):m,n=this.known.get(t),l={model:this.switchedModel(t,r.model)??n?.model??null,mode:r.mode??n?.mode??null};return(!n||n.model!==l.model||n.mode!==l.mode)&&this.known.set(t,l),l}switchedModel(t,e){const r=this.switched.get(t);return r&&e===r.stale?r.model:e}factsOf(t){let e;try{e=o(t).size}catch{return{size:-1,markerAt:null,model:null,mode:null}}const r=this.marks.get(t);if(r&&r.size===e)return r;const n=readTail(t),l={size:e,markerAt:n===null?null:f(n),model:n===null?null:h(n),mode:n===null?null:u(n)};return this.marks.set(t,l),l}}
@@ -34,6 +34,8 @@ export interface DaemonSettings {
34
34
  hooks: HooksSettings;
35
35
  /** 事件日志(hook_events)保留策略——缺省走默认值(读时归一化)。 */
36
36
  events?: EventsSettings;
37
+ /** 会话闲置移除策略(无操作 n 天后自动移除)——缺省走默认值(读时归一化)。 */
38
+ sessions?: SessionsSettings;
37
39
  /** 开机自启动 daemon(系统级自启动项;缺省关闭——读时归一化)。 */
38
40
  startup?: StartupSettings;
39
41
  /** 监听面(绑定地址;缺省放开 0.0.0.0——读时归一化)。 */
@@ -48,6 +50,10 @@ export interface HooksSettings {
48
50
  export interface EventsSettings {
49
51
  retentionDays: number;
50
52
  }
53
+ /** 会话闲置移除保留天数(= lastSeenAt 起算的无操作窗,到期自动移除会话行)。 */
54
+ export interface SessionsSettings {
55
+ idleDays: number;
56
+ }
51
57
  /** daemon 是否随系统登录自启(默认关)。 */
52
58
  export interface StartupSettings {
53
59
  launchOnLogin: boolean;
@@ -71,6 +77,10 @@ export declare const DEFAULT_HOOKS_SETTINGS: HooksSettings;
71
77
  /** 保留 90 天:与总览「大于30天」档兼容,留足回溯窗口。 */
72
78
  export declare const DEFAULT_EVENT_RETENTION_DAYS = 90;
73
79
  export declare const DEFAULT_EVENTS_SETTINGS: EventsSettings;
80
+ /** 闲置 90 天移除:与事件日志同界(会话行连同其事件一起走),总览「大于30天」
81
+ * 档仍留有 30-90 天窗口可看;新会话随首个事件即建档,不会被快清误伤。 */
82
+ export declare const DEFAULT_SESSION_IDLE_DAYS = 90;
83
+ export declare const DEFAULT_SESSIONS_SETTINGS: SessionsSettings;
74
84
  export declare const DEFAULT_STARTUP_SETTINGS: StartupSettings;
75
85
  /** 默认放开绑定(局域网可达):dashboard 密码认证是这层的兜底。HTTPS 与 HTTP 并存(见 daemon/tls.ts)。 */
76
86
  export declare const DEFAULT_SERVER_SETTINGS: ServerSettings;
@@ -1,2 +1,2 @@
1
- import{openDatabase as g}from"../db/db.js";import{getDbPath as h}from"../db/paths.js";import{DEFAULT_BIND_HOST as d}from"./port.js";export const SUPPORTED_LOCALES=["zh-CN","en"],DEFAULT_LOCALE="zh-CN",DEFAULT_TERMINAL_SETTINGS={preset:"auto",customCommand:""},DEFAULT_HOOKS_SETTINGS={enabled:!0},DEFAULT_EVENT_RETENTION_DAYS=90,DEFAULT_EVENTS_SETTINGS={retentionDays:DEFAULT_EVENT_RETENTION_DAYS},DEFAULT_STARTUP_SETTINGS={launchOnLogin:!1},DEFAULT_SERVER_SETTINGS={bindHost:d,tlsPort:6443},DEFAULT_AI_SETTINGS={baseUrl:"",model:""},DEFAULT_DAEMON_SETTINGS={terminal:DEFAULT_TERMINAL_SETTINGS,locale:DEFAULT_LOCALE,hooks:DEFAULT_HOOKS_SETTINGS,events:DEFAULT_EVENTS_SETTINGS,startup:DEFAULT_STARTUP_SETTINGS,server:DEFAULT_SERVER_SETTINGS,ai:DEFAULT_AI_SETTINGS};export function resolveLocale(e){return SUPPORTED_LOCALES.includes(e)?e:DEFAULT_LOCALE}export const ALL_TERMINAL_PRESETS=["auto","wt","powershell","cmd","terminal","iterm","gnome","konsole","wezterm","ghostty","custom"];const b={auto:"\u81EA\u52A8\uFF08\u63A2\u6D4B\u53EF\u7528\u7EC8\u7AEF\uFF09",wt:"Windows Terminal",powershell:"PowerShell",cmd:"\u547D\u4EE4\u63D0\u793A\u7B26 (cmd)",terminal:"Terminal.app",iterm:"iTerm2",gnome:"gnome-terminal",konsole:"Konsole",wezterm:"WezTerm",ghostty:"Ghostty",custom:"\u81EA\u5B9A\u4E49\u547D\u4EE4"};export function terminalPresetsFor(e){return(e==="win32"?["auto","wt","wezterm","powershell","cmd","custom"]:e==="darwin"?["auto","terminal","iterm","wezterm","ghostty","custom"]:["auto","gnome","konsole","wezterm","ghostty","custom"]).map(n=>({id:n,label:b[n]}))}function D(e){return Number.isInteger(e)&&e>=0&&e<=65535?e:DEFAULT_SERVER_SETTINGS.tlsPort}function E(e){const n=e??{},o=n.terminal??{},r=n.hooks??{},s=n.events??{},c=n.startup??{},l=n.server??{},i=n.ai??{},p=Number.isInteger(s.retentionDays)&&s.retentionDays>=1?s.retentionDays:DEFAULT_EVENTS_SETTINGS.retentionDays;return{terminal:{preset:ALL_TERMINAL_PRESETS.includes(o.preset)?o.preset:DEFAULT_TERMINAL_SETTINGS.preset,customCommand:typeof o.customCommand=="string"?o.customCommand:""},locale:resolveLocale(n.locale),hooks:{enabled:typeof r.enabled=="boolean"?r.enabled:DEFAULT_HOOKS_SETTINGS.enabled},events:{retentionDays:p},startup:{launchOnLogin:typeof c.launchOnLogin=="boolean"?c.launchOnLogin:DEFAULT_STARTUP_SETTINGS.launchOnLogin},server:{bindHost:typeof l.bindHost=="string"&&l.bindHost.trim()!==""?l.bindHost.trim():DEFAULT_SERVER_SETTINGS.bindHost,tlsPort:D(l.tlsPort)},ai:{baseUrl:typeof i.baseUrl=="string"?i.baseUrl.trim():"",model:typeof i.model=="string"?i.model.trim():""}}}const t={terminalPreset:"terminal.preset",terminalCustomCommand:"terminal.customCommand",locale:"locale",hooksEnabled:"hooks.enabled",eventRetentionDays:"events.retentionDays",startupLaunchOnLogin:"startup.launchOnLogin",serverBindHost:"server.bindHost",serverTlsPort:"server.tlsPort",aiBaseUrl:"ai.baseUrl",aiModel:"ai.model"};let a=null,u=null;export function setDaemonSettingsDb(e){a=e,u=null}function T(e){if(a)return e(a);const n=g(h());try{return e(n)}finally{n.close()}}function L(e){const n=e.prepare("SELECT key, value FROM settings").all();return new Map(n.map(o=>[o.key,o.value]))}function S(e){return E({terminal:{preset:e.get(t.terminalPreset),customCommand:e.get(t.terminalCustomCommand)},locale:e.get(t.locale),...e.has(t.hooksEnabled)?{hooks:{enabled:e.get(t.hooksEnabled)==="true"}}:{},...e.has(t.eventRetentionDays)?{events:{retentionDays:Number(e.get(t.eventRetentionDays))}}:{},...e.has(t.startupLaunchOnLogin)?{startup:{launchOnLogin:e.get(t.startupLaunchOnLogin)==="true"}}:{},...e.has(t.serverBindHost)||e.has(t.serverTlsPort)?{server:{...e.has(t.serverBindHost)?{bindHost:e.get(t.serverBindHost)}:{},...e.has(t.serverTlsPort)?{tlsPort:Number(e.get(t.serverTlsPort))}:{}}}:{},...e.has(t.aiBaseUrl)||e.has(t.aiModel)?{ai:{baseUrl:e.get(t.aiBaseUrl)??"",model:e.get(t.aiModel)??""}}:{}})}function v(e){return[[t.terminalPreset,e.terminal.preset],[t.terminalCustomCommand,e.terminal.customCommand],[t.locale,e.locale],[t.hooksEnabled,String(e.hooks.enabled)],[t.eventRetentionDays,String(e.events?.retentionDays??DEFAULT_EVENT_RETENTION_DAYS)],[t.startupLaunchOnLogin,String(e.startup?.launchOnLogin??!1)],[t.serverBindHost,e.server?.bindHost??d],[t.serverTlsPort,String(e.server?.tlsPort??DEFAULT_SERVER_SETTINGS.tlsPort)],[t.aiBaseUrl,e.ai?.baseUrl??""],[t.aiModel,e.ai?.model??""]]}function y(e,n){const o=e.prepare(`INSERT INTO settings (key, value) VALUES (?, ?)
2
- ON CONFLICT(key) DO UPDATE SET value = excluded.value`);e.exec("BEGIN");try{for(const[r,s]of n)o.run(r,s);e.exec("COMMIT")}catch(r){throw e.exec("ROLLBACK"),r}}function m(){try{return T(e=>S(L(e)))}catch{return DEFAULT_DAEMON_SETTINGS}}export async function readDaemonSettings(){return m()}export function readDaemonSettingsSync(){return m()}export function readHooksEnabled(){const e=u;if(e&&e.db===a)return e.value;const n=m().hooks.enabled;return u={db:a,value:n},n}export async function writeDaemonSettings(e){const n=E(e);return T(o=>y(o,v(n))),u=null,n}
1
+ import{openDatabase as y}from"../db/db.js";import{getDbPath as b}from"../db/paths.js";import{DEFAULT_BIND_HOST as E}from"./port.js";export const SUPPORTED_LOCALES=["zh-CN","en"],DEFAULT_LOCALE="zh-CN",DEFAULT_TERMINAL_SETTINGS={preset:"auto",customCommand:""},DEFAULT_HOOKS_SETTINGS={enabled:!0},DEFAULT_EVENT_RETENTION_DAYS=90,DEFAULT_EVENTS_SETTINGS={retentionDays:DEFAULT_EVENT_RETENTION_DAYS},DEFAULT_SESSION_IDLE_DAYS=90,DEFAULT_SESSIONS_SETTINGS={idleDays:DEFAULT_SESSION_IDLE_DAYS},DEFAULT_STARTUP_SETTINGS={launchOnLogin:!1},DEFAULT_SERVER_SETTINGS={bindHost:E,tlsPort:6443},DEFAULT_AI_SETTINGS={baseUrl:"",model:""},DEFAULT_DAEMON_SETTINGS={terminal:DEFAULT_TERMINAL_SETTINGS,locale:DEFAULT_LOCALE,hooks:DEFAULT_HOOKS_SETTINGS,events:DEFAULT_EVENTS_SETTINGS,sessions:DEFAULT_SESSIONS_SETTINGS,startup:DEFAULT_STARTUP_SETTINGS,server:DEFAULT_SERVER_SETTINGS,ai:DEFAULT_AI_SETTINGS};export function resolveLocale(e){return SUPPORTED_LOCALES.includes(e)?e:DEFAULT_LOCALE}export const ALL_TERMINAL_PRESETS=["auto","wt","powershell","cmd","terminal","iterm","gnome","konsole","wezterm","ghostty","custom"];const L={auto:"\u81EA\u52A8\uFF08\u63A2\u6D4B\u53EF\u7528\u7EC8\u7AEF\uFF09",wt:"Windows Terminal",powershell:"PowerShell",cmd:"\u547D\u4EE4\u63D0\u793A\u7B26 (cmd)",terminal:"Terminal.app",iterm:"iTerm2",gnome:"gnome-terminal",konsole:"Konsole",wezterm:"WezTerm",ghostty:"Ghostty",custom:"\u81EA\u5B9A\u4E49\u547D\u4EE4"};export function terminalPresetsFor(e){return(e==="win32"?["auto","wt","wezterm","powershell","cmd","custom"]:e==="darwin"?["auto","terminal","iterm","wezterm","ghostty","custom"]:["auto","gnome","konsole","wezterm","ghostty","custom"]).map(o=>({id:o,label:L[o]}))}function p(e){return Number.isInteger(e)&&e>=0&&e<=65535?e:DEFAULT_SERVER_SETTINGS.tlsPort}function T(e){const n=e??{},o=n.terminal??{},s=n.hooks??{},r=n.events??{},u=n.sessions??{},d=n.startup??{},l=n.server??{},i=n.ai??{},h=Number.isInteger(r.retentionDays)&&r.retentionDays>=1?r.retentionDays:DEFAULT_EVENTS_SETTINGS.retentionDays,S=Number.isInteger(u.idleDays)&&u.idleDays>=1?u.idleDays:DEFAULT_SESSIONS_SETTINGS.idleDays;return{terminal:{preset:ALL_TERMINAL_PRESETS.includes(o.preset)?o.preset:DEFAULT_TERMINAL_SETTINGS.preset,customCommand:typeof o.customCommand=="string"?o.customCommand:""},locale:resolveLocale(n.locale),hooks:{enabled:typeof s.enabled=="boolean"?s.enabled:DEFAULT_HOOKS_SETTINGS.enabled},events:{retentionDays:h},sessions:{idleDays:S},startup:{launchOnLogin:typeof d.launchOnLogin=="boolean"?d.launchOnLogin:DEFAULT_STARTUP_SETTINGS.launchOnLogin},server:{bindHost:typeof l.bindHost=="string"&&l.bindHost.trim()!==""?l.bindHost.trim():DEFAULT_SERVER_SETTINGS.bindHost,tlsPort:p(l.tlsPort)},ai:{baseUrl:typeof i.baseUrl=="string"?i.baseUrl.trim():"",model:typeof i.model=="string"?i.model.trim():""}}}const t={terminalPreset:"terminal.preset",terminalCustomCommand:"terminal.customCommand",locale:"locale",hooksEnabled:"hooks.enabled",eventRetentionDays:"events.retentionDays",sessionIdleDays:"sessions.idleDays",startupLaunchOnLogin:"startup.launchOnLogin",serverBindHost:"server.bindHost",serverTlsPort:"server.tlsPort",aiBaseUrl:"ai.baseUrl",aiModel:"ai.model"};let a=null,c=null;export function setDaemonSettingsDb(e){a=e,c=null}function D(e){if(a)return e(a);const n=y(b());try{return e(n)}finally{n.close()}}function g(e){const n=e.prepare("SELECT key, value FROM settings").all();return new Map(n.map(o=>[o.key,o.value]))}function v(e){return T({terminal:{preset:e.get(t.terminalPreset),customCommand:e.get(t.terminalCustomCommand)},locale:e.get(t.locale),...e.has(t.hooksEnabled)?{hooks:{enabled:e.get(t.hooksEnabled)==="true"}}:{},...e.has(t.eventRetentionDays)?{events:{retentionDays:Number(e.get(t.eventRetentionDays))}}:{},...e.has(t.sessionIdleDays)?{sessions:{idleDays:Number(e.get(t.sessionIdleDays))}}:{},...e.has(t.startupLaunchOnLogin)?{startup:{launchOnLogin:e.get(t.startupLaunchOnLogin)==="true"}}:{},...e.has(t.serverBindHost)||e.has(t.serverTlsPort)?{server:{...e.has(t.serverBindHost)?{bindHost:e.get(t.serverBindHost)}:{},...e.has(t.serverTlsPort)?{tlsPort:Number(e.get(t.serverTlsPort))}:{}}}:{},...e.has(t.aiBaseUrl)||e.has(t.aiModel)?{ai:{baseUrl:e.get(t.aiBaseUrl)??"",model:e.get(t.aiModel)??""}}:{}})}function f(e){return[[t.terminalPreset,e.terminal.preset],[t.terminalCustomCommand,e.terminal.customCommand],[t.locale,e.locale],[t.hooksEnabled,String(e.hooks.enabled)],[t.eventRetentionDays,String(e.events?.retentionDays??DEFAULT_EVENT_RETENTION_DAYS)],[t.sessionIdleDays,String(e.sessions?.idleDays??DEFAULT_SESSION_IDLE_DAYS)],[t.startupLaunchOnLogin,String(e.startup?.launchOnLogin??!1)],[t.serverBindHost,e.server?.bindHost??E],[t.serverTlsPort,String(e.server?.tlsPort??DEFAULT_SERVER_SETTINGS.tlsPort)],[t.aiBaseUrl,e.ai?.baseUrl??""],[t.aiModel,e.ai?.model??""]]}function N(e,n){const o=e.prepare(`INSERT INTO settings (key, value) VALUES (?, ?)
2
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`);e.exec("BEGIN");try{for(const[s,r]of n)o.run(s,r);e.exec("COMMIT")}catch(s){throw e.exec("ROLLBACK"),s}}function m(){try{return D(e=>v(g(e)))}catch{return DEFAULT_DAEMON_SETTINGS}}export async function readDaemonSettings(){return m()}export function readDaemonSettingsSync(){return m()}export function readHooksEnabled(){const e=c;if(e&&e.db===a)return e.value;const n=m().hooks.enabled;return c={db:a,value:n},n}export async function writeDaemonSettings(e){const n=T(e);return D(o=>N(o,f(n))),c=null,n}
@@ -1,7 +1,7 @@
1
1
  import type { DataBus, DataKey } from './data-bus.js';
2
2
  /**
3
3
  * SnapshotRefresher — 「前端不轮询,后端有人看时定期探、只在值变化时推绝对值快照」
4
- * 的通用骨架(两个使用者:会话存活 pidAlive、会话中断态)。
4
+ * 的通用骨架(使用者:会话存活 pidAlive、会话中断态、状态栏底条的 git 事实)。
5
5
  *
6
6
  * 为什么要有它:这两类事实都可能**没有** hook 事件来触发变化(claude 进程被杀 =
7
7
  * 无 SessionEnd;用户按 ESC 打断 = 无任何事件),GET /sessions 里算好的值于是卡在
@@ -15,6 +15,12 @@ export interface SnapshotRefresherOptions {
15
15
  intervalMs?: number;
16
16
  /** 是否值得探测(一般为「有 SSE 客户端」)。缺省恒真(测试用)。 */
17
17
  shouldRun?: () => boolean;
18
+ /**
19
+ * 只发失效帧(不带 payload):前端按 key 调既有 fetcher 重拉,而不是拿这份
20
+ * 快照直写状态。用于「快照是别的进程算的、前端已经有一份更完整的取数口」的域
21
+ * (如 statusline 底条的 git 事实:同一份 GET 里还带着配置与脚本)。
22
+ */
23
+ invalidateOnly?: boolean;
18
24
  }
19
25
  export declare class SnapshotRefresher {
20
26
  /** 现算一份载荷(前端直接写状态的那份绝对值快照)。 */
@@ -1 +1 @@
1
- export class SnapshotRefresher{snapshot;bus;options;timer;lastFingerprint=null;constructor(t,s,i){this.snapshot=t,this.bus=s,this.options=i}start(){this.timer||(this.timer=setInterval(()=>this.tick(),this.options.intervalMs??15e3))}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}tick(){if(!(this.options.shouldRun&&!this.options.shouldRun()))try{const t=this.snapshot(),s=JSON.stringify(t);if(s===this.lastFingerprint)return;this.lastFingerprint=s,this.bus.emit({key:this.options.key,payload:t})}catch{}}}
1
+ export class SnapshotRefresher{snapshot;bus;options;timer;lastFingerprint=null;constructor(t,i,s){this.snapshot=t,this.bus=i,this.options=s}start(){this.timer||(this.timer=setInterval(()=>this.tick(),this.options.intervalMs??15e3))}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}tick(){if(!(this.options.shouldRun&&!this.options.shouldRun()))try{const t=this.snapshot(),i=JSON.stringify(t);if(i===this.lastFingerprint)return;this.lastFingerprint=i,this.bus.emit(this.options.invalidateOnly?{key:this.options.key}:{key:this.options.key,payload:t})}catch{}}}
@@ -0,0 +1,40 @@
1
+ import type { WatchService } from '../watch/watch-service.js';
2
+ import type { HookEventBus } from '../hooks/bus.js';
3
+ import type { DataBus } from './data-bus.js';
4
+ export interface SseSources {
5
+ watch?: Pick<WatchService, 'subscribe' | 'subscribeProjects'>;
6
+ hookBus?: HookEventBus;
7
+ dataBus?: DataBus;
8
+ }
9
+ export interface SseFrameOut {
10
+ id: string;
11
+ /** 已序列化的 JSON(重放时原样再写一遍,不重新拼)。 */
12
+ data: string;
13
+ }
14
+ export declare class SseHub {
15
+ private readonly sources;
16
+ /** 本进程的流纪元:daemon 重启后序号从头来,旧客户端的 offset 一看就不认。 */
17
+ readonly epoch: string;
18
+ private seq;
19
+ private readonly buffer;
20
+ private readonly subs;
21
+ private detach;
22
+ private graceTimer;
23
+ /** 源被摘掉那一刻的序号:客户端拿着比它早(或正好)的 offset 回来,中间那段
24
+ * 没人在听、帧是真的丢了,补不回来。 */
25
+ private brokenAt;
26
+ constructor(sources: SseSources);
27
+ /** 每个连接一个写出口;第一个连接进来才订阅源。返回退订。 */
28
+ subscribe(fn: (frame: SseFrameOut) => void): () => void;
29
+ /** 广播一帧:编号、入环、各写一份。 */
30
+ push(payload: Record<string, unknown>): void;
31
+ /** 断线重连:`offset` 之后的帧;补不齐(纪元不同 / 缓冲越界 / 中途没人听)→ gap。
32
+ * gap 时不给帧:那段历史已经不可信,前端要整页重来,补一半的帧只会白写一屏。 */
33
+ replay(offset: string | null): {
34
+ frames: SseFrameOut[];
35
+ gap: boolean;
36
+ };
37
+ private frameId;
38
+ private attach;
39
+ private scheduleDetach;
40
+ }
@@ -0,0 +1 @@
1
+ import{randomBytes as u}from"node:crypto";const a=1e3,c=6e4;export class SseHub{sources;epoch=u(4).toString("hex");seq=0;buffer=[];subs=new Set;detach=null;graceTimer=null;brokenAt=0;constructor(s){this.sources=s}subscribe(s){return this.subs.add(s),this.attach(),()=>{this.subs.delete(s),this.subs.size===0&&this.scheduleDetach()}}push(s){const i=++this.seq,r=JSON.stringify(s);this.buffer.push({seq:i,data:r}),this.buffer.length>a&&this.buffer.shift();const t={id:this.frameId(i),data:r};for(const e of this.subs)e(t)}replay(s){if(!s)return{frames:[],gap:!1};const[i,r]=s.split("-"),t=Number(r);if(i!==this.epoch||!Number.isInteger(t)||t<0)return{frames:[],gap:!0};const e=this.buffer[0]?.seq;return t<=this.brokenAt||e!==void 0&&t<e-1?{frames:[],gap:!0}:{frames:this.buffer.filter(h=>h.seq>t).map(h=>({id:this.frameId(h.seq),data:h.data})),gap:!1}}frameId(s){return`${this.epoch}-${s}`}attach(){if(this.graceTimer!==null&&(clearTimeout(this.graceTimer),this.graceTimer=null),this.detach)return;const s=[],{watch:i,hookBus:r,dataBus:t}=this.sources;i&&(s.push(i.subscribe(e=>this.push({type:"asset",...e}))),s.push(i.subscribeProjects(e=>this.push({type:"project",...e})))),r&&s.push(r.subscribe(e=>this.push({type:"hook",...e}))),t&&s.push(t.subscribe(e=>this.push({type:e.payload===void 0?"invalidate":"push",...e}))),this.detach=()=>{for(const e of s)e()}}scheduleDetach(){this.graceTimer!==null||!this.detach||(this.graceTimer=setTimeout(()=>{this.graceTimer=null,this.brokenAt=this.seq,this.detach?.(),this.detach=null},c),this.graceTimer.unref?.())}}
@@ -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 re}from"../repositories/libraries.js";import{HookRuleRepository as G}from"../repositories/hook-rules.js";import{HookDispatchRepository as te}from"../repositories/hook-dispatches.js";import{PluginStateRepository as S}from"../repositories/plugin-states.js";import{SessionRepository as ne}from"../repositories/sessions.js";import{createRuntimeRegistry as ie}from"@weavecode/harness";import{startSessionSweeper as ae}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as pe}from"../statusline/cache-sweeper.js";import{wireHookFilePipeline as me}from"./hook-pipeline.js";import{ensureBuiltinMarket as le,builtinMarketDir as ce}from"../market/builtin.js";import{HookRuleRegistry as ue}from"../hooks/registry.js";import{HookDispatcher as he}from"../hooks/dispatcher.js";import{HookEventBus as fe}from"../hooks/bus.js";import{ResumeRunner as de}from"../hooks/resume-runner.js";import{HeadlessRunner as we}from"../hooks/headless-runner.js";import{MessageDeliverer as ge}from"../hooks/message-deliverer.js";import{QuestionTracker as Se}from"../hooks/question-tracker.js";import{startPromptFlusher as be}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as Re}from"../repositories/session-watches.js";import{PushSubscriptionRepository as ve}from"../repositories/push-subscriptions.js";import{PushNotifier as ke}from"../hooks/push-notify.js";import{SessionSequenceRepository as ye}from"../repositories/session-sequences.js";import{WatchEngine as De}from"../hooks/watch-engine.js";import{SequenceEngine as Ee}from"../hooks/sequence-engine.js";import{loadAllPlugins as Pe}from"../hooks/plugin-loader.js";import{ToolkitService as Ce}from"../hooks/toolkit.js";import{WatchService as Te}from"../watch/watch-service.js";import{SyncScheduler as He}from"../watch/sync-scheduler.js";import{FingerprintCache as Ie}from"../install/fingerprint.js";import{detectProjectUpdateCounts as qe}from"../install/updates.js";import{weaveRequestHandler as Ae}from"./server.js";import{startTlsServer as je}from"./tls.js";import{DataBus as Le}from"./data-bus.js";import{TerminalTopologyRefresher as Me}from"./terminal-topology-refresher.js";import{SnapshotRefresher as Q}from"./snapshot-refresher.js";import{SessionProbe as Be}from"./session-probe.js";import{InflightCountsRefresher as Ne}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as We}from"./project-updates-refresher.js";import{claudeLivenessById as _e,pidAliveOf as Fe}from"./claude-liveness.js";import{promptTerminalChannel as Oe,readTerminalCounts as Ue}from"./opener.js";import{DEFAULT_BIND_HOST as $e}from"./port.js";import{readDaemonState as xe,writeDaemonState as Ge}from"./state.js";import{readDaemonSettingsSync as j,setDaemonSettingsDb as Qe,DEFAULT_SERVER_SETTINGS as Ve}from"./settings.js";import{AuthService as ze}from"./dashboard-auth.js";import{syncLaunchOnLogin as Je}from"./auto-start.js";import{resolveStaticDir as Ke}from"./static.js";delete process.env.CLAUDE_CODE_CHILD_SESSION;export function startDaemon(){const c=xe();c||(console.error("Daemon state not found. Run `weave daemon start` first."),process.exit(1));const s=ee();Qe(s);const b=j().server?.bindHost??$e,R=j().server?.tlsPort??Ve.tlsPort,v=new ze;v.initialPassword&&console.log(`[weave] initial dashboard password: ${v.initialPassword}`);const r=new se(s),u=new oe(s),a=new re(s),k=ie(),V=k.byCapability("events").flatMap(e=>e.events??[]),h=new ue(new G(s)),f=new te(s),t=new ne(s),n=new fe,y={getHandler:()=>{},getConfig:()=>({})};let l;const D={list:()=>l?.list()??[],setPluginEnabled:(e,o)=>l?.setPluginEnabled(e,o)??!1,reloadAll:async()=>{await l?.reloadAll()},rescan:async()=>{await l?.rescanRoots(r.list(),a)}},z=new Ce({projects:r,states:new S(s),plugins:D,libraries:a}),L=new he({registry:h,dispatches:f,bus:n,projects:r,sessions:t,plugins:y,pluginStates:new S(s)});le({libraries:a}).then(e=>(e.error?console.error(`[weave] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[weave] builtin market ${e.form==="link"?"linked":"copied"} -> ${ce(a.dataDir)}`),Pe({rules:new G(s),registry:h,states:new S(s),bus:n,libraries:a},r.list()))).then(({loader:e})=>{l=e,y.getHandler=(o,m)=>e.getHandler(o,m),y.getConfig=o=>e.getConfig(o),e.watchRoots()});const E=new we,J=new de({dispatches:f,sessions:t,projects:r,bus:n,resumeSpec:k.get("claude")?.resume,headless:E}),p=new ge({sessions:t,projects:r,hookEvents:u,bus:n,headless:E,terminal:Oe(()=>j().terminal)});be(p);const P=new Re(s),C=new De({watches:P,deliverer:p,sessions:t,bus:n}),M=new ve(s),K=new ke({subscriptions:M,sessions:t,bus:n}),T=new ye(s),d=new Ee({sequences:T,deliverer:p,sessions:t,bus:n});d.rearm();const w=new Se({sessions:t,hookEvents:u,onPending:e=>{n.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});w.seedFromDb();const H=new Te(r);H.start();const I=new Ie,i=new Le,g=new Be,B=new We(()=>qe(r.list(),a.list(),I),i,n,()=>i.hasSubscribers()),N=new He(r,a,{cache:I,plugins:D,onSynced:()=>{B.refreshNow(!0)}});N.start();const q=new Me(async()=>({counts:await Ue(r.list()),terminals:await p.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});q.start();const W=new Q(()=>{const e=_e(),o={};for(const m of t.listWithCounts()){const x=Fe(m,e);x!==null&&(o[m.sessionId]=x)}return{alive:o}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});W.start();const A=new Q(()=>{const e={};for(const o of t.listWithCounts()){if(o.turnOpen!==!0)continue;const m=g.interruptedAt(o.sessionId,o.lastSeenAt);m!==null&&(e[o.sessionId]=m)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});A.start();const X=new Ne(()=>p.listInflightCounts(),i,n);ae({sessions:t,events:u,dispatches:f,deliverer:p,watches:P,sequences:T,watchEngine:C,sequenceEngine:d,questions:w,probe:g}),pe();const _=me({projects:r,rules:h,sessions:t,bus:n,dispatcher:L,watchEngine:C,sequenceEngine:d,messagePipe:p,questionTracker:w,sessionProbe:g}),Y=Ke(),F=Ae({projects:r,port:c.port,tlsPort:R,watch:H,hookEvents:u,adapters:V,harnesses:k,libraries:a,fingerprintCache:I,staticDir:Y,hookRegistry:h,hookDispatches:f,hookSessions:t,hookBus:n,dataBus:i,terminalRefresher:q,interruptRefresher:A,sessionProbe:g,inflightRefresher:X,updatesRefresher:B,hookDispatcher:L,hookRunner:J,messageDeliverer:p,questionTracker:w,sessionWatches:P,watchEngine:C,sessionSequences:T,sequenceEngine:d,pushSubscriptions:M,pushNotifier:K,hookPlugins:D,hookMirror:_.mirror,pluginStates:new S(s),toolkit:z,auth:v}),O=Z.createServer(F);let U=null;je({port:R,bindHost:b,handler:F}).then(e=>{U=e});const $=()=>{l?.stopWatching(),q.stop(),W.stop(),A.stop(),N.stop(),H.stop(),E.killAll(),_.stop(),O.close(),U?.server.close(),process.exit(0)};process.on("SIGTERM",$),process.on("SIGINT",$),O.listen(c.port,b,()=>{Ge({...c,pid:process.pid,host:b,tlsPort:R}),Je()})}
1
+ import oe from"node:http";import{openDatabase as te}from"../db/db.js";import{ProjectRepository as re}from"../repositories/projects.js";import{HookEventRepository as ne}from"../repositories/hook-events.js";import{LibraryRepository as ie}from"../repositories/libraries.js";import{HookRuleRepository as Y}from"../repositories/hook-rules.js";import{HookDispatchRepository as ae}from"../repositories/hook-dispatches.js";import{PluginStateRepository as S}from"../repositories/plugin-states.js";import{SessionRepository as ce}from"../repositories/sessions.js";import{createRuntimeRegistry as pe}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as me}from"@weavecode/core";import{startSessionSweeper as le}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as ue}from"../statusline/cache-sweeper.js";import{readStatuslineFacts as fe}from"../statusline/manager.js";import{wireHookFilePipeline as de}from"./hook-pipeline.js";import{ensureBuiltinMarket as he,builtinMarketDir as we}from"../market/builtin.js";import{HookRuleRegistry as ge}from"../hooks/registry.js";import{HookDispatcher as Se}from"../hooks/dispatcher.js";import{HookEventBus as Re}from"../hooks/bus.js";import{ResumeRunner as ve}from"../hooks/resume-runner.js";import{HeadlessRunner as be}from"../hooks/headless-runner.js";import{MessageDeliverer as ke}from"../hooks/message-deliverer.js";import{QuestionTracker as ye}from"../hooks/question-tracker.js";import{SideQuestionRepository as De}from"../repositories/side-questions.js";import{claimSideAnswer as Pe}from"../hooks/side-questions.js";import{startPromptFlusher as Ee}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as He}from"../repositories/session-watches.js";import{PushSubscriptionRepository as Te}from"../repositories/push-subscriptions.js";import{UploadRepository as Ce}from"../repositories/uploads.js";import{PushNotifier as Ie}from"../hooks/push-notify.js";import{SessionSequenceRepository as Ae}from"../repositories/session-sequences.js";import{WatchEngine as _e}from"../hooks/watch-engine.js";import{SequenceEngine as qe}from"../hooks/sequence-engine.js";import{loadAllPlugins as Le}from"../hooks/plugin-loader.js";import{ToolkitService as Me}from"../hooks/toolkit.js";import{WatchService as Ne}from"../watch/watch-service.js";import{SyncScheduler as Oe}from"../watch/sync-scheduler.js";import{FingerprintCache as Be}from"../install/fingerprint.js";import{detectProjectUpdateCounts as Fe}from"../install/updates.js";import{weaveRequestHandler as We}from"./server.js";import{startTlsServer as Qe}from"./tls.js";import{DataBus as Ue}from"./data-bus.js";import{TerminalTopologyRefresher as je}from"./terminal-topology-refresher.js";import{SnapshotRefresher as M}from"./snapshot-refresher.js";import{SessionProbe as $e,dbTranscriptPathResolver as xe}from"./session-probe.js";import{InflightCountsRefresher as Ge}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as Ve}from"./project-updates-refresher.js";import{claudeLivenessById as Ke,pidAliveOf as Ye}from"./claude-liveness.js";import{promptTerminalChannel as ze,readTerminalCounts as Je}from"./opener.js";import{DEFAULT_BIND_HOST as Xe}from"./port.js";import{readDaemonState as Ze,writeDaemonState as es}from"./state.js";import{readDaemonSettingsSync as N,setDaemonSettingsDb as ss,DEFAULT_SERVER_SETTINGS as os}from"./settings.js";import{AuthService as ts}from"./dashboard-auth.js";import{syncLaunchOnLogin as rs}from"./auto-start.js";import{resolveStaticDir as ns}from"./static.js";delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const m of me)delete process.env[m];export function startDaemon(){const m=Ze();m||(console.error("Daemon state not found. Run `weave daemon start` first."),process.exit(1));const o=te();ss(o);const R=N().server?.bindHost??Xe,v=N().server?.tlsPort??os.tlsPort,b=new ts;b.initialPassword&&console.log(`[weave] initial dashboard password: ${b.initialPassword}`);const t=new re(o),u=new ne(o),c=new ie(o),k=pe(),z=k.byCapability("events").flatMap(e=>e.events??[]),f=new ge(new Y(o)),d=new ae(o),n=new ce(o),r=new Re,y={getHandler:()=>{},getConfig:()=>({})};let l;const D={list:()=>l?.list()??[],setPluginEnabled:(e,s)=>l?.setPluginEnabled(e,s)??!1,reloadAll:async()=>{await l?.reloadAll()},rescan:async()=>{await l?.rescanRoots(t.list(),c)}},J=new Me({projects:t,states:new S(o),plugins:D,libraries:c}),O=new Se({registry:f,dispatches:d,bus:r,projects:t,sessions:n,plugins:y,pluginStates:new S(o)});he({libraries:c}).then(e=>(e.error?console.error(`[weave] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[weave] builtin market ${e.form==="link"?"linked":"copied"} -> ${we(c.dataDir)}`),Le({rules:new Y(o),registry:f,states:new S(o),bus:r,libraries:c},t.list()))).then(({loader:e})=>{l=e,y.getHandler=(s,p)=>e.getHandler(s,p),y.getConfig=s=>e.getConfig(s),e.watchRoots()});const P=new be,X=new ve({dispatches:d,sessions:n,projects:t,bus:r,resumeSpec:k.get("claude")?.resume,headless:P}),a=new ke({sessions:n,projects:t,hookEvents:u,bus:r,headless:P,terminal:ze(()=>N().terminal)});Ee(a);const E=new He(o),H=new _e({watches:E,deliverer:a,sessions:n,bus:r}),B=new Te(o),T=new Ce(o),Z=new Ie({subscriptions:B,sessions:n,bus:r}),C=new Ae(o),h=new qe({sequences:C,deliverer:a,sessions:n,bus:r});h.rearm();const w=new ye({sessions:n,hookEvents:u,onPending:e=>{r.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});w.seedFromDb();const F=new De(o),W={repo:F,bus:r},I=new Ne(t);I.start();const A=new Be,i=new Ue,g=new $e(xe(u)),Q=new Ve(()=>Fe(t.list(),c.list(),A),i,r,()=>i.hasSubscribers()),U=new Oe(t,c,{cache:A,plugins:D,onSynced:()=>{Q.refreshNow(!0)}});U.start();const _=new je(async()=>({counts:await Je(t.list()),terminals:await a.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});_.start();const q=new M(()=>{const e=Ke(),s={};for(const p of n.listWithCounts()){const K=Ye(p,e);K!==null&&(s[p.sessionId]=K)}return{alive:s}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});q.start();const L=new M(()=>{const e={};for(const s of n.listWithCounts()){if(s.turnOpen!==!0)continue;const p=g.interruptedAt(s.sessionId,s.lastSeenAt);p!==null&&(e[s.sessionId]=p)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});L.start(),new M(()=>{const e={};for(const s of t.list())e[s.id]=fe(s.path);return e},i,{key:"statusline",intervalMs:5e3,shouldRun:()=>i.hasSubscribers(),invalidateOnly:!0}).start();const ee=new Ge(()=>a.listInflightCounts(),i,r);le({sessions:n,events:u,dispatches:d,deliverer:a,watches:E,sequences:C,watchEngine:H,sequenceEngine:h,questions:w,sideQuestions:F,probe:g,uploads:T}),ue();const j=de({projects:t,rules:f,sessions:n,bus:r,dispatcher:O,watchEngine:H,sequenceEngine:h,messagePipe:a,questionTracker:w,sideQuestions:{onEvent:e=>{const s=Pe(W,e);s&&a.interrupt(s.sessionId)}},sessionProbe:g,uploads:T}),se=ns(),$=We({projects:t,port:m.port,tlsPort:v,watch:I,hookEvents:u,adapters:z,harnesses:k,libraries:c,fingerprintCache:A,staticDir:se,hookRegistry:f,hookDispatches:d,hookSessions:n,hookBus:r,dataBus:i,terminalRefresher:_,interruptRefresher:L,livenessRefresher:q,sessionProbe:g,inflightRefresher:ee,updatesRefresher:Q,hookDispatcher:O,hookRunner:X,messageDeliverer:a,uploads:T,questionTracker:w,sideQuestions:W,sessionWatches:E,watchEngine:H,sessionSequences:C,sequenceEngine:h,pushSubscriptions:B,pushNotifier:Z,hookPlugins:D,hookMirror:j.mirror,pluginStates:new S(o),toolkit:J,auth:b}),x=oe.createServer($);let G=null;Qe({port:v,bindHost:R,handler:$}).then(e=>{G=e});const V=()=>{l?.stopWatching(),_.stop(),q.stop(),L.stop(),U.stop(),I.stop(),P.killAll(),j.stop(),x.close(),G?.server.close(),process.exit(0)};process.on("SIGTERM",V),process.on("SIGINT",V),x.listen(m.port,R,()=>{es({...m,pid:process.pid,host:R,tlsPort:v}),rs()})}
@@ -1,2 +1,2 @@
1
- import{existsSync as r,mkdirSync as n,readFileSync as a,rmSync as i,writeFileSync as o}from"node:fs";import{getDataDir as c,getDaemonStatePath as e}from"../db/paths.js";export function readDaemonState(){const t=e();if(!r(t))return null;try{return JSON.parse(a(t,"utf-8"))}catch{return null}}export function writeDaemonState(t){n(c(),{recursive:!0}),o(e(),JSON.stringify(t,null,2)+`
2
- `,"utf-8")}export function clearDaemonState(){const t=e();r(t)&&i(t)}
1
+ import{existsSync as r,mkdirSync as n,readFileSync as i,rmSync as a,writeFileSync as o}from"node:fs";import{getDataDir as c,getDaemonStatePath as e}from"../db/paths.js";export function readDaemonState(){const t=e();if(!r(t))return null;try{return JSON.parse(i(t,"utf-8"))}catch{return null}}export function writeDaemonState(t){n(c(),{recursive:!0}),o(e(),JSON.stringify(t,null,2)+`
2
+ `,"utf-8")}export function clearDaemonState(){const t=e();r(t)&&a(t)}
@@ -1 +1 @@
1
- import{existsSync as i}from"node:fs";import{fileURLToPath as e}from"node:url";import o from"node:path";export function resolveStaticDir(){const t=o.dirname(e(import.meta.url)),r=o.resolve(t,"../../web/dist");return i(r)?r:void 0}
1
+ import{existsSync as o}from"node:fs";import{fileURLToPath as i}from"node:url";import t from"node:path";export function resolveStaticDir(){const e=t.dirname(i(import.meta.url)),r=t.resolve(e,"../../web/dist");return o(r)?r:void 0}
@@ -16,7 +16,10 @@ import type { DataBus } from './data-bus.js';
16
16
  export interface TerminalTopology {
17
17
  /** projectId → 本项目已开终端窗口数(项目卡角标)。 */
18
18
  counts: Record<number, number>;
19
- /** sessionId → 所在可见屏幕;null = 反查不到(pane 已关 / 换了 mux),缺 = 该会话没上报过定位。 */
19
+ /**
20
+ * sessionId → 所在可见屏幕;`null` = 确认不在了(pane 已关 / 换了 mux / 整个
21
+ * GUI 没了),缺 = 这轮没探到或没上报过定位——web 据此保留上次分块,不摘行。
22
+ */
20
23
  terminals: Record<string, SessionTerminal | null>;
21
24
  }
22
25
  export interface TerminalTopologyRefresherOptions {
@@ -1 +1 @@
1
- import v from"node:https";import u from"node:os";import l from"node:path";import{existsSync as f,mkdirSync as w,readFileSync as m,writeFileSync as h}from"node:fs";import{X509Certificate as S,createPrivateKey as k}from"node:crypto";import{generate as D}from"selfsigned";import{getDataDir as $}from"../db/paths.js";export function daemonCertsDir(){return l.join($(),"certs")}export function lanIps(){const e=new Set;for(const t of Object.values(u.networkInterfaces()))for(const r of t??[])r.family==="IPv4"&&!r.internal&&e.add(r.address);return[...e].sort()}export function accessUrls(e,t){const r=[{url:`http://localhost:${e}`,protocol:"http",scope:"local"}];t>0&&r.push({url:`https://localhost:${t}`,protocol:"https",scope:"local"});for(const o of lanIps())r.push({url:`http://${o}:${e}`,protocol:"http",scope:"lan"}),t>0&&r.push({url:`https://${o}:${t}`,protocol:"https",scope:"lan"});return r}function x(e){const t=e.subjectAltName??"",r=new Set;for(const o of t.split(",")){const n=o.trim().match(/^IP Address:(.+)$/);n&&r.add(n[1])}return r}export async function ensureDaemonCert(e=daemonCertsDir(),t={}){const r=t.ips??["127.0.0.1",...lanIps()],o=t.hostname??u.hostname(),n=t.now??new Date,s=l.join(e,"host.key"),a=l.join(e,"host.crt");if(f(s)&&f(a))try{const i=m(s,"utf-8"),p=new S(m(a,"utf-8")),y=r.every(d=>x(p).has(d));if(p.checkPrivateKey(k(i))&&Date.parse(p.validTo)>n.getTime()+7*864e5&&y)return{key:i,cert:m(a,"utf-8")}}catch{}const c=await D([{name:"commonName",value:"weave-daemon"}],{keySize:2048,notAfterDate:new Date(n.getTime()+825*864e5),extensions:[{name:"subjectAltName",altNames:[{type:2,value:"localhost"},{type:2,value:o},...r.map(i=>({type:7,ip:i}))]}]});return w(e,{recursive:!0}),h(s,c.private,{mode:384}),h(a,c.cert),{key:c.private,cert:c.cert}}export async function startTlsServer(e){if(e.port<=0)return null;try{const{key:t,cert:r}=await ensureDaemonCert(e.certDir),o=v.createServer({key:t,cert:r},e.handler);return await new Promise((n,s)=>{o.once("error",s),o.listen(e.port,e.bindHost,()=>{o.off("error",s),n()})}),{server:o,port:e.port}}catch(t){return console.warn(`[weave] https listener disabled (port ${e.port}): ${t instanceof Error?t.message:String(t)}`),null}}
1
+ import w from"node:https";import f from"node:os";import l from"node:path";import{existsSync as u,mkdirSync as d,readFileSync as m,writeFileSync as h}from"node:fs";import{X509Certificate as S,createPrivateKey as k}from"node:crypto";import{generate as D}from"selfsigned";import{getDataDir as $}from"../db/paths.js";export function daemonCertsDir(){return l.join($(),"certs")}export function lanIps(){const t=new Set;for(const e of Object.values(f.networkInterfaces()))for(const r of e??[])r.family==="IPv4"&&!r.internal&&t.add(r.address);return[...t].sort()}export function accessUrls(t,e){const r=[{url:`http://localhost:${t}`,protocol:"http",scope:"local"}];e>0&&r.push({url:`https://localhost:${e}`,protocol:"https",scope:"local"});for(const o of lanIps())r.push({url:`http://${o}:${t}`,protocol:"http",scope:"lan"}),e>0&&r.push({url:`https://${o}:${e}`,protocol:"https",scope:"lan"});return r}function x(t){const e=t.subjectAltName??"",r=new Set;for(const o of e.split(",")){const n=o.trim().match(/^IP Address:(.+)$/);n&&r.add(n[1])}return r}export async function ensureDaemonCert(t=daemonCertsDir(),e={}){const r=e.ips??["127.0.0.1",...lanIps()],o=e.hostname??f.hostname(),n=e.now??new Date,s=l.join(t,"host.key"),a=l.join(t,"host.crt");if(u(s)&&u(a))try{const i=m(s,"utf-8"),p=new S(m(a,"utf-8")),y=r.every(v=>x(p).has(v));if(p.checkPrivateKey(k(i))&&Date.parse(p.validTo)>n.getTime()+7*864e5&&y)return{key:i,cert:m(a,"utf-8")}}catch{}const c=await D([{name:"commonName",value:"weave-daemon"}],{keySize:2048,notAfterDate:new Date(n.getTime()+825*864e5),extensions:[{name:"subjectAltName",altNames:[{type:2,value:"localhost"},{type:2,value:o},...r.map(i=>({type:7,ip:i}))]}]});return d(t,{recursive:!0}),h(s,c.private,{mode:384}),h(a,c.cert),{key:c.private,cert:c.cert}}export async function startTlsServer(t){if(t.port<=0)return null;try{const{key:e,cert:r}=await ensureDaemonCert(t.certDir),o=w.createServer({key:e,cert:r},t.handler);return await new Promise((n,s)=>{o.once("error",s),o.listen(t.port,t.bindHost,()=>{o.off("error",s),n()})}),{server:o,port:t.port}}catch(e){return console.warn(`[weave] https listener disabled (port ${t.port}): ${e instanceof Error?e.message:String(e)}`),null}}
@@ -1 +1 @@
1
- import{sendJson as e}from"./http.js";import{ToolkitError as h}from"../hooks/toolkit.js";export async function handleToolkitRoutes(n,o,r,a,f){if(!a.includes("/toolkit"))return!1;if(!r.toolkit)return e(o,503,{error:"Toolkit unavailable"}),!0;const l=t=>{if(t instanceof h){e(o,t.code==="not-found"?404:400,{error:t.message,code:t.code});return}e(o,400,{error:t instanceof Error?t.message:"Toolkit operation failed"})},u=a.match(/^\/projects\/(\d+)\/toolkit$/);if(u){if(n.method!=="GET")return e(o,405,{error:"Method not allowed"}),!0;try{e(o,200,await r.toolkit.list(Number(u[1])))}catch(t){l(t)}return!0}const i=a.match(/^\/projects\/(\d+)\/toolkit\/([^/]+)\/(enable|disable|uninstall)$/);if(i){if(n.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;const t=Number(i[1]),s=decodeURIComponent(i[2]),m=i[3],c=f.searchParams.get("source");try{const d=m==="enable"?await r.toolkit.enable(t,s,c??void 0):m==="disable"?await r.toolkit.disable(t,s,c??void 0):await r.toolkit.uninstall(t,s,c??void 0);r.dataBus?.emit({key:"toolkit"}),e(o,200,d)}catch(d){l(d)}return!0}const k=a.match(/^\/projects\/(\d+)\/toolkit\/legacy-copies\/cleanup$/);if(k){if(n.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;try{const t=await r.toolkit.cleanupLegacyCopies(Number(k[1]));r.dataBus?.emit({key:"toolkit"}),e(o,200,t)}catch(t){l(t)}return!0}return!1}
1
+ import{sendJson as e}from"./http.js";import{ToolkitError as h}from"../hooks/toolkit.js";export async function handleToolkitRoutes(a,o,r,i,m){if(!i.includes("/toolkit"))return!1;if(!r.toolkit)return e(o,503,{error:"Toolkit unavailable"}),!0;const l=t=>{if(t instanceof h){e(o,t.code==="not-found"?404:400,{error:t.message,code:t.code});return}e(o,400,{error:t instanceof Error?t.message:"Toolkit operation failed"})},s=i.match(/^\/projects\/(\d+)\/toolkit$/);if(s){if(a.method!=="GET")return e(o,405,{error:"Method not allowed"}),!0;try{e(o,200,await r.toolkit.list(Number(s[1])))}catch(t){l(t)}return!0}const n=i.match(/^\/projects\/(\d+)\/toolkit\/([^/]+)\/(enable|disable|uninstall)$/);if(n){if(a.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;const t=Number(n[1]),c=decodeURIComponent(n[2]),k=n[3],u=m.searchParams.get("source");try{const d=k==="enable"?await r.toolkit.enable(t,c,u??void 0):k==="disable"?await r.toolkit.disable(t,c,u??void 0):await r.toolkit.uninstall(t,c,u??void 0);r.dataBus?.emit({key:"toolkit"}),e(o,200,d)}catch(d){l(d)}return!0}const f=i.match(/^\/projects\/(\d+)\/toolkit\/legacy-copies\/cleanup$/);if(f){if(a.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;try{const t=await r.toolkit.cleanupLegacyCopies(Number(f[1]));r.dataBus?.emit({key:"toolkit"}),e(o,200,t)}catch(t){l(t)}return!0}return!1}