@weavecode/weave 0.1.8 → 0.1.9

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 (351) hide show
  1. package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/dist/index.cjs +31 -6
  2. package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/dist/index.mjs +31 -6
  3. package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/package.json +1 -1
  4. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.cjs +1 -1
  5. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.mjs +1 -1
  6. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/README.md +39 -39
  7. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/dist/ipv6.js +1 -1
  8. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/package.json +1 -1
  9. package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/package.json +1 -1
  10. package/node_modules/@weavecode/cli/dist/cli.js +4 -4
  11. package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
  12. package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
  13. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  14. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -2
  15. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  16. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  17. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  18. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  19. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  20. package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
  21. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +2 -2
  22. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +7 -0
  23. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +3 -3
  24. package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
  25. package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
  26. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +5 -5
  27. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  28. package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
  29. package/node_modules/@weavecode/cli/dist/init/git-exclude.d.ts +20 -0
  30. package/node_modules/@weavecode/cli/dist/init/git-exclude.js +7 -0
  31. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  32. package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
  33. package/node_modules/@weavecode/cli/dist/init/instruction-files.d.ts +14 -0
  34. package/node_modules/@weavecode/cli/dist/init/instruction-files.js +1 -0
  35. package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
  36. package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
  37. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  38. package/node_modules/@weavecode/cli/dist/init/provision.js +1 -1
  39. package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
  40. package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
  41. package/node_modules/@weavecode/cli/dist/parser.js +1 -1
  42. package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
  43. package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
  44. package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
  45. package/node_modules/@weavecode/cli/package.json +5 -5
  46. package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
  47. package/node_modules/@weavecode/core/dist/harness.d.ts +37 -0
  48. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  49. package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
  50. package/node_modules/@weavecode/core/dist/index.js +1 -1
  51. package/node_modules/@weavecode/core/dist/platform.js +1 -1
  52. package/node_modules/@weavecode/core/dist/types.d.ts +4 -4
  53. package/node_modules/@weavecode/core/dist/types.js +1 -1
  54. package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
  55. package/node_modules/@weavecode/core/package.json +1 -1
  56. package/node_modules/@weavecode/harness/dist/claude/assets.js +3 -3
  57. package/node_modules/@weavecode/harness/dist/claude/capture.js +9 -9
  58. package/node_modules/@weavecode/harness/dist/claude/commands.js +3 -3
  59. package/node_modules/@weavecode/harness/dist/claude/config.js +2 -2
  60. package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
  61. package/node_modules/@weavecode/harness/dist/claude/edits.js +1 -1
  62. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  63. package/node_modules/@weavecode/harness/dist/claude/images.js +2 -2
  64. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  65. package/node_modules/@weavecode/harness/dist/claude/liveness.js +1 -1
  66. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -1
  67. package/node_modules/@weavecode/harness/dist/claude/messaging.js +2 -2
  68. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
  69. package/node_modules/@weavecode/harness/dist/claude/narration.js +1 -1
  70. package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
  71. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -1
  72. package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
  73. package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
  74. package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
  75. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -2
  76. package/node_modules/@weavecode/harness/dist/claude/resume.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/claude/rewind.js +1 -1
  78. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -1
  79. package/node_modules/@weavecode/harness/dist/claude/side-question.js +2 -2
  80. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +6 -0
  81. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +21 -14
  82. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -1
  83. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -2
  84. package/node_modules/@weavecode/harness/dist/claude/transcript-cursor.js +2 -2
  85. package/node_modules/@weavecode/harness/dist/claude/transcript.js +7 -7
  86. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  87. package/node_modules/@weavecode/harness/dist/codex/capture.js +2 -2
  88. package/node_modules/@weavecode/harness/dist/codex/commands.js +4 -4
  89. package/node_modules/@weavecode/harness/dist/codex/config.js +2 -2
  90. package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
  91. package/node_modules/@weavecode/harness/dist/codex/event-source.js +2 -2
  92. package/node_modules/@weavecode/harness/dist/codex/images.js +1 -1
  93. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  94. package/node_modules/@weavecode/harness/dist/codex/liveness.js +1 -1
  95. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -1
  96. package/node_modules/@weavecode/harness/dist/codex/messaging.js +2 -2
  97. package/node_modules/@weavecode/harness/dist/codex/narration.js +1 -1
  98. package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
  99. package/node_modules/@weavecode/harness/dist/codex/plugins.js +3 -3
  100. package/node_modules/@weavecode/harness/dist/codex/provision.js +1 -1
  101. package/node_modules/@weavecode/harness/dist/codex/questions.js +2 -2
  102. package/node_modules/@weavecode/harness/dist/codex/rollout.js +5 -5
  103. package/node_modules/@weavecode/harness/dist/codex/side-question.js +4 -4
  104. package/node_modules/@weavecode/harness/dist/codex/titles.js +4 -4
  105. package/node_modules/@weavecode/harness/dist/codex/toml.js +13 -13
  106. package/node_modules/@weavecode/harness/dist/codex/transcript.js +2 -2
  107. package/node_modules/@weavecode/harness/dist/driver.js +1 -1
  108. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
  109. package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
  110. package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
  111. package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
  112. package/node_modules/@weavecode/harness/dist/shared/json-cap.js +1 -1
  113. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -1
  114. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -3
  115. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -2
  116. package/node_modules/@weavecode/harness/package.json +2 -2
  117. package/node_modules/@weavecode/server/dist/config/dotted.js +1 -1
  118. package/node_modules/@weavecode/server/dist/config/profiles.js +2 -2
  119. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  120. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  121. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  122. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -3
  123. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  124. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +3 -3
  125. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  126. package/node_modules/@weavecode/server/dist/daemon/config-routes.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/cron.js +1 -1
  128. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  129. package/node_modules/@weavecode/server/dist/daemon/dashboard-pusher.js +1 -1
  130. package/node_modules/@weavecode/server/dist/daemon/decision-config.js +2 -2
  131. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  132. package/node_modules/@weavecode/server/dist/daemon/entry.js +2 -2
  133. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  134. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  135. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  136. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  137. package/node_modules/@weavecode/server/dist/daemon/liveness.js +1 -1
  138. package/node_modules/@weavecode/server/dist/daemon/mcp-orchestration.js +1 -1
  139. package/node_modules/@weavecode/server/dist/daemon/narration-watcher.js +2 -2
  140. package/node_modules/@weavecode/server/dist/daemon/opener/backend-ghostty.js +1 -1
  141. package/node_modules/@weavecode/server/dist/daemon/opener/backend-iterm.js +1 -1
  142. package/node_modules/@weavecode/server/dist/daemon/opener/backend-konsole.js +2 -2
  143. package/node_modules/@weavecode/server/dist/daemon/opener/backend-terminal-app.js +1 -1
  144. package/node_modules/@weavecode/server/dist/daemon/opener/backend-wezterm.js +1 -1
  145. package/node_modules/@weavecode/server/dist/daemon/opener/backend-wt.js +1 -1
  146. package/node_modules/@weavecode/server/dist/daemon/opener/backend.js +1 -1
  147. package/node_modules/@weavecode/server/dist/daemon/opener/launch.js +1 -1
  148. package/node_modules/@weavecode/server/dist/daemon/opener/pty-terminals.js +1 -1
  149. package/node_modules/@weavecode/server/dist/daemon/opener/shared.js +1 -1
  150. package/node_modules/@weavecode/server/dist/daemon/opener/wezterm-mux.js +1 -1
  151. package/node_modules/@weavecode/server/dist/daemon/opener/wt.js +3 -3
  152. package/node_modules/@weavecode/server/dist/daemon/opener.js +1 -1
  153. package/node_modules/@weavecode/server/dist/daemon/pet-seed.d.ts +4 -6
  154. package/node_modules/@weavecode/server/dist/daemon/pet-seed.js +2 -1
  155. package/node_modules/@weavecode/server/dist/daemon/pet-window.js +1 -1
  156. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  157. package/node_modules/@weavecode/server/dist/daemon/project-files.js +2 -2
  158. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  159. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  160. package/node_modules/@weavecode/server/dist/daemon/prompt-images.js +1 -1
  161. package/node_modules/@weavecode/server/dist/daemon/routes/hooks-admin.js +1 -1
  162. package/node_modules/@weavecode/server/dist/daemon/routes/installations.d.ts +29 -0
  163. package/node_modules/@weavecode/server/dist/daemon/routes/installations.js +1 -0
  164. package/node_modules/@weavecode/server/dist/daemon/routes/market.js +1 -1
  165. package/node_modules/@weavecode/server/dist/daemon/routes/orchestration.js +1 -1
  166. package/node_modules/@weavecode/server/dist/daemon/routes/path-refs.js +1 -1
  167. package/node_modules/@weavecode/server/dist/daemon/routes/pets.js +1 -1
  168. package/node_modules/@weavecode/server/dist/daemon/routes/project-files.js +1 -1
  169. package/node_modules/@weavecode/server/dist/daemon/routes/projects.js +1 -1
  170. package/node_modules/@weavecode/server/dist/daemon/routes/search.js +1 -1
  171. package/node_modules/@weavecode/server/dist/daemon/routes/session-control.js +1 -1
  172. package/node_modules/@weavecode/server/dist/daemon/routes/session-insights.js +1 -1
  173. package/node_modules/@weavecode/server/dist/daemon/routes/settings-statusline.js +1 -1
  174. package/node_modules/@weavecode/server/dist/daemon/routes/uploads.js +1 -1
  175. package/node_modules/@weavecode/server/dist/daemon/routes/visualizations.js +2 -2
  176. package/node_modules/@weavecode/server/dist/daemon/routes/watches.js +1 -1
  177. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +2 -0
  178. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -8
  179. package/node_modules/@weavecode/server/dist/daemon/session-open.js +1 -1
  180. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  181. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  182. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  183. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -1
  184. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  185. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  186. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  187. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.js +1 -1
  188. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  189. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  190. package/node_modules/@weavecode/server/dist/daemon/upload-sessions.js +1 -1
  191. package/node_modules/@weavecode/server/dist/db/db.js +2 -2
  192. package/node_modules/@weavecode/server/dist/db/layout.d.ts +5 -0
  193. package/node_modules/@weavecode/server/dist/db/layout.js +2 -1
  194. package/node_modules/@weavecode/server/dist/db/paths.d.ts +5 -0
  195. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  196. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  197. package/node_modules/@weavecode/server/dist/hooks/dashboard-rate.js +1 -1
  198. package/node_modules/@weavecode/server/dist/hooks/decision-judge.js +1 -1
  199. package/node_modules/@weavecode/server/dist/hooks/delivery/ack-gate.js +1 -1
  200. package/node_modules/@weavecode/server/dist/hooks/delivery/channels.js +1 -1
  201. package/node_modules/@weavecode/server/dist/hooks/delivery/keys.js +1 -1
  202. package/node_modules/@weavecode/server/dist/hooks/delivery/queue.js +1 -1
  203. package/node_modules/@weavecode/server/dist/hooks/delivery/relay.js +1 -1
  204. package/node_modules/@weavecode/server/dist/hooks/delivery/send.js +2 -2
  205. package/node_modules/@weavecode/server/dist/hooks/delivery/views.js +1 -1
  206. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  207. package/node_modules/@weavecode/server/dist/hooks/edge-extract.js +1 -1
  208. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  209. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  210. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -2
  211. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  212. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  213. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +5 -5
  214. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  215. package/node_modules/@weavecode/server/dist/hooks/orchestration-engine.js +7 -7
  216. package/node_modules/@weavecode/server/dist/hooks/orchestration-graph.js +1 -1
  217. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  218. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  219. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  220. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  221. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  222. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  223. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  224. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  225. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  226. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  227. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -1
  228. package/node_modules/@weavecode/server/dist/hooks/synthetic-sessions.js +1 -1
  229. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  230. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  231. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  232. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  233. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  234. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  235. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  236. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  237. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -1
  238. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  239. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +0 -9
  240. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -2
  241. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  242. package/node_modules/@weavecode/server/dist/install/installer.js +1 -1
  243. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  244. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  245. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  246. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  247. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  248. package/node_modules/@weavecode/server/dist/install/project-config.js +1 -1
  249. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  250. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  251. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  252. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  253. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  254. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  255. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  256. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  257. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  258. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  259. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  260. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  261. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +4 -4
  262. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +6 -6
  263. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  264. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  265. package/node_modules/@weavecode/server/dist/repositories/orchestrations.js +7 -7
  266. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  267. package/node_modules/@weavecode/server/dist/repositories/projects.js +1 -1
  268. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  269. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  270. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  271. package/node_modules/@weavecode/server/dist/repositories/uploads.js +11 -11
  272. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  273. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -1
  274. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -3
  275. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  276. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  277. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  278. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  279. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  280. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  281. package/node_modules/@weavecode/server/package.json +4 -4
  282. package/node_modules/@weavecode/server/web/dist/assets/{abnfDiagram-WEYOIA3C-t5OQjhuS.js → abnfDiagram-WEYOIA3C-S1lL1V_n.js} +1 -1
  283. package/node_modules/@weavecode/server/web/dist/assets/{arc-De-uH_Q9.js → arc-CoTNHyHV.js} +1 -1
  284. package/node_modules/@weavecode/server/web/dist/assets/{architectureDiagram-ZHVYKT53-ImPclD43.js → architectureDiagram-ZHVYKT53-C6ttfnzW.js} +1 -1
  285. package/node_modules/@weavecode/server/web/dist/assets/{blockDiagram-RJAE7QA3-B5xEQs6X.js → blockDiagram-RJAE7QA3-CYr3Cpu9.js} +1 -1
  286. package/node_modules/@weavecode/server/web/dist/assets/{c4Diagram-XDPPPE54-DP8MjIgJ.js → c4Diagram-XDPPPE54-BFS7PhLD.js} +1 -1
  287. package/node_modules/@weavecode/server/web/dist/assets/channel-DxQHp3Yc.js +1 -0
  288. package/node_modules/@weavecode/server/web/dist/assets/{chunk-2E7WHVMD-C3UFIDyj.js → chunk-2E7WHVMD-DJ7X_Shu.js} +1 -1
  289. package/node_modules/@weavecode/server/web/dist/assets/{chunk-2Q5K7J3B-Bgw-3YfG.js → chunk-2Q5K7J3B-B8nr2rdz.js} +1 -1
  290. package/node_modules/@weavecode/server/web/dist/assets/{chunk-4EMNKR2T-Dy_Wq9qn.js → chunk-4EMNKR2T-DmnZmUMU.js} +1 -1
  291. package/node_modules/@weavecode/server/web/dist/assets/{chunk-55XCU76K-D32C0DXX.js → chunk-55XCU76K-Xz9a8dmp.js} +1 -1
  292. package/node_modules/@weavecode/server/web/dist/assets/{chunk-5VM5RSS4-Dpmi-9Gi.js → chunk-5VM5RSS4-Dg9mg7pf.js} +1 -1
  293. package/node_modules/@weavecode/server/web/dist/assets/{chunk-JWPE2WC7-CEYXaZDX.js → chunk-JWPE2WC7-CmjTZO8o.js} +1 -1
  294. package/node_modules/@weavecode/server/web/dist/assets/{chunk-VQ5W62QI-A616Pgzo.js → chunk-VQ5W62QI-D3YDdJ3E.js} +1 -1
  295. package/node_modules/@weavecode/server/web/dist/assets/{chunk-XXDRQBXY-CnxFMLWV.js → chunk-XXDRQBXY-s1OG9sqW.js} +1 -1
  296. package/node_modules/@weavecode/server/web/dist/assets/{chunk-ZCHMQSOR-BhjCTig8.js → chunk-ZCHMQSOR-C3hINQU3.js} +2 -2
  297. package/node_modules/@weavecode/server/web/dist/assets/{classDiagram-v2-4MYWR3UA-rzlq5tPv.js → classDiagram-v2-4MYWR3UA-BTsbYrVl.js} +1 -1
  298. package/node_modules/@weavecode/server/web/dist/assets/{cose-bilkent-JH36ORCC-CxWQXzj8.js → cose-bilkent-JH36ORCC-C0W8Y-jI.js} +1 -1
  299. package/node_modules/@weavecode/server/web/dist/assets/{cynefin-EF2NZ3EQ-AFHjx2wU.js → cynefin-EF2NZ3EQ-stAu4Rh-.js} +1 -1
  300. package/node_modules/@weavecode/server/web/dist/assets/{cynefinDiagram-WF24UDRP-Bp_Oaf9U.js → cynefinDiagram-WF24UDRP-CqYibiiv.js} +1 -1
  301. package/node_modules/@weavecode/server/web/dist/assets/{dagre-NK4GIZVX-7oUPIU35.js → dagre-NK4GIZVX-qqcoJAqB.js} +1 -1
  302. package/node_modules/@weavecode/server/web/dist/assets/{diagram-CBK3MWTC-D_rS_rSY.js → diagram-CBK3MWTC-D0YTopb7.js} +1 -1
  303. package/node_modules/@weavecode/server/web/dist/assets/{diagram-I5XIIV2D-Duc_cKMb.js → diagram-I5XIIV2D-Csvw6aYr.js} +1 -1
  304. package/node_modules/@weavecode/server/web/dist/assets/{diagram-ODIL2UCW-DA0XFVXm.js → diagram-ODIL2UCW-Dl0tYLkF.js} +1 -1
  305. package/node_modules/@weavecode/server/web/dist/assets/{diagram-PFBEJUXE-D1U0Xhtt.js → diagram-PFBEJUXE-BCPSWZPe.js} +1 -1
  306. package/node_modules/@weavecode/server/web/dist/assets/{diagram-RJA3I4VV-CbDFY871.js → diagram-RJA3I4VV-ETg-BrAJ.js} +1 -1
  307. package/node_modules/@weavecode/server/web/dist/assets/{diagram-TYUNFSNR-jPg9AxQv.js → diagram-TYUNFSNR-_M6ZxBG7.js} +1 -1
  308. package/node_modules/@weavecode/server/web/dist/assets/{ebnfDiagram-V4P3TTPT-ZHfGTB0N.js → ebnfDiagram-V4P3TTPT-C-e_W7qx.js} +1 -1
  309. package/node_modules/@weavecode/server/web/dist/assets/{elk-QONTBCTQ-C-ESJrUi.js → elk-QONTBCTQ-B5TBharB.js} +1 -1
  310. package/node_modules/@weavecode/server/web/dist/assets/{erDiagram-KYQIGQAA-DGK7TeHj.js → erDiagram-KYQIGQAA-D08rj2pv.js} +1 -1
  311. package/node_modules/@weavecode/server/web/dist/assets/{flowDiagram-IUGLLWBU-CVV4rL8v.js → flowDiagram-IUGLLWBU-BALTxsKh.js} +1 -1
  312. package/node_modules/@weavecode/server/web/dist/assets/{ganttDiagram-R7GPNTJY-CuAwNvbm.js → ganttDiagram-R7GPNTJY-Cts193jT.js} +1 -1
  313. package/node_modules/@weavecode/server/web/dist/assets/{gitGraphDiagram-PDYL7XHY-D_15Wtf-.js → gitGraphDiagram-PDYL7XHY-L9qYUX0v.js} +1 -1
  314. package/node_modules/@weavecode/server/web/dist/assets/{infoDiagram-MVDRKAX5-ClqhbrCa.js → infoDiagram-MVDRKAX5-Bv47rgU0.js} +1 -1
  315. package/node_modules/@weavecode/server/web/dist/assets/{ishikawaDiagram-HPEHV2GE-CUJ891JX.js → ishikawaDiagram-HPEHV2GE-Da8_s6cs.js} +1 -1
  316. package/node_modules/@weavecode/server/web/dist/assets/{journeyDiagram-BOSHW7O7-B4skiMu-.js → journeyDiagram-BOSHW7O7-Bj3CjZOf.js} +1 -1
  317. package/node_modules/@weavecode/server/web/dist/assets/{kanban-definition-FNSA4HC5-UNGJR_y_.js → kanban-definition-FNSA4HC5-D1hicmMu.js} +1 -1
  318. package/node_modules/@weavecode/server/web/dist/assets/{linear-BEB-UwbR.js → linear-CWQg2iA1.js} +1 -1
  319. package/node_modules/@weavecode/server/web/dist/assets/main-XLn3EZFh.css +11 -0
  320. package/node_modules/@weavecode/server/web/dist/assets/main-bsb0lQoL.js +1096 -0
  321. package/node_modules/@weavecode/server/web/dist/assets/{mermaid.core-knGXJfjz.js → mermaid.core-C-wP0Zg2.js} +4 -4
  322. package/node_modules/@weavecode/server/web/dist/assets/{mindmap-definition-6OY57UG3-CEldbr3a.js → mindmap-definition-6OY57UG3-Dk0VKqre.js} +1 -1
  323. package/node_modules/@weavecode/server/web/dist/assets/{pegDiagram-ECIUJNBX-cNCkGLx3.js → pegDiagram-ECIUJNBX-Bp1K_F9z.js} +1 -1
  324. package/node_modules/@weavecode/server/web/dist/assets/pet-J6izA90s.js +1 -0
  325. package/node_modules/@weavecode/server/web/dist/assets/{pieDiagram-GNMPY74T-CfMEFiQD.js → pieDiagram-GNMPY74T-BZ4rGy3t.js} +1 -1
  326. package/node_modules/@weavecode/server/web/dist/assets/{quadrantDiagram-D57K4MC3-knmi2rwP.js → quadrantDiagram-D57K4MC3-B4N5KRsR.js} +1 -1
  327. package/node_modules/@weavecode/server/web/dist/assets/{railroadDiagram-Y72NRBL7-BJ7AzhEo.js → railroadDiagram-Y72NRBL7-C8nx8oHf.js} +1 -1
  328. package/node_modules/@weavecode/server/web/dist/assets/{requirementDiagram-EQYSW5RA-Dte2LGQM.js → requirementDiagram-EQYSW5RA-VSH57d0d.js} +1 -1
  329. package/node_modules/@weavecode/server/web/dist/assets/{sankeyDiagram-SY24JHO5-3noLaWgd.js → sankeyDiagram-SY24JHO5-jUb1hcya.js} +1 -1
  330. package/node_modules/@weavecode/server/web/dist/assets/{sequenceDiagram-BLEHNHQU-CclOWTTc.js → sequenceDiagram-BLEHNHQU-E2BioCNi.js} +1 -1
  331. package/node_modules/@weavecode/server/web/dist/assets/{sizeCapture-INFHLROL-B82sbLhA.js → sizeCapture-INFHLROL-BdKrbRmI.js} +1 -1
  332. package/node_modules/@weavecode/server/web/dist/assets/{stateDiagram-v2-A6IESKWZ-BXfVDwSN.js → stateDiagram-v2-A6IESKWZ-tFz7uNM7.js} +1 -1
  333. package/node_modules/@weavecode/server/web/dist/assets/{swimlanes-B3ENRKFQ-D4lKZaeV.js → swimlanes-B3ENRKFQ-B9BAPDWw.js} +1 -1
  334. package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-DQ2NPLl9.js +8 -0
  335. package/node_modules/@weavecode/server/web/dist/assets/{timeline-definition-JXYKGLGB-D6H6zP5b.js → timeline-definition-JXYKGLGB-CofNnFTK.js} +1 -1
  336. package/node_modules/@weavecode/server/web/dist/assets/{usecaseDiagram-WPOLBNNX-D2J2bKo_.js → usecaseDiagram-WPOLBNNX-DOvjhJjJ.js} +1 -1
  337. package/node_modules/@weavecode/server/web/dist/assets/{vennDiagram-Q3Y3IDCW-pdRbIkpB.js → vennDiagram-Q3Y3IDCW-BcFHWnhS.js} +1 -1
  338. package/node_modules/@weavecode/server/web/dist/assets/{wardleyDiagram-IVAIDKWA-Cyd2QPMf.js → wardleyDiagram-IVAIDKWA-Bz2aqRAs.js} +1 -1
  339. package/node_modules/@weavecode/server/web/dist/assets/{xychartDiagram-4URNHDU4-Bd4BkwVM.js → xychartDiagram-4URNHDU4-DpNF6Vsq.js} +1 -1
  340. package/node_modules/@weavecode/server/web/dist/index.html +2 -2
  341. package/node_modules/@weavecode/server/web/dist/pet.html +80 -10
  342. package/node_modules/@weavecode/templates/dist/resources/pets/weave-spider/pet.json +1 -1
  343. package/node_modules/@weavecode/templates/dist/resources/pets/weave-spider/spritesheet.png +0 -0
  344. package/node_modules/@weavecode/templates/package.json +2 -2
  345. package/package.json +6 -6
  346. package/scripts/preinstall.mjs +60 -22
  347. package/node_modules/@weavecode/server/web/dist/assets/channel-C0RGiobt.js +0 -1
  348. package/node_modules/@weavecode/server/web/dist/assets/main-B_0jS_Gz.js +0 -1096
  349. package/node_modules/@weavecode/server/web/dist/assets/main-Czzlavi4.css +0 -11
  350. package/node_modules/@weavecode/server/web/dist/assets/pet-DJCpIDM5.js +0 -1
  351. package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-DbdFh_d6.js +0 -8
