@weavecode/weave 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@weavecode/cli/dist/cli.js +4 -4
- package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
- package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
- package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +5 -3
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -4
- package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
- package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
- package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
- package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
- package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
- package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
- package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
- package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
- package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
- package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
- package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
- package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
- package/node_modules/@weavecode/cli/dist/parser.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
- package/node_modules/@weavecode/cli/package.json +5 -5
- package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
- package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
- package/node_modules/@weavecode/core/dist/harness.js +1 -1
- package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
- package/node_modules/@weavecode/core/dist/index.js +1 -1
- package/node_modules/@weavecode/core/dist/platform.js +1 -1
- package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
- package/node_modules/@weavecode/core/dist/terminal.js +1 -1
- package/node_modules/@weavecode/core/dist/types.d.ts +188 -11
- package/node_modules/@weavecode/core/dist/types.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
- package/node_modules/@weavecode/core/package.json +1 -1
- package/node_modules/@weavecode/harness/dist/claude/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +11 -1
- package/node_modules/@weavecode/harness/dist/claude/capture.js +5 -5
- package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
- package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
- package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
- package/node_modules/@weavecode/harness/dist/claude/index.d.ts +5 -1
- package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
- package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
- package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +25 -0
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
- package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
- package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
- package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
- package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
- package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/toml.js +9 -9
- package/node_modules/@weavecode/harness/dist/driver.d.ts +58 -1
- package/node_modules/@weavecode/harness/dist/driver.js +1 -1
- package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
- package/node_modules/@weavecode/harness/dist/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
- package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
- package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
- package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
- package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
- package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
- package/node_modules/@weavecode/harness/package.json +2 -2
- package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
- package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
- package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
- package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
- package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
- package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +6 -1
- package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
- package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
- package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
- package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/server.d.ts +8 -0
- package/node_modules/@weavecode/server/dist/daemon/server.js +6 -6
- package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +59 -2
- package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
- package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
- package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/db/db.js +20 -2
- package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
- package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
- package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
- package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
- package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
- package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +20 -6
- package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
- package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +171 -13
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
- package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
- package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
- package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
- package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
- package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
- package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
- package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +4 -0
- package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
- package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
- package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
- package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
- package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
- package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
- package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
- package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
- package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
- package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
- package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
- package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
- package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
- package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
- package/node_modules/@weavecode/server/dist/install/global-config.js +2 -2
- package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
- package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
- package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
- package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
- package/node_modules/@weavecode/server/dist/install/installer.js +3 -3
- package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
- package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
- package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
- package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
- package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
- package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
- package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
- package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
- package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
- package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
- package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
- package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
- package/node_modules/@weavecode/server/dist/market/import.js +2 -2
- package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
- package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
- package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
- package/node_modules/@weavecode/server/dist/registry.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
- package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
- package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
- package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
- package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
- package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +17 -4
- package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
- package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
- package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/generator.js +81 -40
- package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +2 -0
- package/node_modules/@weavecode/server/dist/statusline/manager.js +4 -4
- package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
- package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
- package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
- package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
- package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
- package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
- package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
- package/node_modules/@weavecode/server/package.json +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/index-D5WFh77i.css +11 -0
- package/node_modules/@weavecode/server/web/dist/assets/index-DJibaGnJ.js +585 -0
- package/node_modules/@weavecode/server/web/dist/index.html +14 -2
- package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
- package/node_modules/@weavecode/templates/package.json +2 -2
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
- package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
- package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
- package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
- package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
- package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
- package/package.json +6 -6
- package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
- package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),y(
|
|
1
|
+
import{chmodSync as o,existsSync as c,mkdirSync as i,readFileSync as u,renameSync as y,rmSync as m,writeFileSync as p}from"node:fs";import a from"node:path";import{getAiKeyPath as n}from"../db/paths.js";export function readAiKey(t=n()){if(!c(t))return null;try{const r=JSON.parse(u(t,"utf8"));return typeof r.apiKey=="string"&&r.apiKey!==""?r.apiKey:null}catch{return null}}export function writeAiKey(t,r=n()){if(t===null||t===""){m(r,{force:!0});return}i(a.dirname(r),{recursive:!0});const e=`${r}.tmp`;p(e,`${JSON.stringify({apiKey:t},null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),y(e,r);try{o(r,384)}catch{}}export function hasAiKey(t=n()){return readAiKey(t)!==null}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`),
|
|
1
|
+
import{existsSync as d,readdirSync as h,readFileSync as S}from"node:fs";import c from"node:path";import{builtinMarketDir as b}from"../market/builtin.js";const p=6e4,w=40,y=6;export function findDocsDir(r){let t=c.resolve(r);for(let n=0;n<y;n++){const s=c.join(t,"docs");if(d(c.join(s,"FEATURES.md")))return s;const i=c.dirname(t);if(i===t)break;t=i}return null}export function collectSkillFiles(r,t=w){const n=[],s=(i,a)=>{if(n.length>=t||a>6)return;let u;try{u=h(i,{withFileTypes:!0})}catch{return}for(const l of u){if(n.length>=t)return;const e=c.join(i,l.name);l.isDirectory()?s(e,a+1):l.name==="SKILL.md"&&n.push(e)}};return s(r,0),n.sort()}function m(r){try{return S(r,"utf8")}catch{return null}}export function buildSystemPrompt(r){const t=[],n=findDocsDir(r.cwd??process.cwd());if(n)for(const e of["ARCHITECTURE.md","FEATURES.md"]){const o=c.join(n,e);if(!d(o))continue;const f=m(o);f&&t.push({label:`docs/${e}`,text:f})}const s=b(r.dataDir);for(const e of collectSkillFiles(s)){const o=m(e);o&&t.push({label:c.relative(s,e).split(c.sep).join("/"),text:o})}const i=["\u4F60\u662F weave \u63A7\u5236\u53F0\u5185\u7F6E\u7684 AI \u52A9\u624B\uFF0C**\u53EA\u8D1F\u8D23 weave \u672C\u8EAB**\uFF1A\u5B83\u7684\u529F\u80FD\u3001\u7528\u6CD5\u3001\u914D\u7F6E\u3001\u67B6\u6784\u3001","\u5185\u7F6E\u6280\u80FD\uFF0C\u4EE5\u53CA\u57FA\u4E8E\u4E0B\u9762\u6CE8\u5165\u8D44\u6599\u7684\u6392\u969C\u3002","","\u56DE\u7B54\u8303\u56F4\uFF08\u8D8A\u754C\u7684\u60C5\u51B5\u4E00\u5F8B\u793C\u8C8C\u62D2\u7B54\uFF1A\u7528\u4E00\u53E5\u8BDD\u8BF4\u660E\u4F60\u53EA\u804A weave\uFF0C\u7136\u540E\u628A\u8BDD\u9898\u5F15\u56DE weave\uFF09\uFF1A","- \u53EF\u4EE5\u7B54\uFF1Aweave \u7684\u80FD\u529B\u4E0E\u64CD\u4F5C\uFF08\u547D\u4EE4\u3001\u8BBE\u7F6E\u9879\u3001\u6587\u4EF6\u843D\u70B9\u3001\u63D2\u4EF6/\u6280\u80FD/\u5E02\u573A\u3001hooks\u3001\u4F1A\u8BDD\u4E0E\u4EFB\u52A1\u3001\u8BA4\u8BC1\u7B49\uFF09\uFF0C"," \u4EE5\u53CA\u6CE8\u5165\u8D44\u6599\u91CC\u80FD\u67E5\u5230\u7684\u4E8B\u5B9E\uFF1B","- \u4E0D\u8981\u7B54\uFF1A\u4E0E weave \u65E0\u5173\u7684\u901A\u7528\u7F16\u7A0B\u3001\u5199\u4F5C\u3001\u7FFB\u8BD1\u3001\u95F2\u804A\uFF0C\u5176\u5B83\u4EA7\u54C1\u6216\u670D\u52A1\uFF0C\u4EE5\u53CA\u4EFB\u4F55\u6709\u5BB3\u6216\u8D8A\u754C\u7684\u8BF7\u6C42\uFF1B","- \u8D44\u6599\u672A\u8986\u76D6\u65F6\u660E\u786E\u8BF4\u300C\u4E0D\u786E\u5B9A\u300D\uFF0C\u4E0D\u8981\u7F16\u9020 weave \u7684\u884C\u4E3A\u3001\u547D\u4EE4\u6216\u53C2\u6570\uFF1B","- \u4E0D\u7C98\u8D34\u5927\u6BB5\u6CE8\u5165\u8D44\u6599\u539F\u6587\uFF08\u7528\u6237\u70B9\u540D\u8981\u67D0\u4E00\u6BB5\u65F6\u9664\u5916\uFF09\uFF1B","- \u53EA\u505A\u53EA\u8BFB\u95EE\u7B54\uFF1A\u4E0D\u58F0\u79F0\u5DF2\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\uFF0C\u4E5F\u4E0D\u627F\u8BFA\u4EE3\u66FF\u7528\u6237\u53BB\u6539\u6587\u4EF6\u6216\u8DD1\u547D\u4EE4\u3002","","\u56DE\u7B54\u4F7F\u7528\u4E0E\u63D0\u95EE\u76F8\u540C\u7684\u8BED\u8A00\uFF1B\u6D89\u53CA\u64CD\u4F5C\u65F6\u7ED9\u51FA\u786E\u5207\u547D\u4EE4\u4E0E\u8DEF\u5F84\u3002"].join(`
|
|
2
|
+
`),a=[];let u=i.length;const l=[];for(const e of t){const o=`
|
|
3
3
|
|
|
4
|
-
## \u6CE8\u5165\u8D44\u6599\uFF1A${
|
|
4
|
+
## \u6CE8\u5165\u8D44\u6599\uFF1A${e.label}
|
|
5
5
|
|
|
6
|
-
${
|
|
6
|
+
${e.text}`;if(u+o.length>p){const f=p-u;f>500&&(a.push(`
|
|
7
7
|
|
|
8
|
-
## \u6CE8\u5165\u8D44\u6599\uFF1A${
|
|
8
|
+
## \u6CE8\u5165\u8D44\u6599\uFF1A${e.label}\uFF08\u6309\u9884\u7B97\u622A\u65AD\uFF09
|
|
9
9
|
|
|
10
|
-
${
|
|
10
|
+
${e.text.slice(0,f)}`),l.push(`${e.label}(\u622A\u65AD)`));break}u+=o.length,a.push(o),l.push(e.label)}return{prompt:i+a.join(""),labels:l,docsFound:n!==null}}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{getDataDir as
|
|
1
|
+
import{getDataDir as I}from"../db/paths.js";import{DEFAULT_AI_SETTINGS as v,readDaemonSettings as N}from"./settings.js";import{hasAiKey as J,readAiKey as O}from"./ai-config.js";import{buildSystemPrompt as P,findDocsDir as j}from"./ai-context.js";import{readJson as k,sendJson as f}from"./http.js";const z=12e4,C=15e3,G=500,L=40,R=2e4;export function normalizeMessages(r){if(!Array.isArray(r)||r.length===0||r.length>L)return null;const e=[];for(const t of r){const o=t;if(o?.role!=="user"&&o?.role!=="assistant")return null;const a=o.content;if(typeof a!="string"||a===""||a.length>R)return null;e.push({role:o.role,content:a})}return e}export function aiConfigured(r,e,t){return r!==""&&e!==""&&t}export async function handleAiRoutes(r,e,t,o){if(o!=="/ai"&&!o.startsWith("/ai/"))return!1;const n=(await N()).ai??v,p=J(t.aiKeyPath);if(o==="/ai/status"&&r.method==="GET")return f(e,200,{configured:aiConfigured(n.baseUrl,n.model,p),baseUrl:n.baseUrl,model:n.model,apiKeySet:p,docsFound:j(process.cwd())!==null}),!0;if(o==="/ai/models"&&r.method==="POST"){let i;try{i=await k(r)}catch{return f(e,400,{error:"Invalid JSON body"}),!0}const u=typeof i.baseUrl=="string"&&i.baseUrl.trim()!==""?i.baseUrl.trim():n.baseUrl,m=typeof i.apiKey=="string"&&i.apiKey!==""?i.apiKey:O(t.aiKeyPath);if(u===""||m===null)return f(e,409,{error:"AI assistant is not configured"}),!0;const l=await B(u,m);return l.ok?(f(e,200,{models:l.models}),!0):(f(e,502,{error:l.error}),!0)}if(o==="/ai/chat"&&r.method==="POST"){const i=O(t.aiKeyPath);if(!aiConfigured(n.baseUrl,n.model,p)||i===null)return f(e,409,{error:"AI assistant is not configured"}),!0;let u;try{u=await k(r)}catch{return f(e,400,{error:"Invalid JSON body"}),!0}const m=normalizeMessages(u.messages);if(!m)return f(e,400,{error:"Invalid messages"}),!0;const l=P({dataDir:t.libraries?.dataDir??I()});return await X({req:r,res:e,baseUrl:n.baseUrl,model:n.model,apiKey:i,messages:m,system:l.prompt}),!0}return f(e,404,{error:"Not found"}),!0}function A(r){const t=r?.choices?.[0],o=t?.delta?.content??t?.message?.content;return typeof o=="string"&&o!==""?o:null}export const STREAM_MEMO_TTL_MS=1440*60*1e3;const S=new Map;export function streamMemoKey(r,e){return`${r}#${e}`}export function streamSupported(r,e=Date.now()){const t=S.get(r);return!t||e-t.checkedAt>STREAM_MEMO_TTL_MS?!0:t.streaming}export function rememberStreamSupport(r,e,t=Date.now()){const o=S.get(r);o!==void 0&&o.streaming!==e&&console.log(`[weave] ai gateway ${e?"supports":"rejects"} streaming: ${r}`),S.set(r,{streaming:e,checkedAt:t})}export function resetStreamMemory(){S.clear()}async function B(r,e){try{const t=await fetch(`${r.replace(/\/+$/,"")}/models`,{headers:{authorization:`Bearer ${e}`},signal:AbortSignal.timeout(C)});if(!t.ok){const n=await t.text().catch(()=>"");return{ok:!1,error:`upstream ${t.status}${n?`: ${n.slice(0,200)}`:""}`}}const o=await t.json().catch(()=>null),a=[...new Set((o?.data??[]).map(n=>n?.id).filter(n=>typeof n=="string"&&n!==""))].sort();return a.length===0?{ok:!1,error:"upstream returned no models"}:{ok:!0,models:a.slice(0,G)}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}async function E(r){try{const e=await fetch(r.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.apiKey}`},body:JSON.stringify({model:r.model,stream:!1,messages:r.messages}),signal:r.signal});if(!e.ok){const o=await e.text().catch(()=>"");return{ok:!1,error:`upstream ${e.status}${o?`: ${o.slice(0,300)}`:""}`}}const t=A(await e.json().catch(()=>null));return t===null?{ok:!1,error:"upstream returned no content"}:{ok:!0,content:t}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function X(r){const{req:e,res:t,baseUrl:o,model:a,apiKey:n,messages:p,system:i}=r,u=`${o.replace(/\/+$/,"")}/chat/completions`,m=[{role:"system",content:i},...p],l=new AbortController,_=setTimeout(()=>l.abort(),z);e.on("close",()=>l.abort()),t.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"});let b=!1;const d=s=>{if(!b)try{t.write(`data: ${JSON.stringify(s)}
|
|
2
2
|
|
|
3
|
-
`)}catch{}},
|
|
3
|
+
`)}catch{}},K=()=>{if(!b){b=!0;try{t.write(`data: {"done":true}
|
|
4
4
|
|
|
5
|
-
`),
|
|
6
|
-
`))>=0;){const
|
|
5
|
+
`),t.end()}catch{}}},g=streamMemoKey(u,a),M={url:u,apiKey:n,model:a,messages:m,signal:l.signal};try{if(!streamSupported(g)){const c=await E(M);c.ok?d({delta:c.content}):d({error:c.error});return}const s=await fetch(u,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${n}`},body:JSON.stringify({model:a,stream:!0,messages:m}),signal:l.signal});if(!s.ok||!s.body){const c=await s.text().catch(()=>""),h=await E(M);h.ok?(rememberStreamSupport(g,!1),d({delta:h.content})):d({error:`upstream ${s.status}${c?`: ${c.slice(0,300)}`:""}`});return}if(!(s.headers.get("content-type")??"").includes("text/event-stream")){const c=A(await s.json().catch(()=>null));rememberStreamSupport(g,!1),d(c===null?{error:"upstream returned no content"}:{delta:c});return}rememberStreamSupport(g,!0);const U=s.body.getReader(),D=new TextDecoder;let y="";for(;;){const{done:c,value:h}=await U.read();if(c)break;y+=D.decode(h,{stream:!0});let w;for(;(w=y.indexOf(`
|
|
6
|
+
`))>=0;){const $=y.slice(0,w).trim();if(y=y.slice(w+1),!$.startsWith("data:"))continue;const T=$.slice(5).trim();if(T==="[DONE]")return;try{const x=A(JSON.parse(T));x!==null&&d({delta:x})}catch{}}}}catch(s){d({error:s instanceof Error?s.message:String(s)})}finally{clearTimeout(_),K()}}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
/** 保留的小时文件数(= 24 小时)。 */
|
|
3
|
+
export declare const MAX_LOG_FILES = 24;
|
|
4
|
+
export interface ApiLogEntry {
|
|
5
|
+
ts: string;
|
|
6
|
+
method: string;
|
|
7
|
+
path: string;
|
|
8
|
+
status: number;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
ip: string;
|
|
11
|
+
ua?: string;
|
|
12
|
+
req?: unknown;
|
|
13
|
+
res?: unknown;
|
|
14
|
+
resBytes?: number;
|
|
15
|
+
stream?: boolean;
|
|
16
|
+
aborted?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ApiLogQuery {
|
|
19
|
+
from?: string;
|
|
20
|
+
to?: string;
|
|
21
|
+
path?: string;
|
|
22
|
+
method?: string;
|
|
23
|
+
status?: number;
|
|
24
|
+
limit?: number;
|
|
25
|
+
}
|
|
26
|
+
/** 本地小时戳文件名:`api-YYYY-MM-DDTHH.jsonl`。 */
|
|
27
|
+
export declare function logFileFor(dir: string, at: Date): string;
|
|
28
|
+
export declare function noteRequestBody(req: IncomingMessage, text: string): void;
|
|
29
|
+
export declare class ApiLogger {
|
|
30
|
+
private readonly dir;
|
|
31
|
+
private chain;
|
|
32
|
+
constructor(opts?: {
|
|
33
|
+
dir?: string;
|
|
34
|
+
});
|
|
35
|
+
/** 挂上计时与响应捕获;响应收尾(finish/abort)即落一行。 */
|
|
36
|
+
begin(req: IncomingMessage, res: ServerResponse): void;
|
|
37
|
+
/** 落盘恒异步:串行链保序,失败静默(日志不打扰请求路径)。 */
|
|
38
|
+
private write;
|
|
39
|
+
/** 只留最近 MAX_LOG_FILES 个小时文件(按文件名小时序)。 */
|
|
40
|
+
private purge;
|
|
41
|
+
/** 测试/关停用:等在写的链落地。 */
|
|
42
|
+
onIdle(): Promise<void>;
|
|
43
|
+
/** 只读查询:按小时文件倒序扫,过滤后截到 limit。 */
|
|
44
|
+
query(q: ApiLogQuery): Promise<{
|
|
45
|
+
entries: ApiLogEntry[];
|
|
46
|
+
files: number;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{appendFile as F,mkdir as L,readdir as T,readFile as N,rm as j}from"node:fs/promises";import g from"node:path";import{getApiLogsDir as x}from"../db/paths.js";const w=8*1024,C=2e3,b=50,D=6;export const MAX_LOG_FILES=24;const I=200,O=1e3,H=new Set(["password","apikey","token","secret","authorization","cookie","x-weave-local"]);function y(n,t=0){if(typeof n=="string")return n.length>C?`[truncated ${n.length} chars]`:n;if(Array.isArray(n)){if(t>=D)return"[depth-limited]";const e=n.slice(0,b).map(i=>y(i,t+1));return n.length>b&&e.push(`[truncated ${n.length-b} items]`),e}if(n&&typeof n=="object"){if(t>=D)return"[depth-limited]";const e={};for(const[i,a]of Object.entries(n))e[i]=H.has(i.toLowerCase())?"[redacted]":y(a,t+1);return e}return n}function M(n,t){if(t>w)return`[truncated body ${t} bytes]`;try{return y(JSON.parse(n))}catch{return y(n)}}export function logFileFor(n,t){const e=a=>String(a).padStart(2,"0"),i=`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}T${e(t.getHours())}`;return g.join(n,`api-${i}.jsonl`)}function _(n){const t=g.basename(n).match(/^api-(\d{4}-\d{2}-\d{2}T\d{2})\.jsonl$/);return t?t[1]:null}const E=new WeakMap;export function noteRequestBody(n,t){E.get(n)?.(t)}export class ApiLogger{dir;chain=Promise.resolve();constructor(t={}){this.dir=t.dir??x()}begin(t,e){const i=Date.now(),a=[];let u=0,c=0,d="",h=0,l=!1;E.set(t,r=>{d=r,h=Buffer.byteLength(r,"utf8")});const f=r=>{const o=Buffer.isBuffer(r)?r:Buffer.from(typeof r=="string"?r:String(r??""),"utf8");if(c+=o.length,u<w){const s=o.subarray(0,w-u);a.push(s),u+=s.length}},m=e.write.bind(e),$=e.end.bind(e);let A="";const B=e.writeHead.bind(e);e.writeHead=((...r)=>{const o=r[1];if(o&&typeof o=="object"&&!Array.isArray(o)){const s=o,p=s["content-type"]??s["Content-Type"];typeof p=="string"&&(A=p)}return B(...r)}),e.write=((r,...o)=>(f(r),m(r,...o))),e.end=((r,...o)=>(typeof r!="function"&&r!=null&&f(r),$(r,...o)));const S=()=>{if(l)return;l=!0;const o=(String(e.getHeader("content-type")??"")||A).includes("event-stream"),s={ts:new Date(i).toISOString(),method:t.method??"GET",path:t.url??"/",status:e.statusCode,durationMs:Date.now()-i,ip:(t.socket?.remoteAddress??"").replace(/^::ffff:/,""),resBytes:c},p=t.headers["user-agent"];typeof p=="string"&&p&&(s.ua=p.slice(0,120)),h&&(s.req=M(d,h)),o?s.stream=!0:c&&(s.res=M(Buffer.concat(a).toString("utf8"),c)),e.writableEnded||(s.aborted=!0),this.write(logFileFor(this.dir,new Date(i)),`${JSON.stringify(s)}
|
|
2
|
+
`)};e.on("finish",S),e.on("close",S)}write(t,e){this.chain=this.chain.then(async()=>{try{await L(this.dir,{recursive:!0}),await F(t,e,"utf8"),await this.purge()}catch{}})}async purge(){const t=(await T(this.dir)).filter(e=>_(e)!=null);if(!(t.length<=MAX_LOG_FILES)){t.sort();for(const e of t.slice(0,t.length-MAX_LOG_FILES))await j(g.join(this.dir,e),{force:!0})}}onIdle(){return this.chain}async query(t){const e=(await T(this.dir).catch(()=>[])).filter(d=>_(d)!=null).sort().reverse(),i=Math.min(Math.max(t.limit??I,1),O),a=t.from?Date.parse(t.from):NaN,u=t.to?Date.parse(t.to):NaN,c=[];for(const d of e){if(c.length>=i)break;const h=await N(g.join(this.dir,d),"utf8").catch(()=>"");for(const l of h.split(`
|
|
3
|
+
`).reverse()){if(!l.trim())continue;let f;try{f=JSON.parse(l)}catch{continue}const m=Date.parse(f.ts);if(!(Number.isFinite(a)&&m<a)&&!(Number.isFinite(u)&&m>u)&&!(t.status!=null&&f.status!==t.status)&&!(t.method&&f.method.toUpperCase()!==t.method.toUpperCase())&&!(t.path&&!f.path.includes(t.path))&&(c.push(f),c.length>=i))break}}return{entries:c,files:e.length}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{clearedSessionCookie as
|
|
1
|
+
import{clearedSessionCookie as c,sessionCookie as h}from"./dashboard-auth.js";import{readJson as i,sendJson as r}from"./http.js";const l=300,n=6,f=e=>new Promise(t=>setTimeout(t,e));export async function handleAuthRoutes(e,t,d,u){if(u!=="/auth"&&!u.startsWith("/auth/"))return!1;const o=d.auth;if(!o)return r(t,503,{error:"Auth subsystem unavailable"}),!0;if(u==="/auth/status"&&e.method==="GET")return r(t,200,{passwordSet:o.isPasswordSet(),authenticated:o.isAuthenticated(e.headers)}),!0;if(u==="/auth/login"&&e.method==="POST"){let s;try{s=await i(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const a=typeof s.password=="string"?s.password:"";return!a||!o.verifyPassword(a)?(await f(l),r(t,401,{error:"Invalid password"}),!0):(t.setHeader("set-cookie",h(o.issueSession())),r(t,200,{ok:!0}),!0)}if(u==="/auth/logout"&&e.method==="POST")return t.setHeader("set-cookie",c()),r(t,200,{ok:!0}),!0;if(u==="/auth/password"&&e.method==="PUT"){if(!o.isLocallyTrusted(e.headers))return r(t,401,{error:"Unauthorized (local token required)"}),!0;let s;try{s=await i(e)}catch{return r(t,400,{error:"Invalid JSON body"}),!0}const a=typeof s.next=="string"?s.next:"";return a.length<n?(r(t,400,{error:`Password must be at least ${n} characters`}),!0):(o.setPassword(a),r(t,200,{ok:!0}),!0)}return r(t,404,{error:"Not found"}),!0}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{spawnSync as u}from"node:child_process";import{fileURLToPath as
|
|
2
|
-
CreateObject("WScript.Shell").Run "${
|
|
3
|
-
`),
|
|
1
|
+
import{spawnSync as u}from"node:child_process";import{fileURLToPath as l}from"node:url";import{mkdirSync as a,writeFileSync as i,unlinkSync as s}from"node:fs";import{homedir as m}from"node:os";import r from"node:path";import{getDataDir as p}from"../db/paths.js";import{readDaemonSettingsSync as f}from"./settings.js";const o="weave-daemon",c="HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";export function relaunchArgs(){return[process.execPath,...process.execArgv.map(t=>{if(t!=="tsx"&&!t.startsWith("tsx/"))return t;try{return l(import.meta.resolve(t))}catch{return t}}),r.resolve(process.argv[1]??process.argv[0])]}function d(t){return{platform:t.platform??process.platform,dataDir:t.dataDir??p(),home:t.home??m(),run:t.run??((e,n)=>({status:u(e,n,{stdio:"ignore"}).status}))}}function h(t){return t.map(e=>`"${e}"`).join(" ")}function y(t){const e=r.join(t.dataDir,"weave-autostart.vbs");a(t.dataDir,{recursive:!0});const n=h(relaunchArgs());i(e,`' Generated by weave \u2014 daemon auto-start. Do not edit.
|
|
2
|
+
CreateObject("WScript.Shell").Run "${n.replace(/"/g,'""')}", 0, False
|
|
3
|
+
`),t.run("reg",["add",c,"/v",o,"/t","REG_SZ","/d",`wscript.exe "${e}"`,"/f"])}function g(t){t.run("reg",["delete",c,"/v",o,"/f"]);try{s(r.join(t.dataDir,"weave-autostart.vbs"))}catch{}}function v(t){const e=n=>n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");return`<?xml version="1.0" encoding="UTF-8"?>
|
|
4
4
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
5
5
|
<plist version="1.0">
|
|
6
6
|
<dict>
|
|
7
7
|
<key>Label</key><string>com.weave.daemon</string>
|
|
8
8
|
<key>ProgramArguments</key>
|
|
9
9
|
<array>
|
|
10
|
-
`+
|
|
10
|
+
`+t.map(n=>` <string>${e(n)}</string>`).join(`
|
|
11
11
|
`)+`
|
|
12
12
|
</array>
|
|
13
13
|
<key>RunAtLoad</key><true/>
|
|
14
14
|
</dict>
|
|
15
15
|
</plist>
|
|
16
|
-
`}function w(
|
|
17
|
-
`))}function
|
|
16
|
+
`}function w(t){const e=r.join(t.home,"Library","LaunchAgents","com.weave.daemon.plist");a(r.dirname(e),{recursive:!0}),i(e,v(relaunchArgs())),t.run("launchctl",["unload",e]),t.run("launchctl",["load",e])}function L(t){const e=r.join(t.home,"Library","LaunchAgents","com.weave.daemon.plist");t.run("launchctl",["unload",e]);try{s(e)}catch{}}function D(t){return t.map(e=>/[\s"]/.test(e)?`"${e}"`:e).join(" ")}function b(t){const e=r.join(t.home,".config","autostart",`${o}.desktop`);a(r.dirname(e),{recursive:!0}),i(e,["[Desktop Entry]","Type=Application","Name=weave daemon",`Exec=${D(relaunchArgs())}`,"X-GNOME-Autostart-enabled=true",""].join(`
|
|
17
|
+
`))}function k(t){try{s(r.join(t.home,".config","autostart",`${o}.desktop`))}catch{}}export function applyLaunchOnLogin(t,e={}){try{const n=d(e);n.platform==="win32"?t?y(n):g(n):n.platform==="darwin"?t?w(n):L(n):t?b(n):k(n)}catch(n){console.error(`[weave] auto-start ${t?"enable":"disable"} failed:`,n)}}export function syncLaunchOnLogin(t={}){const e=f().startup;applyLaunchOnLogin(e?.launchOnLogin??!1,t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as
|
|
1
|
+
import{z as n}from"zod";import{isHarness as f}from"@weavecode/core";import{WEAVE_VERSION as p}from"../version.js";import{readJson as d,sendJson as s}from"./http.js";import{captureSurfaces as i}from"../surfaces.js";const l=n.object({harness:n.string(),enabled:n.boolean()});export async function handleCaptureRoutes(o,t,u,c){if(c!=="/capture")return!1;if(o.method==="GET"){const e=await Promise.all(i().map(async({harness:a,surface:r})=>({harness:a,...await r.readUserCapture()})));return s(t,200,{rows:e}),!0}if(o.method==="PUT"){let e;try{e=l.parse(await d(o))}catch(r){return s(t,400,{error:r instanceof Error?r.message:"Invalid body"}),!0}if(!f(e.harness))return s(t,400,{error:`Unknown harness: ${e.harness}`}),!0;const a=i().find(r=>r.harness===e.harness);if(!a)return s(t,400,{error:`No capture surface for harness: ${e.harness}`}),!0;try{if(e.enabled){await a.surface.installUserCapture({version:p});for(const r of u.projects.list())await a.surface.stripProjectCapture(r.path)}else await a.surface.uninstallUserCapture();u.dataBus?.emit({key:"capture"}),s(t,200,{harness:a.harness,...await a.surface.readUserCapture()})}catch(r){s(t,400,{error:r instanceof Error?r.message:"Capture update failed"})}return!0}return s(t,405,{error:"Method not allowed"}),!0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdirSync as
|
|
1
|
+
import{readdirSync as c,readFileSync as l}from"node:fs";import{join as u}from"node:path";export function parseClaudeSessionReg(e){let t;try{t=JSON.parse(e)}catch{return null}const n=t;return typeof n?.pid!="number"||!Number.isInteger(n.pid)||n.pid<0||typeof n.sessionId!="string"||!n.sessionId?null:{pid:n.pid,sessionId:n.sessionId}}export function pidAlive(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function a(){const e=process.platform==="win32"?process.env.USERPROFILE:process.env.HOME;return e?u(e,".claude","sessions"):null}export const CLAUDE_REG_GRACE_MS=9e4;export function pidAliveOf(e,t,n=Date.now()){const r=t.get(e.sessionId);if(r!==void 0)return r;if(e.harness!=="claude"||e.lastEventType==="SessionStart"&&(e.eventCount??0)<=1)return null;const s=Date.parse(e.lastSeenAt);return!Number.isFinite(s)||n-s<CLAUDE_REG_GRACE_MS?null:!1}export function claudeLivenessById(e=null){const t=e??a(),n=new Map;if(!t)return n;let r;try{r=c(t)}catch{return n}for(const s of r){if(!/^\d+\.json$/.test(s))continue;let o;try{o=l(u(t,s),"utf8")}catch{continue}const i=parseClaudeSessionReg(o);i&&n.set(i.sessionId,pidAlive(i.pid))}return n}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createHmac as d,randomBytes as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),P(e,
|
|
1
|
+
import{createHmac as d,randomBytes as s,randomInt as m,scryptSync as o,timingSafeEqual as w}from"node:crypto";import{chmodSync as g,existsSync as p,mkdirSync as a,readFileSync as y,renameSync as P,rmSync as x,writeFileSync as c}from"node:fs";import h from"node:path";import{getAuthPath as k,getInitialPasswordPath as A}from"../db/paths.js";export const SESSION_COOKIE="weave_session",LOCAL_TOKEN_HEADER="x-weave-local",SESSION_TTL_MS=720*60*60*1e3;const u=64,T=16,l="abcdefghjkmnpqrstuvwxyz23456789";export function generatePassword(){const r=()=>Array.from({length:4},()=>l[m(l.length)]??"a").join("");return[r(),r(),r(),r()].join("-")}function f(r,t){const e=s(T).toString("hex");return{algo:"scrypt",salt:e,hash:o(r,e,u).toString("hex"),updatedAt:t}}function i(r,t){const e=Buffer.from(r),n=Buffer.from(t);return e.length===n.length&&w(e,n)}export function readCookie(r,t){if(r)for(const e of r.split(";")){const n=e.indexOf("=");if(!(n<0)&&e.slice(0,n).trim()===t)return e.slice(n+1).trim()}}export function sessionCookie(r){return`${SESSION_COOKIE}=${r}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${Math.floor(SESSION_TTL_MS/1e3)}`}export function clearedSessionCookie(){return`${SESSION_COOKIE}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`}function O(r){if(!p(r))return null;try{const t=JSON.parse(y(r,"utf8"));return t?.version!==1||typeof t.sessionSecret!="string"||typeof t.localToken!="string"?null:{version:1,password:t.password??null,sessionSecret:t.sessionSecret,localToken:t.localToken,createdAt:typeof t.createdAt=="string"?t.createdAt:new Date().toISOString()}}catch{return null}}function S(r,t){a(h.dirname(r),{recursive:!0});const e=`${r}.tmp`;c(e,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),P(e,r);try{g(r,384)}catch{}}export class AuthService{file;authPath;markerPath;now;initialPassword;constructor(t={}){this.authPath=t.authPath??k(),this.markerPath=t.initialPasswordPath??A(),this.now=t.now??Date.now;const e=O(this.authPath);if(e){this.file=e,this.initialPassword=null;return}const n=generatePassword();this.file={version:1,password:f(n,this.nowIso()),sessionSecret:s(32).toString("hex"),localToken:s(24).toString("hex"),createdAt:this.nowIso()},S(this.authPath,this.file),this.writeMarker(n),this.initialPassword=n}isPasswordSet(){return this.file.password!==null}verifyPassword(t){const e=this.file.password;return e?i(o(t,e.salt,u).toString("hex"),e.hash):!1}setPassword(t){this.file={...this.file,password:f(t,this.nowIso()),sessionSecret:s(32).toString("hex")},S(this.authPath,this.file),x(this.markerPath,{force:!0})}getLocalToken(){return this.file.localToken}verifyLocalToken(t){return typeof t=="string"&&t!==""&&i(t,this.file.localToken)}issueSession(){const t=this.now()+SESSION_TTL_MS;return`${t}.${this.sign(t)}`}verifySession(t){if(!t)return!1;const e=t.indexOf(".");if(e<=0)return!1;const n=Number(t.slice(0,e));return!Number.isFinite(n)||n<=this.now()?!1:i(t.slice(e+1),this.sign(n))}isAuthenticated(t){return this.isLocallyTrusted(t)?!0:this.verifySession(readCookie(t.cookie,SESSION_COOKIE))}isLocallyTrusted(t){const e=t[LOCAL_TOKEN_HEADER];return this.verifyLocalToken(typeof e=="string"?e:void 0)}sign(t){return d("sha256",this.file.sessionSecret).update(`weave-session:${t}`).digest("hex")}nowIso(){return new Date(this.now()).toISOString()}writeMarker(t){a(h.dirname(this.markerPath),{recursive:!0}),c(this.markerPath,`${t}
|
|
3
3
|
`,{encoding:"utf8",mode:384})}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as
|
|
1
|
+
import{EventEmitter as t}from"node:events";export class DataBus{emitter=new t;subscribers=0;constructor(){this.emitter.setMaxListeners(100)}emit(s){this.emitter.emit("change",s)}hasSubscribers(){return this.subscribers>0}subscribe(s){return this.subscribers+=1,this.emitter.on("change",s),()=>{this.subscribers-=1,this.emitter.off("change",s)}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ee from"node:http";import{openDatabase as se}from"../db/db.js";import{ProjectRepository as oe}from"../repositories/projects.js";import{HookEventRepository as te}from"../repositories/hook-events.js";import{LibraryRepository as re}from"../repositories/libraries.js";import{HookRuleRepository as G}from"../repositories/hook-rules.js";import{HookDispatchRepository as ne}from"../repositories/hook-dispatches.js";import{PluginStateRepository as v}from"../repositories/plugin-states.js";import{SessionRepository as ie}from"../repositories/sessions.js";import{createRuntimeRegistry as ae}from"@weavecode/harness";import{TERMINAL_LOCATOR_ENV_KEYS as le}from"@weavecode/core";import{HookRuleRegistry as ce}from"../hooks/registry.js";import{HookDispatcher as pe}from"../hooks/dispatcher.js";import{HookEventBus as me}from"../hooks/bus.js";import{ResumeRunner as ue}from"../hooks/resume-runner.js";import{HeadlessRunner as de}from"../hooks/headless-runner.js";import{MessageDeliverer as fe}from"../hooks/message-deliverer.js";import{QuestionTracker as he}from"../hooks/question-tracker.js";import{startPromptFlusher as we}from"../hooks/prompt-flusher.js";import{SessionWatchRepository as ge}from"../repositories/session-watches.js";import{PushSubscriptionRepository as Se}from"../repositories/push-subscriptions.js";import{UploadRepository as ve}from"../repositories/uploads.js";import{PushNotifier as be}from"../hooks/push-notify.js";import{SessionSequenceRepository as Re}from"../repositories/session-sequences.js";import{WatchEngine as ke}from"../hooks/watch-engine.js";import{SequenceEngine as De}from"../hooks/sequence-engine.js";import{loadAllPlugins as Pe}from"../hooks/plugin-loader.js";import{ensureBuiltinMarket as Ee,builtinMarketDir as ye}from"../market/builtin.js";import{ToolkitService as Te}from"../hooks/toolkit.js";import{startSessionSweeper as Ie}from"../hooks/session-sweeper.js";import{startStatuslineCacheSweeper as Ae}from"../statusline/cache-sweeper.js";import{WatchService as Ce}from"../watch/watch-service.js";import{weaveRequestHandler as _e}from"./server.js";import{startTlsServer as He}from"./tls.js";import{DataBus as $e}from"./data-bus.js";import{TerminalTopologyRefresher as Oe}from"./terminal-topology-refresher.js";import{SnapshotRefresher as V}from"./snapshot-refresher.js";import{SessionProbe as qe,dbTranscriptPathResolver as Le}from"./session-probe.js";import{InflightCountsRefresher as Me}from"./inflight-counts-refresher.js";import{ProjectUpdatesRefresher as Fe}from"./project-updates-refresher.js";import{FingerprintCache as Ne}from"../install/fingerprint.js";import{detectProjectUpdateCounts as je}from"../install/updates.js";import{claudeLivenessById as Ue,pidAliveOf as Be}from"./claude-liveness.js";import{promptTerminalChannel as We,readTerminalCounts as Ge}from"./opener.js";import{wireHookFilePipeline as Ve}from"./hook-pipeline.js";import{DEFAULT_PORT as H,DAEMON_HOST as xe,DEFAULT_BIND_HOST as Ke,findFreePort as Qe,isPortFree as Ye}from"./port.js";import{writeDaemonState as x}from"./state.js";import{readDaemonSettingsSync as $,setDaemonSettingsDb as ze,DEFAULT_SERVER_SETTINGS as Je}from"./settings.js";import{AuthService as Xe}from"./dashboard-auth.js";import{resolveStaticDir as Ze}from"./static.js";const es="CLAUDE_CODE_CHILD_SESSION"in process.env;delete process.env.CLAUDE_CODE_CHILD_SESSION;for(const a of le)delete process.env[a];async function ss(){const a=await Ye(H)?H:await Qe(H+1);x({pid:process.pid,port:a,startedAt:new Date().toISOString()});const s=se();ze(s);const m=$().server?.bindHost??Ke,b=$().server?.tlsPort??Je.tlsPort,R=new Xe;R.initialPassword&&console.log(`[dev] initial dashboard password: ${R.initialPassword}`);const n=new oe(s),u=new te(s),p=new re(s),k=ae(),K=k.byCapability("events").flatMap(e=>e.events??[]),f=new ce(new G(s)),h=new ne(s),t=new ie(s),r=new me;{const e=await Ee({libraries:p});e.error?console.error(`[dev] builtin market unavailable: ${e.error}`):e.changed&&console.log(`[dev] builtin market ${e.form==="link"?"linked":"copied"} -> ${ye(p.dataDir)}`)}const{loader:l}=await Pe({rules:new G(s),registry:f,states:new v(s),bus:r,libraries:p},n.list());{const e=l.list().filter(o=>o.status==="rejected");console.log(`[dev] plugins loaded: ${l.list().length} (rejected: ${e.length})`);for(const o of e)console.log(`[dev] rejected ${o.id}: ${o.error}`)}l.watchRoots();const O={list:()=>l.list(),setPluginEnabled:(e,o)=>l.setPluginEnabled(e,o),reloadAll:()=>l.reloadAll(),rescan:()=>l.rescanRoots(n.list(),p)},Q=new Te({projects:n,states:new v(s),plugins:O,libraries:p}),q=new pe({registry:f,dispatches:h,bus:r,projects:n,sessions:t,plugins:l,pluginStates:new v(s)}),D=new de,Y=new ue({dispatches:h,sessions:t,projects:n,bus:r,resumeSpec:k.get("claude")?.resume,headless:D}),c=new fe({sessions:t,projects:n,hookEvents:u,bus:r,headless:D,terminal:We(()=>$().terminal)});we(c);const P=new ge(s),E=new ke({watches:P,deliverer:c,sessions:t,bus:r}),L=new Se(s),y=new ve(s),z=new be({subscriptions:L,sessions:t,bus:r}),T=new Re(s),w=new De({sequences:T,deliverer:c,sessions:t,bus:r});w.rearm();const g=new he({sessions:t,hookEvents:u,onPending:e=>{r.emit({kind:"question.pending",sessionId:e.sessionId,harness:e.harness,count:e.questions.length,at:e.at})}});g.seedFromDb();const M=new Ce(n);M.start();const i=new $e,S=new qe(Le(u)),I=new Oe(async()=>({counts:await Ge(n.list()),terminals:await c.sessionTerminals()}),i,{shouldRun:()=>i.hasSubscribers(),graceMs:1e4});I.start();const A=new V(()=>{const e=Ue(),o={};for(const d of t.listWithCounts()){const W=Be(d,e);W!==null&&(o[d.sessionId]=W)}return{alive:o}},i,{key:"sessionLiveness",shouldRun:()=>i.hasSubscribers()});A.start();const C=new V(()=>{const e={};for(const o of t.listWithCounts()){if(o.turnOpen!==!0)continue;const d=S.interruptedAt(o.sessionId,o.lastSeenAt);d!==null&&(e[o.sessionId]=d)}return{interrupted:e}},i,{key:"sessionInterrupt",intervalMs:5e3,shouldRun:()=>i.hasSubscribers()});C.start();const J=new Me(()=>c.listInflightCounts(),i,r),X=new Ne,Z=new Fe(()=>je(n.list(),p.list(),X),i,r,()=>i.hasSubscribers());Ie({sessions:t,events:u,dispatches:h,deliverer:c,watches:P,sequences:T,watchEngine:E,sequenceEngine:w,questions:g,probe:S,uploads:y}),Ae();const F=Ve({projects:n,rules:f,sessions:t,bus:r,dispatcher:q,watchEngine:E,sequenceEngine:w,messagePipe:c,questionTracker:g,sessionProbe:S,uploads:y}),_=Ze(),N=_e({projects:n,port:a,tlsPort:b,watch:M,hookEvents:u,adapters:K,harnesses:k,libraries:p,staticDir:_,hookRegistry:f,hookDispatches:h,hookSessions:t,hookBus:r,dataBus:i,terminalRefresher:I,interruptRefresher:C,livenessRefresher:A,sessionProbe:S,inflightRefresher:J,updatesRefresher:Z,hookDispatcher:q,hookRunner:Y,messageDeliverer:c,uploads:y,questionTracker:g,sessionWatches:P,watchEngine:E,sessionSequences:T,sequenceEngine:w,pushSubscriptions:L,pushNotifier:z,hookPlugins:O,hookMirror:F.mirror,pluginStates:new v(s),toolkit:Q,auth:R}),j=ee.createServer(N);let U=null;He({port:b,bindHost:m,handler:N}).then(e=>{U=e,e&&console.log(`[dev] weave daemon tls listening on https://${m}:${e.port}`)});const B=()=>{I.stop(),A.stop(),C.stop(),D.killAll(),F.stop(),j.close(),U?.server.close(),process.exit(0)};process.on("SIGTERM",B),process.on("SIGINT",B),j.listen(a,m,()=>{x({pid:process.pid,port:a,startedAt:new Date().toISOString(),host:m,tlsPort:b}),console.log(`[dev] weave daemon listening on http://${m}:${a}`),console.log(`[dev] cli/dashboard local url: http://${xe}:${a}`),console.log(`[dev] child-session marker stripped: ${es}`),console.log(_?`[dev] static: ${_}`:"[dev] static: (web/dist not built \u2014 run pnpm build:web)")})}ss();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdir as
|
|
1
|
+
import{readdir as d,stat as l}from"node:fs/promises";import p from"node:os";import a from"node:path";function f(n,s){return new Promise((r,t)=>{const e=setTimeout(()=>t(new Error("timeout")),s);n.then(i=>{clearTimeout(e),r(i)},i=>{clearTimeout(e),t(i)})})}let c=null;const h=5*6e4;async function w(){if(c&&Date.now()-c.at<h)return c.drives;const n="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),r=(await Promise.all(n.map(async t=>{const e=`${t}:\\`;try{return await f(l(e),4e3),e}catch{return null}}))).filter(t=>t!==null);return c={at:Date.now(),drives:r},r}export async function listBrowseRoots(n){const s=[],r=new Set,t=(o,m)=>{r.has(o)||(r.add(o),s.push({path:o,kind:m}))},e=p.homedir();t(e,"home");const i=[["Desktop","desktop"],["Downloads","downloads"],["Documents","documents"]];for(const[o,m]of i){const u=a.join(e,o);try{await l(u),t(u,m)}catch{}}for(const o of n)typeof o=="string"&&o&&t(a.dirname(o),"library-parent");if(process.platform==="win32")for(const o of await w())t(o,"drive");else t(a.parse(e).root,"root");return s}export async function listDirectoryChildren(n){const r=(await d(n,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>({name:t.name,path:a.join(n,t.name)}));return r.sort((t,e)=>t.name.localeCompare(e.name,void 0,{numeric:!0})),r}
|
|
@@ -22,9 +22,14 @@ export interface HookPipelineDeps {
|
|
|
22
22
|
messagePipe?: Pick<MessageDeliverer, 'hasQueued' | 'flushSession'>;
|
|
23
23
|
/** 阻塞式问答跟踪(AskUserQuestion/计划/权限确认):ingest 事件派生待答面。 */
|
|
24
24
|
questionTracker?: Pick<QuestionTracker, 'onEvent'>;
|
|
25
|
-
/** 会话转录路径上报(中断态探测;同 pane env
|
|
25
|
+
/** 会话转录路径上报(中断态探测;同 pane env 口径)+ 换模型落定(`PostModelSwitch`)。 */
|
|
26
26
|
sessionProbe?: {
|
|
27
27
|
noteTranscript(sessionId: string, path: string | null): void;
|
|
28
|
+
noteModel(sessionId: string, model: string): void;
|
|
29
|
+
};
|
|
30
|
+
/** 上传件落库面:回执命中时把消息的随附图挂到开轮事件(对话气泡缩略图)。 */
|
|
31
|
+
uploads?: {
|
|
32
|
+
linkToEvent(eventId: number, uploadIds: readonly string[]): void;
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
/** 删除一个项目的全部管道文件(忽略不存在)。删项目路由落地时一行调用。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdirSync as
|
|
1
|
+
import{readdirSync as f,unlinkSync as a}from"node:fs";import{join as c}from"node:path";import{getDbPath as m}from"../db/paths.js";import{MirrorWriter as b,hookShardId as l,hooksRoot as h,mirrorPathOf as g,outboxPathOf as x}from"../hooks/mirror.js";import{promptboxPathOf as P}from"../hooks/promptbox.js";import{startInboxWorker as j,handleIngestedRecords as k,unparkFailedInbox as $,INBOX_CLAIM_SUFFIX as p,INBOX_FAILED_SUFFIX as u}from"../hooks/inbox-worker.js";function w(e,o){return[c(e,"inbox",`${o}.jsonl`),c(e,"inbox",`${o}${p}`),c(e,"inbox",`${o}${u}`),g(e,o),x(e,o),P(e,o)]}export function purgeProjectPipeline(e,o){for(const n of w(e,l(o)))try{a(n)}catch{}}function F(e){return(e.endsWith(".tmp")?e.slice(0,-4):e).replace(new RegExp(`(${p}|${u})$`),"").replace(/\.(jsonl|json)$/,"")}const v=/^[0-9a-f]{16}$/;export function purgeOrphanPipelineFiles(e){const o=new Set(e.projects.list().map(r=>l(r.token)));let n=0;for(const r of["inbox","mirror","outbox","promptbox"]){let t;try{t=f(c(e.hooksDir,r))}catch{continue}for(const i of t){const s=F(i);if(!(!v.test(s)||o.has(s)))try{a(c(e.hooksDir,r,i)),n++}catch{}}}return n}export function wireHookFilePipeline(e){const o=h(),n=purgeOrphanPipelineFiles({projects:e.projects,hooksDir:o});n>0&&console.log(`[weave] hook pipeline: purged ${n} orphan file(s)`);const r=$(o);r>0&&console.log(`[weave] hook pipeline: revived ${r} parked inbox file(s)`);const t=new b({projects:e.projects,rules:e.rules,sessions:e.sessions});e.rules.onChange=()=>t.syncAll(),t.attachToBus(e.bus),t.syncAll();const i=j({dbPath:m(),hooksDir:o});return i.on("message",s=>{k({projects:e.projects,hooksDir:o,bus:e.bus,dispatcher:e.dispatcher,watchEngine:e.watchEngine,sequenceEngine:e.sequenceEngine,messagePipe:e.messagePipe,questionTracker:e.questionTracker,sessionProbe:e.sessionProbe,uploads:e.uploads},s)}),i.on("error",s=>console.error("[weave] inbox worker failed:",s)),{mirror:t,stop:()=>i.terminate().then(()=>{})}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stat as x}from"node:fs/promises";import{z as a}from"zod";import{HookRuleFilterSchema as N,HookRuleSourceSchema as G,HandlerConfigSchema as F,HookDispatchStatusSchema as L,isHarness as v}from"@weavecode/core";import{readJson as g,sendJson as s}from"./http.js";import{installPlugin as K,uninstallPlugin as _}from"../hooks/plugin-installer.js";import{purgeSession as Q}from"../hooks/session-purge.js";import{composeAnswerAtoms as z}from"../hooks/answer-keys.js";import{effective as J,setProjectEnabled as V}from"../hooks/plugin-project-state.js";import{readDaemonSettings as X}from"./settings.js";import{defaultProjectOpener as Y,terminalBackendFor as Z}from"./opener.js";import{claudeLivenessById as ee,pidAliveOf as se}from"./claude-liveness.js";import{messagingSurfaceFor as w,messagingSurfaces as oe}from"../surfaces.js";import{DEFAULT_WATCH_ON as ne}from"../repositories/session-watches.js";import{SEQUENCE_HOP_LIMIT as U}from"../hooks/sequence-engine.js";const M=a.object({name:a.string().min(1),enabled:a.boolean().optional(),priority:a.number().int().optional(),projectId:a.number().int().nullable(),source:G,filter:N.optional(),handler:F,timeoutMs:a.number().int().positive().optional(),record:a.boolean().optional()}),te=M.partial(),re=a.object({enabled:a.boolean()}),ie=a.object({enabled:a.boolean(),projectId:a.number().int().optional()}),ae=a.object({title:a.string().min(1).max(200)}),ue=a.object({sessionId:a.string().min(1)}),le=a.object({text:a.string().min(1).max(2e4),fromKind:a.enum(["dashboard","session"]).optional(),fromSessionId:a.string().min(1).nullable().optional()}),ce=a.object({answers:a.array(a.object({questionKey:a.string().min(1),options:a.array(a.number().int().min(0)).max(32),text:a.string().max(2e3).optional()})).min(1)}),de=a.object({watcherSessionId:a.string().min(1).nullable().optional(),notify:a.string().min(1).max(2e4).nullable().optional(),on:a.array(a.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:a.number().int().min(1).max(100).nullable().optional()}),me=a.object({watchId:a.number().int().positive()}),he=a.object({endpoint:a.string().url(),keys:a.object({p256dh:a.string().min(1),auth:a.string().min(1)})}),ge=a.object({endpoint:a.string().url()}),pe=a.object({name:a.string().max(200).optional(),steps:a.array(a.object({to:a.string().min(1),text:a.string().min(1).max(2e4),mode:a.enum(["prompt","inject","headless","auto"]).optional()})).min(1)}),fe=a.object({src:a.string().min(1)});function E(r,e){return r.prompt!==null||e}export async function handleHooksRoutes(r,e,o,l,k){if(!(l.startsWith("/hooks/")||l==="/sessions"||l.startsWith("/sessions/")||l.startsWith("/messaging")))return!1;if(l==="/hooks/rules"){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;if(r.method==="GET"){const n=k.searchParams.get("projectId"),t=n!=null&&n!==""?Number(n):void 0;return s(e,200,{rules:o.hookRegistry.list(t)}),!0}if(r.method==="POST"){try{const n=M.parse(await g(r)),t=o.hookRegistry.create(n);s(e,201,{rule:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}}const P=l.match(/^\/hooks\/rules\/([^/]+)$/);if(P){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(P[1]);if(r.method==="PUT"){try{const t=te.parse(await g(r)),i=o.hookRegistry.update(n,t);if(!i)return s(e,404,{error:"Rule not found"}),!0;s(e,200,{rule:i})}catch(t){s(e,400,{error:t instanceof Error?t.message:"Invalid rule body"})}return!0}if(r.method==="DELETE")return o.hookRegistry.remove(n)?(s(e,200,{ok:!0}),!0):(s(e,404,{error:"Rule not found"}),!0)}const T=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(T&&r.method==="POST"){if(!o.hookRegistry)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const n=re.parse(await g(r)),t=o.hookRegistry.setEnabled(decodeURIComponent(T[1]),n.enabled);if(!t)return s(e,404,{error:"Rule not found"}),!0;s(e,200,{rule:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(r.method==="GET"){const n=k.searchParams.get("projectId");if(n==null||n==="")return s(e,200,{plugins:o.hookPlugins?.list()??[]}),!0;const t=o.projects.getById(Number(n));if(!t)return s(e,404,{error:"Project not found"}),!0;if(!o.pluginStates)return s(e,503,{error:"Plugin states unavailable"}),!0;const i=o.pluginStates;return s(e,200,{plugins:(o.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const d=J(t,u.id,{states:i})?"active":"disabled";return d===u.status?u:{...u,status:d}})}),!0}if(r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=fe.parse(await g(r)),t=await K(n.src);await o.hookPlugins.reloadAll(),s(e,201,t)}catch(n){s(e,400,{error:n instanceof Error?n.message:"Install failed"})}return!0}}const j=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(j&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;const n=decodeURIComponent(j[1]);return await _(n)?(await o.hookPlugins.reloadAll(),s(e,200,{ok:!0}),!0):(s(e,404,{error:"Plugin directory not found"}),!0)}if(l==="/hooks/plugins/rescan"&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{await o.hookPlugins.rescan(),s(e,200,{ok:!0,plugins:o.hookPlugins.list().length})}catch(n){s(e,500,{error:n instanceof Error?n.message:"Rescan failed"})}return!0}const R=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(R&&r.method==="POST"){if(!o.hookPlugins)return s(e,503,{error:"Plugin loader unavailable"}),!0;try{const n=ie.parse(await g(r)),t=decodeURIComponent(R[1]);if(n.projectId!==void 0){const i=o.projects.getById(n.projectId);return i?o.hookPlugins.list().some(u=>u.id===t)?(V(i,t,n.enabled,{projects:o.projects}),s(e,200,{ok:!0}),!0):(s(e,404,{error:"Plugin not found"}),!0):(s(e,404,{error:"Project not found"}),!0)}if(!o.hookPlugins.setPluginEnabled(t,n.enabled))return s(e,404,{error:"Plugin not found"}),!0;s(e,200,{ok:!0})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&r.method==="GET"){if(!o.hookDispatches)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=k.searchParams.get("ruleId")??void 0,t=k.searchParams.get("status"),i=t?L.parse(t):void 0,u=k.searchParams.get("sessionId")??void 0,d=k.searchParams.get("limit"),c=d?Number(d):void 0;return s(e,200,{dispatches:o.hookDispatches.list({ruleId:n,status:i,sessionId:u,limit:Number.isFinite(c)?c:void 0})}),!0}const q=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(q&&r.method==="POST"){if(!o.hookRunner)return s(e,503,{error:"Resume runner unavailable"}),!0;let n;try{n=ue.parse(await g(r)).sessionId}catch(i){return s(e,400,{error:i instanceof Error?i.message:"Invalid body"}),!0}const t=await o.hookRunner.run(Number(q[1]),n);return t.ok?s(e,200,{ok:!0,dispatchId:t.dispatchId}):s(e,t.status,{error:t.error}),!0}if(l==="/sessions"&&r.method==="GET"){if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=k.searchParams.get("projectId"),t=n!=null&&n!==""?Number(n):void 0,i=o.hookSessions.listWithCounts(t),u=ee(),d=o.terminalRefresher?.lastSnapshot?.terminals??{};return s(e,200,{sessions:i.map(c=>({...c,pidAlive:se(c,u),terminal:d[c.sessionId]??null,interruptedAt:c.turnOpen===!0?o.sessionProbe?.interruptedAt(c.sessionId,c.lastSeenAt)??null:null}))}),!0}const y=l.match(/^\/sessions\/([^/]+)$/);if(y&&r.method==="PATCH"){if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(y[1]);if(!o.hookSessions.getBySessionId(n))return s(e,404,{error:"Session not found"}),!0;try{const t=ae.parse(await g(r)),i=o.hookSessions.setPendingTitle(n,t.title);i?.projectId!=null&&o.hookMirror?.syncProject(i.projectId),s(e,200,{session:i})}catch(t){s(e,400,{error:t instanceof Error?t.message:"Invalid body"})}return!0}if(y&&r.method==="DELETE"){if(!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=decodeURIComponent(y[1]),t=o.hookSessions.getBySessionId(n);if(!t)return s(e,404,{error:"Session not found"}),!0;const i=Q({sessions:o.hookSessions,events:o.hookEvents,dispatches:o.hookDispatches,deliverer:o.messageDeliverer,watches:o.sessionWatches,questions:o.questionTracker,probe:o.sessionProbe},n);return t.projectId!=null&&o.hookMirror?.syncProject(t.projectId),s(e,200,{ok:!0,sessionId:n,...i}),!0}const $=l.match(/^\/sessions\/([^/]+)\/open-terminal$/);if($&&r.method==="POST"){const n=decodeURIComponent($[1]);if(!o.hookSessions)return s(e,503,{error:"Hooks subsystem unavailable"}),!0;const t=o.hookSessions.getBySessionId(n);if(!t)return s(e,404,{error:"Session not found"}),!0;if(!o.hookEvents)return s(e,503,{error:"Hook ingestion unavailable"}),!0;const i=o.hookEvents.listBySession(n,1),u=i[i.length-1]?.source;if(!v(u))return s(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=o.harnesses?.get(u)?.resume;if(!d?.supported||!d.openArgs)return s(e,501,{error:`Harness "${u}" does not support interactive resume`}),!0;if(!t.projectId)return s(e,400,{error:"Session is not bound to a project"}),!0;const c=o.projects.getById(t.projectId);if(!c)return s(e,404,{error:"Project not found"}),!0;const p=o.opener??Y;let h;if(r.method==="POST")try{const m=await g(r);typeof m?.target=="string"&&m.target&&(h=m.target)}catch{}try{if(!(await x(c.path)).isDirectory())throw new Error(`Not a directory: ${c.path}`);const m=await X(),b=[d.bin,...d.openArgs(n)];if(h){if(!Z(m.terminal).enumerable)throw new Error(`Terminal preset "${m.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const f=p.runInTerminalAt;if(!f)throw new Error("Targeted attach is unavailable");await f(c.path,b,h,m.terminal)}else await p.runInTerminal(c.path,b,m.terminal);setTimeout(()=>{o.terminalRefresher?.refreshNow()},600),s(e,200,{ok:!0,sessionId:n,command:b.join(" "),cwd:c.path,...h?{target:h}:{}})}catch(m){s(e,400,{error:m instanceof Error?m.message:"Open failed"})}return!0}const D=l.match(/^\/sessions\/([^/]+)\/messages$/);if(D){const n=decodeURIComponent(D[1]);if(r.method==="GET")return o.messageDeliverer?o.hookSessions?.getBySessionId(n)?(s(e,200,{messages:o.messageDeliverer.listVisible(n)}),!0):(s(e,404,{error:"Session not found"}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(r.method==="POST"){if(!o.messageDeliverer||!o.hookSessions)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=le.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const i=await o.messageDeliverer.send({toSessionId:n,text:t.text,mode:"prompt",fromKind:t.fromKind??"dashboard",fromSessionId:t.fromSessionId??null,oneWay:!0});return i.ok?s(e,201,{ok:!0,messageId:i.messageId,status:i.status,message:i.message}):s(e,i.status,{error:i.error}),!0}}const H=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/resend$/);if(H&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=await o.messageDeliverer.resend(decodeURIComponent(H[2]));return n.ok?s(e,200,{ok:!0,messageId:n.messageId,status:n.status,message:n.message}):s(e,n.status,{error:n.error}),!0}const I=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/dismiss$/);if(I&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=o.messageDeliverer.dismiss(decodeURIComponent(I[1]),decodeURIComponent(I[2]));return n.ok?s(e,200,{ok:!0}):s(e,n.status,{error:n.error}),!0}if(l==="/messaging/questions"&&r.method==="GET")return o.questionTracker?(s(e,200,{questions:o.questionTracker.snapshot()}),!0):(s(e,503,{error:"Question tracking unavailable"}),!0);const O=l.match(/^\/sessions\/([^/]+)\/answer$/);if(O&&r.method==="POST"){if(!o.questionTracker||!o.messageDeliverer)return s(e,503,{error:"Question tracking unavailable"}),!0;const n=decodeURIComponent(O[1]);let t;try{t=ce.parse(await g(r))}catch(c){return s(e,400,{error:c instanceof Error?c.message:"Invalid body"}),!0}const i=o.questionTracker.get(n);if(!i)return s(e,409,{error:"Session has no pending question"}),!0;const u=z(i.questions,t.answers);if(!u.ok)return s(e,400,{error:u.error}),!0;const d=await o.messageDeliverer.answer(n,u.atoms);return d.ok?(o.questionTracker.markAnswered(n),s(e,200,{ok:!0,sessionId:n}),!0):(s(e,d.status,{error:d.error}),!0)}const B=l.match(/^\/sessions\/([^/]+)\/interrupt$/);if(B&&r.method==="POST"){if(!o.messageDeliverer)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=decodeURIComponent(B[1]),t=await o.messageDeliverer.interrupt(n);return t.ok?(setTimeout(()=>o.interruptRefresher?.tick(),1500),s(e,200,{ok:!0,sessionId:n}),!0):(s(e,t.status,{error:t.error}),!0)}const C=l.match(/^\/sessions\/([^/]+)\/watch$/);if(C){const n=decodeURIComponent(C[1]);if(r.method==="POST"){if(!o.sessionWatches||!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=de.parse(await g(r))}catch(f){return s(e,400,{error:f instanceof Error?f.message:"Invalid body"}),!0}if(!o.hookSessions.getBySessionId(n))return s(e,404,{error:"Session not found"}),!0;const i=o.hookEvents.listBySession(n,1),u=i[i.length-1]?.source;if(!v(u))return s(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=w(u),c=t.on??[...ne];if((c.includes("idle")||c.includes("turnEnd"))&&d.idleSignals.length===0)return s(e,409,{error:d.unsupportedReasons?.watch??`Harness "${u}" does not support idle watching`}),!0;if(c.includes("messageFailed")&&!(E(d,o.messageDeliverer?.hasTerminalChannel()??!1)||d.inject!==null||d.headless!==null))return s(e,409,{error:d.unsupportedReasons?.prompt??`Harness "${u}" supports no messaging channel`}),!0;if(t.watcherSessionId){if(!o.hookSessions.getBySessionId(t.watcherSessionId))return s(e,404,{error:"Watcher session not found"}),!0;const f=o.hookEvents.listBySession(t.watcherSessionId,1),S=f[f.length-1]?.source;if(!v(S))return s(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const A=w(S);if(!A.inject)return s(e,409,{error:A.unsupportedReasons?.inject??`Harness "${S}" cannot receive watch notifications`}),!0}const p=t.times===void 0?1:t.times,h=(t.watcherSessionId??null)===null?o.sessionWatches.listPendingByTarget(n).find(f=>f.watcherSessionId===null):void 0,m=h?o.sessionWatches.updateById(h.id,{onEvents:c,remaining:p}):void 0,b=m??o.sessionWatches.insert({watcherSessionId:t.watcherSessionId??null,targetSessionId:n,notify:t.notify??null,onEvents:c,times:p});return o.watchEngine?.created(b),s(e,m?200:201,{ok:!0,watchId:b.id,watch:b}),!0}if(r.method==="DELETE"){if(!o.sessionWatches)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let t;try{t=me.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const i=o.sessionWatches.getById(t.watchId);return!i||i.targetSessionId!==n||i.firedAt!==null?(s(e,404,{error:"Watch not found"}),!0):(o.sessionWatches.deleteById(t.watchId),s(e,200,{ok:!0,watchId:t.watchId}),!0)}}if(l==="/messaging/watches"&&r.method==="GET")return o.sessionWatches?(s(e,200,{watches:o.sessionWatches.listPending()}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(l==="/messaging/push/key"&&r.method==="GET")return o.pushNotifier?(s(e,200,{publicKey:o.pushNotifier.publicKey()}),!0):(s(e,503,{error:"Push subsystem unavailable"}),!0);if(l==="/messaging/push/subscribe"&&r.method==="POST"){if(!o.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=he.parse(await g(r)),t=o.pushSubscriptions.upsert({endpoint:n.endpoint,p256dh:n.keys.p256dh,auth:n.keys.auth,userAgent:r.headers["user-agent"]??null});s(e,201,{ok:!0,subscription:t})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/messaging/push/unsubscribe"&&r.method==="POST"){if(!o.pushSubscriptions)return s(e,503,{error:"Push subsystem unavailable"}),!0;try{const n=ge.parse(await g(r));o.pushSubscriptions.deleteByEndpoint(n.endpoint),s(e,200,{ok:!0})}catch(n){s(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(l==="/messaging/sequences"){if(r.method==="GET")return o.sessionSequences?(s(e,200,{sequences:o.sessionSequences.list()}),!0):(s(e,503,{error:"Messaging subsystem unavailable"}),!0);if(r.method==="POST"){if(!o.sessionSequences||!o.sequenceEngine||!o.hookSessions||!o.hookEvents)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=pe.parse(await g(r))}catch(u){return s(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(n.steps.length>U)return s(e,400,{error:`Sequences are capped at ${U} steps (hop limit)`}),!0;const t=o.messageDeliverer?.hasTerminalChannel()??!1;for(let u=0;u<n.steps.length;u++){const d=n.steps[u];if(!o.hookSessions.getBySessionId(d.to))return s(e,404,{error:`Step ${u+1}: session not found`}),!0;const c=o.hookEvents.listBySession(d.to,1),p=c[c.length-1]?.source;if(!v(p))return s(e,400,{error:`Step ${u+1}: session has no hook events to determine its harness`}),!0;const h=w(p),m=d.mode??"auto";if(!(m==="prompt"?E(h,t):m==="inject"?h.inject!==null:m==="headless"?h.headless!==null:h.inject!==null||h.headless!==null)){const b=m==="auto"?h.unsupportedReasons?.inject??`Harness "${p}" supports no messaging channel`:h.unsupportedReasons?.[m]??`Harness "${p}" does not support the ${m} channel`;return s(e,409,{error:`Step ${u+1}: ${b}`}),!0}}const i=o.sessionSequences.insert({name:n.name??"",steps:n.steps.map(u=>({...u,mode:u.mode??"auto"}))});return await o.sequenceEngine.trigger(i),s(e,201,{ok:!0,sequence:o.sessionSequences.getById(i.id)??i}),!0}}const W=l.match(/^\/messaging\/sequences\/(\d+)$/);if(W&&r.method==="DELETE"){if(!o.sessionSequences)return s(e,503,{error:"Messaging subsystem unavailable"}),!0;const n=o.sessionSequences.getById(Number(W[1]));return n?n.status!=="running"?(s(e,409,{error:`Sequence already ${n.status}`}),!0):(o.sequenceEngine?o.sequenceEngine.cancel(n.id):o.sessionSequences.finish(n.id,"cancelled"),s(e,200,{ok:!0,sequenceId:n.id}),!0):(s(e,404,{error:"Sequence not found"}),!0)}if(l==="/messaging/capabilities"&&r.method==="GET"){const n=o.messageDeliverer?.hasTerminalChannel()??!1;return s(e,200,{capabilities:oe().map(({harness:t,surface:i})=>({harness:t,discovery:i.discovery,prompt:E(i,n),inject:i.inject!==null,headless:i.headless!==null,watch:i.idleSignals.length>0,unsupportedReasons:i.unsupportedReasons??null}))}),!0}return!1}
|
|
1
|
+
import{stat as V}from"node:fs/promises";import{z as i}from"zod";import{HARNESS_SESSION_CONTROL as J,HookRuleFilterSchema as Y,HookRuleSourceSchema as X,HandlerConfigSchema as Z,HookDispatchStatusSchema as q,isHarness as w}from"@weavecode/core";import{aliasOfModel as ee,modelAliasTargets as te}from"@weavecode/harness";import{readJson as k,sendJson as r}from"./http.js";import{installPlugin as re,uninstallPlugin as oe}from"../hooks/plugin-installer.js";import{purgeSession as ne}from"../hooks/session-purge.js";import{composeAnswerAtoms as se}from"../hooks/answer-keys.js";import{effective as ie,setProjectEnabled as ae}from"../hooks/plugin-project-state.js";import{readDaemonSettings as ue,readDaemonSettingsSync as le,readHooksEnabled as ce}from"./settings.js";import{defaultProjectOpener as me,terminalBackendFor as de}from"./opener.js";import{claudeLivenessById as F,pidAliveOf as K}from"./claude-liveness.js";import{captureSurfaces as he,messagingSurfaceFor as E,messagingSurfaces as ge}from"../surfaces.js";import{getDataDir as fe}from"../db/paths.js";import{UPLOAD_MAX_BYTES as be,UPLOAD_MEDIA_TYPES as ye}from"../repositories/uploads.js";import{WEAVE_VERSION as pe}from"../version.js";import{DEFAULT_WATCH_ON as ke}from"../repositories/session-watches.js";import{SEQUENCE_HOP_LIMIT as z}from"../hooks/sequence-engine.js";const Q=i.object({name:i.string().min(1),enabled:i.boolean().optional(),priority:i.number().int().optional(),projectId:i.number().int().nullable(),source:X,filter:Y.optional(),handler:Z,timeoutMs:i.number().int().positive().optional(),record:i.boolean().optional()}),ve=Q.partial(),Ie=i.object({enabled:i.boolean()}),Se=i.object({enabled:i.boolean(),projectId:i.number().int().optional()}),we=i.object({title:i.string().min(1).max(200)}),Pe=i.object({sessionId:i.string().min(1)}),Ee=i.object({text:i.string().max(2e4),fromKind:i.enum(["dashboard","session"]).optional(),fromSessionId:i.string().min(1).nullable().optional(),images:i.array(i.string().regex(/^[a-f0-9]{64}$/)).max(8).optional(),forceTerminal:i.boolean().optional()}),Te=i.object({name:i.string().min(1).max(200),mediaType:i.enum(ye),data:i.string().min(1)});function je(s){return{id:s.id,name:s.name,mediaType:s.mediaType,size:s.size}}const Re=i.object({answers:i.array(i.object({questionKey:i.string().min(1),options:i.array(i.number().int().min(0)).max(32),text:i.string().max(2e3).optional()})).min(1)}),Me=i.object({watcherSessionId:i.string().min(1).nullable().optional(),notify:i.string().min(1).max(2e4).nullable().optional(),on:i.array(i.enum(["idle","turnEnd","messageFailed"])).min(1).optional(),times:i.number().int().min(1).max(100).nullable().optional()}),De=i.object({watchId:i.number().int().positive()}),Oe=i.object({model:i.string().min(1).max(128)}),Be=i.object({endpoint:i.string().url(),keys:i.object({p256dh:i.string().min(1),auth:i.string().min(1)})}),Ce=i.object({endpoint:i.string().url()}),$e=i.object({name:i.string().max(200).optional(),steps:i.array(i.object({to:i.string().min(1),text:i.string().min(1).max(2e4),mode:i.enum(["prompt","inject","headless","auto"]).optional()})).min(1)}),Ae=i.object({src:i.string().min(1)});function T(s,e){return s.prompt!==null||e}function xe(s){const{diag:e,capture:t,eventCount:l}=s,g=[];return!t||t.source==="none"||!t.present?g.push("no-hook-script"):t.weaveOwned?t.reportsInbox||g.push("hook-script-stale"):g.push("hook-script-not-weave"),l===0&&g.push("no-events"),e&&(e.alive===!1&&g.push("not-running"),e.inbox.reason==="no-credentials"&&t?.reportsInbox===!0&&g.push("no-inbox-credentials"),e.inbox.reason==="auth-token-required"&&g.push("inbox-token-required"),e.relay.reason==="no-peer-name"&&g.push("no-peer-name"),e.terminal.reason==="no-backend"&&g.push("terminal-no-backend"),e.terminal.reason==="no-pane-env"&&g.push("terminal-no-pane-env"),e.pending>0&&g.push("queued"),e.stalled&&g.push("stalled")),g}export async function handleHooksRoutes(s,e,t,l,g){if(!(l.startsWith("/hooks/")||l==="/sessions"||l.startsWith("/sessions/")||l.startsWith("/messaging")||l==="/uploads"||l.startsWith("/images/")))return!1;if(l==="/hooks/rules"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;if(s.method==="GET"){const o=g.searchParams.get("projectId"),n=o!=null&&o!==""?Number(o):void 0;return r(e,200,{rules:t.hookRegistry.list(n)}),!0}if(s.method==="POST"){try{const o=Q.parse(await k(s)),n=t.hookRegistry.create(o);r(e,201,{rule:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid rule body"})}return!0}}const j=l.match(/^\/hooks\/rules\/([^/]+)$/);if(j){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(j[1]);if(s.method==="PUT"){try{const n=ve.parse(await k(s)),a=t.hookRegistry.update(o,n);if(!a)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:a})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid rule body"})}return!0}if(s.method==="DELETE")return t.hookRegistry.remove(o)?(r(e,200,{ok:!0}),!0):(r(e,404,{error:"Rule not found"}),!0)}const R=l.match(/^\/hooks\/rules\/([^/]+)\/toggle$/);if(R&&s.method==="POST"){if(!t.hookRegistry)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;try{const o=Ie.parse(await k(s)),n=t.hookRegistry.setEnabled(decodeURIComponent(R[1]),o.enabled);if(!n)return r(e,404,{error:"Rule not found"}),!0;r(e,200,{rule:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/hooks/plugins"){if(s.method==="GET"){const o=g.searchParams.get("projectId");if(o==null||o==="")return r(e,200,{plugins:t.hookPlugins?.list()??[]}),!0;const n=t.projects.getById(Number(o));if(!n)return r(e,404,{error:"Project not found"}),!0;if(!t.pluginStates)return r(e,503,{error:"Plugin states unavailable"}),!0;const a=t.pluginStates;return r(e,200,{plugins:(t.hookPlugins?.list()??[]).map(u=>{if(u.status==="rejected")return u;const c=ie(n,u.id,{states:a})?"active":"disabled";return c===u.status?u:{...u,status:c}})}),!0}if(s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const o=Ae.parse(await k(s)),n=await re(o.src);await t.hookPlugins.reloadAll(),r(e,201,n)}catch(o){r(e,400,{error:o instanceof Error?o.message:"Install failed"})}return!0}}const M=l.match(/^\/hooks\/plugins\/([^/]+)\/uninstall$/);if(M&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;const o=decodeURIComponent(M[1]);return await oe(o)?(await t.hookPlugins.reloadAll(),r(e,200,{ok:!0}),!0):(r(e,404,{error:"Plugin directory not found"}),!0)}if(l==="/hooks/plugins/rescan"&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{await t.hookPlugins.rescan(),r(e,200,{ok:!0,plugins:t.hookPlugins.list().length})}catch(o){r(e,500,{error:o instanceof Error?o.message:"Rescan failed"})}return!0}const D=l.match(/^\/hooks\/plugins\/([^/]+)\/toggle$/);if(D&&s.method==="POST"){if(!t.hookPlugins)return r(e,503,{error:"Plugin loader unavailable"}),!0;try{const o=Se.parse(await k(s)),n=decodeURIComponent(D[1]);if(o.projectId!==void 0){const u=t.projects.getById(o.projectId);return u?t.hookPlugins.list().some(c=>c.id===n)?(ae(u,n,o.enabled,{projects:t.projects}),r(e,200,{ok:!0}),!0):(r(e,404,{error:"Plugin not found"}),!0):(r(e,404,{error:"Project not found"}),!0)}if(!t.hookPlugins.setPluginEnabled(n,o.enabled))return r(e,404,{error:"Plugin not found"}),!0;r(e,200,{ok:!0})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/hooks/dispatches"&&s.method==="GET"){if(!t.hookDispatches)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=g.searchParams.get("ruleId")??void 0,n=g.searchParams.get("status"),a=n?q.parse(n):void 0,u=g.searchParams.get("sessionId")??void 0,c=g.searchParams.get("limit"),d=c?Number(c):void 0;return r(e,200,{dispatches:t.hookDispatches.list({ruleId:o,status:a,sessionId:u,limit:Number.isFinite(d)?d:void 0})}),!0}const O=l.match(/^\/hooks\/dispatches\/(\d+)\/run$/);if(O&&s.method==="POST"){if(!t.hookRunner)return r(e,503,{error:"Resume runner unavailable"}),!0;let o;try{o=Pe.parse(await k(s)).sessionId}catch(a){return r(e,400,{error:a instanceof Error?a.message:"Invalid body"}),!0}const n=await t.hookRunner.run(Number(O[1]),o);return n.ok?r(e,200,{ok:!0,dispatchId:n.dispatchId}):r(e,n.status,{error:n.error}),!0}if(l==="/sessions"&&s.method==="GET"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=g.searchParams.get("projectId"),n=o!=null&&o!==""?Number(o):void 0,a=t.hookSessions.listWithCounts(n),u=F(),c=t.terminalRefresher?.lastSnapshot?.terminals??{},d={};for(const h of a){const b=h.harness??"";b in d||(d[b]=te(J[h.harness]?.modelNames??[]))}return r(e,200,{sessions:a.map(h=>{const b=t.sessionProbe?.currentModel(h.sessionId)??null;return{...h,pidAlive:K(h,u),terminal:c[h.sessionId]??null,interruptedAt:h.turnOpen===!0?t.sessionProbe?.interruptedAt(h.sessionId,h.lastSeenAt)??null:null,model:b,modelAlias:ee(d[h.harness??""]??[],b),mode:t.sessionProbe?.currentMode(h.sessionId)??null,transcriptPresent:t.sessionProbe?.transcriptPresent(h.sessionId)??null}}),modelCatalog:d}),!0}const S=l.match(/^\/sessions\/([^/]+)$/);if(S&&s.method==="PATCH"){if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(S[1]);if(!t.hookSessions.getBySessionId(o))return r(e,404,{error:"Session not found"}),!0;try{const n=we.parse(await k(s)),a=t.hookSessions.setPendingTitle(o,n.title);a?.projectId!=null&&t.hookMirror?.syncProject(a.projectId),r(e,200,{session:a})}catch(n){r(e,400,{error:n instanceof Error?n.message:"Invalid body"})}return!0}if(S&&s.method==="DELETE"){if(!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const o=decodeURIComponent(S[1]),n=t.hookSessions.getBySessionId(o);if(!n)return r(e,404,{error:"Session not found"}),!0;const a=ne({sessions:t.hookSessions,events:t.hookEvents,dispatches:t.hookDispatches,deliverer:t.messageDeliverer,watches:t.sessionWatches,questions:t.questionTracker,probe:t.sessionProbe,uploads:t.uploads},o);return n.projectId!=null&&t.hookMirror?.syncProject(n.projectId),r(e,200,{ok:!0,sessionId:o,...a}),!0}const B=l.match(/^\/sessions\/([^/]+)\/open-terminal$/);if(B&&s.method==="POST"){const o=decodeURIComponent(B[1]);if(!t.hookSessions)return r(e,503,{error:"Hooks subsystem unavailable"}),!0;const n=t.hookSessions.getBySessionId(o);if(!n)return r(e,404,{error:"Session not found"}),!0;if(!t.hookEvents)return r(e,503,{error:"Hook ingestion unavailable"}),!0;const a=t.hookEvents.listBySession(o,1),u=a[a.length-1]?.source;if(!w(u))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const c=t.harnesses?.get(u)?.resume;if(!c?.supported||!c.openArgs)return r(e,501,{error:`Harness "${u}" does not support interactive resume`}),!0;if(!n.projectId)return r(e,400,{error:"Session is not bound to a project"}),!0;const d=t.projects.getById(n.projectId);if(!d)return r(e,404,{error:"Project not found"}),!0;if(t.sessionProbe?.transcriptPresent(o)===!1)return r(e,409,{error:"Session transcript is missing \u2014 nothing to resume"}),!0;const h=t.opener??me;let b;if(s.method==="POST")try{const y=await k(s);typeof y?.target=="string"&&y.target&&(b=y.target)}catch{}try{if(!(await V(d.path)).isDirectory())throw new Error(`Not a directory: ${d.path}`);const m=await ue(),f=[c.bin,...c.openArgs(o)];if(b){if(!de(m.terminal).enumerable)throw new Error(`Terminal preset "${m.terminal.preset}" cannot attach to a chosen pane \u2014 pick wezterm, wt or Terminal.app in settings`);const p=h.runInTerminalAt;if(!p)throw new Error("Targeted attach is unavailable");await p(d.path,f,b,m.terminal)}else await h.runInTerminal(d.path,f,m.terminal);setTimeout(()=>{t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:o,command:f.join(" "),cwd:d.path,...b?{target:b}:{}})}catch(y){r(e,400,{error:y instanceof Error?y.message:"Open failed"})}return!0}if(l==="/uploads"&&s.method==="POST"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;let o;try{o=Te.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const n=Buffer.from(o.data,"base64");if(n.length===0)return r(e,400,{error:"Empty image"}),!0;if(n.length>be)return r(e,413,{error:"Image too large"}),!0;const a=t.uploads.save({name:o.name,mediaType:o.mediaType,bytes:n});return r(e,201,{upload:je(a)}),!0}const C=l.match(/^\/images\/([a-f0-9]{64})$/);if(C&&s.method==="GET"){if(!t.uploads)return r(e,503,{error:"Upload subsystem unavailable"}),!0;const o=t.uploads.fileOf(C[1]);return o?(e.writeHead(200,{"content-type":o.row.mediaType,"content-length":String(o.bytes.length),"cache-control":"private, max-age=31536000, immutable"}),e.end(o.bytes),!0):(r(e,404,{error:"Image not found"}),!0)}const $=l.match(/^\/sessions\/([^/]+)\/messages$/);if($){const o=decodeURIComponent($[1]);if(s.method==="GET")return t.messageDeliverer?t.hookSessions?.getBySessionId(o)?(r(e,200,{messages:t.messageDeliverer.listVisible(o)}),!0):(r(e,404,{error:"Session not found"}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(s.method==="POST"){if(!t.messageDeliverer||!t.hookSessions)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=Ee.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const a=n.images??[];if(!n.text.trim()&&a.length===0)return r(e,400,{error:"Message is empty"}),!0;let u=[];if(a.length>0){const d=t.uploads?.refsOf(a)??null;if(!d)return r(e,404,{error:"Image not found"}),!0;u=d}const c=await t.messageDeliverer.send({toSessionId:o,text:n.text,...u.length>0?{images:u}:{},...n.forceTerminal===!0?{forceTerminal:!0}:{},mode:"prompt",fromKind:n.fromKind??"dashboard",fromSessionId:n.fromSessionId??null,oneWay:!0});return c.ok?r(e,201,{ok:!0,messageId:c.messageId,status:c.status,message:c.message}):r(e,c.status,{error:c.error}),!0}}const A=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/resend$/);if(A&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=await t.messageDeliverer.resend(decodeURIComponent(A[2]));return o.ok?r(e,200,{ok:!0,messageId:o.messageId,status:o.status,message:o.message}):r(e,o.status,{error:o.error}),!0}const P=l.match(/^\/sessions\/([^/]+)\/messages\/([^/]+)\/dismiss$/);if(P&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=t.messageDeliverer.dismiss(decodeURIComponent(P[1]),decodeURIComponent(P[2]));return o.ok?r(e,200,{ok:!0}):r(e,o.status,{error:o.error}),!0}if(l==="/messaging/questions"&&s.method==="GET")return t.questionTracker?(r(e,200,{questions:t.questionTracker.snapshot()}),!0):(r(e,503,{error:"Question tracking unavailable"}),!0);const x=l.match(/^\/sessions\/([^/]+)\/answer$/);if(x&&s.method==="POST"){if(!t.questionTracker||!t.messageDeliverer)return r(e,503,{error:"Question tracking unavailable"}),!0;const o=decodeURIComponent(x[1]);let n;try{n=Re.parse(await k(s))}catch(d){return r(e,400,{error:d instanceof Error?d.message:"Invalid body"}),!0}const a=t.questionTracker.get(o);if(!a)return r(e,409,{error:"Session has no pending question"}),!0;const u=se(a.questions,n.answers);if(!u.ok)return r(e,400,{error:u.error}),!0;const c=await t.messageDeliverer.answer(o,u.atoms);return c.ok?(t.questionTracker.markAnswered(o),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,c.status,{error:c.error}),!0)}const H=l.match(/^\/sessions\/([^/]+)\/interrupt$/);if(H&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(H[1]),n=await t.messageDeliverer.interrupt(o);return n.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const U=l.match(/^\/sessions\/([^/]+)\/close-pane$/);if(U&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(U[1]),n=await t.messageDeliverer.closePane(o);return n.ok?(setTimeout(()=>{t.livenessRefresher?.tick(),t.terminalRefresher?.refreshNow()},600),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const W=l.match(/^\/sessions\/([^/]+)\/mode$/);if(W&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(W[1]),n=await t.messageDeliverer.cycleMode(o);return n.ok?(r(e,200,{ok:!0,sessionId:o}),!0):(r(e,n.status,{error:n.error}),!0)}const N=l.match(/^\/sessions\/([^/]+)\/model$/);if(N&&s.method==="POST"){if(!t.messageDeliverer)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=decodeURIComponent(N[1]),n=Oe.parse(await k(s)),a=await t.messageDeliverer.setModel(o,n.model);return a.ok?(setTimeout(()=>t.interruptRefresher?.tick(),1500),r(e,200,{ok:!0,sessionId:o}),!0):(r(e,a.status,{error:a.error}),!0)}const _=l.match(/^\/sessions\/([^/]+)\/watch$/);if(_){const o=decodeURIComponent(_[1]);if(s.method==="POST"){if(!t.sessionWatches||!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=Me.parse(await k(s))}catch(p){return r(e,400,{error:p instanceof Error?p.message:"Invalid body"}),!0}if(!t.hookSessions.getBySessionId(o))return r(e,404,{error:"Session not found"}),!0;const u=t.hookEvents.listBySession(o,1),c=u[u.length-1]?.source;if(!w(c))return r(e,400,{error:"Session has no hook events to determine its harness"}),!0;const d=E(c),h=n.on??[...ke];if((h.includes("idle")||h.includes("turnEnd"))&&d.idleSignals.length===0)return r(e,409,{error:d.unsupportedReasons?.watch??`Harness "${c}" does not support idle watching`}),!0;if(h.includes("messageFailed")&&!(T(d,t.messageDeliverer?.hasTerminalChannel()??!1)||d.inject!==null||d.headless!==null))return r(e,409,{error:d.unsupportedReasons?.prompt??`Harness "${c}" supports no messaging channel`}),!0;if(n.watcherSessionId){if(!t.hookSessions.getBySessionId(n.watcherSessionId))return r(e,404,{error:"Watcher session not found"}),!0;const v=t.hookEvents.listBySession(n.watcherSessionId,1),I=v[v.length-1]?.source;if(!w(I))return r(e,400,{error:"Watcher session has no hook events to determine its harness"}),!0;const L=E(I);if(!L.inject)return r(e,409,{error:L.unsupportedReasons?.inject??`Harness "${I}" cannot receive watch notifications`}),!0}const b=n.times===void 0?1:n.times,y=(n.watcherSessionId??null)===null?t.sessionWatches.listPendingByTarget(o).find(p=>p.watcherSessionId===null):void 0,m=y?t.sessionWatches.updateById(y.id,{onEvents:h,remaining:b}):void 0,f=m??t.sessionWatches.insert({watcherSessionId:n.watcherSessionId??null,targetSessionId:o,notify:n.notify??null,onEvents:h,times:b});return t.watchEngine?.created(f),r(e,m?200:201,{ok:!0,watchId:f.id,watch:f}),!0}if(s.method==="DELETE"){if(!t.sessionWatches)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let n;try{n=De.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}const a=t.sessionWatches.getById(n.watchId);return!a||a.targetSessionId!==o||a.firedAt!==null?(r(e,404,{error:"Watch not found"}),!0):(t.sessionWatches.deleteById(n.watchId),r(e,200,{ok:!0,watchId:n.watchId}),!0)}}if(l==="/messaging/watches"&&s.method==="GET")return t.sessionWatches?(r(e,200,{watches:t.sessionWatches.listPending()}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(l==="/messaging/push/key"&&s.method==="GET")return t.pushNotifier?(r(e,200,{publicKey:t.pushNotifier.publicKey()}),!0):(r(e,503,{error:"Push subsystem unavailable"}),!0);if(l==="/messaging/push/subscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const o=Be.parse(await k(s)),n=t.pushSubscriptions.upsert({endpoint:o.endpoint,p256dh:o.keys.p256dh,auth:o.keys.auth,userAgent:s.headers["user-agent"]??null});r(e,201,{ok:!0,subscription:n})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/messaging/push/unsubscribe"&&s.method==="POST"){if(!t.pushSubscriptions)return r(e,503,{error:"Push subsystem unavailable"}),!0;try{const o=Ce.parse(await k(s));t.pushSubscriptions.deleteByEndpoint(o.endpoint),r(e,200,{ok:!0})}catch(o){r(e,400,{error:o instanceof Error?o.message:"Invalid body"})}return!0}if(l==="/messaging/sequences"){if(s.method==="GET")return t.sessionSequences?(r(e,200,{sequences:t.sessionSequences.list()}),!0):(r(e,503,{error:"Messaging subsystem unavailable"}),!0);if(s.method==="POST"){if(!t.sessionSequences||!t.sequenceEngine||!t.hookSessions||!t.hookEvents)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;let o;try{o=$e.parse(await k(s))}catch(u){return r(e,400,{error:u instanceof Error?u.message:"Invalid body"}),!0}if(o.steps.length>z)return r(e,400,{error:`Sequences are capped at ${z} steps (hop limit)`}),!0;const n=t.messageDeliverer?.hasTerminalChannel()??!1;for(let u=0;u<o.steps.length;u++){const c=o.steps[u];if(!t.hookSessions.getBySessionId(c.to))return r(e,404,{error:`Step ${u+1}: session not found`}),!0;const h=t.hookEvents.listBySession(c.to,1),b=h[h.length-1]?.source;if(!w(b))return r(e,400,{error:`Step ${u+1}: session has no hook events to determine its harness`}),!0;const y=E(b),m=c.mode??"auto";if(!(m==="prompt"?T(y,n):m==="inject"?y.inject!==null:m==="headless"?y.headless!==null:y.inject!==null||y.headless!==null)){const p=m==="auto"?y.unsupportedReasons?.inject??`Harness "${b}" supports no messaging channel`:y.unsupportedReasons?.[m]??`Harness "${b}" does not support the ${m} channel`;return r(e,409,{error:`Step ${u+1}: ${p}`}),!0}}const a=t.sessionSequences.insert({name:o.name??"",steps:o.steps.map(u=>({...u,mode:u.mode??"auto"}))});return await t.sequenceEngine.trigger(a),r(e,201,{ok:!0,sequence:t.sessionSequences.getById(a.id)??a}),!0}}const G=l.match(/^\/messaging\/sequences\/(\d+)$/);if(G&&s.method==="DELETE"){if(!t.sessionSequences)return r(e,503,{error:"Messaging subsystem unavailable"}),!0;const o=t.sessionSequences.getById(Number(G[1]));return o?o.status!=="running"?(r(e,409,{error:`Sequence already ${o.status}`}),!0):(t.sequenceEngine?t.sequenceEngine.cancel(o.id):t.sessionSequences.finish(o.id,"cancelled"),r(e,200,{ok:!0,sequenceId:o.id}),!0):(r(e,404,{error:"Sequence not found"}),!0)}if(l==="/messaging/capabilities"&&s.method==="GET"){const o=t.messageDeliverer?.hasTerminalChannel()??!1;return r(e,200,{capabilities:ge().map(({harness:n,surface:a})=>({harness:n,discovery:a.discovery,prompt:T(a,o),inject:a.inject!==null,headless:a.headless!==null,watch:a.idleSignals.length>0,imageAttach:a.imageAttach!==null,unsupportedReasons:a.unsupportedReasons??null}))}),!0}if(l==="/messaging/diagnostics"&&s.method==="GET"){if(!t.messageDeliverer||!t.hookSessions)return r(e,503,{error:"Message subsystem unavailable"}),!0;const o=g.searchParams.get("session"),n=g.searchParams.get("project"),a=he(),u=t.projects.list(),c=await Promise.all(u.map(async m=>({id:m.id,name:m.name,path:m.path,captures:await Promise.all(a.map(async({harness:f,surface:p})=>({harness:f,...await p.scriptHealth({projectPath:m.path})})))}))),d=(m,f)=>c.find(p=>p.id===m)?.captures.find(p=>p.harness===f)??null,h=F(),y=t.hookSessions.listWithCounts(o?void 0:n?Number(n):void 0).filter(m=>o?m.sessionId===o:K(m,h)!==!1).map(m=>{const f=t.messageDeliverer.diagnose(m.sessionId),p=d(m.projectId,m.harness??null),v={inbox:f.inbox,relay:f.relay,terminal:f.terminal};return{sessionId:m.sessionId,projectId:m.projectId,harness:m.harness??null,title:m.title,lastSeenAt:m.lastSeenAt,eventCount:m.eventCount??0,lastEventType:m.lastEventType??null,alive:f.alive,paneEnvReported:f.paneEnvReported,channels:v,queue:{pending:f.pending,stalled:f.stalled},reachable:Object.values(v).some(I=>I.status==="ready"),hints:xe({diag:f,capture:p,eventCount:m.eventCount??0})}});return r(e,200,{daemon:{version:pe,platform:process.platform,dataDir:fe(),uptimeMs:Math.round(process.uptime()*1e3),terminalPreset:le().terminal.preset,terminalTextChannel:t.messageDeliverer.hasTerminalChannel(),hooksEnabled:ce()},projects:c,sessions:y}),!0}return!1}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function readBody(
|
|
1
|
+
import{noteRequestBody as s}from"./api-log.js";export function readBody(n){return new Promise((o,e)=>{const r=[];n.on("data",t=>r.push(t)),n.on("end",()=>{const t=Buffer.concat(r).toString("utf8");s(n,t),o(t)}),n.on("error",e)})}export async function readJson(n){return JSON.parse(await readBody(n))}export function sendJson(n,o,e){n.statusCode=o,n.setHeader("content-type","application/json"),n.end(JSON.stringify(e))}
|