@@ -1,2 +1,2 @@
1
- import c from"node:path";import x from"node:os";import{promises as u}from"node:fs";import{HARNESS_DIRS as w,VISUALIZATION_PROTOCOL as l}from"@weavecode/core";import{sendJson as f}from"../http.js";import{isInsideDir as O}from"../../market/resolve.js";import{getVisualizationsDir as b}from"../../db/paths.js";function y(r){return r.visualizationsDir??b()}function A(r){const t=x.homedir(),o=[c.join(t,w.codex.userDir,"visualizations"),c.join(t,w.claude.userDir),c.join(t,w.codex.userDir,"plugins"),c.join(x.tmpdir(),"weave"),y(r)];for(const n of r.projects.list())o.push(n.path);return o}const S=1440*60*1e3,P=[l.referencePrefix,...l.referencePrefixAliases],j=[l.referenceSuffix,...l.referenceSuffixAliases];function C(r){const t=[];for(const o of r.split(`
2
- `)){const n=o.trim(),a=P.find(s=>n.startsWith(s));if(!a)continue;let e=n.slice(a.length);const i=j.find(s=>e.endsWith(s));i&&(e=e.slice(0,-i.length));try{const s=JSON.parse(e);typeof s.path=="string"&&s.path&&t.push(c.resolve(s.path))}catch{}}return t}function I(r){const t=new Set;for(const o of r.hookEvents?.conversationTextsContaining("visualize")??[])for(const n of C(o))t.add(n.toLowerCase());return t}async function R(r){const t=[],o=async n=>{let a;try{a=await u.readdir(n,{withFileTypes:!0})}catch{return}for(const e of a){const i=c.join(n,e.name);if(e.isDirectory()){await o(i);continue}if(!(!e.isFile()||c.extname(e.name).toLowerCase()!==".html"))try{const s=await u.stat(i);t.push({file:i,size:s.size,mtimeMs:s.mtimeMs})}catch{}}};return await o(r),t}async function L(r){const t=y(r),o=await R(t),n=I(r),a=Date.now()-S,e={root:t,count:o.length,bytes:0,unreferenced:{count:0,bytes:0}};for(const i of o)e.bytes+=i.size,!(n.has(i.file.toLowerCase())||i.mtimeMs>a)&&(e.unreferenced.count+=1,e.unreferenced.bytes+=i.size);return e}export async function handleVisualizationRoutes(r,t,o,n,a){if(n==="/visualizations/stats"&&r.method==="GET")return f(t,200,await L(o)),!0;if(n==="/visualizations/cleanup"&&r.method==="POST"){const p=await R(y(o)),E=I(o),M=Date.now()-S;let v=0,F=0;for(const h of p)if(!(E.has(h.file.toLowerCase())||h.mtimeMs>M))try{await u.unlink(h.file),v+=1,F+=h.size}catch{}return f(t,200,{removed:v,freedBytes:F}),!0}if(n!=="/visualizations/fragment"||r.method!=="GET")return!1;const e=a.searchParams.get("path")??"",i=c.resolve(e);if(!e||!c.isAbsolute(e))return f(t,400,{error:'Missing or relative "path" query parameter'}),!0;const s=A(o);if(!s.some(p=>O(i,p)))return f(t,403,{error:`Fragment path is outside the allowed roots: ${s.join(", ")}`}),!0;if(c.extname(i).toLowerCase()!==".html")return f(t,403,{error:"Only .html fragments are served"}),!0;let m;try{m=await u.stat(i)}catch{return f(t,404,{error:"Fragment file not found"}),!0}if(!m.isFile())return f(t,404,{error:"Fragment path is not a file"}),!0;t.setHeader("cache-control","no-store");const d=Math.floor(m.mtimeMs),g=a.searchParams.get("mtime"),z=g==null?NaN:Number(g);if(Number.isFinite(z)&&z===d)return f(t,200,{unchanged:!0,mtimeMs:d}),!0;if(m.size>l.maxFragmentBytes)return f(t,413,{error:"Fragment exceeds the 1 MB size limit"}),!0;const D=await u.readFile(i,"utf8");return f(t,200,{html:D,mtimeMs:d}),!0}
1
+ import c from"node:path";import D from"node:os";import{promises as u}from"node:fs";import{HARNESS_DIRS as w,VISUALIZATION_PROTOCOL as m}from"@weavecode/core";import{sendJson as f}from"../http.js";import{isInsideDir as L}from"../../market/resolve.js";import{getVisualizationsDir as N}from"../../db/paths.js";function y(r){return r.visualizationsDir??N()}function O(r){const e=D.homedir(),i=[c.join(e,w.codex.userDir,"visualizations"),c.join(e,w.claude.userDir),c.join(e,w.codex.userDir,"plugins"),c.join(D.tmpdir(),"weave"),y(r)];for(const n of r.projects.list())i.push(n.path);return i}const F=1440*60*1e3,T=[m.referencePrefix,...m.referencePrefixAliases],A=[m.referenceSuffix,...m.referenceSuffixAliases];function P(r){const e=[];for(const i of r.split(`
2
+ `)){const n=i.trim(),a=T.find(o=>n.startsWith(o));if(!a)continue;let t=n.slice(a.length);const s=A.find(o=>t.endsWith(o));s&&(t=t.slice(0,-s.length));try{const o=JSON.parse(t);typeof o.path=="string"&&o.path&&e.push(c.resolve(o.path))}catch{}}return e}function M(r){const e=new Set;for(const i of r.hookEvents?.conversationTextsContaining("visualize")??[])for(const n of P(i))e.add(n.toLowerCase());return e}async function S(r){const e=[],i=async n=>{let a;try{a=await u.readdir(n,{withFileTypes:!0})}catch{return}for(const t of a){const s=c.join(n,t.name);if(t.isDirectory()){await i(s);continue}if(!(!t.isFile()||c.extname(t.name).toLowerCase()!==".html"))try{const o=await u.stat(s);e.push({file:s,size:o.size,mtimeMs:o.mtimeMs})}catch{}}};return await i(r),e}async function I(r){const e=y(r),i=await S(e),n=M(r),a=Date.now()-F,t={root:e,count:i.length,bytes:0,unreferenced:{count:0,bytes:0}};for(const s of i)t.bytes+=s.size,!(n.has(s.file.toLowerCase())||s.mtimeMs>a)&&(t.unreferenced.count+=1,t.unreferenced.bytes+=s.size);return t}export async function handleVisualizationRoutes(r,e,i,n,a){if(n==="/visualizations/stats"&&r.method==="GET")return f(e,200,await I(i)),!0;if(n==="/visualizations/cleanup"&&r.method==="POST"){const p=await S(y(i)),j=M(i),C=Date.now()-F;let v=0,x=0;for(const h of p)if(!(j.has(h.file.toLowerCase())||h.mtimeMs>C))try{await u.unlink(h.file),v+=1,x+=h.size}catch{}return f(e,200,{removed:v,freedBytes:x}),!0}if(n!=="/visualizations/fragment"||r.method!=="GET")return!1;const t=a.searchParams.get("path")??"",s=c.resolve(t);if(!t||!c.isAbsolute(t))return f(e,400,{error:'Missing or relative "path" query parameter'}),!0;const o=O(i);if(!o.some(p=>L(s,p)))return f(e,403,{error:`Fragment path is outside the allowed roots: ${o.join(", ")}`}),!0;if(c.extname(s).toLowerCase()!==".html")return f(e,403,{error:"Only .html fragments are served"}),!0;let l;try{l=await u.stat(s)}catch{return f(e,404,{error:"Fragment file not found"}),!0}if(!l.isFile())return f(e,404,{error:"Fragment path is not a file"}),!0;e.setHeader("cache-control","no-store");const d=Math.floor(l.mtimeMs),g=a.searchParams.get("mtime"),z=g==null?NaN:Number(g);if(Number.isFinite(z)&&z===d)return f(e,200,{unchanged:!0,mtimeMs:d}),!0;if(l.size>m.maxFragmentBytes)return f(e,413,{error:"Fragment exceeds the 1 MB size limit"}),!0;const b=await u.readFile(s,"utf8");return f(e,200,{html:b,mtimeMs:d}),!0}
@@ -1 +1 @@
1
- import{z as o}from"zod";import{isHarness as E}from"@weavecode/core";import{readJson as g,sendJson as t}from"../http.js";import{messagingSurfaceFor as k}from"../../surfaces.js";import{DEFAULT_WATCH_ON as W}from"../../repositories/session-watches.js";const B=o.object({watcherSessionId:o.string().min(1).nullable().optional(),notify:o.string().min(1).max(2e4).nullable().optional(),on:o.array(o.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:o.number().int().min(1).max(100).nullable().optional()}),P=o.object({watchId:o.number().int().positive()}),T=o.object({endpoint:o.string().url(),keys:o.object({p256dh:o.string().min(1),auth:o.string().min(1)})}),j=o.object({endpoint:o.string().url()});function C(i,e){return i.queuedPrompt!==null||i.prompt!==null||e}export async function handleWatchRoutes(i,e,n,c){const y=c.match(/^\/sessions\/([^/]+)\/watch$/);if(y){const s=decodeURIComponent(y[1]);if(i.method==="POST"){if(!n.sessionWatches||!n.hookSessions||!n.hookEvents)return t(e,503,{error:"Messaging subsystem unavailable"}),!0;let r;try{r=B.parse(await g(i))}catch(u){return t(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(!n.hookSessions.getBySessionId(s))return t(e,404,{error:"Session not found"}),!0;const h=n.hookEvents.listBySession(s,1),m=h[h.length-1]?.source;if(!E(m))return t(e,400,{error:"Session has no hook events to determine its harness"}),!0;const a=k(m),l=r.on??[...W];if((l.includes("idle")||l.includes("turnEnd"))&&a.idleSignals.length===0)return t(e,409,{error:a.unsupportedReasons?.watch??`Harness "${m}" does not support idle watching`}),!0;if(l.includes("messageFailed")&&!(C(a,n.messageDeliverer?.hasTerminalChannel()??!1)||a.inject!==null||a.headless!==null))return t(e,409,{error:a.unsupportedReasons?.prompt??`Harness "${m}" supports no messaging channel`}),!0;if(r.watcherSessionId){if(!n.hookSessions.getBySessionId(r.watcherSessionId))return t(e,404,{error:"Watcher session not found"}),!0;const I=n.hookEvents.listBySession(r.watcherSessionId,1),b=I[I.length-1]?.source;if(!E(b))return t(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const v=k(b);if(!v.inject)return t(e,409,{error:v.unsupportedReasons?.inject??`Harness "${b}" cannot receive watch notifications`}),!0}const p=r.times===void 0?1:r.times,w=(r.watcherSessionId??null)===null?n.sessionWatches.listPendingByTarget(s).find(u=>u.watcherSessionId===null):void 0,S=w?n.sessionWatches.updateById(w.id,{onEvents:l,remaining:p}):void 0,f=S??n.sessionWatches.insert({watcherSessionId:r.watcherSessionId??null,targetSessionId:s,notify:r.notify??null,onEvents:l,times:p});return n.watchEngine?.created(f),t(e,S?200:201,{ok:!0,watchId:f.id,watch:f}),!0}if(i.method==="DELETE"){if(!n.sessionWatches)return t(e,503,{error:"Messaging subsystem unavailable"}),!0;let r;try{r=P.parse(await g(i))}catch(h){return t(e,400,{error:h instanceof Error?h.message:"Invalid body"}),!0}const d=n.sessionWatches.getById(r.watchId);return!d||d.targetSessionId!==s||d.firedAt!==null?(t(e,404,{error:"Watch not found"}),!0):(n.sessionWatches.deleteById(r.watchId),t(e,200,{ok:!0,watchId:r.watchId}),!0)}}if(c==="/messaging/watches"&&i.method==="GET")return n.sessionWatches?(t(e,200,{watches:n.sessionWatches.listPending()}),!0):(t(e,503,{error:"Messaging subsystem unavailable"}),!0);if(c==="/messaging/push/key"&&i.method==="GET")return n.pushNotifier?(t(e,200,{publicKey:n.pushNotifier.publicKey()}),!0):(t(e,503,{error:"Push subsystem unavailable"}),!0);if(c==="/messaging/push/subscribe"&&i.method==="POST"){if(!n.pushSubscriptions)return t(e,503,{error:"Push subsystem unavailable"}),!0;try{const s=T.parse(await g(i)),r=n.pushSubscriptions.upsert({endpoint:s.endpoint,p256dh:s.keys.p256dh,auth:s.keys.auth,userAgent:i.headers["user-agent"]??null});t(e,201,{ok:!0,subscription:r})}catch(s){t(e,400,{error:s instanceof Error?s.message:"Invalid body"})}return!0}if(c==="/messaging/push/unsubscribe"&&i.method==="POST"){if(!n.pushSubscriptions)return t(e,503,{error:"Push subsystem unavailable"}),!0;try{const s=j.parse(await g(i));n.pushSubscriptions.deleteByEndpoint(s.endpoint),t(e,200,{ok:!0})}catch(s){t(e,400,{error:s instanceof Error?s.message:"Invalid body"})}return!0}return!1}
1
+ import{z as t}from"zod";import{isHarness as I}from"@weavecode/core";import{readJson as m,sendJson as s}from"../http.js";import{messagingSurfaceFor as v}from"../../surfaces.js";import{DEFAULT_WATCH_ON as E}from"../../repositories/session-watches.js";const k=t.object({watcherSessionId:t.string().min(1).nullable().optional(),notify:t.string().min(1).max(2e4).nullable().optional(),on:t.array(t.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:t.number().int().min(1).max(100).nullable().optional()}),W=t.object({watchId:t.number().int().positive()}),T=t.object({endpoint:t.string().url(),keys:t.object({p256dh:t.string().min(1),auth:t.string().min(1)})}),B=t.object({endpoint:t.string().url()});function P(i,e){return i.queuedPrompt!==null||i.prompt!==null||e}export async function handleWatchRoutes(i,e,n,l){const f=l.match(/^\/sessions\/([^/]+)\/watch$/);if(f){const r=decodeURIComponent(f[1]);if(i.method==="POST"){if(!n.sessionWatches||!n.hookSessions||!n.hookEvents)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=k.parse(await m(i))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(!n.hookSessions.getBySessionId(r))return s(e,404,{error:"Session not found"}),!0;const c=n.hookEvents.listBySession(r,1),a=c[c.length-1]?.source;if(!I(a))return s(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=v(a),h=o.on??[...E];if((h.includes("idle")||h.includes("turnEnd"))&&d.idleSignals.length===0)return s(e,409,{error:d.unsupportedReasons?.watch??`Harness "${a}" does not support idle watching`}),!0;if(h.includes("messageFailed")&&!(P(d,n.messageDeliverer?.hasTerminalChannel()??!1)||d.inject!==null||d.headless!==null))return s(e,409,{error:d.unsupportedReasons?.prompt??`Harness "${a}" supports no messaging channel`}),!0;if(o.watcherSessionId){if(!n.hookSessions.getBySessionId(o.watcherSessionId))return s(e,404,{error:"Watcher session not found"}),!0;const u=n.hookEvents.listBySession(o.watcherSessionId,1),g=u[u.length-1]?.source;if(!I(g))return s(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const w=v(g);if(!w.inject)return s(e,409,{error:w.unsupportedReasons?.inject??`Harness "${g}" cannot receive watch notifications`}),!0}const b=o.times===void 0?1:o.times,y=(o.watcherSessionId??null)===null?n.sessionWatches.listPendingByTarget(r).find(u=>u.watcherSessionId===null):void 0,S=y?n.sessionWatches.updateById(y.id,{onEvents:h,remaining:b}):void 0,p=S??n.sessionWatches.insert({watcherSessionId:o.watcherSessionId??null,targetSessionId:r,notify:o.notify??null,onEvents:h,times:b});return n.watchEngine?.created(p),s(e,S?200:201,{ok:!0,watchId:p.id,watch:p}),!0}if(i.method==="DELETE"){if(!n.sessionWatches)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=W.parse(await m(i))}catch(a){return s(e,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const c=n.sessionWatches.getById(o.watchId);return!c||c.targetSessionId!==r||c.firedAt!==null?(s(e,404,{error:"Watch not found"}),!0):(n.sessionWatches.deleteById(o.watchId),s(e,200,{ok:!0,watchId:o.watchId}),!0)}}if(l==="/messaging/watches"&&i.method==="GET")return n.sessionWatches?(s(e,200,{watches:n.sessionWatches.listPending()}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(l==="/messaging/push/key"&&i.method==="GET")return n.pushNotifier?(s(e,200,{publicKey:n.pushNotifier.publicKey()}),!0):(s(e,503,{error:"Push subsystem unavailable"}),!0);if(l==="/messaging/push/subscribe"&&i.method==="POST"){if(!n.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const r=T.parse(await m(i)),o=n.pushSubscriptions.upsert({endpoint:r.endpoint,p256dh:r.keys.p256dh,auth:r.keys.auth,userAgent:i.headers["user-agent"]??null});s(e,201,{ok:!0,subscription:o})}catch(r){s(e,400,{error:r instanceof Error?r.message:"Invalid body"})}return!0}if(l==="/messaging/push/unsubscribe"&&i.method==="POST"){if(!n.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const r=B.parse(await m(i));n.pushSubscriptions.deleteByEndpoint(r.endpoint),s(e,200,{ok:!0})}catch(r){s(e,400,{error:r instanceof Error?r.message:"Invalid body"})}return!0}return!1}
@@ -48,6 +48,8 @@ export interface WeaveServerDeps {
48
48
  hookEvents?: HookEventRepository;
49
49
  /** 渲染块 fragment 落点根;缺省 `<data>/visualizations`(测试注入临时目录)。 */
50
50
  visualizationsDir?: string;
51
+ /** 本机停机入口(`POST /daemon/shutdown`):走 start.ts 的 shutdown 链,先并 WAL 再退。 */
52
+ requestShutdown?: () => void;
51
53
  /**
52
54
  * 事件接入源(批 4b:类型由 HookAdapter 放宽为结构兼容的 EventSource,
53
55
  * `HookAdapter[]` 仍可赋值);`harnesses` 存在时 POST /hooks 由其派生。
@@ -1,13 +1,13 @@
1
- import y from"node:http";import{WEAVE_VERSION as S}from"../version.js";import{isHarness as R}from"@weavecode/core";import h from"node:fs";import d from"node:path";import{SseHub as E}from"./sse-hub.js";import{importPromptImagesOnce as H,needsImageImport as N}from"./prompt-images.js";import{sendJson as u}from"./http.js";import{FingerprintCache as j}from"../install/fingerprint.js";import{ApiLogger as k}from"./api-log.js";import{handleHooksRoutes as P}from"./hooks-routes.js";import{handleMcpRequest as x}from"./mcp-orchestration.js";import{handleToolkitRoutes as I}from"./toolkit-routes.js";import{handleCaptureRoutes as W}from"./capture-routes.js";import{handleConfigRoutes as T}from"./config-routes.js";import{handleMarketRoutes as A}from"./routes/market.js";import{handleProjectRoutes as O}from"./routes/projects.js";import{handleSettingsRoutes as M}from"./routes/settings-statusline.js";import{handleSearchRoutes as C}from"./routes/search.js";import{handleProjectFileRoutes as B}from"./routes/project-files.js";import{DAEMON_HOST as J}from"./port.js";import{handleAuthRoutes as L}from"./auth-routes.js";import{handleAiRoutes as $}from"./ai-routes.js";export const DAEMON_VERSION=S;export function weaveRequestHandler(t){const n=t.fingerprintCache??new j,e=t.apiLog??new k,r=t.sseHub??new E(t),i={...t,fingerprintCache:n,apiLog:e,sseHub:r};return(s,o)=>{e.begin(s,o),D(s,o,i)}}export function createWeaveServer(t){return y.createServer(weaveRequestHandler(t))}async function D(t,n,e){const r=new URL(t.url??"/",`http://${J}`);let i=r.pathname;if(i.startsWith("/api/")?i=i.slice(4):i==="/api"&&(i="/"),i==="/health"&&t.method==="GET"){u(n,200,{service:"weave-daemon",version:DAEMON_VERSION,pid:process.pid,port:e.port,uptimeMs:Math.round(process.uptime()*1e3)});return}if(await L(t,n,e,i)||await $(t,n,e,i))return;if(e.auth&&!G(t,i,e)&&!e.auth.isAuthenticated(t.headers)){u(n,401,{error:"Unauthorized"});return}if(i==="/mcp"){await x(t,n,{port:e.port,token:e.auth?.getLocalToken()??null});return}if(i==="/api-logs"&&t.method==="GET"){if(!e.apiLog){u(n,503,{error:"API log unavailable"});return}const o=r.searchParams.get("status"),c=r.searchParams.get("limit"),a=await e.apiLog.query({from:r.searchParams.get("from")??void 0,to:r.searchParams.get("to")??void 0,path:r.searchParams.get("path")??void 0,method:r.searchParams.get("method")??void 0,status:o==null?void 0:Number(o),limit:c==null?void 0:Number(c)});u(n,200,a);return}if(await P(t,n,e,i,r)||await I(t,n,e,i,r)||await W(t,n,e,i)||await T(t,n,e,i,r))return;const s=i.match(/^\/projects\/(\d+)\/hooks$/);if(s&&t.method==="GET"){if(!e.hookEvents){u(n,503,{error:"Hook ingestion unavailable"});return}const o=Number(s[1]),c=Q(r.searchParams.get("limit")),a=r.searchParams.get("sessionId"),p=r.searchParams.get("beforeId"),m=p?Number(p):void 0,v=(r.searchParams.get("types")??"").split(",").map(f=>f.trim()).filter(Boolean);if(a){const f=e.hookEvents.listBySession(a,c??300,m,v);let b=e.uploads?.imagesBySession(a);if(N(f,b)){const l=e.projects.getMeta(o);await H({hookEvents:e.hookEvents,uploads:e.uploads,sessionProbe:e.sessionProbe,uploadDir:l?.storage?.images??null},a,K(f))&&(b=e.uploads?.imagesBySession(a))}u(n,200,{events:f.map(l=>{const w=b?.get(l.id);return w?.length?{...l,images:w.map(g=>({id:g.id,name:g.name,mediaType:g.mediaType,size:g.size}))}:l})});return}u(n,200,{events:e.hookEvents.listByProject(o,c)});return}if(!await A(t,n,e,i,r)&&!await M(t,n,e,i,r)&&!await C(t,n,e,i,r)&&!await B(t,n,e,i,r)){if(i==="/events"&&t.method==="GET"){z(t,n,e,r);return}if(!await O(t,n,e,i)){if(t.method==="GET"&&e.staticDir){V(n,i,e.staticDir);return}u(n,404,{error:"Not found"})}}}const F=25e3;function z(t,n,e,r){const i=e.sseHub;if(!i||!e.watch&&!e.hookBus&&!e.dataBus){n.statusCode=503,n.setHeader("content-type","application/json"),n.end(JSON.stringify({error:"Event stream unavailable"}));return}const s=t.headers["last-event-id"],o=(Array.isArray(s)?s[0]:s)??r.searchParams.get("since")??null,c=i.replay(o);n.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),n.write(`: connected
1
+ import y from"node:http";import{WEAVE_VERSION as S}from"../version.js";import{isHarness as R}from"@weavecode/core";import d from"node:fs";import h from"node:path";import{SseHub as E}from"./sse-hub.js";import{importPromptImagesOnce as H,needsImageImport as N}from"./prompt-images.js";import{sendJson as m}from"./http.js";import{FingerprintCache as P}from"../install/fingerprint.js";import{ApiLogger as j}from"./api-log.js";import{handleHooksRoutes as k}from"./hooks-routes.js";import{handleMcpRequest as x}from"./mcp-orchestration.js";import{handleToolkitRoutes as W}from"./toolkit-routes.js";import{handleCaptureRoutes as I}from"./capture-routes.js";import{handleConfigRoutes as O}from"./config-routes.js";import{handleMarketRoutes as T}from"./routes/market.js";import{handleInstallationRoutes as A}from"./routes/installations.js";import{handleProjectRoutes as M}from"./routes/projects.js";import{handleSettingsRoutes as C}from"./routes/settings-statusline.js";import{handleSearchRoutes as D}from"./routes/search.js";import{handleProjectFileRoutes as J}from"./routes/project-files.js";import{DAEMON_HOST as $}from"./port.js";import{handleAuthRoutes as B}from"./auth-routes.js";import{handleAiRoutes as F}from"./ai-routes.js";export const DAEMON_VERSION=S;export function weaveRequestHandler(e){const a=e.fingerprintCache??new P,t=e.apiLog??new j,r=e.sseHub??new E(e),o={...e,fingerprintCache:a,apiLog:t,sseHub:r};return(n,i)=>{t.begin(n,i),L(n,i,o)}}export function createWeaveServer(e){return y.createServer(weaveRequestHandler(e))}async function L(e,a,t){const r=new URL(e.url??"/",`http://${$}`);let o=r.pathname;if(o.startsWith("/api/")?o=o.slice(4):o==="/api"&&(o="/"),o==="/health"&&e.method==="GET"){m(a,200,{service:"weave-daemon",version:DAEMON_VERSION,pid:process.pid,port:t.port,uptimeMs:Math.round(process.uptime()*1e3)});return}if(await B(e,a,t,o)||await F(e,a,t,o))return;if(t.auth&&!q(e,o,t)&&!t.auth.isAuthenticated(e.headers)){m(a,401,{error:"Unauthorized"});return}if(o==="/mcp"){await x(e,a,{port:t.port,token:t.auth?.getLocalToken()??null});return}if(o==="/api-logs"&&e.method==="GET"){if(!t.apiLog){m(a,503,{error:"API log unavailable"});return}const i=r.searchParams.get("status"),c=r.searchParams.get("limit"),s=await t.apiLog.query({from:r.searchParams.get("from")??void 0,to:r.searchParams.get("to")??void 0,path:r.searchParams.get("path")??void 0,method:r.searchParams.get("method")??void 0,status:i==null?void 0:Number(i),limit:c==null?void 0:Number(c)});m(a,200,s);return}if(await k(e,a,t,o,r)||await W(e,a,t,o,r)||await I(e,a,t,o)||await O(e,a,t,o,r))return;const n=o.match(/^\/projects\/(\d+)\/hooks$/);if(n&&e.method==="GET"){if(!t.hookEvents){m(a,503,{error:"Hook ingestion unavailable"});return}const i=Number(n[1]),c=Q(r.searchParams.get("limit")),s=r.searchParams.get("sessionId"),f=r.searchParams.get("beforeId"),u=f?Number(f):void 0,b=(r.searchParams.get("types")??"").split(",").map(p=>p.trim()).filter(Boolean);if(s){const p=t.hookEvents.listBySession(s,c??300,u,b);let v=t.uploads?.imagesBySession(s);if(N(p,v)){const l=t.projects.getMeta(i);await H({hookEvents:t.hookEvents,uploads:t.uploads,sessionProbe:t.sessionProbe,uploadDir:l?.storage?.images??null},s,K(p))&&(v=t.uploads?.imagesBySession(s))}m(a,200,{events:p.map(l=>{const w=v?.get(l.id);return w?.length?{...l,images:w.map(g=>({id:g.id,name:g.name,mediaType:g.mediaType,size:g.size}))}:l})});return}m(a,200,{events:t.hookEvents.listByProject(i,c)});return}if(!await T(e,a,t,o,r)&&!await A(e,a,t,o)&&!await C(e,a,t,o,r)&&!await D(e,a,t,o,r)&&!await J(e,a,t,o,r)){if(o==="/events"&&e.method==="GET"){G(e,a,t,r);return}if(!await M(e,a,t,o)){if(e.method==="GET"&&t.staticDir){_(a,o,t.staticDir);return}m(a,404,{error:"Not found"})}}}const z=25e3;function G(e,a,t,r){const o=t.sseHub;if(!o||!t.watch&&!t.hookBus&&!t.dataBus){a.statusCode=503,a.setHeader("content-type","application/json"),a.end(JSON.stringify({error:"Event stream unavailable"}));return}const n=e.headers["last-event-id"],i=(Array.isArray(n)?n[0]:n)??r.searchParams.get("since")??null,c=o.replay(i);a.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),a.write(`: connected
2
2
 
3
- `);const a=setInterval(()=>{n.writableEnded||n.write(`data: ${JSON.stringify({type:"ping"})}
3
+ `);const s=setInterval(()=>{a.writableEnded||a.write(`data: ${JSON.stringify({type:"ping"})}
4
4
 
5
- `)},F);a.unref?.(),c.gap&&n.write(`data: ${JSON.stringify({type:"resync"})}
5
+ `)},z);s.unref?.(),c.gap&&a.write(`data: ${JSON.stringify({type:"resync"})}
6
6
 
7
- `);for(const m of c.frames)n.write(`id: ${m.id}
8
- data: ${m.data}
7
+ `);for(const u of c.frames)a.write(`id: ${u.id}
8
+ data: ${u.data}
9
9
 
10
- `);const p=i.subscribe(m=>{n.write(`id: ${m.id}
11
- data: ${m.data}
10
+ `);const f=o.subscribe(u=>{a.write(`id: ${u.id}
11
+ data: ${u.data}
12
12
 
13
- `)});e.inflightRefresher?.refreshNow(),e.terminalRefresher?.onSubscriberJoin(),e.updatesRefresher?.onSubscriberJoin(),t.on("close",()=>{clearInterval(a),p()})}function G(t,n,e){if(n==="/health"||n.startsWith("/webhooks/orchestrate/"))return!0;if(t.method!=="GET")return!1;if((t.headers.accept??"").includes("text/html"))return!0;if(!e.staticDir)return!1;const r=d.normalize(n).replace(/^([/\\]\.\.[/\\])+/,""),i=d.join(e.staticDir,r);return i.startsWith(e.staticDir)&&h.existsSync(i)&&h.statSync(i).isFile()}function _(t,n){t.setHeader("cache-control",n.startsWith("/assets/")?"public, max-age=31536000, immutable":"no-cache")}function V(t,n,e){const r=d.normalize(n).replace(/^([/\\]\.\.[/\\])+/,""),i=d.join(e,r);if(!i.startsWith(e)){t.statusCode=403,t.setHeader("content-type","application/json"),t.end(JSON.stringify({error:"Forbidden"}));return}h.stat(i,(s,o)=>{if(!s&&o.isFile()){t.setHeader("content-type",U(i)),_(t,n),t.setHeader("content-length",String(o.size)),h.createReadStream(i).pipe(t);return}h.readFile(d.join(e,"index.html"),(c,a)=>{if(c){t.statusCode=404,t.setHeader("content-type","application/json"),t.end(JSON.stringify({error:"Not found"}));return}t.setHeader("content-type","text/html"),t.setHeader("cache-control","no-cache"),t.end(a)})})}function U(t){return t.endsWith(".js")?"text/javascript":t.endsWith(".css")?"text/css":t.endsWith(".html")?"text/html":t.endsWith(".svg")?"image/svg+xml":t.endsWith(".png")?"image/png":t.endsWith(".json")?"application/json":t.endsWith(".webmanifest")?"application/manifest+json":"application/octet-stream"}function K(t){for(let n=t.length-1;n>=0;n--){const e=t[n].source;if(R(e))return e}return null}function Q(t){const n=Number(t??"100");return!Number.isFinite(n)||n<=0?100:Math.min(Math.floor(n),500)}
13
+ `)});t.inflightRefresher?.refreshNow(),t.terminalRefresher?.onSubscriberJoin(),t.updatesRefresher?.onSubscriberJoin(),e.on("close",()=>{clearInterval(s),f()})}function q(e,a,t){if(a==="/health"||a.startsWith("/webhooks/orchestrate/"))return!0;if(e.method!=="GET")return!1;if((e.headers.accept??"").includes("text/html"))return!0;if(!t.staticDir)return!1;const r=h.normalize(a).replace(/^([/\\]\.\.[/\\])+/,""),o=h.join(t.staticDir,r);return o.startsWith(t.staticDir)&&d.existsSync(o)&&d.statSync(o).isFile()}function V(e,a){e.setHeader("cache-control",a.startsWith("/assets/")?"public, max-age=31536000, immutable":"no-cache")}function _(e,a,t){const r=h.normalize(a).replace(/^([/\\]\.\.[/\\])+/,""),o=h.join(t,r);if(!o.startsWith(t)){e.statusCode=403,e.setHeader("content-type","application/json"),e.end(JSON.stringify({error:"Forbidden"}));return}d.stat(o,(n,i)=>{if(!n&&i.isFile()){e.setHeader("content-type",U(o)),V(e,a),e.setHeader("content-length",String(i.size)),d.createReadStream(o).pipe(e);return}d.readFile(h.join(t,"index.html"),(c,s)=>{if(c){e.statusCode=404,e.setHeader("content-type","application/json"),e.end(JSON.stringify({error:"Not found"}));return}e.setHeader("content-type","text/html"),e.setHeader("cache-control","no-cache"),e.end(s)})})}function U(e){return e.endsWith(".js")?"text/javascript":e.endsWith(".css")?"text/css":e.endsWith(".html")?"text/html":e.endsWith(".svg")?"image/svg+xml":e.endsWith(".png")?"image/png":e.endsWith(".json")?"application/json":e.endsWith(".webmanifest")?"application/manifest+json":"application/octet-stream"}function K(e){for(let a=e.length-1;a>=0;a--){const t=e[a].source;if(R(t))return t}return null}function Q(e){const a=Number(e??"100");return!Number.isFinite(a)||a<=0?100:Math.min(Math.floor(a),500)}
@@ -1 +1 @@
1
- import{stat as g}from"node:fs/promises";import{isHarness as w}from"@weavecode/core";import{readDaemonSettings as S}from"./settings.js";import{defaultProjectOpener as T,terminalBackendFor as y}from"./opener.js";import{combinedLivenessOf as E}from"./liveness.js";import{messagingSurfaceFor as O}from"../surfaces.js";const h=8e3,P=11e3,b=14e3;export function transcriptState(e,r){return e!==!1?e:r===!0?!1:null}function k(e,r,s,t){!t||O(r).paneEnvSource!=="launch"||e.messageDeliverer?.notePaneEnv(s,t.env)}export function scheduleBootstrapInjection(e,r,s){const t=e.terminal;t&&(async()=>{await new Promise(a=>setTimeout(a,h));const o=await t.locatePane?.(r.env).catch(()=>null)??null;if(!o)return;const n=async()=>{try{await t.sendText(o,s)}catch{return}};await n(),setTimeout(()=>{t.sendKeys(o,"\r").catch(()=>{})},P-h),setTimeout(()=>{n()},b-h)})()}export async function openSessionTerminal(e,r,s){if(!e.hookSessions)return{ok:!1,status:503,error:"Hooks subsystem unavailable"};const t=e.hookSessions.getBySessionId(r);if(!t)return{ok:!1,status:404,error:"Session not found"};if(!e.hookEvents)return{ok:!1,status:503,error:"Hook ingestion unavailable"};const o=e.hookEvents.listBySession(r,1),n=o[o.length-1]?.source;if(!w(n))return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};const a=e.harnesses?.get(n)?.resume;if(!a?.supported||!a.openArgs)return{ok:!1,status:501,error:`Harness "${n}" does not support interactive resume`};if(!t.projectId)return{ok:!1,status:400,error:"Session is not bound to a project"};const i=e.projects?.getById(t.projectId);if(!i)return{ok:!1,status:404,error:"Project not found"};const p=e.sessionProbe?.transcriptPresent(r)??null;if(transcriptState(p,e.hookSessions.hasRunOf(r))===!1)return{ok:!1,status:409,error:"Session transcript is missing \u2014 nothing to resume"};const c=e.opener??T;try{if(!(await g(i.path)).isDirectory())throw new Error(`Not a directory: ${i.path}`);const u=await S(),m=[a.bin,...a.launchArgs??[],...a.openArgs(r)];if(s){if(!y(u.terminal).enumerable)throw new Error(`Terminal preset "${u.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const l=c.runInTerminalAt;if(!l)throw new Error("Targeted attach is unavailable");const v=await l(i.path,m,s,u.terminal);k(e,n,r,v)}else{const l=await c.runInTerminal(i.path,m,u.terminal);k(e,n,r,l)}return setTimeout(()=>{e.terminalRefresher?.refreshNow()},600),{ok:!0,sessionId:r,command:m.join(" "),cwd:i.path,...s?{target:s}:{}}}catch(f){return{ok:!1,status:400,error:f instanceof Error?f.message:"Open failed"}}}export function createEnsureOpen(e){const r=new Map,s=async t=>{if(!e.hookEvents)return{ok:!1,error:"Hook ingestion unavailable"};const o=e.hookEvents.listBySession(t,1).at(-1)?.id??0,n=await openSessionTerminal(e,t);if(!n.ok)return{ok:!1,error:n.error};let a=!1;for(let i=0;i<60;i++){if(e.hookEvents.listBySession(t,20).some(c=>c.id>o&&c.eventType==="SessionStart"))return{ok:!0,ack:"session-start"};(e.livenessOf?.()??E()).get(t)===!0&&(a=!0),await new Promise(c=>setTimeout(c,250))}return a?{ok:!0,ack:"registry"}:{ok:!1,error:"session did not report ready within 15s"}};return t=>{const o=r.get(t);if(o)return o;const n=s(t).finally(()=>r.delete(t));return r.set(t,n),n}}
1
+ import{stat as d}from"node:fs/promises";import{isHarness as w}from"@weavecode/core";import{readDaemonSettings as g}from"./settings.js";import{defaultProjectOpener as v,terminalBackendFor as y}from"./opener.js";import{combinedLivenessOf as S}from"./liveness.js";import{messagingSurfaceFor as T}from"../surfaces.js";const p=8e3,E=11e3,b=14e3;export function transcriptState(e,r){return e!==!1?e:r===!0?!1:null}function h(e,r,s,t){!t||T(r).paneEnvSource!=="launch"||e.messageDeliverer?.notePaneEnv(s,t.env)}export function scheduleBootstrapInjection(e,r,s){const t=e.terminal;t&&(async()=>{await new Promise(a=>setTimeout(a,p));const o=await t.locatePane?.(r.env).catch(()=>null)??null;if(!o)return;const n=async()=>{try{await t.sendText(o,s)}catch{return}};await n(),setTimeout(()=>{t.sendKeys(o,"\r").catch(()=>{})},E-p),setTimeout(()=>{n()},b-p)})()}export async function openSessionTerminal(e,r,s){if(!e.hookSessions)return{ok:!1,status:503,error:"Hooks subsystem unavailable"};const t=e.hookSessions.getBySessionId(r);if(!t)return{ok:!1,status:404,error:"Session not found"};if(!e.hookEvents)return{ok:!1,status:503,error:"Hook ingestion unavailable"};const o=e.hookEvents.listBySession(r,1),n=o[o.length-1]?.source;if(!w(n))return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};const a=e.harnesses?.get(n)?.resume;if(!a?.supported||!a.openArgs)return{ok:!1,status:501,error:`Harness "${n}" does not support interactive resume`};if(!t.projectId)return{ok:!1,status:400,error:"Session is not bound to a project"};const i=e.projects?.getById(t.projectId);if(!i)return{ok:!1,status:404,error:"Project not found"};const c=e.sessionProbe?.transcriptPresent(r)??null;if(transcriptState(c,e.hookSessions.hasRunOf(r))===!1)return{ok:!1,status:409,error:"Session transcript is missing \u2014 nothing to resume"};const f=e.opener??v;try{if(!(await d(i.path)).isDirectory())throw new Error(`Not a directory: ${i.path}`);const u=await g(),m=[a.bin,...a.launchArgs??[],...a.openArgs(r)];if(s){if(!y(u.terminal).enumerable)throw new Error(`Terminal preset "${u.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const l=f.runInTerminalAt;if(!l)throw new Error("Targeted attach is unavailable");const k=await l(i.path,m,s,u.terminal);h(e,n,r,k)}else{const l=await f.runInTerminal(i.path,m,u.terminal);h(e,n,r,l)}return setTimeout(()=>{e.terminalRefresher?.refreshNow()},600),{ok:!0,sessionId:r,command:m.join(" "),cwd:i.path,...s?{target:s}:{}}}catch(u){return{ok:!1,status:400,error:u instanceof Error?u.message:"Open failed"}}}export function createEnsureOpen(e){const r=new Map,s=async t=>{if(!e.hookEvents)return{ok:!1,error:"Hook ingestion unavailable"};const o=e.hookEvents.listBySession(t,1).at(-1)?.id??0,n=await openSessionTerminal(e,t);if(!n.ok)return{ok:!1,error:n.error};let a=!1;for(let i=0;i<60;i++){if(e.hookEvents.listBySession(t,20).some(c=>c.id>o&&c.eventType==="SessionStart"))return{ok:!0,ack:"session-start"};(e.livenessOf?.()??S()).get(t)===!0&&(a=!0),await new Promise(c=>setTimeout(c,250))}return a?{ok:!0,ack:"registry"}:{ok:!1,error:"session did not report ready within 15s"}};return t=>{const o=r.get(t);if(o)return o;const n=s(t).finally(()=>r.delete(t));return r.set(t,n),n}}
@@ -1 +1 @@
1
- import{closeSync as u,openSync as f,readSync as i,statSync as c}from"node:fs";import{bareModelName as a,codexInterruptMarkerAt as d,currentContextTokensAt as p,currentEffortAt as m,currentModelAt as k,currentModeAt as w,interruptMarkerAt as M,switchedModelOf as O}from"@weavecode/harness";import{HARNESS_SESSION_CONTROL as S,isHarness as x}from"@weavecode/core";const b=64*1024,y={model:null,mode:null,effort:null,contextTokens:null};export function readTail(o,t=b){try{const e=c(o).size,r=Math.max(0,e-t),n=f(o,"r");try{const l=Buffer.alloc(e-r);return i(n,l,0,l.length,r),l.toString("utf8")}finally{u(n)}}catch{return null}}export function dbTranscriptPathResolver(o){return t=>{try{const e=JSON.parse(o.listBySession(t,1)[0]?.payload??"");return typeof e.transcriptPath=="string"&&e.transcriptPath?e.transcriptPath:null}catch{return null}}}export function dbModelFactResolver(o,t){return e=>{const r=t(e),n=r&&x(r)?S[r].modelFactEvents:[];if(n.length===0)return null;const l=o.listBySession(e,1,void 0,n),s=l[l.length-1];if(!s)return null;try{const h=JSON.parse(s.payload).raw;return O(s.eventType,h)}catch{return null}}}function T(o){const t=M(o),e=d(o);return t===null?e:e===null?t:Math.max(t,e)}export class SessionProbe{fallbackPath;fallbackSwitch;constructor(t,e){this.fallbackPath=t,this.fallbackSwitch=e}paths=new Map;marks=new Map;known=new Map;switched=new Map;probed=new Set;efforts=new Map;modes=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}transcriptPathOf(t){return this.pathOf(t)}forget(t){this.paths.delete(t),this.known.delete(t),this.switched.delete(t),this.probed.delete(t),this.efforts.delete(t),this.modes.delete(t)}noteEffort(t,e){this.efforts.set(t,e)}currentEffort(t){return this.efforts.get(t)??this.latched(t).effort}currentContextTokens(t){return this.latched(t).contextTokens}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),this.probed.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}noteMode(t,e){this.modes.set(t,e)}currentMode(t){return this.modes.get(t)??this.latched(t).mode}latched(t){const e=this.pathOf(t),r=e?this.factsOf(e):y,n=this.known.get(t),l={model:this.switchedModel(t,r.model)??n?.model??null,mode:r.mode??n?.mode??null,effort:r.effort??n?.effort??null,contextTokens:r.contextTokens??n?.contextTokens??null};return(!n||n.model!==l.model||n.mode!==l.mode||n.effort!==l.effort||n.contextTokens!==l.contextTokens)&&this.known.set(t,l),l}switchedModel(t,e){const r=this.switchOf(t,e);return r&&e===r.stale?r.model:e}switchOf(t,e){const r=this.switched.get(t);if(r||!e||this.probed.has(t))return r;this.probed.add(t);const n=this.fallbackSwitch?.(t);if(!n||n.from===null||a(n.from)!==a(e))return;const l={stale:e,model:n.to};return this.switched.set(t,l),l}factsOf(t){let e;try{e=c(t).size}catch{return{size:-1,markerAt:null,model:null,mode:null,effort:null,contextTokens: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:T(n),model:n===null?null:k(n),mode:n===null?null:w(n),effort:n===null?null:m(n),contextTokens:n===null?null:p(n)};return this.marks.set(t,l),l}}
1
+ import{closeSync as h,openSync as u,readSync as f,statSync as a}from"node:fs";import{bareModelName as i,codexInterruptMarkerAt as d,currentContextTokensAt as p,currentEffortAt as m,currentModelAt as k,currentModeAt as w,interruptMarkerAt as M,switchedModelOf as O}from"@weavecode/harness";import{HARNESS_SESSION_CONTROL as S,isHarness as x}from"@weavecode/core";const b=64*1024,y={model:null,mode:null,effort:null,contextTokens:null};export function readTail(o,t=b){try{const e=a(o).size,s=Math.max(0,e-t),n=u(o,"r");try{const r=Buffer.alloc(e-s);return f(n,r,0,r.length,s),r.toString("utf8")}finally{h(n)}}catch{return null}}export function dbTranscriptPathResolver(o){return t=>{try{const e=JSON.parse(o.listBySession(t,1)[0]?.payload??"");return typeof e.transcriptPath=="string"&&e.transcriptPath?e.transcriptPath:null}catch{return null}}}export function dbModelFactResolver(o,t){return e=>{const s=t(e),n=s&&x(s)?S[s].modelFactEvents:[];if(n.length===0)return null;const r=o.listBySession(e,1,void 0,n),l=r[r.length-1];if(!l)return null;try{const c=JSON.parse(l.payload).raw;return O(l.eventType,c)}catch{return null}}}function T(o){const t=M(o),e=d(o);return t===null?e:e===null?t:Math.max(t,e)}export class SessionProbe{fallbackPath;fallbackSwitch;constructor(t,e){this.fallbackPath=t,this.fallbackSwitch=e}paths=new Map;marks=new Map;known=new Map;switched=new Map;probed=new Set;efforts=new Map;modes=new Map;noteTranscript(t,e){e&&this.paths.set(t,e)}pathOf(t){const e=this.paths.get(t);if(e)return e;const s=this.fallbackPath?.(t)??null;return s&&this.paths.set(t,s),s}transcriptPathOf(t){return this.pathOf(t)}forget(t){this.paths.delete(t),this.known.delete(t),this.switched.delete(t),this.probed.delete(t),this.efforts.delete(t),this.modes.delete(t)}noteEffort(t,e){this.efforts.set(t,e)}currentEffort(t){return this.efforts.get(t)??this.latched(t).effort}currentContextTokens(t){return this.latched(t).contextTokens}noteModel(t,e){const s=this.pathOf(t);this.switched.set(t,{stale:s?this.factsOf(s).model:null,model:e})}sessionStarted(t,e){this.known.delete(t),this.switched.delete(t),this.probed.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 s=this.pathOf(t);if(!s)return null;const n=this.factsOf(s).markerAt;if(n===null)return null;const r=Date.parse(e);return Number.isFinite(r)&&n>r?n:null}currentModel(t){return this.latched(t).model}noteMode(t,e){this.modes.set(t,e)}currentMode(t){return this.modes.get(t)??this.latched(t).mode}latched(t){const e=this.pathOf(t),s=e?this.factsOf(e):y,n=this.known.get(t),r={model:this.switchedModel(t,s.model)??n?.model??null,mode:s.mode??n?.mode??null,effort:s.effort??n?.effort??null,contextTokens:s.contextTokens??n?.contextTokens??null};return(!n||n.model!==r.model||n.mode!==r.mode||n.effort!==r.effort||n.contextTokens!==r.contextTokens)&&this.known.set(t,r),r}switchedModel(t,e){const s=this.switchOf(t,e);return s&&e===s.stale?s.model:e}switchOf(t,e){const s=this.switched.get(t);if(s||!e||this.probed.has(t))return s;this.probed.add(t);const n=this.fallbackSwitch?.(t);if(!n||n.from===null||i(n.from)!==i(e))return;const r={stale:e,model:n.to};return this.switched.set(t,r),r}factsOf(t){let e;try{e=a(t).size}catch{return{size:-1,markerAt:null,model:null,mode:null,effort:null,contextTokens:null}}const s=this.marks.get(t);if(s&&s.size===e)return s;const n=readTail(t),r={size:e,markerAt:n===null?null:T(n),model:n===null?null:k(n),mode:n===null?null:w(n),effort:n===null?null:m(n),contextTokens:n===null?null:p(n)};return this.marks.set(t,r),r}}
@@ -1,2 +1,2 @@
1
- import{openDatabase as D}from"../db/db.js";import{getDbPath as L}from"../db/paths.js";import{DEFAULT_BIND_HOST as h}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:h,tlsPort:6443},DEFAULT_AI_SETTINGS={baseUrl:"",model:""},DEFAULT_DECISION_SETTINGS={baseUrl:"",model:""},DEFAULT_HTML_EXPORT_SETTINGS={activeId:null,profiles:[]},DEFAULT_PET_SETTINGS={enabled:!1,petId:"weave-spider",notifications:!0,size:"small"},PET_SIZE_PRESETS={small:{width:160,height:192},medium:{width:200,height:240},large:{width:280,height:336}},DEFAULT_DAEMON_SETTINGS={terminal:DEFAULT_TERMINAL_SETTINGS,locale:DEFAULT_LOCALE,hooks:DEFAULT_HOOKS_SETTINGS,decision:DEFAULT_DECISION_SETTINGS,events:DEFAULT_EVENTS_SETTINGS,sessions:DEFAULT_SESSIONS_SETTINGS,startup:DEFAULT_STARTUP_SETTINGS,server:DEFAULT_SERVER_SETTINGS,ai:DEFAULT_AI_SETTINGS,htmlExport:DEFAULT_HTML_EXPORT_SETTINGS,pet:DEFAULT_PET_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 I={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:I[n]}))}function v(e){return Number.isInteger(e)&&e>=0&&e<=65535?e:DEFAULT_SERVER_SETTINGS.tlsPort}const _=50,x=2e5;function U(e){const t=e??{},n=new Set,r=[];for(const l of Array.isArray(t.profiles)?t.profiles:[]){const s=l??{};if(!(typeof s.id!="string"||s.id===""||n.has(s.id))&&!(typeof s.name!="string"||typeof s.head!="string")&&(n.add(s.id),r.push({id:s.id,name:s.name.trim()||`profile-${r.length+1}`,head:s.head.slice(0,x)}),r.length>=_))break}return{activeId:typeof t.activeId=="string"&&n.has(t.activeId)?t.activeId:null,profiles:r}}function N(e){const t=e??{};return{enabled:typeof t.enabled=="boolean"?t.enabled:DEFAULT_PET_SETTINGS.enabled,petId:typeof t.petId=="string"&&/^[a-z0-9][a-z0-9-]{0,63}$/i.test(t.petId)?t.petId:DEFAULT_PET_SETTINGS.petId,notifications:typeof t.notifications=="boolean"?t.notifications:DEFAULT_PET_SETTINGS.notifications,size:t.size==="small"||t.size==="medium"||t.size==="large"?t.size:DEFAULT_PET_SETTINGS.size,pos:t.pos&&typeof t.pos=="object"&&typeof t.pos.x=="number"&&typeof t.pos.y=="number"?{x:t.pos.x,y:t.pos.y}:void 0}}function T(e){const t=e??{},n=t.terminal??{},r=t.hooks??{},i=t.events??{},l=t.sessions??{},s=t.startup??{},c=t.server??{},d=t.ai??{},u=t.decision??{},f=U(t.htmlExport),b=N(t.pet),S=Number.isInteger(i.retentionDays)&&i.retentionDays>=1?i.retentionDays:DEFAULT_EVENTS_SETTINGS.retentionDays,g=Number.isInteger(l.idleDays)&&l.idleDays>=1?l.idleDays:DEFAULT_SESSIONS_SETTINGS.idleDays;return{terminal:{preset:ALL_TERMINAL_PRESETS.includes(n.preset)?n.preset:DEFAULT_TERMINAL_SETTINGS.preset,customCommand:typeof n.customCommand=="string"?n.customCommand:""},locale:resolveLocale(t.locale),hooks:{enabled:typeof r.enabled=="boolean"?r.enabled:DEFAULT_HOOKS_SETTINGS.enabled},events:{retentionDays:S},sessions:{idleDays:g},startup:{launchOnLogin:typeof s.launchOnLogin=="boolean"?s.launchOnLogin:DEFAULT_STARTUP_SETTINGS.launchOnLogin},server:{bindHost:typeof c.bindHost=="string"&&c.bindHost.trim()!==""?c.bindHost.trim():DEFAULT_SERVER_SETTINGS.bindHost,tlsPort:v(c.tlsPort)},ai:{baseUrl:typeof d.baseUrl=="string"?d.baseUrl.trim():"",model:typeof d.model=="string"?d.model.trim():""},decision:{baseUrl:typeof u.baseUrl=="string"?u.baseUrl.trim():"",model:typeof u.model=="string"?u.model.trim():""},htmlExport:f,pet:b}}const o={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",decisionBaseUrl:"decision.baseUrl",decisionModel:"decision.model",htmlExport:"htmlExport",pet:"pet.config"};let a=null,m=null;export function setDaemonSettingsDb(e){a=e,m=null}function y(e){if(a)return e(a);const t=D(L());try{return e(t)}finally{t.close()}}function O(e){const t=e.prepare("SELECT key, value FROM settings").all();return new Map(t.map(n=>[n.key,n.value]))}function A(e){return T({terminal:{preset:e.get(o.terminalPreset),customCommand:e.get(o.terminalCustomCommand)},locale:e.get(o.locale),...e.has(o.hooksEnabled)?{hooks:{enabled:e.get(o.hooksEnabled)==="true"}}:{},...e.has(o.eventRetentionDays)?{events:{retentionDays:Number(e.get(o.eventRetentionDays))}}:{},...e.has(o.sessionIdleDays)?{sessions:{idleDays:Number(e.get(o.sessionIdleDays))}}:{},...e.has(o.startupLaunchOnLogin)?{startup:{launchOnLogin:e.get(o.startupLaunchOnLogin)==="true"}}:{},...e.has(o.serverBindHost)||e.has(o.serverTlsPort)?{server:{...e.has(o.serverBindHost)?{bindHost:e.get(o.serverBindHost)}:{},...e.has(o.serverTlsPort)?{tlsPort:Number(e.get(o.serverTlsPort))}:{}}}:{},...e.has(o.aiBaseUrl)||e.has(o.aiModel)?{ai:{baseUrl:e.get(o.aiBaseUrl)??"",model:e.get(o.aiModel)??""}}:{},...e.has(o.decisionBaseUrl)||e.has(o.decisionModel)?{decision:{baseUrl:e.get(o.decisionBaseUrl)??"",model:e.get(o.decisionModel)??""}}:{},...p(e.get(o.htmlExport))!=null?{htmlExport:p(e.get(o.htmlExport))}:{},...p(e.get(o.pet))!=null?{pet:p(e.get(o.pet))}:{}})}function p(e){if(!e)return null;try{const t=JSON.parse(e);return t!=null&&typeof t=="object"?t:null}catch{return null}}function P(e){return[[o.terminalPreset,e.terminal.preset],[o.terminalCustomCommand,e.terminal.customCommand],[o.locale,e.locale],[o.hooksEnabled,String(e.hooks.enabled)],[o.eventRetentionDays,String(e.events?.retentionDays??DEFAULT_EVENT_RETENTION_DAYS)],[o.sessionIdleDays,String(e.sessions?.idleDays??DEFAULT_SESSION_IDLE_DAYS)],[o.startupLaunchOnLogin,String(e.startup?.launchOnLogin??!1)],[o.serverBindHost,e.server?.bindHost??h],[o.serverTlsPort,String(e.server?.tlsPort??DEFAULT_SERVER_SETTINGS.tlsPort)],[o.aiBaseUrl,e.ai?.baseUrl??""],[o.aiModel,e.ai?.model??""],[o.decisionBaseUrl,e.decision?.baseUrl??""],[o.decisionModel,e.decision?.model??""],[o.htmlExport,JSON.stringify(e.htmlExport??DEFAULT_HTML_EXPORT_SETTINGS)],[o.pet,JSON.stringify(e.pet??DEFAULT_PET_SETTINGS)]]}function C(e,t){const n=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,i]of t)n.run(r,i);e.exec("COMMIT")}catch(r){throw e.exec("ROLLBACK"),r}}function E(){try{return y(e=>A(O(e)))}catch{return DEFAULT_DAEMON_SETTINGS}}export async function readDaemonSettings(){return E()}export function readDaemonSettingsSync(){return E()}export function readHooksEnabled(){const e=m;if(e&&e.db===a)return e.value;const t=E().hooks.enabled;return m={db:a,value:t},t}export async function writeDaemonSettings(e){const t=T(e);return y(n=>C(n,P(t))),m=null,t}
1
+ import{openDatabase as D}from"../db/db.js";import{getDbPath as L}from"../db/paths.js";import{DEFAULT_BIND_HOST as h}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:h,tlsPort:6443},DEFAULT_AI_SETTINGS={baseUrl:"",model:""},DEFAULT_DECISION_SETTINGS={baseUrl:"",model:""},DEFAULT_HTML_EXPORT_SETTINGS={activeId:null,profiles:[]},DEFAULT_PET_SETTINGS={enabled:!1,petId:"weave-spider",notifications:!0,size:"small"},PET_SIZE_PRESETS={small:{width:160,height:192},medium:{width:200,height:240},large:{width:280,height:336}},DEFAULT_DAEMON_SETTINGS={terminal:DEFAULT_TERMINAL_SETTINGS,locale:DEFAULT_LOCALE,hooks:DEFAULT_HOOKS_SETTINGS,decision:DEFAULT_DECISION_SETTINGS,events:DEFAULT_EVENTS_SETTINGS,sessions:DEFAULT_SESSIONS_SETTINGS,startup:DEFAULT_STARTUP_SETTINGS,server:DEFAULT_SERVER_SETTINGS,ai:DEFAULT_AI_SETTINGS,htmlExport:DEFAULT_HTML_EXPORT_SETTINGS,pet:DEFAULT_PET_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 I={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(t=>({id:t,label:I[t]}))}function v(e){return Number.isInteger(e)&&e>=0&&e<=65535?e:DEFAULT_SERVER_SETTINGS.tlsPort}const U=50,N=2e5;function A(e){const t=e??{},o=new Set,r=[];for(const i of Array.isArray(t.profiles)?t.profiles:[]){const s=i??{};if(!(typeof s.id!="string"||s.id===""||o.has(s.id))&&!(typeof s.name!="string"||typeof s.head!="string")&&(o.add(s.id),r.push({id:s.id,name:s.name.trim()||`profile-${r.length+1}`,head:s.head.slice(0,N)}),r.length>=U))break}return{activeId:typeof t.activeId=="string"&&o.has(t.activeId)?t.activeId:null,profiles:r}}function _(e){const t=e??{};return{enabled:typeof t.enabled=="boolean"?t.enabled:DEFAULT_PET_SETTINGS.enabled,petId:typeof t.petId=="string"&&/^[a-z0-9][a-z0-9-]{0,63}$/i.test(t.petId)?t.petId:DEFAULT_PET_SETTINGS.petId,notifications:typeof t.notifications=="boolean"?t.notifications:DEFAULT_PET_SETTINGS.notifications,size:t.size==="small"||t.size==="medium"||t.size==="large"?t.size:DEFAULT_PET_SETTINGS.size,pos:t.pos&&typeof t.pos=="object"&&typeof t.pos.x=="number"&&typeof t.pos.y=="number"?{x:t.pos.x,y:t.pos.y}:void 0}}function g(e){const t=e??{},o=t.terminal??{},r=t.hooks??{},i=t.events??{},s=t.sessions??{},E=t.startup??{},l=t.server??{},d=t.ai??{},u=t.decision??{},T=A(t.htmlExport),b=_(t.pet),S=Number.isInteger(i.retentionDays)&&i.retentionDays>=1?i.retentionDays:DEFAULT_EVENTS_SETTINGS.retentionDays,f=Number.isInteger(s.idleDays)&&s.idleDays>=1?s.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(t.locale),hooks:{enabled:typeof r.enabled=="boolean"?r.enabled:DEFAULT_HOOKS_SETTINGS.enabled},events:{retentionDays:S},sessions:{idleDays:f},startup:{launchOnLogin:typeof E.launchOnLogin=="boolean"?E.launchOnLogin:DEFAULT_STARTUP_SETTINGS.launchOnLogin},server:{bindHost:typeof l.bindHost=="string"&&l.bindHost.trim()!==""?l.bindHost.trim():DEFAULT_SERVER_SETTINGS.bindHost,tlsPort:v(l.tlsPort)},ai:{baseUrl:typeof d.baseUrl=="string"?d.baseUrl.trim():"",model:typeof d.model=="string"?d.model.trim():""},decision:{baseUrl:typeof u.baseUrl=="string"?u.baseUrl.trim():"",model:typeof u.model=="string"?u.model.trim():""},htmlExport:T,pet:b}}const n={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",decisionBaseUrl:"decision.baseUrl",decisionModel:"decision.model",htmlExport:"htmlExport",pet:"pet.config"};let a=null,m=null;export function setDaemonSettingsDb(e){a=e,m=null}function y(e){if(a)return e(a);const t=D(L());try{return e(t)}finally{t.close()}}function O(e){const t=e.prepare("SELECT key, value FROM settings").all();return new Map(t.map(o=>[o.key,o.value]))}function P(e){return g({terminal:{preset:e.get(n.terminalPreset),customCommand:e.get(n.terminalCustomCommand)},locale:e.get(n.locale),...e.has(n.hooksEnabled)?{hooks:{enabled:e.get(n.hooksEnabled)==="true"}}:{},...e.has(n.eventRetentionDays)?{events:{retentionDays:Number(e.get(n.eventRetentionDays))}}:{},...e.has(n.sessionIdleDays)?{sessions:{idleDays:Number(e.get(n.sessionIdleDays))}}:{},...e.has(n.startupLaunchOnLogin)?{startup:{launchOnLogin:e.get(n.startupLaunchOnLogin)==="true"}}:{},...e.has(n.serverBindHost)||e.has(n.serverTlsPort)?{server:{...e.has(n.serverBindHost)?{bindHost:e.get(n.serverBindHost)}:{},...e.has(n.serverTlsPort)?{tlsPort:Number(e.get(n.serverTlsPort))}:{}}}:{},...e.has(n.aiBaseUrl)||e.has(n.aiModel)?{ai:{baseUrl:e.get(n.aiBaseUrl)??"",model:e.get(n.aiModel)??""}}:{},...e.has(n.decisionBaseUrl)||e.has(n.decisionModel)?{decision:{baseUrl:e.get(n.decisionBaseUrl)??"",model:e.get(n.decisionModel)??""}}:{},...c(e.get(n.htmlExport))!=null?{htmlExport:c(e.get(n.htmlExport))}:{},...c(e.get(n.pet))!=null?{pet:c(e.get(n.pet))}:{}})}function c(e){if(!e)return null;try{const t=JSON.parse(e);return t!=null&&typeof t=="object"?t:null}catch{return null}}function x(e){return[[n.terminalPreset,e.terminal.preset],[n.terminalCustomCommand,e.terminal.customCommand],[n.locale,e.locale],[n.hooksEnabled,String(e.hooks.enabled)],[n.eventRetentionDays,String(e.events?.retentionDays??DEFAULT_EVENT_RETENTION_DAYS)],[n.sessionIdleDays,String(e.sessions?.idleDays??DEFAULT_SESSION_IDLE_DAYS)],[n.startupLaunchOnLogin,String(e.startup?.launchOnLogin??!1)],[n.serverBindHost,e.server?.bindHost??h],[n.serverTlsPort,String(e.server?.tlsPort??DEFAULT_SERVER_SETTINGS.tlsPort)],[n.aiBaseUrl,e.ai?.baseUrl??""],[n.aiModel,e.ai?.model??""],[n.decisionBaseUrl,e.decision?.baseUrl??""],[n.decisionModel,e.decision?.model??""],[n.htmlExport,JSON.stringify(e.htmlExport??DEFAULT_HTML_EXPORT_SETTINGS)],[n.pet,JSON.stringify(e.pet??DEFAULT_PET_SETTINGS)]]}function C(e,t){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,i]of t)o.run(r,i);e.exec("COMMIT")}catch(r){throw e.exec("ROLLBACK"),r}}function p(){try{return y(e=>P(O(e)))}catch{return DEFAULT_DAEMON_SETTINGS}}export async function readDaemonSettings(){return p()}export function readDaemonSettingsSync(){return p()}export function readHooksEnabled(){const e=m;if(e&&e.db===a)return e.value;const t=p().hooks.enabled;return m={db:a,value:t},t}export async function writeDaemonSettings(e){const t=g(e);return y(o=>C(o,x(t))),m=null,t}
@@ -1 +1 @@
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{}}}
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(this.options.invalidateOnly?{key:this.options.key}:{key:this.options.key,payload:t})}catch{}}}
@@ -1 +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;this.sources.onAttach?.();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
+ import{randomBytes as a}from"node:crypto";const u=1e3,c=6e4;export class SseHub{sources;epoch=a(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 r=++this.seq,i=JSON.stringify(s);this.buffer.push({seq:r,data:i}),this.buffer.length>u&&this.buffer.shift();const t={id:this.frameId(r),data:i};for(const e of this.subs)e(t)}replay(s){if(!s)return{frames:[],gap:!1};const[r,i]=s.split("-"),t=Number(i);if(r!==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;this.sources.onAttach?.();const s=[],{watch:r,hookBus:i,dataBus:t}=this.sources;r&&(s.push(r.subscribe(e=>this.push({type:"asset",...e}))),s.push(r.subscribeProjects(e=>this.push({type:"project",...e})))),i&&s.push(i.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 he from"node:http";import{openDatabase as we}from"../db/db.js";import{ProjectRepository as ge}from"../repositories/projects.js";import{HookEventRepository as Se}from"../repositories/hook-events.js";import{LibraryRepository as Re}from"../repositories/libraries.js";import{HookRuleRepository as ne}from"../repositories/hook-rules.js";import{HookDispatchRepository as ve}from"../repositories/hook-dispatches.js";import{PluginStateRepository as E}from"../repositories/plugin-states.js";import{SessionRepository as be}from"../repositories/sessions.js";import{createRuntimeRegistry as ye}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as ke,isHarness as Q}from"@weavecode/core";import{messagingSurfaceFor as Pe,narrationSurfaceFor as De}from"../surfaces.js";import{syntheticSessionIds as Ee}from"../hooks/synthetic-sessions.js";import{createEdgeExtract as Te}from"../hooks/edge-extract.js";import{startSessionSweeper as Oe}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as Ae}from"../statusline/cache-sweeper.js";import{readStatuslineFacts as Ie}from"../statusline/manager.js";import{wireHookFilePipeline as Ce}from"./hook-pipeline.js";import{ensureBuiltinMarket as He,builtinMarketDir as _e}from"../market/builtin.js";import{HookRuleRegistry as Me}from"../hooks/registry.js";import{HookDispatcher as Be}from"../hooks/dispatcher.js";import{HookEventBus as Fe}from"../hooks/bus.js";import{ResumeRunner as Le}from"../hooks/resume-runner.js";import{HeadlessRunner as Ue}from"../hooks/headless-runner.js";import{MessageDeliverer as xe}from"../hooks/message-deliverer.js";import{QuestionTracker as Ne}from"../hooks/question-tracker.js";import{SideQuestionRepository as We}from"../repositories/side-questions.js";import{claimSideAnswer as $e}from"../hooks/side-questions.js";import{DashboardRateCache as Qe}from"../hooks/dashboard-rate.js";import{startDashboardPusher as qe}from"./dashboard-pusher.js";import{startPromptFlusher as je}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as Ge}from"../repositories/session-watches.js";import{PushSubscriptionRepository as Ke}from"../repositories/push-subscriptions.js";import{UploadRepository as Je}from"../repositories/uploads.js";import{defaultUploadSessions as Ve}from"./upload-sessions.js";import{PushNotifier as Ye}from"../hooks/push-notify.js";import{OrchestrationRepository as ze,OrchestrationRunRepository as Xe}from"../repositories/orchestrations.js";import{WatchEngine as Ze}from"../hooks/watch-engine.js";import{OrchestrationEngine as es,createForkConditionJudge as ss}from"../hooks/orchestration-engine.js";import{createDecisionConditionJudge as ts}from"../hooks/decision-judge.js";import{readDecisionKey as os}from"./decision-config.js";import{createEnsureOpen as rs}from"./session-open.js";import{loadAllPlugins as ns}from"../hooks/plugin-loader.js";import{ToolkitService as is}from"../hooks/toolkit.js";import{WatchService as as}from"../watch/watch-service.js";import{SyncScheduler as cs}from"../watch/sync-scheduler.js";import{FingerprintCache as ls}from"../install/fingerprint.js";import{detectProjectUpdateCounts as ps}from"../install/updates.js";import{weaveRequestHandler as ms}from"./server.js";import{startTlsServer as us}from"./tls.js";import{DataBus as fs}from"./data-bus.js";import{TerminalTopologyRefresher as ds}from"./terminal-topology-refresher.js";import{SnapshotRefresher as q}from"./snapshot-refresher.js";import{SessionProbe as hs,dbModelFactResolver as ws,dbTranscriptPathResolver as gs}from"./session-probe.js";import{NarrationWatcher as Ss}from"./narration-watcher.js";import{InflightCountsRefresher as Rs}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as vs}from"./project-updates-refresher.js";import{pidAliveOf as bs}from"./claude-liveness.js";import{combinedLivenessOf as R}from"./liveness.js";import{promptTerminalChannel as ie,readTerminalCounts as ys}from"./opener.js";import{DEFAULT_BIND_HOST as ks}from"./port.js";import{readDaemonState as Ps,writeDaemonState as Ds}from"./state.js";import{ensureDataLayout as Es}from"../db/layout.js";import{pruneFileIndexes as Ts}from"./project-files.js";import{pruneInstallTmp as Os}from"../hooks/plugin-installer.js";import{readDaemonSettingsSync as v,setDaemonSettingsDb as As,DEFAULT_SERVER_SETTINGS as Is}from"./settings.js";import{AuthService as Cs}from"./dashboard-auth.js";import{syncLaunchOnLogin as Hs}from"./auto-start.js";import{resolveStaticDir as _s}from"./static.js";import{openPetWindow as Ms,shutdownPetWindow as Bs}from"./pet-window.js";import{seedBuiltinPets as Fs}from"./pet-seed.js";delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const p of ke)delete process.env[p];export function startDaemon(){Es();const p=Ps();p||(console.error("Daemon state not found. Run `weave daemon start` first."),process.exit(1));const t=we();As(t);const b=v().server?.bindHost??ks,T=v().server?.tlsPort??Is.tlsPort,y=new Cs;y.initialPassword&&console.log(`[weave] initial dashboard password: ${y.initialPassword}`);const r=new ge(t);Ts(r.list().map(e=>e.id)),Os();const c=new Se(t),m=new Re(t),d=ye(),ae=d.byCapability("events").flatMap(e=>e.events??[]),k=new Me(new ne(t)),P=new ve(t),o=new be(t),n=new Fe,O={getHandler:()=>{},getConfig:()=>({})};let f;const A={list:()=>f?.list()??[],setPluginEnabled:(e,s)=>f?.setPluginEnabled(e,s)??!1,reloadAll:async()=>{await f?.reloadAll()},rescan:async()=>{await f?.rescanRoots(r.list(),m)}},ce=new is({projects:r,states:new E(t),plugins:A,libraries:m}),I={run:null},j=new Be({registry:k,dispatches:P,bus:n,projects:r,sessions:o,plugins:O,pluginStates:new E(t),classify:e=>I.run?I.run(e):Promise.resolve(null),sessionTitleOf:async e=>{const s=c.listBySession(e,1).at(-1)?.source;return Q(s)?d.get(s)?.titles?.sessionTitleOf(e)??null:null}});He({libraries:m}).then(e=>(e.error?console.error(`[weave] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[weave] builtin market ${e.form==="link"?"linked":"copied"} -> ${_e(m.dataRoot)}`),ns({rules:new ne(t),registry:k,states:new E(t),bus:n,libraries:m},r.list()))).then(({loader:e})=>{f=e,O.getHandler=(s,a)=>e.getHandler(s,a),O.getConfig=s=>e.getConfig(s),e.watchRoots()}).catch(e=>{console.error("[weave] plugin load failed:",e instanceof Error?e.message:e)});const D=new Ue,le=new Le({dispatches:P,sessions:o,projects:r,bus:n,resumeSpec:d.get("claude")?.resume,headless:D}),l=new xe({sessions:o,projects:r,hookEvents:c,bus:n,headless:D,terminal:ie(()=>v().terminal),blockedByQuestion:e=>h.get(e)!=null,livenessOf:R,sideAnswerStore:{answerById:(e,s,a)=>{B.answerById(e,s,a)}}});je(l);const C=new Ge(t),H=new Ze({watches:C,deliverer:l,sessions:o,bus:n,livenessOf:R}),G=new Ke(t),_=new Je(t),pe=new Ye({subscriptions:G,sessions:o,bus:n}),M=new ze(t),K=new Xe(t),u=new hs(gs(c),ws(c,e=>o.getBySessionId(e)?.harness??null)),J=new Ss(n,e=>De(Q(e)?e:"claude"),e=>u.transcriptPathOf(e),e=>o.livenessRowOf(e)?.harness??null);J.start();const h=new Ne({sessions:o,hookEvents:c,onPending:e=>{n.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})},interruptedAt:e=>{const s=o.getBySessionId(e);return s?u.interruptedAt(e,o.lastMainEventAtOf(e)??s.lastSeenAt):null}});h.seedFromDb();const B=new We(t),V=new Qe,F=qe({rate:V,events:c,sessions:o,projects:r,bus:n}),Y={repo:B,bus:n,settle:e=>{l.interrupt(e.sessionId)}},L=new as(r);L.start();const U=new ls,i=new fs,z=new vs(()=>ps(r.list(),m.list(),U),i,n,()=>i.hasSubscribers()),X=new cs(r,m,{cache:U,plugins:A,onSynced:()=>{z.refreshNow(!0)}});X.start();const w=new ds(async()=>({counts:await ys(r.list()),terminals:await l.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});w.start();const x=new q(()=>{const e=R(),s={};for(const a of o.listWithCounts()){const re=bs(a,e);re!==null&&(s[a.sessionId]=re)}return{alive:s}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});x.start();const N=new q(()=>{const e={};for(const s of o.listWithCounts()){if(s.turnOpen!==!0)continue;const a=u.interruptedAt(s.sessionId,o.lastMainEventAtOf(s.sessionId)??s.lastSeenAt);a!==null&&(e[s.sessionId]=a)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});N.start(),new q(()=>{const e={};for(const s of r.list())e[s.id]=Ie(s.path);return e},i,{key:"statusline",intervalMs:5e3,shouldRun:()=>i.hasSubscribers(),invalidateOnly:!0}).start();const me=new Rs(()=>l.listInflightCounts(),i,n);let Z=null;const g=Te({sessions:o,projects:r,harnessOf:e=>{const s=c.listBySession(e,1),a=s[s.length-1]?.source;return Q(a)?a:null},surfaceFor:Pe,headless:D,onSyntheticChange:()=>Z?.pushSyntheticSessions(Ee())});I.run=e=>g.run(e);const ue=ts({config:async()=>{const e=v().decision;if(!e?.baseUrl||!e.model)return null;const s=os();return s?{baseUrl:e.baseUrl,model:e.model,apiKey:s}:null},fallback:ss({supports:e=>g.supports(e),extract:e=>g.run(e)})}),fe=rs({hookSessions:o,hookEvents:c,projects:r,harnesses:d,sessionProbe:u,terminalRefresher:w,livenessOf:R}),S=new es({orchestrations:M,runs:K,deliverer:l,sessions:o,bus:n,supportsExtract:e=>g.supports(e),extract:e=>g.run(e),conditionJudge:ue,deferWhenUserPresent:!0,ensureOpen:fe});S.rearm();const ee=setInterval(()=>S.cronTick(),3e4);ee.unref(),Oe({sessions:o,events:c,dispatches:P,deliverer:l,watches:C,orchestrations:M,watchEngine:H,orchestrationEngine:S,questions:h,sideQuestions:B,probe:u,uploads:_,uploadSessions:Ve,livenessOf:R}),Ae();const W=Ce({projects:r,rules:k,sessions:o,bus:n,dispatcher:j,watchEngine:H,orchestrationEngine:S,messagePipe:l,questionTracker:h,sideQuestions:{onEvent:e=>{$e(Y,e)}},sessionProbe:u,uploads:_,dashboardRate:V,terminalTopologyKick:()=>{w.refreshNow()}});Z=W;const de=_s(),se=ms({projects:r,port:p.port,tlsPort:T,watch:L,hookEvents:c,adapters:ae,harnesses:d,libraries:m,fingerprintCache:U,staticDir:de,hookRegistry:k,hookDispatches:P,hookSessions:o,hookBus:n,dataBus:i,terminalRefresher:w,interruptRefresher:N,livenessRefresher:x,sessionProbe:u,inflightRefresher:me,updatesRefresher:z,hookDispatcher:j,hookRunner:le,messageDeliverer:l,terminal:ie(()=>v().terminal),uploads:_,questionTracker:h,sideQuestions:Y,sessionWatches:C,watchEngine:H,orchestrations:M,orchestrationRuns:K,orchestrationEngine:S,pushSubscriptions:G,pushNotifier:pe,onAttach:F.attach,dashboardRefresh:F.attach,hookPlugins:A,hookMirror:W.mirror,pluginStates:new E(t),toolkit:ce,auth:y}),$=he.createServer(se);let te=null;us({port:T,bindHost:b,handler:se}).then(e=>{te=e});const oe=()=>{f?.stopWatching(),w.stop(),x.stop(),N.stop(),X.stop(),L.stop(),Bs(),D.killAll(),clearInterval(ee),J.stop(),F.stop(),$.close(),te?.server.close();const e=()=>{try{t.exec("PRAGMA wal_checkpoint(TRUNCATE)"),t.close()}catch{}},s=setTimeout(()=>{e(),process.exit(0)},3e3);W.stop().catch(()=>{}).finally(()=>{clearTimeout(s),e(),process.exit(0)})};process.on("SIGTERM",oe),process.on("SIGINT",oe),$.listen(p.port,b,()=>{Ds({...p,pid:process.pid,host:b,tlsPort:T}),Hs(),Fs().then(()=>{Ms({baseUrl:`http://localhost:${p.port}`,auth:y})})}),$.on("error",e=>{throw console.error(`[weave] daemon listen failed on ${b}:${p.port}: ${e.message}`),e})}
1
+ import we from"node:http";import{openDatabase as ge}from"../db/db.js";import{ProjectRepository as Se}from"../repositories/projects.js";import{HookEventRepository as be}from"../repositories/hook-events.js";import{LibraryRepository as Re}from"../repositories/libraries.js";import{HookRuleRepository as ie}from"../repositories/hook-rules.js";import{HookDispatchRepository as ve}from"../repositories/hook-dispatches.js";import{PluginStateRepository as D}from"../repositories/plugin-states.js";import{SessionRepository as ye}from"../repositories/sessions.js";import{createRuntimeRegistry as ke}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as Ee,isHarness as q}from"@weavecode/core";import{messagingSurfaceFor as Pe,narrationSurfaceFor as De}from"../surfaces.js";import{syntheticSessionIds as Te}from"../hooks/synthetic-sessions.js";import{createEdgeExtract as Ie}from"../hooks/edge-extract.js";import{startSessionSweeper as Oe}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as Ae}from"../statusline/cache-sweeper.js";import{readStatuslineFacts as Ce}from"../statusline/manager.js";import{wireHookFilePipeline as He}from"./hook-pipeline.js";import{ensureBuiltinMarket as Be,builtinMarketDir as Me}from"../market/builtin.js";import{HookRuleRegistry as Fe}from"../hooks/registry.js";import{HookDispatcher as Ue}from"../hooks/dispatcher.js";import{HookEventBus as Le}from"../hooks/bus.js";import{ResumeRunner as je}from"../hooks/resume-runner.js";import{HeadlessRunner as Ne}from"../hooks/headless-runner.js";import{MessageDeliverer as We}from"../hooks/message-deliverer.js";import{QuestionTracker as _e}from"../hooks/question-tracker.js";import{SideQuestionRepository as xe}from"../repositories/side-questions.js";import{claimSideAnswer as $e}from"../hooks/side-questions.js";import{DashboardRateCache as qe}from"../hooks/dashboard-rate.js";import{startDashboardPusher as Qe}from"./dashboard-pusher.js";import{startPromptFlusher as Ge}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as Ke}from"../repositories/session-watches.js";import{PushSubscriptionRepository as Je}from"../repositories/push-subscriptions.js";import{UploadRepository as Ve}from"../repositories/uploads.js";import{defaultUploadSessions as Ye}from"./upload-sessions.js";import{PushNotifier as ze}from"../hooks/push-notify.js";import{OrchestrationRepository as Xe,OrchestrationRunRepository as Ze}from"../repositories/orchestrations.js";import{WatchEngine as es}from"../hooks/watch-engine.js";import{OrchestrationEngine as ss,createForkConditionJudge as os}from"../hooks/orchestration-engine.js";import{createDecisionConditionJudge as rs}from"../hooks/decision-judge.js";import{readDecisionKey as ts}from"./decision-config.js";import{createEnsureOpen as ns}from"./session-open.js";import{loadAllPlugins as is}from"../hooks/plugin-loader.js";import{ToolkitService as as}from"../hooks/toolkit.js";import{WatchService as ls}from"../watch/watch-service.js";import{SyncScheduler as ps}from"../watch/sync-scheduler.js";import{FingerprintCache as cs}from"../install/fingerprint.js";import{detectProjectUpdateCounts as ms}from"../install/updates.js";import{weaveRequestHandler as us}from"./server.js";import{startTlsServer as fs}from"./tls.js";import{DataBus as hs}from"./data-bus.js";import{TerminalTopologyRefresher as ds}from"./terminal-topology-refresher.js";import{SnapshotRefresher as Q}from"./snapshot-refresher.js";import{SessionProbe as ws,dbModelFactResolver as gs,dbTranscriptPathResolver as Ss}from"./session-probe.js";import{NarrationWatcher as bs}from"./narration-watcher.js";import{InflightCountsRefresher as Rs}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as vs}from"./project-updates-refresher.js";import{pidAliveOf as ys}from"./claude-liveness.js";import{combinedLivenessOf as b}from"./liveness.js";import{promptTerminalChannel as ae,readTerminalCounts as ks}from"./opener.js";import{DEFAULT_BIND_HOST as Es}from"./port.js";import{readDaemonState as Ps,writeDaemonState as Ds}from"./state.js";import{ensureDataLayout as Ts}from"../db/layout.js";import{pruneFileIndexes as Is}from"./project-files.js";import{pruneInstallTmp as Os}from"../hooks/plugin-installer.js";import{readDaemonSettingsSync as R,setDaemonSettingsDb as As,DEFAULT_SERVER_SETTINGS as Cs}from"./settings.js";import{AuthService as Hs}from"./dashboard-auth.js";import{syncLaunchOnLogin as Bs}from"./auto-start.js";import{resolveStaticDir as Ms}from"./static.js";import{openPetWindow as Fs,shutdownPetWindow as Us}from"./pet-window.js";import{seedBuiltinPets as Ls}from"./pet-seed.js";delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const c of Ee)delete process.env[c];export function startDaemon(){Ts();const c=Ps();c||(console.error("Daemon state not found. Run `weave daemon start` first."),process.exit(1));const o=ge();As(o);const v=R().server?.bindHost??Es,T=R().server?.tlsPort??Cs.tlsPort,y=new Hs;y.initialPassword&&console.log(`[weave] initial dashboard password: ${y.initialPassword}`);const t=new Se(o);Is(t.list().map(e=>e.id)),Os();const l=new be(o),m=new Re(o),h=ke(),le=h.byCapability("events").flatMap(e=>e.events??[]),k=new Fe(new ie(o)),E=new ve(o),r=new ye(o),n=new Le,I={getHandler:()=>{},getConfig:()=>({})};let f;const O={list:()=>f?.list()??[],setPluginEnabled:(e,s)=>f?.setPluginEnabled(e,s)??!1,reloadAll:async()=>{await f?.reloadAll()},rescan:async()=>{await f?.rescanRoots(t.list(),m)}},pe=new as({projects:t,states:new D(o),plugins:O,libraries:m}),A={run:null},G=new Ue({registry:k,dispatches:E,bus:n,projects:t,sessions:r,plugins:I,pluginStates:new D(o),classify:e=>A.run?A.run(e):Promise.resolve(null),sessionTitleOf:async e=>{const s=l.listBySession(e,1).at(-1)?.source;return q(s)?h.get(s)?.titles?.sessionTitleOf(e)??null:null}});Be({libraries:m}).then(e=>(e.error?console.error(`[weave] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[weave] builtin market ${e.form==="link"?"linked":"copied"} -> ${Me(m.dataRoot)}`),is({rules:new ie(o),registry:k,states:new D(o),bus:n,libraries:m},t.list()))).then(({loader:e})=>{f=e,I.getHandler=(s,a)=>e.getHandler(s,a),I.getConfig=s=>e.getConfig(s),e.watchRoots()}).catch(e=>{console.error("[weave] plugin load failed:",e instanceof Error?e.message:e)});const P=new Ne,ce=new je({dispatches:E,sessions:r,projects:t,bus:n,resumeSpec:h.get("claude")?.resume,headless:P}),p=new We({sessions:r,projects:t,hookEvents:l,bus:n,headless:P,terminal:ae(()=>R().terminal),blockedByQuestion:e=>d.get(e)!=null,livenessOf:b,sideAnswerStore:{answerById:(e,s,a)=>{F.answerById(e,s,a)}}});Ge(p);const C=new Ke(o),H=new es({watches:C,deliverer:p,sessions:r,bus:n,livenessOf:b}),K=new Je(o),B=new Ve(o),me=new ze({subscriptions:K,sessions:r,bus:n}),M=new Xe(o),J=new Ze(o),u=new ws(Ss(l),gs(l,e=>r.getBySessionId(e)?.harness??null)),V=new bs(n,e=>De(q(e)?e:"claude"),e=>u.transcriptPathOf(e),e=>r.livenessRowOf(e)?.harness??null);V.start();const d=new _e({sessions:r,hookEvents:l,onPending:e=>{n.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})},interruptedAt:e=>{const s=r.getBySessionId(e);return s?u.interruptedAt(e,r.lastMainEventAtOf(e)??s.lastSeenAt):null}});d.seedFromDb();const F=new xe(o),Y=new qe,U=Qe({rate:Y,events:l,sessions:r,projects:t,bus:n}),z={repo:F,bus:n,settle:e=>{p.interrupt(e.sessionId)}},L=new ls(t);L.start();const j=new cs,i=new hs,X=new vs(()=>ms(t.list(),m.list(),j),i,n,()=>i.hasSubscribers()),Z=new ps(t,m,{cache:j,plugins:O,onSynced:()=>{X.refreshNow(!0)}});Z.start();const w=new ds(async()=>({counts:await ks(t.list()),terminals:await p.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});w.start();const N=new Q(()=>{const e=b(),s={};for(const a of r.listWithCounts()){const ne=ys(a,e);ne!==null&&(s[a.sessionId]=ne)}return{alive:s}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});N.start();const W=new Q(()=>{const e={};for(const s of r.listWithCounts()){if(s.turnOpen!==!0)continue;const a=u.interruptedAt(s.sessionId,r.lastMainEventAtOf(s.sessionId)??s.lastSeenAt);a!==null&&(e[s.sessionId]=a)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});W.start(),new Q(()=>{const e={};for(const s of t.list())e[s.id]=Ce(s.path);return e},i,{key:"statusline",intervalMs:5e3,shouldRun:()=>i.hasSubscribers(),invalidateOnly:!0}).start();const ue=new Rs(()=>p.listInflightCounts(),i,n);let ee=null;const g=Ie({sessions:r,projects:t,harnessOf:e=>{const s=l.listBySession(e,1),a=s[s.length-1]?.source;return q(a)?a:null},surfaceFor:Pe,headless:P,onSyntheticChange:()=>ee?.pushSyntheticSessions(Te())});A.run=e=>g.run(e);const fe=rs({config:async()=>{const e=R().decision;if(!e?.baseUrl||!e.model)return null;const s=ts();return s?{baseUrl:e.baseUrl,model:e.model,apiKey:s}:null},fallback:os({supports:e=>g.supports(e),extract:e=>g.run(e)})}),he=ns({hookSessions:r,hookEvents:l,projects:t,harnesses:h,sessionProbe:u,terminalRefresher:w,livenessOf:b}),S=new ss({orchestrations:M,runs:J,deliverer:p,sessions:r,bus:n,supportsExtract:e=>g.supports(e),extract:e=>g.run(e),conditionJudge:fe,deferWhenUserPresent:!0,ensureOpen:he});S.rearm();const se=setInterval(()=>S.cronTick(),3e4);se.unref(),Oe({sessions:r,events:l,dispatches:E,deliverer:p,watches:C,orchestrations:M,watchEngine:H,orchestrationEngine:S,questions:d,sideQuestions:F,probe:u,uploads:B,uploadSessions:Ye,livenessOf:b}),Ae();const _=He({projects:t,rules:k,sessions:r,bus:n,dispatcher:G,watchEngine:H,orchestrationEngine:S,messagePipe:p,questionTracker:d,sideQuestions:{onEvent:e=>{$e(z,e)}},sessionProbe:u,uploads:B,dashboardRate:Y,terminalTopologyKick:()=>{w.refreshNow()}});ee=_;const de=Ms(),oe={},re=us({projects:t,port:c.port,tlsPort:T,watch:L,hookEvents:l,adapters:le,harnesses:h,libraries:m,fingerprintCache:j,staticDir:de,hookRegistry:k,hookDispatches:E,hookSessions:r,hookBus:n,dataBus:i,terminalRefresher:w,interruptRefresher:W,livenessRefresher:N,sessionProbe:u,inflightRefresher:ue,updatesRefresher:X,hookDispatcher:G,hookRunner:ce,messageDeliverer:p,terminal:ae(()=>R().terminal),uploads:B,questionTracker:d,sideQuestions:z,sessionWatches:C,requestShutdown:()=>oe.fn?.(),watchEngine:H,orchestrations:M,orchestrationRuns:J,orchestrationEngine:S,pushSubscriptions:K,pushNotifier:me,onAttach:U.attach,dashboardRefresh:U.attach,hookPlugins:O,hookMirror:_.mirror,pluginStates:new D(o),toolkit:pe,auth:y}),x=we.createServer(re);let te=null;fs({port:T,bindHost:v,handler:re}).then(e=>{te=e});const $=()=>{f?.stopWatching(),w.stop(),N.stop(),W.stop(),Z.stop(),L.stop(),Us(),P.killAll(),clearInterval(se),V.stop(),U.stop(),x.close(),te?.server.close();const e=()=>{try{o.exec("PRAGMA wal_checkpoint(TRUNCATE)"),o.close()}catch{}},s=setTimeout(()=>{e(),process.exit(0)},3e3);_.stop().catch(()=>{}).finally(()=>{clearTimeout(s),e(),process.exit(0)})};oe.fn=$,process.on("SIGTERM",$),process.on("SIGINT",$),x.listen(c.port,v,()=>{Ds({...c,pid:process.pid,host:v,tlsPort:T}),Bs(),Ls().then(()=>{Fs({baseUrl:`http://localhost:${c.port}`,auth:y})})}),x.on("error",e=>{throw console.error(`[weave] daemon listen failed on ${v}:${c.port}: ${e.message}`),e})}
@@ -1,2 +1,2 @@
1
- import{existsSync as n,mkdirSync as o,readFileSync as i,rmSync as a,writeFileSync as c}from"node:fs";import m from"node:path";import{getDaemonStatePath as r}from"../db/paths.js";export function readDaemonState(){const t=r();if(!n(t))return null;try{return JSON.parse(i(t,"utf-8"))}catch{return null}}export function writeDaemonState(t){const e=r();o(m.dirname(e),{recursive:!0}),c(e,JSON.stringify(t,null,2)+`
2
- `,"utf-8")}export function clearDaemonState(){const t=r();n(t)&&a(t)}
1
+ import{existsSync as n,mkdirSync as a,readFileSync as o,rmSync as i,writeFileSync as c}from"node:fs";import m from"node:path";import{getDaemonStatePath as r}from"../db/paths.js";export function readDaemonState(){const t=r();if(!n(t))return null;try{return JSON.parse(o(t,"utf-8"))}catch{return null}}export function writeDaemonState(t){const e=r();a(m.dirname(e),{recursive:!0}),c(e,JSON.stringify(t,null,2)+`
2
+ `,"utf-8")}export function clearDaemonState(){const t=r();n(t)&&i(t)}
@@ -1 +1 @@
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}
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 +1 @@
1
- export class TerminalTopologyRefresher{snapshot;bus;options;timer;running=!1;last=null;lastFingerprint=null;startedAt=0;constructor(t,i,s={}){this.snapshot=t,this.bus=i,this.options=s}get lastSnapshot(){return this.last}start(){this.timer||(this.startedAt=Date.now(),this.timer=setInterval(()=>{this.tick()},this.options.intervalMs??3e4))}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}async refreshNow(){await this.run(!0,!0)}onSubscriberJoin(){this.last!==null&&(this.lastFingerprint=JSON.stringify(this.last),this.bus.emit({key:"terminalTopology",payload:this.last})),this.tick()}async tick(t=!1){await this.run(t,!1)}async run(t,i){if(this.running)return;const s=this.options.shouldRun;if(!(!t&&s&&!s())&&!(!i&&Date.now()-this.startedAt<(this.options.graceMs??0))){this.running=!0;try{const r=await this.snapshot(),e={...this.last?.terminals};for(const[l,o]of Object.entries(r.terminals))o!==void 0&&(e[l]=o);const n={counts:r.counts,terminals:e};this.last=n;const a=JSON.stringify(n);if(a===this.lastFingerprint)return;this.lastFingerprint=a,this.bus.emit({key:"terminalTopology",payload:n})}catch{}finally{this.running=!1}}}}
1
+ export class TerminalTopologyRefresher{snapshot;bus;options;timer;running=!1;last=null;lastFingerprint=null;startedAt=0;constructor(t,i,s={}){this.snapshot=t,this.bus=i,this.options=s}get lastSnapshot(){return this.last}start(){this.timer||(this.startedAt=Date.now(),this.timer=setInterval(()=>{this.tick()},this.options.intervalMs??3e4))}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}async refreshNow(){await this.run(!0,!0)}onSubscriberJoin(){this.last!==null&&(this.lastFingerprint=JSON.stringify(this.last),this.bus.emit({key:"terminalTopology",payload:this.last})),this.tick()}async tick(t=!1){await this.run(t,!1)}async run(t,i){if(this.running)return;const s=this.options.shouldRun;if(!(!t&&s&&!s())&&!(!i&&Date.now()-this.startedAt<(this.options.graceMs??0))){this.running=!0;try{const r=await this.snapshot(),a={...this.last?.terminals};for(const[h,o]of Object.entries(r.terminals))o!==void 0&&(a[h]=o);const n={counts:r.counts,terminals:a};this.last=n;const e=JSON.stringify(n);if(e===this.lastFingerprint)return;this.lastFingerprint=e,this.bus.emit({key:"terminalTopology",payload:n})}catch{}finally{this.running=!1}}}}
@@ -1 +1 @@
1
- import w from"node:https";import m from"node:os";import f from"node:path";import{existsSync as u,mkdirSync as d,readFileSync as l,writeFileSync as h}from"node:fs";import{X509Certificate as S,createPrivateKey as k}from"node:crypto";import{generate as $}from"selfsigned";import{getCertsDir as x}from"../db/paths.js";export function daemonCertsDir(){return x()}export function lanIps(){const t=new Set;for(const e of Object.values(m.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 D(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??m.hostname(),n=e.now??new Date,s=f.join(t,"host.key"),c=f.join(t,"host.crt");if(u(s)&&u(c))try{const i=l(s,"utf-8"),p=new S(l(c,"utf-8")),y=r.every(v=>D(p).has(v));if(p.checkPrivateKey(k(i))&&Date.parse(p.validTo)>n.getTime()+7*864e5&&y)return{key:i,cert:l(c,"utf-8")}}catch{}const a=await $([{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,a.private,{mode:384}),h(c,a.cert),{key:a.private,cert:a.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
+ import v from"node:https";import m from"node:os";import u from"node:path";import{existsSync as f,mkdirSync as w,readFileSync as l,writeFileSync as h}from"node:fs";import{X509Certificate as S,createPrivateKey as k}from"node:crypto";import{generate as $}from"selfsigned";import{getCertsDir as D}from"../db/paths.js";export function daemonCertsDir(){return D()}export function lanIps(){const t=new Set;for(const e of Object.values(m.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??m.hostname(),n=e.now??new Date,s=u.join(t,"host.key"),a=u.join(t,"host.crt");if(f(s)&&f(a))try{const i=l(s,"utf-8"),p=new S(l(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:l(a,"utf-8")}}catch{}const c=await $([{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(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=v.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(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}
1
+ import{sendJson as e}from"./http.js";import{ToolkitError as h}from"../hooks/toolkit.js";export async function handleToolkitRoutes(n,o,r,i,f){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"})},u=i.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 a=i.match(/^\/projects\/(\d+)\/toolkit\/([^/]+)\/(enable|disable|uninstall)$/);if(a){if(n.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;const t=Number(a[1]),s=decodeURIComponent(a[2]),k=a[3],c=f.searchParams.get("source");try{const d=k==="enable"?await r.toolkit.enable(t,s,c??void 0):k==="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 m=i.match(/^\/projects\/(\d+)\/toolkit\/legacy-copies\/cleanup$/);if(m){if(n.method!=="POST")return e(o,405,{error:"Method not allowed"}),!0;try{const t=await r.toolkit.cleanupLegacyCopies(Number(m[1]));r.dataBus?.emit({key:"toolkit"}),e(o,200,t)}catch(t){l(t)}return!0}return!1}
@@ -1 +1 @@
1
- import{randomUUID as u}from"node:crypto";import{open as o,mkdir as f,readFile as p,readdir as w,rm as d,stat as m,writeFile as l}from"node:fs/promises";import s from"node:path";import{getTmpDir as y}from"../db/paths.js";export const UPLOAD_SESSION_MAX_AGE_MS=1440*6e4;const c=/^[0-9a-f-]{36}$/;export class UploadSessions{dir;handles=new Map;constructor(e=s.join(y(),"uploads")){this.dir=e}part(e){return s.join(this.dir,`${e}.part`)}meta(e){return s.join(this.dir,`${e}.json`)}async begin(e){await f(this.dir,{recursive:!0});const t=u();await l(this.meta(t),JSON.stringify({name:e.name,mediaType:e.mediaType,size:e.size,received:0,dir:e.dir??null}),"utf8");const r=await o(this.part(t),"w");return await r.truncate(e.size),this.handles.set(t,r),{id:t,...e,received:0}}async get(e){if(!c.test(e))return null;try{const t=JSON.parse(await p(this.meta(e),"utf8"));if(typeof t.name!="string"||typeof t.mediaType!="string"||typeof t.size!="number")return null;const r=typeof t.received=="number"?t.received:(await m(this.part(e))).size;return{id:e,name:t.name,mediaType:t.mediaType,size:t.size,received:r,dir:typeof t.dir=="string"?t.dir:null}}catch{return null}}async append(e,t,r){const i=await this.get(e);if(!i)return{kind:"missing"};if(t!==i.received)return{kind:"conflict",received:i.received};if(i.received+r.length>i.size)return{kind:"overflow",received:i.received};let a=this.handles.get(e);a||(a=await o(this.part(e),"r+"),this.handles.set(e,a));const n=i.received+r.length;return await a.write(r,0,r.length,t),await a.truncate(n),await l(this.meta(e),JSON.stringify({name:i.name,mediaType:i.mediaType,size:i.size,received:n,dir:i.dir??null}),"utf8"),{kind:"ok",received:n}}async finish(e){const t=await this.get(e);return!t||t.received!==t.size?null:{name:t.name,mediaType:t.mediaType,file:this.part(e),size:t.size,dir:t.dir}}async abort(e){c.test(e)&&(await this.handles.get(e)?.close().catch(()=>{}),this.handles.delete(e),await d(this.part(e),{force:!0}),await d(this.meta(e),{force:!0}))}async sweep(e=UPLOAD_SESSION_MAX_AGE_MS,t=Date.now()){let r;try{r=await w(this.dir)}catch{return 0}let i=0;for(const a of r){if(!a.endsWith(".json"))continue;const n=a.slice(0,-5);if(c.test(n))try{const h=await m(this.meta(n));if(t-h.mtimeMs<e)continue;await this.abort(n),i++}catch{}}return i}}export const defaultUploadSessions=new UploadSessions;
1
+ import{randomUUID as p}from"node:crypto";import{open as o,mkdir as u,readFile as f,readdir as w,rm as c,stat as m,writeFile as l}from"node:fs/promises";import n from"node:path";import{getTmpDir as y}from"../db/paths.js";export const UPLOAD_SESSION_MAX_AGE_MS=1440*6e4;const d=/^[0-9a-f-]{36}$/;export class UploadSessions{dir;handles=new Map;constructor(e=n.join(y(),"uploads")){this.dir=e}part(e){return n.join(this.dir,`${e}.part`)}meta(e){return n.join(this.dir,`${e}.json`)}async begin(e){await u(this.dir,{recursive:!0});const t=p();await l(this.meta(t),JSON.stringify({name:e.name,mediaType:e.mediaType,size:e.size,received:0,dir:e.dir??null}),"utf8");const r=await o(this.part(t),"w");return await r.truncate(e.size),this.handles.set(t,r),{id:t,...e,received:0}}async get(e){if(!d.test(e))return null;try{const t=JSON.parse(await f(this.meta(e),"utf8"));if(typeof t.name!="string"||typeof t.mediaType!="string"||typeof t.size!="number")return null;const r=typeof t.received=="number"?t.received:(await m(this.part(e))).size;return{id:e,name:t.name,mediaType:t.mediaType,size:t.size,received:r,dir:typeof t.dir=="string"?t.dir:null}}catch{return null}}async append(e,t,r){const i=await this.get(e);if(!i)return{kind:"missing"};if(t!==i.received)return{kind:"conflict",received:i.received};if(i.received+r.length>i.size)return{kind:"overflow",received:i.received};let a=this.handles.get(e);a||(a=await o(this.part(e),"r+"),this.handles.set(e,a));const s=i.received+r.length;return await a.write(r,0,r.length,t),await a.truncate(s),await l(this.meta(e),JSON.stringify({name:i.name,mediaType:i.mediaType,size:i.size,received:s,dir:i.dir??null}),"utf8"),{kind:"ok",received:s}}async finish(e){const t=await this.get(e);return!t||t.received!==t.size?null:{name:t.name,mediaType:t.mediaType,file:this.part(e),size:t.size,dir:t.dir}}async abort(e){d.test(e)&&(await this.handles.get(e)?.close().catch(()=>{}),this.handles.delete(e),await c(this.part(e),{force:!0}),await c(this.meta(e),{force:!0}))}async sweep(e=UPLOAD_SESSION_MAX_AGE_MS,t=Date.now()){let r;try{r=await w(this.dir)}catch{return 0}let i=0;for(const a of r){if(!a.endsWith(".json"))continue;const s=a.slice(0,-5);if(d.test(s))try{const h=await m(this.meta(s));if(t-h.mtimeMs<e)continue;await this.abort(s),i++}catch{}}return i}}export const defaultUploadSessions=new UploadSessions;
@@ -1,4 +1,4 @@
1
- import{existsSync as L,mkdirSync as a,readdirSync as _,renameSync as d,unlinkSync as A}from"node:fs";import i from"node:path";import{DatabaseSync as O}from"node:sqlite";import{getDbPath as u}from"./paths.js";import{projectKey as R}from"../repositories/projects.js";const I=`
1
+ import{existsSync as A,mkdirSync as n,readdirSync as L,renameSync as D,unlinkSync as d}from"node:fs";import s from"node:path";import{DatabaseSync as c}from"node:sqlite";import{getDbPath as _}from"./paths.js";import{projectKey as B}from"../repositories/projects.js";const C=`
2
2
  CREATE TABLE IF NOT EXISTS projects (
3
3
  id INTEGER PRIMARY KEY AUTOINCREMENT,
4
4
  path TEXT NOT NULL UNIQUE,
@@ -204,4 +204,4 @@ CREATE TABLE IF NOT EXISTS event_images (
204
204
  upload_id TEXT NOT NULL,
205
205
  PRIMARY KEY (event_id, upload_id)
206
206
  );
207
- `,N=1,p=3;function X(T){const e=T instanceof Error?T.message:String(T);return/malformed database schema|database disk image is malformed|file is not a database|SQLITE_CORRUPT/i.test(e)}function l(T){const e=T.prepare("PRAGMA user_version").get();return typeof e?.user_version=="number"?e.user_version:0}function U(T,e){if(e===":memory:")return;const t=l(T);if(t>=N)return;const o=T.prepare("SELECT count(*) AS n FROM sqlite_master").get();if(!o||o.n===0)return;const s=i.join(i.dirname(e),"backups");a(s,{recursive:!0});const E=new Date().toISOString().replace(/[:.]/g,"-"),n=i.join(s,`weave-v${t}-${E}.db`);try{T.exec(`VACUUM INTO '${n.replace(/'/g,"''")}'`),console.log(`[weave] database backup before migration: ${n}`),h(s)}catch(r){console.error(`[weave] database backup failed (continuing): ${r instanceof Error?r.message:r}`)}}function h(T){try{const e=_(T).filter(t=>t.startsWith("weave-v")&&t.endsWith(".db")).sort();for(const t of e.slice(0,Math.max(0,e.length-p)))try{A(i.join(T,t))}catch{}}catch{}}function S(T,e){const t=new Date().toISOString().replace(/[:.]/g,"-"),o=`${T}.corrupt-${t}`;for(const E of["","-wal","-shm"])try{L(T+E)&&d(T+E,o+E)}catch{}const s=e instanceof Error?e.message:String(e);return console.error(`[weave] database is corrupt (${s}); moved to ${o} and starting with a fresh one. Recover the old data with: sqlite3 "${o}" ".recover" | sqlite3 "${T}"`),c(T)}export function openDatabase(T=u()){T!==":memory:"&&a(i.dirname(T),{recursive:!0});try{return c(T)}catch(e){if(!X(e))throw e;return S(T,e)}}function c(T){const e=new O(T);try{e.exec("PRAGMA busy_timeout = 5000"),e.exec("PRAGMA journal_mode = WAL"),e.exec("PRAGMA foreign_keys = ON");const t=e.prepare("PRAGMA quick_check").get();if(t?.quick_check!==void 0&&t.quick_check!=="ok")throw new Error(`malformed database schema (${t.quick_check})`);return U(e,T),g(e),e.exec(I),e.exec("DROP TABLE IF EXISTS session_messages"),k(e),C(e),m(e),f(e),D(e),e.exec(`PRAGMA user_version = ${N}`),e}catch(t){try{e.close()}catch{}throw t}}function m(T){const e=T.prepare("SELECT id, path FROM projects ORDER BY id").all(),t=new Set(e.map(s=>s.path)),o=T.prepare("UPDATE projects SET path = ? WHERE id = ?");for(const s of e){const E=R(s.path);E===s.path||t.has(E)||(t.delete(s.path),t.add(E),o.run(E,s.id))}}function f(T){const e=new Set(T.prepare("PRAGMA table_info(session_watches)").all().map(t=>String(t.name)));e.size!==0&&(e.has("on_events")||T.exec("ALTER TABLE session_watches ADD COLUMN on_events TEXT"),e.has("remaining")||(T.exec("ALTER TABLE session_watches ADD COLUMN remaining INTEGER"),T.exec("UPDATE session_watches SET remaining = 1")))}function C(T){const e=new Set(T.prepare("PRAGMA table_info(projects)").all().map(t=>String(t.name)));e.size!==0&&(e.has("sort_order")||T.exec("ALTER TABLE projects ADD COLUMN sort_order INTEGER"),e.has("archived_at")||T.exec("ALTER TABLE projects ADD COLUMN archived_at TEXT"))}function D(T){const e=new Set(T.prepare("PRAGMA table_info(uploads)").all().map(t=>String(t.name)));e.size!==0&&(e.has("dir")||T.exec("ALTER TABLE uploads ADD COLUMN dir TEXT"))}function g(T){const e=T.prepare("PRAGMA table_info(orchestrations)").all();e.length===0||e.some(t=>t.name==="enabled")||T.exec("DROP TABLE orchestrations")}function k(T){const e=new Set(T.prepare("PRAGMA table_info(hook_rules)").all().map(t=>String(t.name)));e.size!==0&&(e.has("origin")||T.exec("ALTER TABLE hook_rules ADD COLUMN origin TEXT NOT NULL DEFAULT 'user'"),e.has("plugin_id")||T.exec("ALTER TABLE hook_rules ADD COLUMN plugin_id TEXT"),T.exec("CREATE INDEX IF NOT EXISTS idx_hook_rules_plugin ON hook_rules(plugin_id)"))}
207
+ `,r=1,O=3;function R(E){const u=E instanceof Error?E.message:String(E);return/malformed database schema|database disk image is malformed|file is not a database|SQLITE_CORRUPT/i.test(u)}function I(E){const u=E.prepare("PRAGMA user_version").get();return typeof u?.user_version=="number"?u.user_version:0}function X(E,u){if(u===":memory:")return;const e=I(E);if(e>=r)return;const t=E.prepare("PRAGMA quick_check").get();if(t?.quick_check!==void 0&&t.quick_check!=="ok")throw new Error(`malformed database schema (${t.quick_check})`);const F=E.prepare("SELECT count(*) AS n FROM sqlite_master").get();if(!F||F.n===0)return;const T=s.join(s.dirname(u),"backups");n(T,{recursive:!0});const N=new Date().toISOString().replace(/[:.]/g,"-"),i=s.join(T,`weave-v${e}-${N}.db`);try{E.exec(`VACUUM INTO '${i.replace(/'/g,"''")}'`),console.log(`[weave] database backup before migration: ${i}`),p(T)}catch(o){console.error(`[weave] database backup failed (continuing): ${o instanceof Error?o.message:o}`)}}function p(E){try{const u=L(E).filter(e=>e.startsWith("weave-v")&&e.endsWith(".db")).sort();for(const e of u.slice(0,Math.max(0,u.length-O)))try{d(s.join(E,e))}catch{}}catch{}}function h(E,u){const e=new Date().toISOString().replace(/[:.]/g,"-"),t=`${E}.corrupt-${e}`;for(const T of["","-wal","-shm"])try{A(E+T)&&D(E+T,t+T)}catch{}const F=u instanceof Error?u.message:String(u);return console.error(`[weave] database is corrupt (${F}); moved to ${t} and starting with a fresh one. Recover the old data with: sqlite3 "${t}" ".recover" | sqlite3 "${E}"`),a(E)}export function openDatabase(E=_()){E!==":memory:"&&n(s.dirname(E),{recursive:!0});try{return a(E)}catch(u){if(!R(u))throw u;return h(E,u)}}function a(E){const u=new c(E);try{return u.exec("PRAGMA busy_timeout = 5000"),u.exec("PRAGMA journal_mode = WAL"),u.exec("PRAGMA foreign_keys = ON"),X(u,E),g(u),u.exec(C),u.exec("DROP TABLE IF EXISTS session_messages"),k(u),l(u),U(u),S(u),m(u),u.exec(`PRAGMA user_version = ${r}`),u}catch(e){try{u.close()}catch{}throw e}}function U(E){const u=E.prepare("SELECT id, path FROM projects ORDER BY id").all(),e=new Set(u.map(F=>F.path)),t=E.prepare("UPDATE projects SET path = ? WHERE id = ?");for(const F of u){const T=B(F.path);T===F.path||e.has(T)||(e.delete(F.path),e.add(T),t.run(T,F.id))}}function S(E){const u=new Set(E.prepare("PRAGMA table_info(session_watches)").all().map(e=>String(e.name)));u.size!==0&&(u.has("on_events")||E.exec("ALTER TABLE session_watches ADD COLUMN on_events TEXT"),u.has("remaining")||(E.exec("ALTER TABLE session_watches ADD COLUMN remaining INTEGER"),E.exec("UPDATE session_watches SET remaining = 1")))}function l(E){const u=new Set(E.prepare("PRAGMA table_info(projects)").all().map(e=>String(e.name)));u.size!==0&&(u.has("sort_order")||E.exec("ALTER TABLE projects ADD COLUMN sort_order INTEGER"),u.has("archived_at")||E.exec("ALTER TABLE projects ADD COLUMN archived_at TEXT"))}function m(E){const u=new Set(E.prepare("PRAGMA table_info(uploads)").all().map(e=>String(e.name)));u.size!==0&&(u.has("dir")||E.exec("ALTER TABLE uploads ADD COLUMN dir TEXT"))}function g(E){const u=E.prepare("PRAGMA table_info(orchestrations)").all();u.length===0||u.some(e=>e.name==="enabled")||E.exec("DROP TABLE orchestrations")}function k(E){const u=new Set(E.prepare("PRAGMA table_info(hook_rules)").all().map(e=>String(e.name)));u.size!==0&&(u.has("origin")||E.exec("ALTER TABLE hook_rules ADD COLUMN origin TEXT NOT NULL DEFAULT 'user'"),u.has("plugin_id")||E.exec("ALTER TABLE hook_rules ADD COLUMN plugin_id TEXT"),E.exec("CREATE INDEX IF NOT EXISTS idx_hook_rules_plugin ON hook_rules(plugin_id)"))}
@@ -12,4 +12,9 @@ export interface LayoutMigration {
12
12
  export declare function liveDaemonPid(root?: string): number | null;
13
13
  /** 搬迁 + 打一行结果(daemon / CLI 启动点的唯一调用形)。 */
14
14
  export declare function ensureDataLayout(root?: string): LayoutMigration;
15
+ /**
16
+ * 落当前版本号(`<cache>/version`):statusline 脚本每次运行读它显示版本,
17
+ * 生成物里因此不用内联版本号——发版不再让所有项目的脚本判成「需要更新」。
18
+ */
19
+ export declare function writeVersionStamp(root?: string): void;
15
20
  export declare function migrateDataLayout(root?: string): LayoutMigration;
@@ -1 +1,2 @@
1
- import{existsSync as u,lstatSync as g,mkdirSync as f,readFileSync as S,readdirSync as p,renameSync as m,rmSync as b,symlinkSync as D}from"node:fs";import o from"node:path";import{dataRoots as y,getDataDir as l}from"./paths.js";const h={data:["market","uploads","plugins"],local:["auth.json","ai.json","push.json","initial-password","certs","weave-autostart.vbs"],cache:["logs","statusline","hooks","tmp","daemon.json"]},w="weave.db",j=["hooks","statusline"];export function liveDaemonPid(n=l()){const t=y(n);for(const i of[o.join(t.cache,"daemon.json"),o.join(n,"daemon.json")])try{const s=Number(JSON.parse(S(i,"utf-8")).pid);if(s>0&&x(s))return s}catch{}return null}function x(n){try{return process.kill(n,0),!0}catch{return!1}}function L(n){try{return g(n).isSymbolicLink()}catch{return!1}}function k(n,t){f(t,{recursive:!0});for(const i of p(n,{withFileTypes:!0})){const s=o.join(n,i.name),r=o.join(t,i.name);i.isDirectory()?k(s,r):u(r)||m(s,r)}b(n,{recursive:!0,force:!0})}export function ensureDataLayout(n=l()){const t=migrateDataLayout(n);return t.moved.length>0&&console.log(`[weave] data layout: moved ${t.moved.join(", ")}`),t.kept.length>0&&console.log(`[weave] data layout: kept ${t.kept.join(", ")} (target exists)`),t}export function migrateDataLayout(n=l()){const t={moved:[],kept:[],bridged:[],busyPid:null},i=liveDaemonPid(n);if(i!==null)return t.busyPid=i,t;let s;try{s=p(n)}catch{return t}const r=Object.keys(h),d=y(n);for(const e of s){if(L(o.join(n,e)))continue;const a=r.find(v=>h[v].includes(e))??(e.startsWith(w)?"data":null);if(!a)continue;const c=d[a];if(u(o.join(c,e))&&j.includes(e)){try{k(o.join(n,e),o.join(c,e)),t.moved.push(e)}catch{t.kept.push(e)}continue}if(u(o.join(c,e))){t.kept.push(e);continue}try{f(c,{recursive:!0}),m(o.join(n,e),o.join(c,e)),t.moved.push(e)}catch{t.kept.push(e)}}for(const e of j){const a=o.join(n,e),c=o.join(d.cache,e);if(!(!u(c)||u(a)))try{D(c,a,process.platform==="win32"?"junction":"dir"),t.bridged.push(e)}catch{}}return t}
1
+ import{existsSync as u,lstatSync as S,mkdirSync as d,readFileSync as g,readdirSync as m,renameSync as f,rmSync as b,symlinkSync as w,writeFileSync as x}from"node:fs";import n from"node:path";import{dataRoots as y,getDataDir as l,getVersionStampPath as D}from"./paths.js";import{WEAVE_VERSION as P}from"../version.js";const h={data:["market","uploads","plugins"],local:["auth.json","ai.json","push.json","initial-password","certs","weave-autostart.vbs"],cache:["logs","statusline","hooks","tmp","daemon.json"]},E="weave.db",j=["hooks","statusline"];export function liveDaemonPid(o=l()){const t=y(o);for(const i of[n.join(t.cache,"daemon.json"),n.join(o,"daemon.json")])try{const s=Number(JSON.parse(g(i,"utf-8")).pid);if(s>0&&F(s))return s}catch{}return null}function F(o){try{return process.kill(o,0),!0}catch{return!1}}function L(o){try{return S(o).isSymbolicLink()}catch{return!1}}function v(o,t){d(t,{recursive:!0});for(const i of m(o,{withFileTypes:!0})){const s=n.join(o,i.name),a=n.join(t,i.name);i.isDirectory()?v(s,a):u(a)||f(s,a)}b(o,{recursive:!0,force:!0})}export function ensureDataLayout(o=l()){const t=migrateDataLayout(o);return t.moved.length>0&&console.log(`[weave] data layout: moved ${t.moved.join(", ")}`),t.kept.length>0&&console.log(`[weave] data layout: kept ${t.kept.join(", ")} (target exists)`),writeVersionStamp(o),t}export function writeVersionStamp(o=l()){try{const t=D(o);d(n.dirname(t),{recursive:!0}),x(t,`${P}
2
+ `,"utf8")}catch{}}export function migrateDataLayout(o=l()){const t={moved:[],kept:[],bridged:[],busyPid:null},i=liveDaemonPid(o);if(i!==null)return t.busyPid=i,t;let s;try{s=m(o)}catch{return t}const a=Object.keys(h),p=y(o);for(const e of s){if(L(n.join(o,e)))continue;const c=a.find(k=>h[k].includes(e))??(e.startsWith(E)?"data":null);if(!c)continue;const r=p[c];if(u(n.join(r,e))&&j.includes(e)){try{v(n.join(o,e),n.join(r,e)),t.moved.push(e)}catch{t.kept.push(e)}continue}if(u(n.join(r,e))){t.kept.push(e);continue}try{d(r,{recursive:!0}),f(n.join(o,e),n.join(r,e)),t.moved.push(e)}catch{t.kept.push(e)}}for(const e of j){const c=n.join(o,e),r=n.join(p.cache,e);if(!(!u(r)||u(c)))try{w(r,c,process.platform==="win32"?"junction":"dir"),t.bridged.push(e)}catch{}}return t}
@@ -59,5 +59,10 @@ export declare function getHooksDir(dir?: string): string;
59
59
  export declare function getStatuslineDir(dir?: string): string;
60
60
  /** 安装等一次性操作的临时区。 */
61
61
  export declare function getTmpDir(dir?: string): string;
62
+ /**
63
+ * 当前 weave 版本的落盘点(daemon 启动时写、statusline 脚本运行时读):
64
+ * 生成物里不内联版本号,发版才不会被判成「文件需要更新」。
65
+ */
66
+ export declare function getVersionStampPath(dir?: string): string;
62
67
  /** 项目文件索引快照(`<projectId>.json`,见 daemon/project-files.ts)。 */
63
68
  export declare function getIndexDir(dir?: string): string;
@@ -1 +1 @@
1
- import n from"node:path";import{detectPlatform as o}from"@weavecode/core";export function getDataDir(){return n.join(o().configDir,"weave")}export function dataRoots(t=getDataDir()){return{data:n.join(t,"data"),local:n.join(t,"local"),cache:n.join(t,"cache")}}export function getDataRoot(t){return dataRoots(t).data}export function getDbPath(t){return n.join(dataRoots(t).data,"weave.db")}export function getPluginsDir(t){return n.join(dataRoots(t).data,"plugins")}export function getUploadsDir(t){return n.join(dataRoots(t).data,"uploads")}export function getPetsDir(t){return n.join(dataRoots(t).data,"pets")}export function getVisualizationsDir(t){return n.join(dataRoots(t).data,"visualizations")}export function getAuthPath(t){return n.join(dataRoots(t).local,"auth.json")}export function getInitialPasswordPath(t){return n.join(dataRoots(t).local,"initial-password")}export function getAiKeyPath(t){return n.join(dataRoots(t).local,"ai.json")}export function getDecisionKeyPath(t){return n.join(dataRoots(t).local,"decision.json")}export function getPushKeysPath(t){return n.join(dataRoots(t).local,"push.json")}export function getHarnessConfigDir(t){return n.join(dataRoots(t).local,"harness-config")}export function getCertsDir(t){return n.join(dataRoots(t).local,"certs")}export function getAutoStartScriptPath(t){return n.join(dataRoots(t).local,"weave-autostart.vbs")}export function getDaemonStatePath(t){return n.join(dataRoots(t).cache,"daemon.json")}export function getLogsDir(t){return n.join(dataRoots(t).cache,"logs")}export function getApiLogsDir(t){return n.join(getLogsDir(t),"api")}export function getHooksDir(t){return n.join(dataRoots(t).cache,"hooks")}export function getStatuslineDir(t){return n.join(dataRoots(t).cache,"statusline")}export function getTmpDir(t){return n.join(dataRoots(t).cache,"tmp")}export function getIndexDir(t){return n.join(dataRoots(t).cache,"index")}
1
+ import n from"node:path";import{detectPlatform as o}from"@weavecode/core";export function getDataDir(){return n.join(o().configDir,"weave")}export function dataRoots(t=getDataDir()){return{data:n.join(t,"data"),local:n.join(t,"local"),cache:n.join(t,"cache")}}export function getDataRoot(t){return dataRoots(t).data}export function getDbPath(t){return n.join(dataRoots(t).data,"weave.db")}export function getPluginsDir(t){return n.join(dataRoots(t).data,"plugins")}export function getUploadsDir(t){return n.join(dataRoots(t).data,"uploads")}export function getPetsDir(t){return n.join(dataRoots(t).data,"pets")}export function getVisualizationsDir(t){return n.join(dataRoots(t).data,"visualizations")}export function getAuthPath(t){return n.join(dataRoots(t).local,"auth.json")}export function getInitialPasswordPath(t){return n.join(dataRoots(t).local,"initial-password")}export function getAiKeyPath(t){return n.join(dataRoots(t).local,"ai.json")}export function getDecisionKeyPath(t){return n.join(dataRoots(t).local,"decision.json")}export function getPushKeysPath(t){return n.join(dataRoots(t).local,"push.json")}export function getHarnessConfigDir(t){return n.join(dataRoots(t).local,"harness-config")}export function getCertsDir(t){return n.join(dataRoots(t).local,"certs")}export function getAutoStartScriptPath(t){return n.join(dataRoots(t).local,"weave-autostart.vbs")}export function getDaemonStatePath(t){return n.join(dataRoots(t).cache,"daemon.json")}export function getLogsDir(t){return n.join(dataRoots(t).cache,"logs")}export function getApiLogsDir(t){return n.join(getLogsDir(t),"api")}export function getHooksDir(t){return n.join(dataRoots(t).cache,"hooks")}export function getStatuslineDir(t){return n.join(dataRoots(t).cache,"statusline")}export function getTmpDir(t){return n.join(dataRoots(t).cache,"tmp")}export function getVersionStampPath(t){return n.join(dataRoots(t).cache,"version")}export function getIndexDir(t){return n.join(dataRoots(t).cache,"index")}
@@ -1 +1 @@
1
- const p=" ";export function composeAnswerAtoms(i,l){if(i.every(e=>e.options.length===0))return{ok:!1,error:"Question face has no answerable options"};const f=new Map(l.map(e=>[e.questionKey,e]));for(const e of f.keys())if(!i.some(s=>s.key===e))return{ok:!1,error:`Unknown question: ${e}`};const n=[];for(const e of i){const s=f.get(e.key),t=(s?.options??[]).map(o=>e.options[o]);if(t.some(o=>!o))return{ok:!1,error:`Invalid option index: ${e.key}`};if(e.submit&&t.length!==1)return{ok:!1,error:"Submit choice required to finish the call"};const c=t.filter(o=>!o.input);if(!e.multiSelect&&c.length>1)return{ok:!1,error:`Single-select question got ${c.length} options: ${e.key}`};const u=s?.text?.trim()??"",r=t.find(o=>o.input);if(r&&!u)return{ok:!1,error:`Text required for this option: ${e.key}`};for(const o of t)n.push(...o.keys);if(r)n.push(...r.textFocus??[],u,...r.textTail??["\r"]);else for(const o of t)n.push(...o.commit??[]);if(e.submit||t.some(o=>o.chat))break;!r&&(e.multiSelect||t.length===0)&&n.push(" ")}return{ok:!0,atoms:n}}
1
+ const p=" ";export function composeAnswerAtoms(i,l){if(i.every(e=>e.options.length===0))return{ok:!1,error:"Question face has no answerable options"};const u=new Map(l.map(e=>[e.questionKey,e]));for(const e of u.keys())if(!i.some(s=>s.key===e))return{ok:!1,error:`Unknown question: ${e}`};const n=[];for(const e of i){const s=u.get(e.key),t=(s?.options??[]).map(o=>e.options[o]);if(t.some(o=>!o))return{ok:!1,error:`Invalid option index: ${e.key}`};if(e.submit&&t.length!==1)return{ok:!1,error:"Submit choice required to finish the call"};const c=t.filter(o=>!o.input);if(!e.multiSelect&&c.length>1)return{ok:!1,error:`Single-select question got ${c.length} options: ${e.key}`};const f=s?.text?.trim()??"",r=t.find(o=>o.input);if(r&&!f)return{ok:!1,error:`Text required for this option: ${e.key}`};for(const o of t)n.push(...o.keys);if(r)n.push(...r.textFocus??[],f,...r.textTail??["\r"]);else for(const o of t)n.push(...o.commit??[]);if(e.submit||t.some(o=>o.chat))break;!r&&(e.multiSelect||t.length===0)&&n.push(" ")}return{ok:!0,atoms:n}}
@@ -1 +1 @@
1
- export const RATE_BUCKET_MS=1e4,RATE_RETAIN_MS=864e5;const h=6e4;export class DashboardRateCache{buckets=new Map;seeded=!1;lastPrune=0;events=0;today=0;dayKey="";get isSeeded(){return this.seeded}record(t=Date.now()){const e=Math.floor(t/1e4)*1e4;this.buckets.set(e,(this.buckets.get(e)??0)+1),this.events+=1;const s=new Date(t).toDateString();s!==this.dayKey&&(this.dayKey=s,this.today!==0&&(this.today=0)),this.today+=1,this.prune(t)}get totals(){return{events:this.events,today:this.today}}seedTotals(t,e){this.events=Math.max(this.events,t),this.today=Math.max(this.today,e),this.dayKey=new Date().toDateString()}recentBuckets(t,e=Date.now()){const a=Math.floor(e/1e4)*1e4-(t-1)*1e4;return Array.from({length:t},(o,n)=>{const r=a+n*1e4;return{at:new Date(r).toISOString().slice(0,19),n:this.buckets.get(r)??0}})}seed(t){const e=new Map;for(const{at:s,n:a}of t){const o=Date.parse(`${s}Z`);if(!Number.isFinite(o))continue;const n=Math.floor(o/1e4)*1e4;e.set(n,(e.get(n)??0)+a)}for(const[s,a]of e)this.buckets.set(s,Math.max(this.buckets.get(s)??0,a));this.seeded=!0}bucketsFor(t,e){return Array.from({length:e},(s,a)=>this.buckets.get(t+a*1e4)??0)}prune(t){if(t-this.lastPrune<6e4)return;this.lastPrune=t;const e=t-864e5;for(const s of this.buckets.keys())s<e&&this.buckets.delete(s)}}
1
+ export const RATE_BUCKET_MS=1e4,RATE_RETAIN_MS=864e5;const h=6e4;export class DashboardRateCache{buckets=new Map;seeded=!1;lastPrune=0;events=0;today=0;dayKey="";get isSeeded(){return this.seeded}record(t=Date.now()){const e=Math.floor(t/1e4)*1e4;this.buckets.set(e,(this.buckets.get(e)??0)+1),this.events+=1;const s=new Date(t).toDateString();s!==this.dayKey&&(this.dayKey=s,this.today!==0&&(this.today=0)),this.today+=1,this.prune(t)}get totals(){return{events:this.events,today:this.today}}seedTotals(t,e){this.events=Math.max(this.events,t),this.today=Math.max(this.today,e),this.dayKey=new Date().toDateString()}recentBuckets(t,e=Date.now()){const s=Math.floor(e/1e4)*1e4-(t-1)*1e4;return Array.from({length:t},(o,a)=>{const n=s+a*1e4;return{at:new Date(n).toISOString().slice(0,19),n:this.buckets.get(n)??0}})}seed(t){const e=new Map;for(const{at:s,n:o}of t){const a=Date.parse(`${s}Z`);if(!Number.isFinite(a))continue;const n=Math.floor(a/1e4)*1e4;e.set(n,(e.get(n)??0)+o)}for(const[s,o]of e)this.buckets.set(s,Math.max(this.buckets.get(s)??0,o));this.seeded=!0}bucketsFor(t,e){return Array.from({length:e},(s,o)=>this.buckets.get(t+o*1e4)??0)}prune(t){if(t-this.lastPrune<6e4)return;this.lastPrune=t;const e=t-864e5;for(const s of this.buckets.keys())s<e&&this.buckets.delete(s)}}
@@ -1 +1 @@
1
- const k=.7,w=.3,b=1e4;export function createDecisionConditionJudge(o){const i=(e,n)=>({...e,source:"decision-model",...n!==null?{detail:`P(yes)=${n}`}:{}}),c=e=>e>=.7?i({ok:!0},e):e<=.3?i({ok:!1,reason:"condition answered no"},e):{ok:!1};return{async judge(e){const n=e.upstream;if(!n)return{...await o.fallback.judge(e),source:"fork"};const r=await o.config();if(!r)return{...await o.fallback.judge(e),source:"fork"};let s=null;try{s=await y(r,e.condition,n,o)}catch{s=null}if(s===null)return{...await o.fallback.judge(e),source:"fork"};const t=c(s);return!t.ok&&t.source!=="decision-model"?{...await o.fallback.judge(e),source:"fork"}:t},async judgeBatch(e){if(!e.upstream)return Promise.all(e.items.map(async t=>({...await o.fallback.judge({sessionId:e.sessionId,condition:t.condition,upstream:null}),source:"fork"})));const n=await o.config();if(!n)return Promise.all(e.items.map(async t=>({...await o.fallback.judge({sessionId:e.sessionId,condition:t.condition,upstream:e.upstream}),source:"fork"})));const r={};for(const t of e.items)r[t.key]={type:"noul",instructions:t.condition};let s=null;try{s=await f(n,r,e.upstream,o)}catch{s=null}return s?Promise.all(e.items.map(async t=>{const a=s[t.key];return typeof a!="number"||!Number.isFinite(a)?{...await o.fallback.judge({sessionId:e.sessionId,condition:t.condition,upstream:e.upstream}),source:"fork"}:c(a)})):Promise.all(e.items.map(async t=>({...await this.judge({sessionId:e.sessionId,condition:t.condition,upstream:e.upstream})})))}}}async function y(o,i,c,e){return(await f(o,{proceed:{type:"noul",instructions:i}},c,e))?.proceed??null}async function f(o,i,c,e){const n=new AbortController,r=setTimeout(()=>n.abort(),e.timeoutMs??1e4);try{const s=await(e.fetchImpl??fetch)(`${o.baseUrl.replace(/\/+$/,"")}/v1/systemone`,{method:"POST",headers:{authorization:`Bearer ${o.apiKey}`,"content-type":"application/json"},body:JSON.stringify({model:o.model,state:c,questions:i}),signal:n.signal});if(!s.ok)return null;const a=(await s.json()).answers;if(!a||typeof a!="object")return null;const l={};for(const[m,d]of Object.entries(a)){const u=d?.noul;typeof u=="number"&&Number.isFinite(u)&&(l[m]=u)}return Object.keys(l).length>0?l:null}finally{clearTimeout(r)}}
1
+ const p=.7,y=.3,k=1e4;export function createDecisionConditionJudge(o){const r=(e,t)=>({...e,source:"decision-model",...t!==null?{detail:`P(yes)=${t}`}:{}}),c=e=>e>=.7?r({ok:!0},e):e<=.3?r({ok:!1,reason:"condition answered no"},e):{ok:!1};return{async judge(e){const t=e.upstream;if(!t)return{...await o.fallback.judge(e),source:"fork"};const a=await o.config();if(!a)return{...await o.fallback.judge(e),source:"fork"};let i=null;try{i=await m(a,e.condition,t,o)}catch{i=null}if(i===null)return{...await o.fallback.judge(e),source:"fork"};const n=c(i);return!n.ok&&n.source!=="decision-model"?{...await o.fallback.judge(e),source:"fork"}:n},async judgeBatch(e){if(!e.upstream)return Promise.all(e.items.map(async n=>({...await o.fallback.judge({sessionId:e.sessionId,condition:n.condition,upstream:null}),source:"fork"})));const t=await o.config();if(!t)return Promise.all(e.items.map(async n=>({...await o.fallback.judge({sessionId:e.sessionId,condition:n.condition,upstream:e.upstream}),source:"fork"})));const a={};for(const n of e.items)a[n.key]={type:"noul",instructions:n.condition};let i=null;try{i=await l(t,a,e.upstream,o)}catch{i=null}return i?Promise.all(e.items.map(async n=>{const s=i[n.key];return typeof s!="number"||!Number.isFinite(s)?{...await o.fallback.judge({sessionId:e.sessionId,condition:n.condition,upstream:e.upstream}),source:"fork"}:c(s)})):Promise.all(e.items.map(async n=>({...await this.judge({sessionId:e.sessionId,condition:n.condition,upstream:e.upstream})})))}}}async function m(o,r,c,e){return(await l(o,{proceed:{type:"noul",instructions:r}},c,e))?.proceed??null}async function l(o,r,c,e){const t=new AbortController,a=setTimeout(()=>t.abort(),e.timeoutMs??1e4);try{const i=await(e.fetchImpl??fetch)(`${o.baseUrl.replace(/\/+$/,"")}/v1/systemone`,{method:"POST",headers:{authorization:`Bearer ${o.apiKey}`,"content-type":"application/json"},body:JSON.stringify({model:o.model,state:c,questions:r}),signal:t.signal});if(!i.ok)return null;const n=(await i.json()).answers;if(!n||typeof n!="object")return null;const s={};for(const[d,f]of Object.entries(n)){const u=f?.noul;typeof u=="number"&&Number.isFinite(u)&&(s[d]=u)}return Object.keys(s).length>0?s:null}finally{clearTimeout(a)}}
@@ -1 +1 @@
1
- import{isImageMediaType as f}from"../../repositories/uploads.js";const p=a=>new Promise(e=>setTimeout(e,a));export class AckGate{store;times;events;isCommandInput;constructor(e,t,s,i=()=>!1){this.store=e,this.times=t,this.events=s,this.isCommandInput=i}open(e){const t=this.store.awaitingAck.get(e);if(t===void 0)return!0;const s=this.store.memory.get(t);return s&&s.acked!==!0&&s.status!=="failed"&&s.status!=="timeout"?!1:(this.store.awaitingAck.delete(e),!0)}awaiting(e){return!this.open(e)}headOf(e){return this.store.awaitingAck.get(e)}await(e,t){this.store.awaitingAck.set(e,t)}release(e,t){if(t===void 0){this.store.awaitingAck.delete(e);return}this.store.awaitingAck.get(e)===t&&this.store.awaitingAck.delete(e)}isStalled(e){return this.store.stalled.has(e)}stallCause(e){return this.store.stalled.get(e)}clearStall(e,t){const s=this.store.stalled.get(e);s&&(t===void 0||s.messageId===t)&&this.store.stalled.delete(e)}armAckWatch(e){setTimeout(()=>{const s=this.store.memory.get(e.id);!s||s.acked||s.status!=="delivered"||this.stall(e.sessionId,s,"unacked")},this.times.ackStallMs).unref?.()}armCommandAck(e,t){setTimeout(()=>{const i=this.store.memory.get(e);!i||i.acked||i.status!=="delivered"||(this.acknowledge_(i.sessionId,e),t(i.sessionId))},this.times.commandAckGraceMs).unref?.()}noteActivity(e){let t=!1;for(const s of this.store.memory.values())s.sessionId!==e||s.acked||s.status!=="delivered"||s.mode!=="prompt"||!this.isCommandInput(e,s.text)||(this.acknowledge_(e,s.id),t=!0);return t}acknowledge_(e,t){const s=this.store.memory.get(t);!s||s.acked||(this.store.memory.set(t,{...s,acked:!0}),this.release(e,t),this.events.emit({kind:"message.acknowledged",messageId:t,sessionId:e,at:new Date().toISOString()}))}stall(e,t,s){this.store.stalled.set(e,{messageId:t.id,reason:s});const i=this.store.memory.get(t.id),n=i&&i.status==="delivered"&&i.acked!==!0?new Date(Date.now()+this.times.ackStallReleaseMs).toISOString():null;i&&this.store.memory.set(t.id,{...i,stalled:!0,releaseAt:n}),this.events.emit({kind:"message.stalled",messageId:t.id,sessionId:e,reason:s,at:new Date().toISOString()}),setTimeout(()=>this.autoRelease(e,t.id),this.times.ackStallReleaseMs).unref?.()}autoRelease(e,t){if(this.store.stalled.get(e)?.messageId!==t)return;const s=this.store.memory.get(t);if(s&&s.status==="delivered"&&s.acked!==!0){this.dropAndRelease(e,t);return}this.store.stalled.delete(e),this.release(e,t),this.onAutoRelease?.(e)}dropAndRelease(e,t){this.store.memory.delete(t),this.store.stalled.delete(e),this.release(e,t),this.events.emit({kind:"message.dismissed",messageId:t,sessionId:e,at:new Date().toISOString()}),this.onAutoRelease?.(e)}onAutoRelease;hitLast=!1;acknowledge(e,t,s,i){const n=normalizePromptText(t),l=n.replace(/\[Image #\d+\]/gi,"").trim(),d=[];let c=!1;this.hitLast=!1;for(const r of[...this.store.memory.values()].reverse()){if(r.sessionId!==e||r.acked||r.mode!=="prompt")continue;const o=normalizePromptText(r.text),u=dropInlineImagePaths(o,r.attachments),h=!!o&&(o.length>=i.ackMinText?n.includes(o)||stripSpace(n).includes(stripSpace(o)):n.endsWith(o)),m=(r.attachments?.length??0)>0&&(u?stripSpace(l).includes(stripSpace(u))||stripSpace(n).includes(stripSpace(o)):l.length===0);!h&&!m||(c=!0,this.store.memory.set(r.id,{...r,acked:!0,stalled:!1,...s===void 0?{}:{ackedEventId:s}}),this.store.stalled.get(e)?.messageId===r.id&&this.store.stalled.delete(e),this.release(e,r.id),d.push(...r.attachments?.map(g=>g.id)??[]),this.events.emit({kind:"message.acknowledged",messageId:r.id,sessionId:e,...s===void 0?{}:{eventId:s},at:new Date().toISOString()}))}return this.hitLast=c,c?d:[]}sessionExited(e){this.release(e)}static sleep=p}export function normalizePromptText(a){return a.replace(/<\/?cross-session-message[^>]*>/g,"").replace(/\s+/g," ").trim()}export function stripSpace(a){return a.replace(/\s+/g,"")}export function dropInlineImagePaths(a,e){const t=(e??[]).filter(s=>s.path&&f(s.mediaType)).map(s=>s.path.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return t.length===0?a:a.replace(new RegExp(t.join("|"),"g"),"")}
1
+ import{isImageMediaType as k}from"../../repositories/uploads.js";const p=a=>new Promise(e=>setTimeout(e,a));export class AckGate{store;times;events;isCommandInput;constructor(e,t,s,o=()=>!1){this.store=e,this.times=t,this.events=s,this.isCommandInput=o}open(e){const t=this.store.awaitingAck.get(e);if(t===void 0)return!0;const s=this.store.memory.get(t);return s&&s.acked!==!0&&s.status!=="failed"&&s.status!=="timeout"?!1:(this.store.awaitingAck.delete(e),!0)}awaiting(e){return!this.open(e)}headOf(e){return this.store.awaitingAck.get(e)}await(e,t){this.store.awaitingAck.set(e,t)}release(e,t){if(t===void 0){this.store.awaitingAck.delete(e);return}this.store.awaitingAck.get(e)===t&&this.store.awaitingAck.delete(e)}isStalled(e){return this.store.stalled.has(e)}stallCause(e){return this.store.stalled.get(e)}clearStall(e,t){const s=this.store.stalled.get(e);s&&(t===void 0||s.messageId===t)&&this.store.stalled.delete(e)}armAckWatch(e){setTimeout(()=>{const t=this.store.memory.get(e.id);!t||t.acked||t.status!=="delivered"||this.stall(e.sessionId,t,"unacked")},this.times.ackStallMs).unref?.()}armCommandAck(e,t){setTimeout(()=>{const s=this.store.memory.get(e);!s||s.acked||s.status!=="delivered"||(this.acknowledge_(s.sessionId,e),t(s.sessionId))},this.times.commandAckGraceMs).unref?.()}noteActivity(e){let t=!1;for(const s of this.store.memory.values())s.sessionId!==e||s.acked||s.status!=="delivered"||s.mode!=="prompt"||!this.isCommandInput(e,s.text)||(this.acknowledge_(e,s.id),t=!0);return t}acknowledge_(e,t){const s=this.store.memory.get(t);!s||s.acked||(this.store.memory.set(t,{...s,acked:!0}),this.release(e,t),this.events.emit({kind:"message.acknowledged",messageId:t,sessionId:e,at:new Date().toISOString()}))}stall(e,t,s){this.store.stalled.set(e,{messageId:t.id,reason:s});const o=this.store.memory.get(t.id),n=o&&o.status==="delivered"&&o.acked!==!0?new Date(Date.now()+this.times.ackStallReleaseMs).toISOString():null;o&&this.store.memory.set(t.id,{...o,stalled:!0,releaseAt:n}),this.events.emit({kind:"message.stalled",messageId:t.id,sessionId:e,reason:s,at:new Date().toISOString()}),setTimeout(()=>this.autoRelease(e,t.id),this.times.ackStallReleaseMs).unref?.()}autoRelease(e,t){if(this.store.stalled.get(e)?.messageId!==t)return;const s=this.store.memory.get(t);if(s&&s.status==="delivered"&&s.acked!==!0){this.dropAndRelease(e,t);return}this.store.stalled.delete(e),this.release(e,t),this.onAutoRelease?.(e)}dropAndRelease(e,t){this.store.memory.delete(t),this.store.stalled.delete(e),this.release(e,t),this.events.emit({kind:"message.dismissed",messageId:t,sessionId:e,at:new Date().toISOString()}),this.onAutoRelease?.(e)}onAutoRelease;hitLast=!1;acknowledge(e,t,s,o){const n=normalizePromptText(t),l=n.replace(/\[Image #\d+\]/gi,"").trim(),m=[];let d=!1;this.hitLast=!1;for(const i of[...this.store.memory.values()].reverse()){if(i.sessionId!==e||i.acked||i.mode!=="prompt")continue;const r=normalizePromptText(i.text),c=dropInlineImagePaths(r,i.attachments),h=!!r&&(r.length>=o.ackMinText?n.includes(r)||stripSpace(n).includes(stripSpace(r)):n.endsWith(r)),g=(i.attachments?.length??0)>0&&(c?stripSpace(l).includes(stripSpace(c))||stripSpace(n).includes(stripSpace(r)):l.length===0);!h&&!g||(d=!0,this.store.memory.set(i.id,{...i,acked:!0,stalled:!1,...s===void 0?{}:{ackedEventId:s}}),this.store.stalled.get(e)?.messageId===i.id&&this.store.stalled.delete(e),this.release(e,i.id),m.push(...i.attachments?.map(u=>u.id)??[]),this.events.emit({kind:"message.acknowledged",messageId:i.id,sessionId:e,...s===void 0?{}:{eventId:s},at:new Date().toISOString()}))}return this.hitLast=d,d?m:[]}sessionExited(e){this.release(e)}static sleep=p}export function normalizePromptText(a){return a.replace(/<\/?cross-session-message[^>]*>/g,"").replace(/\s+/g," ").trim()}export function stripSpace(a){return a.replace(/\s+/g,"")}export function dropInlineImagePaths(a,e){const t=(e??[]).filter(s=>s.path&&k(s.mediaType)).map(s=>s.path.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return t.length===0?a:a.replace(new RegExp(t.join("|"),"g"),"")}
@@ -1 +1 @@
1
- import{spawn as f}from"node:child_process";import{defaultKill as p}from"../headless-runner.js";import{tmpdir as l}from"node:os";import{isImageMediaType as w}from"../../repositories/uploads.js";export function wireTextOf(t,e){const i=t.attachments;return!i||i.length===0?t.text:e(t.sessionId)?.attach?.composePrompt(t.text,i)??t.text}export function hasImages(t){return(t.attachments??[]).some(e=>w(e.mediaType))}export function spawnOnce(t,e,i,r){const u=r??((a,n,o)=>f(a,[...n],o));return new Promise((a,n)=>{const o=u(t,e,{cwd:l(),windowsHide:!0,stdio:["ignore","pipe","pipe"]}),d=[];o.stdout?.on("data",s=>d.push(s)),o.stderr?.on("data",s=>d.push(s));const m=setTimeout(()=>{if(o.pid!==void 0)try{p(o.pid)}catch{}n(new Error(`queue timeout after ${i}ms`))},i);o.on("error",s=>{clearTimeout(m),n(s)}),o.on("exit",s=>{if(clearTimeout(m),s===0){a();return}const c=Buffer.concat(d).toString("utf8").slice(-500);n(new Error(`queue exit ${s}${c?`: ${c}`:""}`))})})}export function settleDelivered(t,e,i){const r={...e,status:"delivered",via:i,settledAt:new Date().toISOString()};return t.setMemory(r),t.awaitAck(e.sessionId,e.id),t.commandModeOf(e.text,e.sessionId)?t.armCommandAck(e.id):t.armAckWatch(r),t.emit({kind:"message.delivered",messageId:e.id,sessionId:e.sessionId,at:new Date().toISOString()}),r}
1
+ import{spawn as p}from"node:child_process";import{defaultKill as f}from"../headless-runner.js";import{tmpdir as l}from"node:os";import{isImageMediaType as w}from"../../repositories/uploads.js";export function wireTextOf(t,e){const o=t.attachments;return!o||o.length===0?t.text:e(t.sessionId)?.attach?.composePrompt(t.text,o)??t.text}export function hasImages(t){return(t.attachments??[]).some(e=>w(e.mediaType))}export function spawnOnce(t,e,o,r){const u=r??((a,n,s)=>p(a,[...n],s));return new Promise((a,n)=>{const s=u(t,e,{cwd:l(),windowsHide:!0,stdio:["ignore","pipe","pipe"]}),d=[];s.stdout?.on("data",i=>d.push(i)),s.stderr?.on("data",i=>d.push(i));const m=setTimeout(()=>{if(s.pid!==void 0)try{f(s.pid)}catch{}n(new Error(`queue timeout after ${o}ms`))},o);s.on("error",i=>{clearTimeout(m),n(i)}),s.on("exit",i=>{if(clearTimeout(m),i===0){a();return}const c=Buffer.concat(d).toString("utf8").slice(-500);n(new Error(`queue exit ${i}${c?`: ${c}`:""}`))})})}export function settleDelivered(t,e,o){const r={...e,status:"delivered",via:o,settledAt:new Date().toISOString()};return t.setMemory(r),t.awaitAck(e.sessionId,e.id),t.commandModeOf(e.text,e.sessionId)?t.armCommandAck(e.id):t.armAckWatch(r),t.emit({kind:"message.delivered",messageId:e.id,sessionId:e.sessionId,at:new Date().toISOString()}),r}