@weavecode/weave 0.1.4 → 0.1.6
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/@modelcontextprotocol/sdk/node_modules/express/node_modules/encodeurl/README.md +14 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/encodeurl/index.js +5 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/encodeurl/package.json +10 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/CHANGELOG.md +42 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/README.md +38 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/dist/qs.js +18 -18
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/parse.js +16 -4
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/utils.js +13 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.cjs +6 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.mjs +6 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/package.json +10 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/decrypt.d.ts +3 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/unsecured.d.ts +2 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/verify.d.ts +3 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/types.d.ts +8 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/remote.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/package.json +1 -1
- 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.d.ts +2 -0
- package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -2
- 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 +4 -4
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +5 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +5 -5
- 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 +3 -3
- 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/instruction-link.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/provision.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 +14 -0
- 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/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 +4 -4
- package/node_modules/@weavecode/harness/dist/claude/capture.js +9 -9
- package/node_modules/@weavecode/harness/dist/claude/commands.d.ts +3 -0
- package/node_modules/@weavecode/harness/dist/claude/commands.js +2 -3
- package/node_modules/@weavecode/harness/dist/claude/config.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/edits.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/images.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/index.d.ts +1 -0
- package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/liveness.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/messaging.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/narration.d.ts +0 -11
- package/node_modules/@weavecode/harness/dist/claude/narration.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/plan.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 -2
- package/node_modules/@weavecode/harness/dist/claude/resume.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/rewind.d.ts +8 -0
- package/node_modules/@weavecode/harness/dist/claude/rewind.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/side-question.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +39 -18
- package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/transcript-cursor.d.ts +26 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript-cursor.js +2 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript.js +7 -7
- package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/capture.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/commands.js +4 -4
- package/node_modules/@weavecode/harness/dist/codex/config.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/event-source.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/images.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/liveness.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/messaging.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/narration.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/plugins.js +3 -3
- package/node_modules/@weavecode/harness/dist/codex/provision.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/questions.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/rollout.js +5 -5
- package/node_modules/@weavecode/harness/dist/codex/side-question.js +4 -4
- package/node_modules/@weavecode/harness/dist/codex/titles.js +4 -4
- package/node_modules/@weavecode/harness/dist/codex/toml.js +13 -13
- package/node_modules/@weavecode/harness/dist/codex/transcript.js +2 -2
- package/node_modules/@weavecode/harness/dist/driver.d.ts +49 -1
- package/node_modules/@weavecode/harness/dist/driver.js +1 -1
- package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
- package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -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/dist/shared/json-cap.js +1 -1
- package/node_modules/@weavecode/harness/package.json +2 -2
- package/node_modules/@weavecode/server/dist/config/dotted.js +1 -1
- package/node_modules/@weavecode/server/dist/config/profiles.d.ts +19 -13
- package/node_modules/@weavecode/server/dist/config/profiles.js +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.js +3 -3
- 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/config-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/cron.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/dashboard-pusher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/decision-config.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/entry.js +7 -1
- package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -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/liveness.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/mcp-orchestration.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/narration-watcher.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-ghostty.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-iterm.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-konsole.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-terminal-app.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wezterm.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wt.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/backend.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/launch.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/pty-terminals.js +4 -4
- package/node_modules/@weavecode/server/dist/daemon/opener/shared.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/wezterm-mux.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/wt.js +3 -3
- package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +2 -0
- package/node_modules/@weavecode/server/dist/daemon/opener.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/project-files.d.ts +12 -6
- package/node_modules/@weavecode/server/dist/daemon/project-files.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/prompt-images.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/hooks-admin.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/market.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/orchestration.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/path-refs.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/project-files.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/projects.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/search.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/session-control.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/session-insights.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/settings-statusline.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/uploads.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/visualizations.d.ts +3 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/visualizations.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/watches.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/server.js +8 -8
- package/node_modules/@weavecode/server/dist/daemon/session-open.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +5 -4
- package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -1
- 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.js +1 -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/daemon/upload-sessions.js +1 -1
- package/node_modules/@weavecode/server/dist/db/db.js +6 -2
- package/node_modules/@weavecode/server/dist/db/layout.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +3 -1
- package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/dashboard-rate.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/decision-judge.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/ack-gate.d.ts +12 -6
- package/node_modules/@weavecode/server/dist/hooks/delivery/ack-gate.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/channels.d.ts +3 -3
- package/node_modules/@weavecode/server/dist/hooks/delivery/channels.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/keys.d.ts +19 -9
- package/node_modules/@weavecode/server/dist/hooks/delivery/keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/queue.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/relay.d.ts +2 -2
- package/node_modules/@weavecode/server/dist/hooks/delivery/relay.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/send.js +2 -2
- package/node_modules/@weavecode/server/dist/hooks/delivery/views.d.ts +3 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/views.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
- package/node_modules/@weavecode/server/dist/hooks/edge-extract.js +1 -1
- 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.js +2 -2
- 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 +45 -38
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +5 -3
- package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
- package/node_modules/@weavecode/server/dist/hooks/orchestration-engine.js +7 -7
- package/node_modules/@weavecode/server/dist/hooks/orchestration-graph.js +1 -1
- 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.js +8 -8
- package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
- 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/session-purge.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/synthetic-sessions.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
- package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +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.js +1 -1
- package/node_modules/@weavecode/server/dist/install/global-config.js +1 -1
- package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
- package/node_modules/@weavecode/server/dist/install/init-files.js +2 -2
- package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
- package/node_modules/@weavecode/server/dist/install/installer.js +1 -1
- 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.js +1 -1
- 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.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.d.ts +1 -1
- package/node_modules/@weavecode/server/dist/repositories/hook-events.js +5 -5
- 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/orchestrations.js +7 -7
- package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
- 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 +11 -1
- package/node_modules/@weavecode/server/dist/repositories/sessions.js +4 -2
- package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +14 -4
- package/node_modules/@weavecode/server/dist/repositories/uploads.js +11 -11
- package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -3
- package/node_modules/@weavecode/server/dist/surfaces.d.ts +3 -1
- 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.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/{abnfDiagram-WEYOIA3C-DA-K085F.js → abnfDiagram-WEYOIA3C-CbIFQh0R.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{arc-BI1jnmdZ.js → arc-DH8-rYAa.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{architectureDiagram-ZHVYKT53-DbdBgric.js → architectureDiagram-ZHVYKT53-qnv6S0sc.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{blockDiagram-RJAE7QA3-BPRBmzb-.js → blockDiagram-RJAE7QA3-pT5eO-cB.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{c4Diagram-XDPPPE54-C4D5sRs1.js → c4Diagram-XDPPPE54-DHDBDMb1.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/channel-BHPeeuzN.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2E7WHVMD-9ZSKiNU3.js → chunk-2E7WHVMD-CT951PH5.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2Q5K7J3B-i0AOjw_8.js → chunk-2Q5K7J3B-E5AD7_ZY.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-4EMNKR2T-DTpLfX1H.js → chunk-4EMNKR2T-DWz9qkcy.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-55XCU76K-COQYRD4q.js → chunk-55XCU76K-D-SgWD8w.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-5VM5RSS4-VsftEbvo.js → chunk-5VM5RSS4-ci6YzbO5.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-JWPE2WC7-DonektJN.js → chunk-JWPE2WC7-CY4mr2f4.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-VQ5W62QI-CaKUwuul.js → chunk-VQ5W62QI-CON8zyg8.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-XXDRQBXY-DXH3D_MT.js → chunk-XXDRQBXY-DXXXZ4pW.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-ZCHMQSOR-COwyAuGn.js → chunk-ZCHMQSOR-CukvPvkM.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{classDiagram-v2-4MYWR3UA-DEvMZ6mX.js → classDiagram-v2-4MYWR3UA-GiWZ9xtF.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cose-bilkent-JH36ORCC-6JBJHfH6.js → cose-bilkent-JH36ORCC-D7aJ-akq.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cynefin-EF2NZ3EQ-C4GM4sjT.js → cynefin-EF2NZ3EQ-9B__MaRM.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cynefinDiagram-WF24UDRP-Cqgi0MBP.js → cynefinDiagram-WF24UDRP-B2ujZh2k.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{dagre-NK4GIZVX-CljrnkCY.js → dagre-NK4GIZVX-nHaB6IWf.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-CBK3MWTC-C3PyOj5J.js → diagram-CBK3MWTC-xKfjDvgr.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-I5XIIV2D-I5brQlaZ.js → diagram-I5XIIV2D-BHT2-5mY.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-ODIL2UCW-BX9uFNbU.js → diagram-ODIL2UCW-CckywF4W.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-PFBEJUXE-y7D-VmqJ.js → diagram-PFBEJUXE-Dpjlc7Wh.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-RJA3I4VV-DLUL8W42.js → diagram-RJA3I4VV-M6WznOaW.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-TYUNFSNR-DLCC3ILi.js → diagram-TYUNFSNR-DgRJ3zL1.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ebnfDiagram-V4P3TTPT-D7vALia7.js → ebnfDiagram-V4P3TTPT-BzzVN__a.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{elk-QONTBCTQ-Ct2_hatz.js → elk-QONTBCTQ-Ch6Gs9G9.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{erDiagram-KYQIGQAA-DxLai58T.js → erDiagram-KYQIGQAA-COxT-Pxb.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{flowDiagram-IUGLLWBU-AWn2IHrF.js → flowDiagram-IUGLLWBU-CJVWnTBa.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ganttDiagram-R7GPNTJY-DmRHd4Wz.js → ganttDiagram-R7GPNTJY-BkRpWPUl.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{gitGraphDiagram-PDYL7XHY-Ccj-t3zg.js → gitGraphDiagram-PDYL7XHY-Ba8BJcvZ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/index-CtifxEiF.css +11 -0
- package/node_modules/@weavecode/server/web/dist/assets/index-FwH9INgS.js +1090 -0
- package/node_modules/@weavecode/server/web/dist/assets/{infoDiagram-MVDRKAX5-BHquFlQa.js → infoDiagram-MVDRKAX5-HTQ5FUNK.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ishikawaDiagram-HPEHV2GE-CVogEbdm.js → ishikawaDiagram-HPEHV2GE-BNjEDIZy.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{journeyDiagram-BOSHW7O7-DC9XG9oh.js → journeyDiagram-BOSHW7O7-Cao6h91a.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{kanban-definition-FNSA4HC5-C_eu7DC_.js → kanban-definition-FNSA4HC5-CXIx2CHQ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{linear-keTbWHJ-.js → linear-65WmlvQb.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{mermaid.core-4sbg0MnY.js → mermaid.core-D39fi_iR.js} +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/{mindmap-definition-6OY57UG3-kMQS0S2l.js → mindmap-definition-6OY57UG3-DHqpz_AK.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{pegDiagram-ECIUJNBX-DcUFoEwP.js → pegDiagram-ECIUJNBX-Cpy1nsER.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{pieDiagram-GNMPY74T-BQJ7WDCx.js → pieDiagram-GNMPY74T-B1IyNqzr.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{quadrantDiagram-D57K4MC3-C7Oi1-sq.js → quadrantDiagram-D57K4MC3-zSM6o7mB.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{railroadDiagram-Y72NRBL7-CEF2QbOF.js → railroadDiagram-Y72NRBL7-oM4XJIwA.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{requirementDiagram-EQYSW5RA-CTjjFS7X.js → requirementDiagram-EQYSW5RA-CbCLBjHf.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sankeyDiagram-SY24JHO5-j0S5kubS.js → sankeyDiagram-SY24JHO5-BucVk6EP.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sequenceDiagram-BLEHNHQU-B76EsZp4.js → sequenceDiagram-BLEHNHQU-Dg8CYEnT.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sizeCapture-INFHLROL-r0DZuqAy.js → sizeCapture-INFHLROL-C51zb7Oc.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{stateDiagram-v2-A6IESKWZ-B4DR9LHz.js → stateDiagram-v2-A6IESKWZ-BvK2l3is.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{swimlanes-B3ENRKFQ-Dbcl85ro.js → swimlanes-B3ENRKFQ-Ds7QOfXW.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-ByBF02UJ.js +8 -0
- package/node_modules/@weavecode/server/web/dist/assets/{timeline-definition-JXYKGLGB-BlBXXRNf.js → timeline-definition-JXYKGLGB-CadU4Qq4.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{usecaseDiagram-WPOLBNNX-Ck1M0dpc.js → usecaseDiagram-WPOLBNNX-BYuZwTDZ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{vennDiagram-Q3Y3IDCW-N8B-ohWk.js → vennDiagram-Q3Y3IDCW-C7zgxe07.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{wardleyDiagram-IVAIDKWA-DX-AMXq_.js → wardleyDiagram-IVAIDKWA-DA4Otf4s.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{xychartDiagram-4URNHDU4-4fgL48Yl.js → xychartDiagram-4URNHDU4-Bs5YGwMU.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/index.html +2 -2
- package/node_modules/@weavecode/server/web/dist/sw.js +14 -12
- package/node_modules/@weavecode/templates/package.json +2 -2
- package/package.json +6 -6
- package/node_modules/@weavecode/server/web/dist/assets/channel-DcCJrvon.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/index-BSxzia7U.js +0 -1031
- package/node_modules/@weavecode/server/web/dist/assets/index-CEpJpR7P.css +0 -11
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-CZ_6SSBd.js +0 -8
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),O(
|
|
3
|
-
`,{encoding:"utf8",mode:384}),O(s,t),y(t,384),this.persistedPendingOrigins=e}catch{}}sessionExited(e){this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.revokedPaneEnvs.add(e),this.persistPaneEnvs(),this.awaitingAck.delete(e);const t=this.deps.sessions.getBySessionId(e),s=t?.projectId==null?null:this.deps.projects.getById(t.projectId);if(!s)return;const i=k(this.hooksDir,s.token).filter(n=>n.sessionId===e);this.failQueuedOffline(e,i.filter(n=>!this.dismissedIds.has(n.id)))}async sessionTerminals(){return Se(this.deps,this.terminalChannel(),this.paneEnvs,()=>this.persistPaneEnvs(),this.revokedPaneEnvs)}diagnose(e){const t=this.surfaceOfSession(e),s=this.deps.sessions.livenessRowOf(e),i=s?F(s,this.deps.livenessOf?.()??A()):null,n=t?.promptInbox??null,r=this.inboxSockets.get(e),l=n?r?n.requiresAuthOn(process.platform)&&!r.token?{status:"unavailable",reason:"auth-token-required"}:{status:"ready",reason:null}:{status:"unavailable",reason:"no-credentials"}:{status:"unavailable",reason:"no-mechanism"},a=t?.queuedPrompt?{status:"ready",reason:null}:{status:"unavailable",reason:"no-mechanism"},o=t?.prompt?.resolve(e)??null,c=t?.prompt?o?{status:"ready",reason:null}:{status:"unavailable",reason:"no-peer-name"}:{status:"unavailable",reason:"no-mechanism"},h=this.paneEnvs.has(e),u=this.terminalChannel()?h?{status:"ready",reason:null}:{status:"unknown",reason:"no-pane-env"}:{status:"unavailable",reason:"no-backend"},d=this.deps.sessions.getBySessionId(e),S=d?.projectId==null?null:this.deps.projects.getById(d.projectId),q=S?k(this.hooksDir,S.token).filter(K=>K.sessionId===e).length:0;return{alive:i,inbox:l,queue:a,relay:c,terminal:u,paneEnvReported:h,pending:q,stalled:this.gate.isStalled(e)}}onSessionPrompt(e,t,s){const i=this.gate.acknowledge(e,t,s,{ackMinText:Te});return this.gate.hitLast&&this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e),i}noteActivity(e){this.gate.noteActivity(e)&&this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)}armAckWatch(e){this.gate.armAckWatch(e)}armCommandAck(e){this.gate.armCommandAck(e,t=>{this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)})}stall(e,t,s){this.gate.stall(e,t,s)}async answer(e,t){if(t.length===0||!D.test(t[0])||t.some(i=>!D.test(i)&&!V.test(i)))return{ok:!1,status:400,error:"Invalid answer keys"};const s=await this.sessionKeysTarget(e);if(!s.ok)return s;try{for(const[i,n]of t.entries())i>0&&await p(U),await s.terminal.sendKeys(s.paneId,n);return{ok:!0}}catch(i){return{ok:!1,status:409,error:i instanceof Error?i.message:String(i)}}}async interrupt(e,t="both",s){const i=await this.sessionKeysTarget(e,"\u51FB\u952E",t);if(!i.ok)return i;if(s!=null&&i.paneId===s)return{ok:!0,paneId:i.paneId,sent:!1};try{return await i.terminal.sendKeys(i.paneId,z),{ok:!0,paneId:i.paneId,sent:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async closePane(e){const t=await this.sessionKeysTarget(e,"\u5173\u95ED");if(!t.ok)return t;try{return await t.terminal.closePane(t.paneId),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async cycleMode(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,Y),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async pressEnter(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,X),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async pressCtrlC(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,$),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async setModel(e,t){const s=t.trim();if(!Z.test(s))return{ok:!1,status:400,error:"\u6A21\u578B\u540D\u5F62\u6001\u4E0D\u5408\u6CD5\uFF08\u4E0D\u542B\u7A7A\u767D\u4E0E\u63A7\u5236\u5B57\u7B26\uFF0C\u2264128 \u5B57\u7B26\uFF09"};const i=await this.sessionKeysTarget(e);if(!i.ok)return i;try{return await i.terminal.sendText(i.paneId,ie(s)),{ok:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async setEffort(e,t){const s=t.trim(),i=await this.sessionKeysTarget(e);if(!i.ok)return i;const n=te(this.deps.hookEvents,e);if(!n.includes(s))return{ok:!1,status:400,error:`\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\u4E0D\u5408\u6CD5\uFF08\u53EF\u9009\uFF1A${n.join(" / ")||"\u65E0"}\uFF09`};try{return await i.terminal.sendText(i.paneId,ee(s)),{ok:!0}}catch(r){return{ok:!1,status:409,error:r instanceof Error?r.message:String(r)}}}async askSideQuestion(e,t){if(!this.deps.sessions.getBySessionId(e))return{ok:!1,status:404,error:"Session not found"};const s=this.surfaceOfSession(e),i=s?.sideQuestion??null;if(!i)return{ok:!1,status:409,error:s?.unsupportedReasons?.sideQuestion??"\u8FD9\u4E2A harness \u6CA1\u6709\u65C1\u8DEF\u4F1A\u8BDD\u901A\u9053"};const n=i.validate(t);if(!n.ok)return{ok:!1,status:400,error:n.error};if(i.prerequisite&&this.deps.sessions.hasRunOf(e)!==!0)return{ok:!1,status:409,error:i.prerequisite};const r=await this.sessionKeysTarget(e,"\u53D1\u8D77\u65C1\u8DEF\u4F1A\u8BDD");if(!r.ok)return r;try{return i.screen?(this.pollScreenAnswer(e,r.terminal,r.paneId,i,n.text),{ok:!0,question:n.text}):(await r.terminal.sendText(r.paneId,i.command(n.text)),{ok:!0,question:n.text})}catch(l){return{ok:!1,status:409,error:l instanceof Error?l.message:String(l)}}}pollScreenAnswer(e,t,s,i,n){const r=i.screen,l=async()=>await t.getPaneText?.(s).catch(()=>null)??null;(async()=>{const a=await l()??"";await t.sendKeys(s,r.openKeys).catch(()=>{}),await p(j),await t.sendKeys(s,r.submitKey).catch(()=>{}),await p(C);let o=await l();if((!o||!r.panelOpen(o))&&(await t.sendKeys(s,r.submitKey).catch(()=>{}),await p(C),o=await l(),!o||!r.panelOpen(o)))return;await t.sendText(s,n).catch(()=>{}),await p(j),await t.sendKeys(s,r.submitKey).catch(()=>{});const c=Date.now()+je;let h=null;for(;Date.now()<c;){if(await p(Me),o=await l(),o==null)return;const d=r.extractAnswer(n,a,o);if(d.done){h=d.answer;break}}h!=null&&(this.sideAnswerStore?.answerById(e,n,h),this.bus({kind:"sideQuestion.answered",sessionId:e,at:new Date().toISOString()}));const u=await l();u&&r.panelOpen(u)&&await t.sendKeys(s,r.closeKey).catch(()=>{})})()}async sessionKeysTarget(e,t="\u51FB\u952E",s="both"){return ne(this.keysDeps(),e,t,s)}busSafe(){return{emit:e=>this.bus(e)}}channelDeps(){return{setMemory:e=>this.memory.set(e.id,e),deleteMemory:e=>this.memory.delete(e),awaitAck:(e,t)=>this.gate.await(e,t),isSlashCommand,armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:e=>this.gate.armCommandAck(e,t=>{this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)}),emit:e=>this.bus(e),...this.deps.spawnImpl?{spawnImpl:this.deps.spawnImpl}:{}}}wireTextOfEntry(e){return oe(e,t=>this.surfaceOfSession(t))}hasImagesEntry(e){return re(e)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(e,t,s)=>this.terminalPaneFor(e,t,s)}}async resend(e){const t=this.memory.get(e);if(!t)return{ok:!1,status:404,error:"Message not found"};if(!(t.channel==="prompt"&&(t.status==="failed"||t.status==="delivered"&&!t.acked)))return{ok:!1,status:409,error:"Message is not resendable"};const i=this.deps.sessions.getBySessionId(t.sessionId);if(!i)return{ok:!1,status:404,error:"Session not found"};if(i.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const n=this.deps.projects.getById(i.projectId);if(!n)return{ok:!1,status:404,error:"Project not found"};const r=this.surfaceOfSession(t.sessionId);if(!r)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};if(this.gate.clearStall(t.sessionId,e),t.status==="delivered"&&t.via==="terminal"&&this.terminalChannel()){const o=await this.terminalPaneFor(i,n);if(o)return this.memory.set(e,{...t,status:"delivering",stalled:!1,settledAt:null}),this.runTerminalSubmit(e,o.id),this.bus({kind:"message.created",messageId:e,sessionId:t.sessionId,mode:t.mode,at:new Date().toISOString()}),{ok:!0,messageId:e,status:"delivering",message:this.memory.get(e)}}this.memory.delete(e);const l={...t,status:"pending",stalled:!1,acked:!1,settledAt:null,reason:void 0,error:null},a=await this.deliverPrompt(l,i,n,r);return this.bus({kind:"message.created",messageId:l.id,sessionId:l.sessionId,mode:l.mode,at:new Date().toISOString()}),a}dismiss(e,t){const s=this.memory.get(t);if(s){if(s.status==="running")return{ok:!1,status:409,error:"Message is still in flight"};s.status==="delivering"&&this.gate.headOf(s.sessionId)===t&&this.flushing.delete(s.sessionId),this.memory.delete(t),this.gate.clearStall(s.sessionId,t),this.gate.release(s.sessionId,t),this.queuedSessions.has(s.sessionId)&&this.scheduleFlushContinuation(s.sessionId)}else if(!this.dropQueued(e,t))return{ok:!1,status:404,error:"Message not found"};return this.bus({kind:"message.dismissed",messageId:t,sessionId:e,at:new Date().toISOString()}),{ok:!0}}dropQueued(e,t){const s=this.deps.sessions.getBySessionId(e);if(s?.projectId==null)return!1;const i=this.deps.projects.getById(s.projectId);if(!i)return!1;const n=k(this.hooksDir,i.token);if(!n.some(r=>r.id===t&&r.sessionId===e))return!1;for(f(this.hooksDir,i.token,new Set([t])),this.dismissedIds.add(t);this.dismissedIds.size>Pe;){const r=this.dismissedIds.values().next().value;if(r===void 0)break;this.dismissedIds.delete(r)}return n.some(r=>r.sessionId===e&&r.id!==t)||this.queuedSessions.delete(e),!0}async flushSession(e){if(this.stalled.has(e)||this.flushing.has(e)||!this.queuedSessions.has(e))return;const t=Symbol(e);this.flushing.set(e,t);try{await this.flushSessionInner(e)}catch{}finally{this.flushing.get(e)===t&&this.flushing.delete(e)}}async flushSessionInner(e){if(!this.ackGateOpen(e))return;const t=this.deps.sessions.getBySessionId(e);if(t?.projectId==null)return;const s=this.deps.projects.getById(t.projectId);if(!s)return;const i=k(this.hooksDir,s.token).filter(a=>a.sessionId===e);if(i.length===0){this.queuedSessions.delete(e);return}if(this.sessionJudgedDead(e)){this.failQueuedOffline(e,i.filter(a=>!this.dismissedIds.has(a.id)));return}const n=this.surfaceOfSession(e),r=n?.prompt??null,l=this.modalBlocked(e);for(const a of i){if(this.stalled.has(e))return;if(this.dismissedIds.has(a.id))continue;const o={id:a.id,sessionId:e,text:a.text,...a.attachments&&a.attachments.length>0?{attachments:a.attachments}:{},mode:"prompt",oneWay:a.oneWay===!0,...a.forceTerminal===!0?{forceTerminal:!0}:{},via:"socket",channel:"prompt",status:"pending",at:a.at};if(!l&&this.hasImagesEntry(o)&&this.terminalChannel()){const u=await this.terminalPaneFor(t,s);if(u){f(this.hooksDir,s.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(e,o.id),await this.runTerminalPrompt(o.id,u.id,this.wireTextOfEntry(o)),this.settleQueueIndex(e,s.token);return}}if(n&&await this.tryQueuedDeliver(o,n)){f(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}if(n&&await this.tryInboxDeliver(o,n)){f(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}const c=r?.resolve(e)??null,h=o.forceTerminal===!0?["terminal"]:o.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of h){if(u==="relay"&&r&&c){if(this.memory.set(o.id,{...o,status:"delivering",via:"relay"}),!this.runRelay(o,r,c.name)){this.memory.delete(o.id);return}this.awaitingAck.set(e,o.id),f(this.hooksDir,s.token,new Set([a.id]));break}if(u==="terminal"&&!l&&this.terminalChannel()){const d=await this.terminalPaneFor(t,s);if(d){f(this.hooksDir,s.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(e,o.id),await this.runTerminalPrompt(o.id,d.id,this.wireTextOfEntry(o));break}}}if(this.awaitingAck.get(e)===o.id){this.settleQueueIndex(e,s.token);return}return}this.settleQueueIndex(e,s.token)}settleQueueIndex(e,t){k(this.hooksDir,t).every(s=>s.sessionId!==e)&&this.queuedSessions.delete(e)}async flushAll(){for(const e of[...this.queuedSessions])await this.flushSession(e)}forgetSession(e){let t=0;for(const[s,i]of this.memory)i.sessionId===e&&(this.memory.delete(s),t++);return t+=ye(this.hooksDir,e),this.queuedSessions.delete(e),this.gate.clearStall(e),this.gate.release(e),this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.revokedPaneEnvs.add(e),this.persistPaneEnvs(),t}forgetProject(e){const t=this.pendingOrigins.length;this.pendingOrigins=this.pendingOrigins.filter(i=>i.projectId!==e),this.pendingOrigins.length!==t&&this.persistPendingOrigins();let s=0;for(const[i,n]of this.memory)this.deps.sessions.getBySessionId(n.sessionId)?.projectId===e&&(this.memory.delete(i),this.inboxSockets.forget(n.sessionId),this.paneEnvs.delete(n.sessionId),this.gate.clearStall(n.sessionId),this.gate.release(n.sessionId),s++);for(const i of[...this.queuedSessions])this.deps.sessions.getBySessionId(i)?.projectId===e&&(s+=this.forgetSession(i));return this.persistPaneEnvs(),s}surfaceOfSession(e){const t=this.deps.hookEvents.listBySession(e,1),s=t[t.length-1]?.source;return E(s)?this.deps.surfaceFor?.(s)??L(s):null}resolveChannel(e,t,s){return he(this.deps.sessions,()=>this.terminalChannel()!=null,e,t,s)}async terminalPaneFor(e,t,s="both"){return se(this.terminalChannel(),this.paneEnvs,e,t,s)}terminalChannel(){const e=this.deps.terminal;return e&&e.available()?e:null}modalBlocked(e){return this.deps.blockedByQuestion?.(e)===!0}async deliverPrompt(e,t,s,i){if(this.sessionJudgedDead(e.sessionId))return{ok:!0,messageId:e.id,status:"failed",message:this.failOffline(e)};const n=this.modalBlocked(e.sessionId);if(!n&&this.hasImagesEntry(e)&&this.terminalChannel()){const u=await this.terminalPaneFor(t,s);if(u)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,u.id,this.wireTextOfEntry(e)),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)}}const r=await this.tryQueuedDeliver(e,i);if(r)return{ok:!0,messageId:e.id,status:"delivered",message:r};const l=await this.tryInboxDeliver(e,i);if(l)return{ok:!0,messageId:e.id,status:"delivered",message:l};const a=i.prompt,o=a?.resolve(e.sessionId)??null,c=e.forceTerminal===!0?["terminal"]:e.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of c){if(u==="relay"&&a&&o){if(this.memory.set(e.id,{...e,status:"delivering",via:"relay"}),this.runRelay(e,a,o.name))return this.awaitingAck.set(e.sessionId,e.id),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)};this.memory.delete(e.id)}if(u==="terminal"&&!n&&this.terminalChannel()){const d=await this.terminalPaneFor(t,s);if(d)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,d.id,this.wireTextOfEntry(e)),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)}}}if(this.sessionJudgedDead(e.sessionId))return{ok:!0,messageId:e.id,status:"failed",message:this.failOffline(e)};this.queueEntry(e,s.token);const h={...e,status:"pending"};return{ok:!0,messageId:e.id,status:"pending",message:h}}async tryQueuedDeliver(e,t){const s=t.queuedPrompt;if(!s||this.hasImagesEntry(e))return null;const{bin:i,args:n}=s.command(e.sessionId,this.wireTextOfEntry(e));this.memory.set(e.id,{...e,status:"delivering",via:"queue"});try{await ae(i,n,s.timeoutMs??3e4,this.deps.spawnImpl)}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),{...e,via:"queue"},"queue")}async tryInboxDeliver(e,t){const s=t.promptInbox,i=this.inboxSockets.get(e.sessionId);if(!s||!i||e.forceTerminal===!0)return null;this.memory.set(e.id,{...e,status:"delivering",via:"socket"});try{await J(s,i,this.wireTextOfEntry(e))}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),e,"socket")}queueEntry(e,t){de(this.hooksDir,t,e),this.queuedSessions.add(e.sessionId)}sessionJudgedDead(e,t=this.deps.livenessOf?.()??A()){return fe(this.deps.sessions,e,t)}failOffline(e){return ce(this.memory,t=>this.bus(t),e)}failQueuedOffline(e,t){me(this.deps,this.hooksDir,this.memory,s=>this.bus(s),e,t),this.queuedSessions.delete(e)}relayDeps(){return{headless:this.headless,getMemory:e=>this.memory.get(e)??null,setMemory:e=>this.memory.set(e.id,e),awaitAck:(e,t)=>this.gate.await(e,t),stall:(e,t,s)=>this.gate.stall(e,t,s),isSlashCommand,armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:(e,t)=>this.gate.armCommandAck(e,s=>{t(s),this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)}),onReleased:e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)},emit:e=>this.bus(e),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.relayTimeoutMs===void 0?{}:{relayTimeoutMs:this.deps.relayTimeoutMs}}}runRelay(e,t,s){return pe(this.relayDeps(),e,t,s,this.wireTextOfEntry(e))}async runTerminalPrompt(e,t,s){await this.runTerminal(e,i=>i.sendText(t,s))}async runTerminalSubmit(e,t){await this.runTerminal(e,s=>s.sendKeys(t,"\r"))}async runTerminal(e,t){const s=this.memory.get(e);if(!s)return;const i=this.terminalChannel();if(i)try{await t(i);const n=this.memory.get(e);if(!n)return;const r={...n,status:"delivered",settledAt:new Date().toISOString()};this.memory.set(e,r),isSlashCommand(n.text)?this.armCommandAck(e):this.armAckWatch(r),this.bus({kind:"message.delivered",messageId:e,sessionId:s.sessionId,at:new Date().toISOString()})}catch(n){const r=this.memory.get(e);if(!r)return;if(r.acked===!0){const a=new Date().toISOString();this.memory.set(e,{...r,status:"delivered",settledAt:a}),this.bus({kind:"message.delivered",messageId:e,sessionId:r.sessionId,at:a});return}const l={...r,status:"failed",error:n instanceof Error?n.message:String(n),settledAt:new Date().toISOString()};this.memory.set(e,l),this.stall(s.sessionId,l,"failed"),this.bus({kind:"message.finished",messageId:e,sessionId:s.sessionId,status:"failed",at:new Date().toISOString()})}}deliverInject(e,t,s,i){return ue({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},e,t,s,i,this.wireTextOfEntry(e))}deliverHeadless(e,t,s,i){return le({memory:this.memory,headless:this.headless,bus:this.busSafe(),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.timeoutMs===void 0?{}:{timeoutMs:this.deps.timeoutMs}},e,t,s,i,this.wireTextOfEntry(e))}bus(e){try{this.deps.bus?.emit(e)}catch{}}}
|
|
1
|
+
import{randomUUID as K}from"node:crypto";import{chmodSync as S,mkdirSync as v,readFileSync as w,renameSync as O,writeFileSync as E}from"node:fs";import{dirname as b,join as g}from"node:path";import{isHarness as k}from"@weavecode/core";import{commandModeAt as Q,turnOutputOf as R}from"@weavecode/harness";import{isImageMediaType as D}from"../repositories/uploads.js";import{commandsSurfaceFor as N,messagingSurfaceFor as W}from"../surfaces.js";import{pidAliveOf as _}from"../daemon/claude-liveness.js";import{combinedLivenessOf as T}from"../daemon/liveness.js";import{HeadlessRunner as J}from"./headless-runner.js";import{hooksRoot as G}from"./mirror.js";import{INBOX_TARGETS_FILE as L,InboxSocketRegistry as H,deliverViaInboxSocket as $}from"./inbox-socket.js";import{AckGate as V}from"./delivery/ack-gate.js";import{ANSWER_ATOM as A,ANSWER_ATOM_GAP_MS as Y,ANSWER_TEXT as U,CTRL_B as X,CTRL_C_KITTY as z,ENTER as Z,ESC as ss,ESC_KITTY as es,MODEL_NAME as ts,SHIFT_TAB as is,effortCommand as ns,effortLevelsOf as rs,locateTerminalPane as as,modelCommand as os,sessionKeysTarget as ds}from"./delivery/keys.js";import{hasImages as us,settleDelivered as P,spawnOnce as hs,wireTextOf as ls}from"./delivery/channels.js";import{deliverHeadless as cs,deliverInject as ms,resolveChannel as fs}from"./delivery/send.js";import{appendQueueEntry as ps,failOffline as gs,failQueuedOffline as ys,sessionJudgedDead as ks}from"./delivery/queue.js";import{runRelay as Is}from"./delivery/relay.js";import{listInflightCounts as Ss,listVisible as vs,sessionTerminals as ws}from"./delivery/views.js";import{readPromptbox as y,removePromptboxBySession as Os,removePromptboxEntries as p,scanQueuedSessionIds as Es}from"./promptbox.js";const bs=1e3,Ds=6e4,Ts=3e4,As=9e4,Ps=5e3,xs=8,Cs=12e4,js=1200,Ms=/interrupted/i,Fs=/· done/,Bs=12,qs=[es,ss,X],Ks=600,Qs=250,Rs=5,Ns=200,x="pane-envs.json",C="pending-origins.json",j=15*6e4;function Ws(f){try{const s=JSON.parse(w(f,"utf8"));if(!Array.isArray(s))return[];const e=[];for(const t of s){if(typeof t!="object"||t===null)continue;const i=t;if(!k(i.harness)||typeof i.projectId!="number"||typeof i.env!="object"||i.env===null||typeof i.at!="string")continue;const n={};for(const[r,d]of Object.entries(i.env))typeof d=="string"&&d&&(n[r]=d);Object.keys(n).length!==0&&e.push({harness:i.harness,projectId:i.projectId,env:n,at:i.at})}return e.filter(t=>Date.now()-Date.parse(t.at)<j)}catch{return[]}}function _s(f){try{const s=JSON.parse(w(f,"utf8"));if(typeof s!="object"||s===null)return{};const e={};for(const[t,i]of Object.entries(s)){if(typeof i!="object"||i===null)continue;const n={};for(const[r,d]of Object.entries(i))typeof d=="string"&&d&&(n[r]=d);Object.keys(n).length>0&&(e[t]=n)}return e}catch{return{}}}const m=f=>new Promise(s=>setTimeout(s,f)),M=300,F=1500,Js=1e3,Gs=12e4;export class MessageDeliverer{deps;headless;hooksDir;sideAnswerStore;memory=new Map;queuedSessions;inboxSockets;paneEnvs;revokedPaneEnvs=new Set;paneEnvConflicts=new Map;persistedPaneEnvs;pendingOrigins;persistedPendingOrigins;flushScheduled=new Set;flushing=new Map;stalled=new Map;awaitingAck=new Map;dismissedIds=new Set;gate;constructor(s){this.deps=s,this.headless=s.headless??new J({spawnImpl:s.spawnImpl,killImpl:s.killImpl}),this.hooksDir=s.hooksDir??G(),this.sideAnswerStore=s.sideAnswerStore,this.inboxSockets=new H(g(this.hooksDir,L));const e=_s(g(this.hooksDir,x));this.paneEnvs=new Map(Object.entries(e)),this.persistedPaneEnvs=JSON.stringify(e),this.pendingOrigins=Ws(g(this.hooksDir,C)),this.persistedPendingOrigins=JSON.stringify(this.pendingOrigins),this.queuedSessions=Es(this.hooksDir),this.gate=new V({awaitingAck:this.awaitingAck,stalled:this.stalled,memory:this.memory},{ackStallMs:s.ackStallMs??Ts,ackStallReleaseMs:s.ackStallReleaseMs??As,commandAckGraceMs:s.commandAckGraceMs??Ps},{emit:t=>this.bus(t)},(t,i)=>this.commandModeOf(t,i)!==null),this.gate.onAutoRelease=t=>this.scheduleFlushContinuation(t)}async send(s){const e=this.deps.sessions.getBySessionId(s.toSessionId);if(!e)return{ok:!1,status:404,error:"Session not found"};const t=this.surfaceOfSession(s.toSessionId);if(!t)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};const i=s.attachments?[...s.attachments]:[];if(i.length>0){if(!t.attach)return{ok:!1,status:409,error:"This harness cannot receive attachments"};if(i.some(l=>D(l.mediaType))&&!t.attach.kinds.includes("image"))return{ok:!1,status:409,error:"This harness cannot receive images"};if(i.some(l=>!D(l.mediaType))&&!t.attach.kinds.includes("file"))return{ok:!1,status:409,error:"This harness cannot receive file attachments"}}const n=this.resolveChannel(s.mode,s.toSessionId,t);if(typeof n!="string")return{ok:!1,status:409,error:n.reason};if(e.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const r=this.deps.projects.getById(e.projectId);if(!r)return{ok:!1,status:404,error:"Project not found"};if(n==="headless"&&this.headless.isBusy(s.toSessionId))return{ok:!1,status:409,error:"Session already has a running run"};const d={fromLabel:s.fromKind==="session"?`session ${s.fromSessionId??"unknown"}`:s.fromKind,at:new Date().toISOString(),mode:n},a={id:K(),sessionId:s.toSessionId,text:s.text,...i.length>0?{attachments:i}:{},mode:s.mode,oneWay:s.oneWay===!0,...s.forceTerminal===!0?{forceTerminal:!0}:{},channel:n,status:"pending",at:d.at},o=n==="prompt"&&this.blockedAhead(a.sessionId);o&&(this.queueEntry(a,r.token),this.scheduleFlushContinuation(a.sessionId));const h=o?{ok:!0,messageId:a.id,status:"pending",message:a}:n==="inject"?this.deliverInject(a,r.token,d,t):n==="headless"?this.deliverHeadless(a,r.path,d,t):await this.deliverPrompt(a,e,r,t);return this.bus({kind:"message.created",messageId:a.id,sessionId:a.sessionId,mode:a.mode,at:a.at}),h}getMessage(s){return this.memory.get(s)??null}listVisible(s){return vs(this.deps,this.hooksDir,this.memory,s,this.deps.visibleTtlMs??Ds,e=>this.commandModeOf(s,e)!==null)}hasQueued(s){return this.queuedSessions.has(s)}listInflightCounts(){return Ss(this.hooksDir,this.memory)}hasTerminalChannel(){return this.terminalChannel()!=null}scheduleFlushContinuation(s){this.flushScheduled.has(s)||(this.flushScheduled.add(s),setTimeout(()=>{this.flushScheduled.delete(s),this.flushSession(s)},this.deps.flushGapMs??bs).unref?.())}ackGateOpen(s){return this.gate.open(s)}blockedAhead(s){return this.ackGateOpen(s)?this.queuedSessions.has(s)||this.flushing.has(s):!0}noteInboxSocket(s,e){this.inboxSockets.set(s,e)}async awaitInboxReady(s,e){const t=this.surfaceOfSession(s)?.promptInbox??null;if(!t)return!1;const i=()=>{const r=this.inboxSockets.get(s);return!!r&&(!t.requiresAuthOn(process.platform)||!!r.token)},n=Date.now()+e;for(;!i();){if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,Qs))}return!0}lastTurnOutput(s){const e=this.deps.hookEvents.listBySession(s,Rs);for(let t=e.length-1;t>=0;t--){const i=e[t];let n=null;try{n=JSON.parse(i.payload)}catch{continue}const r=R(n?.raw);if(r)return{output:r,at:i.createdAt}}return null}notePaneEnv(s,e){const t=JSON.stringify(e);for(const[i,n]of this.paneEnvs){if(i===s||JSON.stringify(n)!==t)continue;const r=this.deps.sessions.getBySessionId(i)?.lastSeenAt;if((r?Date.now()-Date.parse(r):Number.POSITIVE_INFINITY)<Cs){this.paneEnvs.delete(s),this.paneEnvConflicts.set(s,i),this.persistPaneEnvs();return}this.paneEnvs.delete(i),this.revokedPaneEnvs.add(i)}this.paneEnvConflicts.delete(s),this.paneEnvs.set(s,e),this.revokedPaneEnvs.delete(s),this.persistPaneEnvs()}paneEnvConflictOf(s){return this.paneEnvConflicts.get(s)??null}notePendingOrigin(s){this.pendingOrigins=this.pendingOrigins.filter(e=>Date.now()-Date.parse(e.at)<j),this.pendingOrigins.push({...s,at:new Date().toISOString()}),this.persistPendingOrigins()}claimPendingOrigin(s,e,t){const i=this.pendingOrigins.findIndex(r=>r.harness===e&&r.projectId===t);if(i<0)return;const[n]=this.pendingOrigins.splice(i,1);this.notePaneEnv(s,n.env),this.persistPendingOrigins()}persistPaneEnvs(){const s=JSON.stringify(Object.fromEntries(this.paneEnvs));if(s===this.persistedPaneEnvs)return;const e=g(this.hooksDir,x);try{v(b(e),{recursive:!0});const t=`${e}.tmp`;E(t,`${s}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),O(t,e),S(e,384),this.persistedPaneEnvs=s}catch{}}persistPendingOrigins(){const s=JSON.stringify(this.pendingOrigins);if(s===this.persistedPendingOrigins)return;const e=g(this.hooksDir,C);try{v(b(e),{recursive:!0});const t=`${e}.tmp`;E(t,`${s}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),O(t,e),S(e,384),this.persistedPendingOrigins=s}catch{}}sessionExited(s){this.inboxSockets.forget(s),this.paneEnvs.delete(s),this.revokedPaneEnvs.add(s),this.persistPaneEnvs(),this.awaitingAck.delete(s);const e=this.deps.sessions.getBySessionId(s),t=e?.projectId==null?null:this.deps.projects.getById(e.projectId);if(!t)return;const i=y(this.hooksDir,t.token).filter(n=>n.sessionId===s);this.failQueuedOffline(s,i.filter(n=>!this.dismissedIds.has(n.id)))}async sessionTerminals(){return ws(this.deps,this.terminalChannel(),this.paneEnvs,()=>this.persistPaneEnvs(),this.revokedPaneEnvs)}diagnose(s){const e=this.surfaceOfSession(s),t=this.deps.sessions.livenessRowOf(s),i=t?_(t,this.deps.livenessOf?.()??T()):null,n=e?.promptInbox??null,r=this.inboxSockets.get(s),d=n?r?n.requiresAuthOn(process.platform)&&!r.token?{status:"unavailable",reason:"auth-token-required"}:{status:"ready",reason:null}:{status:"unavailable",reason:"no-credentials"}:{status:"unavailable",reason:"no-mechanism"},a=e?.queuedPrompt?{status:"ready",reason:null}:{status:"unavailable",reason:"no-mechanism"},o=e?.prompt?.resolve(s)??null,h=e?.prompt?o?{status:"ready",reason:null}:{status:"unavailable",reason:"no-peer-name"}:{status:"unavailable",reason:"no-mechanism"},l=this.paneEnvs.has(s),u=this.terminalChannel()?l?{status:"ready",reason:null}:this.paneEnvConflicts.has(s)?{status:"unavailable",reason:"pane-env-conflict"}:{status:"unknown",reason:"no-pane-env"}:{status:"unavailable",reason:"no-backend"},c=this.deps.sessions.getBySessionId(s),I=c?.projectId==null?null:this.deps.projects.getById(c.projectId),B=I?y(this.hooksDir,I.token).filter(q=>q.sessionId===s).length:0;return{alive:i,inbox:d,queue:a,relay:h,terminal:u,paneEnvReported:l,pending:B,stalled:this.gate.isStalled(s)}}onSessionPrompt(s,e,t){const i=this.gate.acknowledge(s,e,t,{ackMinText:xs});return this.gate.hitLast&&this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s),i}noteActivity(s){this.gate.noteActivity(s)&&this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)}armAckWatch(s){this.gate.armAckWatch(s)}armCommandAck(s){this.gate.armCommandAck(s,e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)})}stall(s,e,t){this.gate.stall(s,e,t)}async answer(s,e){if(e.length===0||!A.test(e[0])||e.some(i=>!A.test(i)&&!U.test(i)))return{ok:!1,status:400,error:"Invalid answer keys"};const t=await this.sessionKeysTarget(s);if(!t.ok)return t;try{for(const[i,n]of e.entries())i>0&&await m(Y),await t.terminal.sendKeys(t.paneId,n);return{ok:!0}}catch(i){return{ok:!1,status:409,error:i instanceof Error?i.message:String(i)}}}async interrupt(s){const e=await this.sessionKeysTarget(s,"\u51FB\u952E");if(!e.ok)return e;const t=async()=>{try{return await e.terminal.getPaneText?.(e.paneId)??null}catch{return null}},i=d=>{const a=d.split(`
|
|
4
|
+
`).slice(-Bs).join(`
|
|
5
|
+
`);return Ms.test(a)||Fs.test(a)},n=this.deps.interruptVerifyMs??js;let r=!1;for(const[d,a]of qs.entries()){try{await e.terminal.sendKeys(e.paneId,a)}catch(h){if(d===0)return{ok:!1,status:409,error:h instanceof Error?h.message:String(h)};break}await m(d===0?n:Ks);const o=await t();if(o===null)return{ok:!0,paneId:e.paneId,sent:!0,confirmed:!0};if(i(o)){r=!0;break}}return{ok:!0,paneId:e.paneId,sent:!0,confirmed:r}}async closePane(s){const e=await this.sessionKeysTarget(s,"\u5173\u95ED");if(!e.ok)return e;try{return await e.terminal.closePane(e.paneId),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async cycleMode(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,is),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressEnter(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,Z),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressCtrlC(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,z),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async setModel(s,e){const t=e.trim();if(!ts.test(t))return{ok:!1,status:400,error:"\u6A21\u578B\u540D\u5F62\u6001\u4E0D\u5408\u6CD5\uFF08\u4E0D\u542B\u7A7A\u767D\u4E0E\u63A7\u5236\u5B57\u7B26\uFF0C\u2264128 \u5B57\u7B26\uFF09"};const i=await this.sessionKeysTarget(s);if(!i.ok)return i;try{return await i.terminal.sendText(i.paneId,os(t)),{ok:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async setEffort(s,e){const t=e.trim(),i=await this.sessionKeysTarget(s);if(!i.ok)return i;const n=rs(this.deps.hookEvents,s);if(!n.includes(t))return{ok:!1,status:400,error:`\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\u4E0D\u5408\u6CD5\uFF08\u53EF\u9009\uFF1A${n.join(" / ")||"\u65E0"}\uFF09`};try{return await i.terminal.sendText(i.paneId,ns(t)),{ok:!0}}catch(r){return{ok:!1,status:409,error:r instanceof Error?r.message:String(r)}}}async askSideQuestion(s,e){if(!this.deps.sessions.getBySessionId(s))return{ok:!1,status:404,error:"Session not found"};const t=this.surfaceOfSession(s),i=t?.sideQuestion??null;if(!i)return{ok:!1,status:409,error:t?.unsupportedReasons?.sideQuestion??"\u8FD9\u4E2A harness \u6CA1\u6709\u65C1\u8DEF\u4F1A\u8BDD\u901A\u9053"};const n=i.validate(e);if(!n.ok)return{ok:!1,status:400,error:n.error};if(i.prerequisite&&this.deps.sessions.hasRunOf(s)!==!0)return{ok:!1,status:409,error:i.prerequisite};const r=await this.sessionKeysTarget(s,"\u53D1\u8D77\u65C1\u8DEF\u4F1A\u8BDD");if(!r.ok)return r;try{return i.screen?(this.pollScreenAnswer(s,r.terminal,r.paneId,i,n.text),{ok:!0,question:n.text}):(await r.terminal.sendText(r.paneId,i.command(n.text)),{ok:!0,question:n.text})}catch(d){return{ok:!1,status:409,error:d instanceof Error?d.message:String(d)}}}pollScreenAnswer(s,e,t,i,n){const r=i.screen,d=async()=>await e.getPaneText?.(t).catch(()=>null)??null;(async()=>{const a=await d()??"";await e.sendKeys(t,r.openKeys).catch(()=>{}),await m(M),await e.sendKeys(t,r.submitKey).catch(()=>{}),await m(F);let o=await d();if((!o||!r.panelOpen(o))&&(await e.sendKeys(t,r.submitKey).catch(()=>{}),await m(F),o=await d(),!o||!r.panelOpen(o)))return;await e.sendText(t,n).catch(()=>{}),await m(M),await e.sendKeys(t,r.submitKey).catch(()=>{});const h=Date.now()+Gs;let l=null;for(;Date.now()<h;){if(await m(Js),o=await d(),o==null)return;const c=r.extractAnswer(n,a,o);if(c.done){l=c.answer;break}}l!=null&&(this.sideAnswerStore?.answerById(s,n,l),this.bus({kind:"sideQuestion.answered",sessionId:s,at:new Date().toISOString()}));const u=await d();u&&r.panelOpen(u)&&await e.sendKeys(t,r.closeKey).catch(()=>{})})()}async sessionKeysTarget(s,e="\u51FB\u952E"){return ds(this.keysDeps(),s,e)}busSafe(){return{emit:s=>this.bus(s)}}channelDeps(){return{setMemory:s=>this.memory.set(s.id,s),deleteMemory:s=>this.memory.delete(s),awaitAck:(s,e)=>this.gate.await(s,e),commandModeOf:(s,e)=>this.commandModeOf(e,s),armAckWatch:s=>this.gate.armAckWatch(s),armCommandAck:s=>this.gate.armCommandAck(s,e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)}),emit:s=>this.bus(s),...this.deps.spawnImpl?{spawnImpl:this.deps.spawnImpl}:{}}}wireTextOfEntry(s){return ls(s,e=>this.surfaceOfSession(e))}hasImagesEntry(s){return us(s)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(s,e)=>this.terminalPaneFor(s,e),paneEnvConflictOf:s=>this.paneEnvConflictOf(s)}}async resend(s){const e=this.memory.get(s);if(!e)return{ok:!1,status:404,error:"Message not found"};if(!(e.channel==="prompt"&&(e.status==="failed"||e.status==="delivered"&&!e.acked)))return{ok:!1,status:409,error:"Message is not resendable"};const t=this.deps.sessions.getBySessionId(e.sessionId);if(!t)return{ok:!1,status:404,error:"Session not found"};if(t.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const i=this.deps.projects.getById(t.projectId);if(!i)return{ok:!1,status:404,error:"Project not found"};const n=this.surfaceOfSession(e.sessionId);if(!n)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};if(this.gate.clearStall(e.sessionId,s),e.status==="delivered"&&e.via==="terminal"&&this.terminalChannel()){const a=await this.terminalPaneFor(t,i);if(a)return this.memory.set(s,{...e,status:"delivering",stalled:!1,settledAt:null}),this.runTerminalSubmit(s,a.id),this.bus({kind:"message.created",messageId:s,sessionId:e.sessionId,mode:e.mode,at:new Date().toISOString()}),{ok:!0,messageId:s,status:"delivering",message:this.memory.get(s)}}this.memory.delete(s);const r={...e,status:"pending",stalled:!1,acked:!1,settledAt:null,reason:void 0,error:null},d=await this.deliverPrompt(r,t,i,n);return this.bus({kind:"message.created",messageId:r.id,sessionId:r.sessionId,mode:r.mode,at:new Date().toISOString()}),d}dismiss(s,e){const t=this.memory.get(e);if(t){if(t.status==="running")return{ok:!1,status:409,error:"Message is still in flight"};t.status==="delivering"&&this.gate.headOf(t.sessionId)===e&&this.flushing.delete(t.sessionId),this.memory.delete(e),this.gate.clearStall(t.sessionId,e),this.gate.release(t.sessionId,e),this.queuedSessions.has(t.sessionId)&&this.scheduleFlushContinuation(t.sessionId)}else if(!this.dropQueued(s,e))return{ok:!1,status:404,error:"Message not found"};return this.bus({kind:"message.dismissed",messageId:e,sessionId:s,at:new Date().toISOString()}),{ok:!0}}dropQueued(s,e){const t=this.deps.sessions.getBySessionId(s);if(t?.projectId==null)return!1;const i=this.deps.projects.getById(t.projectId);if(!i)return!1;const n=y(this.hooksDir,i.token);if(!n.some(r=>r.id===e&&r.sessionId===s))return!1;for(p(this.hooksDir,i.token,new Set([e])),this.dismissedIds.add(e);this.dismissedIds.size>Ns;){const r=this.dismissedIds.values().next().value;if(r===void 0)break;this.dismissedIds.delete(r)}return n.some(r=>r.sessionId===s&&r.id!==e)||this.queuedSessions.delete(s),!0}async flushSession(s){if(this.stalled.has(s)||this.flushing.has(s)||!this.queuedSessions.has(s))return;const e=Symbol(s);this.flushing.set(s,e);try{await this.flushSessionInner(s)}catch{}finally{this.flushing.get(s)===e&&this.flushing.delete(s)}}async flushSessionInner(s){if(!this.ackGateOpen(s))return;const e=this.deps.sessions.getBySessionId(s);if(e?.projectId==null)return;const t=this.deps.projects.getById(e.projectId);if(!t)return;const i=y(this.hooksDir,t.token).filter(a=>a.sessionId===s);if(i.length===0){this.queuedSessions.delete(s);return}if(this.sessionJudgedDead(s)){this.failQueuedOffline(s,i.filter(a=>!this.dismissedIds.has(a.id)));return}const n=this.surfaceOfSession(s),r=n?.prompt??null,d=this.modalBlocked(s);for(const a of i){if(this.stalled.has(s))return;if(this.dismissedIds.has(a.id))continue;const o={id:a.id,sessionId:s,text:a.text,...a.attachments&&a.attachments.length>0?{attachments:a.attachments}:{},mode:"prompt",oneWay:a.oneWay===!0,...a.forceTerminal===!0?{forceTerminal:!0}:{},via:"socket",channel:"prompt",status:"pending",at:a.at};if(!d&&this.hasImagesEntry(o)&&this.terminalChannel()){const u=await this.terminalPaneFor(e,t);if(u){p(this.hooksDir,t.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(s,o.id),await this.runTerminalPrompt(o.id,u.id,this.wireTextOfEntry(o)),this.settleQueueIndex(s,t.token);return}}if(n&&await this.tryQueuedDeliver(o,n)){p(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(s,t.token);return}if(n&&await this.tryInboxDeliver(o,n)){p(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(s,t.token);return}const h=r?.resolve(s)??null,l=o.forceTerminal===!0?["terminal"]:o.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of l){if(u==="relay"&&r&&h){if(this.memory.set(o.id,{...o,status:"delivering",via:"relay"}),!this.runRelay(o,r,h.name)){this.memory.delete(o.id);return}this.awaitingAck.set(s,o.id),p(this.hooksDir,t.token,new Set([a.id]));break}if(u==="terminal"&&!d&&this.terminalChannel()){const c=await this.terminalPaneFor(e,t);if(c){p(this.hooksDir,t.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(s,o.id),await this.runTerminalPrompt(o.id,c.id,this.wireTextOfEntry(o));break}}}if(this.awaitingAck.get(s)===o.id){this.settleQueueIndex(s,t.token);return}return}this.settleQueueIndex(s,t.token)}settleQueueIndex(s,e){y(this.hooksDir,e).every(t=>t.sessionId!==s)&&this.queuedSessions.delete(s)}async flushAll(){for(const s of[...this.queuedSessions])await this.flushSession(s)}forgetSession(s){let e=0;for(const[t,i]of this.memory)i.sessionId===s&&(this.memory.delete(t),e++);return e+=Os(this.hooksDir,s),this.queuedSessions.delete(s),this.gate.clearStall(s),this.gate.release(s),this.inboxSockets.forget(s),this.paneEnvs.delete(s),this.paneEnvConflicts.delete(s),this.revokedPaneEnvs.add(s),this.persistPaneEnvs(),e}forgetProject(s){const e=this.pendingOrigins.length;this.pendingOrigins=this.pendingOrigins.filter(i=>i.projectId!==s),this.pendingOrigins.length!==e&&this.persistPendingOrigins();let t=0;for(const[i,n]of this.memory)this.deps.sessions.getBySessionId(n.sessionId)?.projectId===s&&(this.memory.delete(i),this.inboxSockets.forget(n.sessionId),this.paneEnvs.delete(n.sessionId),this.gate.clearStall(n.sessionId),this.gate.release(n.sessionId),t++);for(const i of[...this.queuedSessions])this.deps.sessions.getBySessionId(i)?.projectId===s&&(t+=this.forgetSession(i));return this.persistPaneEnvs(),t}surfaceOfSession(s){const e=this.deps.hookEvents.listBySession(s,1),t=e[e.length-1]?.source;return k(t)?this.deps.surfaceFor?.(t)??W(t):null}commandModeOf(s,e){const t=this.deps.hookEvents.listBySession(s,1),i=t[t.length-1]?.source;if(!k(i))return null;const n=this.deps.commandsFor?.(i)??N(i);return n?Q(e,n.inputModes):null}resolveChannel(s,e,t){return fs(this.deps.sessions,()=>this.terminalChannel()!=null,s,e,t)}async terminalPaneFor(s,e){return this.paneEnvConflicts.has(s.sessionId)?null:as(this.terminalChannel(),this.paneEnvs,s,e)}terminalChannel(){const s=this.deps.terminal;return s&&s.available()?s:null}modalBlocked(s){return this.deps.blockedByQuestion?.(s)===!0}async deliverPrompt(s,e,t,i){if(this.sessionJudgedDead(s.sessionId))return{ok:!0,messageId:s.id,status:"failed",message:this.failOffline(s)};const n=this.modalBlocked(s.sessionId);if(!n&&this.hasImagesEntry(s)&&this.terminalChannel()){const u=await this.terminalPaneFor(e,t);if(u)return this.memory.set(s.id,{...s,status:"delivering",via:"terminal"}),this.awaitingAck.set(s.sessionId,s.id),this.runTerminalPrompt(s.id,u.id,this.wireTextOfEntry(s)),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)}}const r=await this.tryQueuedDeliver(s,i);if(r)return{ok:!0,messageId:s.id,status:"delivered",message:r};const d=await this.tryInboxDeliver(s,i);if(d)return{ok:!0,messageId:s.id,status:"delivered",message:d};const a=i.prompt,o=a?.resolve(s.sessionId)??null,h=s.forceTerminal===!0?["terminal"]:s.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of h){if(u==="relay"&&a&&o){if(this.memory.set(s.id,{...s,status:"delivering",via:"relay"}),this.runRelay(s,a,o.name))return this.awaitingAck.set(s.sessionId,s.id),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)};this.memory.delete(s.id)}if(u==="terminal"&&!n&&this.terminalChannel()){const c=await this.terminalPaneFor(e,t);if(c)return this.memory.set(s.id,{...s,status:"delivering",via:"terminal"}),this.awaitingAck.set(s.sessionId,s.id),this.runTerminalPrompt(s.id,c.id,this.wireTextOfEntry(s)),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)}}}if(this.sessionJudgedDead(s.sessionId))return{ok:!0,messageId:s.id,status:"failed",message:this.failOffline(s)};this.queueEntry(s,t.token);const l={...s,status:"pending"};return{ok:!0,messageId:s.id,status:"pending",message:l}}async tryQueuedDeliver(s,e){const t=e.queuedPrompt;if(!t||this.hasImagesEntry(s))return null;const{bin:i,args:n}=t.command(s.sessionId,this.wireTextOfEntry(s));this.memory.set(s.id,{...s,status:"delivering",via:"queue"});try{await hs(i,n,t.timeoutMs??3e4,this.deps.spawnImpl)}catch{return this.memory.delete(s.id),null}return P(this.channelDeps(),{...s,via:"queue"},"queue")}async tryInboxDeliver(s,e){const t=e.promptInbox,i=this.inboxSockets.get(s.sessionId);if(!t||!i||s.forceTerminal===!0)return null;this.memory.set(s.id,{...s,status:"delivering",via:"socket"});try{await $(t,i,this.wireTextOfEntry(s))}catch{return this.memory.delete(s.id),null}return P(this.channelDeps(),s,"socket")}queueEntry(s,e){ps(this.hooksDir,e,s),this.queuedSessions.add(s.sessionId)}sessionJudgedDead(s,e=this.deps.livenessOf?.()??T()){return ks(this.deps.sessions,s,e)}failOffline(s){return gs(this.memory,e=>this.bus(e),s)}failQueuedOffline(s,e){ys(this.deps,this.hooksDir,this.memory,t=>this.bus(t),s,e),this.queuedSessions.delete(s)}relayDeps(){return{headless:this.headless,getMemory:s=>this.memory.get(s)??null,setMemory:s=>this.memory.set(s.id,s),awaitAck:(s,e)=>this.gate.await(s,e),stall:(s,e,t)=>this.gate.stall(s,e,t),commandModeOf:(s,e)=>this.commandModeOf(e,s),armAckWatch:s=>this.gate.armAckWatch(s),armCommandAck:(s,e)=>this.gate.armCommandAck(s,t=>{e(t),this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)}),onReleased:s=>{this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)},emit:s=>this.bus(s),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.relayTimeoutMs===void 0?{}:{relayTimeoutMs:this.deps.relayTimeoutMs}}}runRelay(s,e,t){return Is(this.relayDeps(),s,e,t,this.wireTextOfEntry(s))}async runTerminalPrompt(s,e,t){await this.runTerminal(s,i=>i.sendText(e,t))}async runTerminalSubmit(s,e){await this.runTerminal(s,t=>t.sendKeys(e,"\r"))}async runTerminal(s,e){const t=this.memory.get(s);if(!t)return;const i=this.terminalChannel();if(i)try{await e(i);const n=this.memory.get(s);if(!n)return;const r={...n,status:"delivered",settledAt:new Date().toISOString()};this.memory.set(s,r),this.commandModeOf(n.sessionId,n.text)?this.armCommandAck(s):this.armAckWatch(r),this.bus({kind:"message.delivered",messageId:s,sessionId:t.sessionId,at:new Date().toISOString()})}catch(n){const r=this.memory.get(s);if(!r)return;if(r.acked===!0){const a=new Date().toISOString();this.memory.set(s,{...r,status:"delivered",settledAt:a}),this.bus({kind:"message.delivered",messageId:s,sessionId:r.sessionId,at:a});return}const d={...r,status:"failed",error:n instanceof Error?n.message:String(n),settledAt:new Date().toISOString()};this.memory.set(s,d),this.stall(t.sessionId,d,"failed"),this.bus({kind:"message.finished",messageId:s,sessionId:t.sessionId,status:"failed",at:new Date().toISOString()})}}deliverInject(s,e,t,i){return ms({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},s,e,t,i,this.wireTextOfEntry(s))}deliverHeadless(s,e,t,i){return cs({memory:this.memory,headless:this.headless,bus:this.busSafe(),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.timeoutMs===void 0?{}:{timeoutMs:this.deps.timeoutMs}},s,e,t,i,this.wireTextOfEntry(s))}bus(s){try{this.deps.bus?.emit(s)}catch{}}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createHash as
|
|
2
|
-
`,{flag:"a"})}export function appendOutbox(
|
|
3
|
-
`).filter(c=>c.trim())}catch{t=[]}for(const c of
|
|
1
|
+
import{createHash as h}from"node:crypto";import{mkdirSync as a,readFileSync as u,renameSync as d,writeFileSync as l}from"node:fs";import{join as i}from"node:path";import{hookSourceHarness as f}from"@weavecode/core";import{getDataDir as m,getHooksDir as y}from"../db/paths.js";import{projectLabel as j}from"./match.js";export const MIRROR_VERSION=1,OUTBOX_MAX_LINES=200;export function hookShardId(s){return h("sha256").update(s).digest("hex").slice(0,16)}export function hooksRoot(s){return y(s)}export function mirrorPathOf(s,e){return i(s,"mirror",`${e}.json`)}export function outboxPathOf(s,e){return i(s,"outbox",`${e}.jsonl`)}export function buildMirrorDoc(s,e,o){const r=e.filter(t=>!(t.source.kind!=="hook-event"||t.handler.type!=="inject"||!t.enabled||t.projectId!==null&&t.projectId!==s.id||t.filter.crossProjectOnly)).sort((t,n)=>n.priority-t.priority).map(t=>({id:t.id,name:t.name,harness:f(t.source)??"claude",events:[t.source.kind==="hook-event"?t.source.event:""],tools:t.filter.toolNames?.length?[...t.filter.toolNames]:null,globs:t.filter.pathGlobs?.length?[...t.filter.pathGlobs]:null,template:t.handler.type==="inject"?t.handler.template:""}));return{version:MIRROR_VERSION,project:j(s.path),pendingTitles:o,rules:r}}export class MirrorWriter{deps;dataDir;constructor(e){this.deps=e,this.dataDir=e.dataDir??m()}syncAll(){for(const e of this.deps.projects.list())this.syncProject(e.id)}syncProject(e){const o=this.deps.projects.getById(e);if(!o||o.archivedAt)return;const r={};for(const t of this.deps.sessions.list(e))t.pendingTitle&&(r[t.sessionId]=t.pendingTitle);this.write(o.token,buildMirrorDoc(o,this.deps.rules.list(),r))}write(e,o){try{const r=mirrorPathOf(hooksRoot(this.dataDir),hookShardId(e));a(i(hooksRoot(this.dataDir),"mirror"),{recursive:!0});const t=`${r}.tmp`;l(t,JSON.stringify(o)),d(t,r)}catch{}}attachToBus(e){e.subscribe(o=>{if(o.kind!=="session.renamed"||!o.sessionId)return;const r=this.deps.sessions.getBySessionId(o.sessionId);r?.projectId!=null&&this.syncProject(r.projectId)})}}export function appendInbox(s,e,o){const r=i(s,"inbox");a(r,{recursive:!0}),l(i(r,`${hookShardId(e)}.jsonl`),JSON.stringify({v:1,token:e,report:o})+`
|
|
2
|
+
`,{flag:"a"})}export function appendOutbox(s,e,o){if(o.length!==0)try{const r=outboxPathOf(s,hookShardId(e));a(i(s,"outbox"),{recursive:!0});let t=[];try{t=u(r,"utf8").split(`
|
|
3
|
+
`).filter(c=>c.trim())}catch{t=[]}for(const c of o)t.push(JSON.stringify({...c,at:new Date().toISOString()}));const n=t.slice(-OUTBOX_MAX_LINES),p=`${r}.tmp`;l(p,n.length?n.join(`
|
|
4
4
|
`)+`
|
|
5
|
-
`:""),
|
|
5
|
+
`:""),d(p,r)}catch{}}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{randomUUID as
|
|
1
|
+
import{randomUUID as D}from"node:crypto";import{graphDirections as m,pendingCountsOf as v}from"../repositories/orchestrations.js";import{messagingSurfaceFor as S}from"../surfaces.js";import{matchesMinute as C,minuteKey as $,parseCron as F}from"../daemon/cron.js";import{pidAliveOf as y}from"../daemon/claude-liveness.js";import{combinedLivenessOf as I}from"../daemon/liveness.js";import{postJson as E}from"./handlers/webhook.js";import{renderTemplate as B}from"./match.js";import{ORCH_MAX_DELIVERIES as w,ORCH_MAX_FORKS as p,validateOrchestration as k}from"./orchestration-graph.js";const A=5e3;function j(h,e){const t=h.trim();return t?`${t}
|
|
2
2
|
|
|
3
|
-
${e}`:e}const
|
|
4
|
-
\u2026[weave: ${
|
|
5
|
-
${
|
|
3
|
+
${e}`:e}const x=4e3,g=32e3;function P(h){if(h.length<=g)return{text:h,truncated:!1};const e=g/2;return{text:`${h.slice(0,e)}
|
|
4
|
+
\u2026[weave: ${h.length-g} chars truncated]\u2026
|
|
5
|
+
${h.slice(-e)}`,truncated:!0}}function O(h,e){return B(h,{upstream:e.upstream,summary:e.summary,session:e.session})}const M=/\{(upstream|summary|session)\}/,R=new Set(["yes","y","true","\u662F","\u5BF9\u7684","\u5BF9","\u9700\u8981","\u53D1"]),J=new Set(["no","n","false","\u5426","\u4E0D\u5BF9","\u4E0D\u9700\u8981","\u4E0D\u53D1"]);export function parseConditionAnswer(h){const e=((h??"").trim().toLowerCase().split(/\s+/)[0]??"").replace(/[.。!!??]/g,"");return R.has(e)?!0:J.has(e)?!1:null}export function createForkConditionJudge(h){const e=t=>t===null?{ok:!1,source:"fork",reason:"condition could not be evaluated (no clear yes/no answer) \u2014 delivery blocked"}:t?{ok:!0,source:"fork"}:{ok:!1,source:"fork",reason:"condition answered no \u2014 delivery skipped"};return{async judge({sessionId:t,condition:n}){if(!h.supports(t))return{ok:!1,source:"fork",reason:"condition not evaluable \u2014 harness has no context sub-agent face"};const s=await h.extract({sessionId:t,prompt:`${n}
|
|
6
6
|
|
|
7
|
-
Based on the conversation context above, answer with exactly one word: yes or no.`});return e(parseConditionAnswer(s))},async judgeBatch({sessionId:t,items:n}){if(!
|
|
8
|
-
`),r=await
|
|
7
|
+
Based on the conversation context above, answer with exactly one word: yes or no.`});return e(parseConditionAnswer(s))},async judgeBatch({sessionId:t,items:n}){if(!h.supports(t))return n.map(()=>({ok:!1,source:"fork",reason:"condition not evaluable \u2014 harness has no context sub-agent face"}));const s=n.map((d,u)=>`${u+1}. key=${d.key}: ${d.condition}`).join(`
|
|
8
|
+
`),r=await h.extract({sessionId:t,prompt:`For EACH item below, decide yes/no based on the conversation context.
|
|
9
9
|
${s}
|
|
10
10
|
|
|
11
|
-
Respond with ONLY a JSON object mapping each key to true or false, e.g. {"k1":true,"k2":false}. No other text.`}),i=B(r,n.map(o=>o.key));return i?n.map(o=>{const d=i.get(o.key);return e(d===void 0?null:d)}):n.map(()=>e(null))}}}function B(l,e){if(!l)return null;const t=l.match(/\{[\s\S]*\}/);if(!t)return null;try{const n=JSON.parse(t[0]),s=new Map;for(const r of e){const i=n[r];if(typeof i!="boolean")return null;s.set(r,i)}return s}catch{return null}}export function matchWhen(l,e){const t=(e??"").toLowerCase();return l.split(/[,,\n;;]/).map(n=>n.trim().toLowerCase()).filter(n=>n.length>0).some(n=>t.includes(n))}const P=5e3,U=1e4,J=6e4,L=2*36e5,W=1500,Y=9e4;export class OrchestrationEngine{deps;runtime=new Map;opening=new Map;startedByOrchestration=new Map;forkJudge;constructor(e){this.deps=e,this.forkJudge=createForkConditionJudge({supports:t=>e.supportsExtract?.(t)??!1,extract:t=>e.extract?.(t)??Promise.resolve(null)})}async start(e,t,n,s){const r=this.deps.orchestrations.getById(e);if(!r)return{ok:!1,status:404,error:"Orchestration not found"};const i=k(r);if(!i.ok)return{ok:!1,status:409,error:i.error};const{entries:o}=m(r.nodes,r.edges),d=s?o.filter(f=>s.includes(f.id)):o.filter(f=>f.kind==="session");if(d.length===0)return{ok:!1,status:409,error:"No matching entry node"};const u=this.activeOf(e);if(u)return await Promise.allSettled(d.map(f=>f.kind==="session"?this.deliver(u,{from:"",to:f.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(u,f.id,n??""))),this.maybeDone(u),{ok:!0,runId:u.id};const c={id:this.deps.runs.insert({orchestrationId:r.id,orchestrationName:r.name,projectId:r.projectId,trigger:t}).id,orchestrationId:r.id,trigger:t,name:r.name,nodes:r.nodes,edges:r.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};return this.runtime.set(c.id,c),this.emitRun(c,"running"),await Promise.allSettled(d.map(f=>f.kind==="session"?this.deliver(c,{from:"",to:f.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(c,f.id,n??""))),this.maybeDone(c),{ok:!0,runId:c.id}}cancel(e){const t=this.runtime.get(e);return t?this.finish(t,"cancelled"):!1}onEvent(e){try{if(!(this.deps.surfaceFor?.(e.source)??_(e.source)).idleSignals.includes(e.eventType))return;const n=this.hasPendingAnywhere(e.sessionId);for(const s of[...this.runtime.values()]){const r=s.state.pending[e.sessionId];!s.running||!r||r.length===0||(r.shift(),this.persist(s),this.fireEdges(s,e.sessionId))}if(!n){const s=Date.now(),r=this.startedByOrchestration.get(e.sessionId);r!==void 0&&s-r<J?this.startedByOrchestration.delete(e.sessionId):(this.startedByOrchestration.delete(e.sessionId),this.maybeAutoFire(e.sessionId))}}catch{}}hasPendingAnywhere(e){return[...this.runtime.values()].some(t=>(t.state.pending[e]?.length??0)>0)}maybeAutoFire(e){const t=Date.now();for(const n of this.entryIndex().get(e)??[]){if(!n.enabled||this.activeOf(n.id))continue;const s=`${n.id}:${e}`;if(t-(this.lastAutoFireAt.get(s)??0)<P)continue;const r=n.nodes.find(i=>i.id===e&&i.kind==="session");!r||!n.edges.some(i=>i.from===r.id)||(this.lastAutoFireAt.set(s,t),this.fireFromEntry(n,r.id))}}async fireFromEntry(e,t){if(!k(e).ok)return;const r={id:this.deps.runs.insert({orchestrationId:e.id,orchestrationName:e.name,projectId:e.projectId,trigger:"manual"}).id,orchestrationId:e.id,trigger:"manual",name:e.name,nodes:e.nodes,edges:e.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(r.id,r),this.emitRun(r,"running"),await this.fireEdges(r,t),this.maybeDone(r)}entryIndexCache=null;lastAutoFireAt=new Map;entryIndex(){if(this.entryIndexCache&&Date.now()-this.entryIndexCache.at<U)return this.entryIndexCache.map;const e=new Map;for(const t of this.deps.orchestrations.list()){if(!t.enabled)continue;const n=new Set(m(t.nodes,t.edges).entries.map(s=>s.id));for(const s of t.nodes){if(s.kind!=="session"||!n.has(s.id)&&!s.autoFire)continue;const r=e.get(s.id)??[];r.push(t),e.set(s.id,r)}}return this.entryIndexCache={at:Date.now(),map:e},e}cronTick(e=new Date){let t=0;try{const n=E(e);for(const s of this.deps.orchestrations.list()){if(!s.enabled||!s.cron||s.lastCronAt===n)continue;const r=A(s.cron);if(!r||!b(r,e))continue;const{entries:i}=m(s.nodes,s.edges);i.some(o=>o.kind==="session")&&(this.deps.orchestrations.setCronFired(s.id,n),!this.activeOf(s.id)&&(this.start(s.id,"cron"),t++))}}catch{}return t}rearm(){try{for(const e of this.deps.runs.listRunning()){const t=this.deps.orchestrations.getById(e.orchestrationId);if(!(t?k(t):{ok:!1}).ok){this.deps.runs.finish(e.id,"interrupted","daemon restarted \u2014 definition gone");continue}const s={id:e.id,orchestrationId:e.orchestrationId,trigger:e.trigger,name:e.orchestrationName,nodes:t.nodes,edges:t.edges,state:e.state,deliveries:e.deliveries,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(s.id,s),this.emitRun(s,"running")}}catch{}try{this.deps.runs.prune()}catch{}}sweepTerminated(){let e=0;try{const t=this.deps.livenessOf?.()??w(),n=new Map(this.deps.sessions.listWithCounts().map(r=>[r.sessionId,r])),s=Date.now();for(const r of[...this.runtime.values()])if(r.running)for(const[i,o]of Object.entries(r.state.pending)){if(o.length===0)continue;const d=n.get(i);if(d&&y(d,t)!==!1){const u=Date.parse(o[0].at);Number.isFinite(u)&&s-u>L&&(this.staleOut(r,i,o[0].at),e++);continue}this.reviveOrDrop(r,i),e++}}catch{return e}return e}staleOut(e,t,n){const s=((Date.now()-Date.parse(n))/36e5).toFixed(1);this.dropPending(e,t,`pending stale ${s}h (oldest ${n}) \u2014 target alive but never turned; run failed to release the single-run gate`),this.finish(e,"failed",`pending stale on ${t} (${s}h) \u2014 run aborted`)}ensureOpenOnce(e){const t=this.opening.get(e);if(t)return t;const n=(this.deps.ensureOpen?.(e)??Promise.resolve({ok:!0})).finally(()=>this.opening.delete(e));return this.opening.set(e,n),n}async reviveOrDrop(e,t){const n=await this.ensureOpen(t);n.ok||!e.running||(this.dropPending(e,t,`pending dropped \u2014 session is not running: ${n.error}`),this.maybeDone(e))}async fireEdges(e,t,n=""){const s=e.edges.filter(a=>a.from===t);if(s.length===0){this.maybeDone(e);return}const r=n||(this.deps.deliverer.lastTurnOutput?.(t)?.output??null),i=r?r.length>O?`${r.slice(0,O)}\u2026`:r:null,o=r?T(r):{text:null,truncated:!1},d=this.deps.sessions.getBySessionId(t)?.title||t,u=new Map;if(!n){const a=s.filter(c=>c.condition?.trim()&&!(c.when?.trim()&&!matchWhen(c.when,o.text)));if(a.length>0){const c=await this.evaluateConditionsBatch(e,t,a,o.text,o.truncated);for(const[f,h]of c)u.set(f,h)}}await Promise.allSettled(s.map(async a=>{if(n){const h=x(a.text,{upstream:n,summary:n,session:t}),D=a.text.includes("{upstream}")?h:$(h,n);return this.deliver(e,{from:t,to:a.to,edgeId:a.id,text:D})}let c=null;if(a.extract?.trim()&&this.takeFork(e)&&(c=this.deps.supportsExtract?.(t)?await this.deps.extract?.({sessionId:t,prompt:a.extract.trim()})??null:null),a.when?.trim()&&!matchWhen(a.when,o.text)){this.record(e,{from:t,to:a.to,edgeId:a.id,ok:!1,stage:"condition",error:"pre-filter no match \u2014 upstream output lacks all keywords"});return}if(a.condition?.trim()){const h=u.get(a.id);if(h!==!0){h===void 0&&this.record(e,{from:t,to:a.to,edgeId:a.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return}}const f=x(a.text,{upstream:i,summary:c??i,session:d});if(M.test(f)){this.record(e,{from:t,to:a.to,edgeId:a.id,ok:!1,error:"unresolved template variable \u2014 no upstream output and no extract result"});return}return this.deliver(e,{from:t,to:a.to,edgeId:a.id,text:f})})),this.maybeDone(e)}async evaluateConditionsBatch(e,t,n,s,r){const i=new Map,o=this.deps.conditionJudge??this.forkJudge;if(!this.takeFork(e)){for(const d of n)this.record(e,{from:t,to:d.to,edgeId:d.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return i}if(o.judgeBatch&&n.length>1)try{const d=await o.judgeBatch({sessionId:t,items:n.map(u=>({key:u.id,condition:u.condition.trim()})),upstream:s});return n.forEach((u,a)=>{const c=d[a];c&&(i.set(u.id,c.ok),this.record(e,{from:t,to:u.to,edgeId:u.id,ok:c.ok,stage:"condition",...c.ok?{}:{error:c.reason??"condition not satisfied \u2014 delivery blocked"},...c.source?{source:c.source}:{},...this.conditionDetail(c.detail,r)}))}),i}catch{}for(const d of n)i.set(d.id,await this.evaluateCondition(e,t,d,s,r));return i}conditionDetail(e,t){const n=[e,t?`state truncated to ${g} chars`:null].filter(Boolean);return n.length>0?{detail:n.join(" \u2014 ")}:{}}async evaluateCondition(e,t,n,s,r=!1){const i=a=>(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!1,stage:"condition",error:a,...o?{source:o}:{},...this.conditionDetail(d,r)}),!1);let o,d,u;try{u=await(this.deps.conditionJudge??this.forkJudge).judge({sessionId:t,condition:n.condition.trim(),upstream:s}),o=u.source,d=u.detail}catch(a){return i(`condition judge failed \u2014 delivery blocked: ${a instanceof Error?a.message:String(a)}`)}return u.ok?(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!0,stage:"condition",...o?{source:o}:{},...this.conditionDetail(d,r)}),!0):i(u.reason??"condition not satisfied \u2014 delivery blocked")}async deliver(e,t){const n=await this.deliverOnce(e,t);return n||!e.running?n:(await new Promise(s=>setTimeout(s,this.deps.retryDelayMs??W)),e.running?this.deliverOnce(e,t):!1)}async deliverOnce(e,t){e.inflight++;try{if(!e.running)return!1;const n=e.nodes.find(i=>i.id===t.to);if(!n)return this.record(e,{...t,ok:!1,error:"target node is not in the snapshot"}),!1;if(n.kind==="webhook"){const i=await(this.deps.postJsonImpl??C)(n.url??"",n.secret,{orchestrationName:e.name,runId:e.id,from:t.from,text:t.text,at:new Date().toISOString()});return e.running?(e.deliveries++,this.record(e,{...t,ok:i.ok,...i.ok?{}:{error:i.error}}),this.checkBudget(e),i.ok):!1}if(!t.text.trim())return this.record(e,{...t,ok:!1,error:"edge has no message"}),!1;if(this.deps.deferWhenUserPresent&&this.userPresent(t.to)){const i=e.state.pending[t.to]??[];return i.push({messageId:`defer-${S()}`,at:new Date().toISOString()}),e.state.pending[t.to]=i,this.record(e,{from:t.from,to:t.to,edgeId:t.edgeId,ok:!0,stage:"defer"}),!0}if(this.aliveOf(t.to)===!1){const i=Date.now(),o=await this.ensureOpenOnce(t.to);if(!e.running)return!1;if(this.record(e,{from:"",to:t.to,edgeId:t.edgeId,ok:o.ok,stage:"ensure",ms:Date.now()-i,...o.ok?{}:{error:o.error}}),!o.ok)return this.record(e,{...t,ok:!1,error:`target session is not open: ${o.error}`}),!1;if(this.startedByOrchestration.set(t.to,Date.now()),await this.deps.deliverer.awaitInboxReady?.(t.to,N),!e.running)return!1}const s=await this.deps.deliverer.send({toSessionId:t.to,text:t.text,mode:"prompt",fromKind:"dashboard"});if(!e.running)return!1;if(!s.ok)return this.record(e,{...t,ok:!1,error:s.error}),!1;if(s.status==="failed"){const i=s.message;return this.record(e,{...t,ok:!1,error:i.error??(i.reason==="offline"?"target session is offline":"delivery failed")}),!1}const r=e.state.pending[t.to]??[];return r.push({messageId:s.messageId,at:new Date().toISOString()}),e.state.pending[t.to]=r,e.deliveries++,this.record(e,{...t,ok:!0}),this.checkBudget(e),!0}catch(n){return this.record(e,{...t,ok:!1,error:n instanceof Error?n.message:String(n)}),!1}finally{e.inflight--}}checkBudget(e){e.deliveries>=(this.deps.maxDeliveries??I)&&this.finish(e,"failed",`delivery budget exceeded (${I})`)}takeFork(e){return e.forks>=p?!1:(e.forks++,!0)}record(e,t){if(!e.running)return;const n={at:new Date().toISOString(),from:t.from,to:t.to,edgeId:t.edgeId,ok:t.ok,...t.error?{error:t.error}:{},...t.stage?{stage:t.stage}:{},...t.ms===void 0?{}:{ms:t.ms},...t.source?{source:t.source}:{},...t.detail?{detail:t.detail}:{}};e.state.events.push(n),e.state.events.length>200&&e.state.events.splice(0,e.state.events.length-200),this.persist(e),this.deps.bus.emit({kind:"orchestration.delivery",orchestrationId:e.orchestrationId,runId:e.id,edgeId:t.edgeId,from:t.from,to:t.to,ok:t.ok,...t.error?{error:t.error}:{},deliveries:e.deliveries,pendingCounts:v(e.state),at:n.at})}maybeDone(e){if(!e.running||e.finishing||e.inflight>0||Object.values(e.state.pending).some(s=>s.length>0))return;e.finishing=!0;const t=e.state.events.some(s=>s.ok&&s.stage===void 0);if(!t&&e.state.events.length>0&&e.state.events.every(s=>s.stage==="condition")){this.finish(e,"done");return}const n=[...e.state.events].reverse().find(s=>!s.ok)?.error??null;this.finish(e,t?"done":"failed",t?null:n??"no delivery succeeded")}finish(e,t,n=null){if(!e.running||(e.running=!1,!this.deps.runs.finish(e.id,t,n,e.state)))return!1;this.runtime.delete(e.id),this.emitRun(e,t);try{this.deps.runs.prune()}catch{}return!0}persist(e){this.deps.runs.updateState(e.id,e.state,e.deliveries),this.emitRun(e,"running")}emitRun(e,t){this.deps.bus.emit({kind:"orchestration.run",orchestrationId:e.orchestrationId,runId:e.id,status:t,trigger:e.trigger,deliveries:e.deliveries,pendingCounts:v(e.state),at:new Date().toISOString()})}dropPending(e,t,n){delete e.state.pending[t],this.record(e,{from:"",to:t,edgeId:"",ok:!1,error:n})}activeOf(e){return[...this.runtime.values()].find(t=>t.running&&t.orchestrationId===e)}aliveOf(e){const t=this.deps.sessions.listWithCounts().find(s=>s.sessionId===e);if(!t)return!1;const n=this.deps.livenessOf?.()??w();return y(t,n)}userPresent(e){if(this.deps.sessions.turnOpenOf(e))return!1;const t=this.deps.sessions.listWithCounts().find(s=>s.sessionId===e);if(!t)return!1;const n=Date.parse(t.lastSeenAt);return Number.isFinite(n)&&Date.now()-n<Y}async ensureOpen(e){if(!this.deps.ensureOpen)return{ok:!1,error:"terminal auto-open unavailable"};try{return await this.deps.ensureOpen(e)}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}}
|
|
11
|
+
Respond with ONLY a JSON object mapping each key to true or false, e.g. {"k1":true,"k2":false}. No other text.`}),i=N(r,n.map(d=>d.key));return i?n.map(d=>{const u=i.get(d.key);return e(u===void 0?null:u)}):n.map(()=>e(null))}}}function N(h,e){if(!h)return null;const t=h.match(/\{[\s\S]*\}/);if(!t)return null;try{const n=JSON.parse(t[0]),s=new Map;for(const r of e){const i=n[r];if(typeof i!="boolean")return null;s.set(r,i)}return s}catch{return null}}export function matchWhen(h,e){const t=(e??"").toLowerCase();return h.split(/[,,\n;;]/).map(n=>n.trim().toLowerCase()).filter(n=>n.length>0).some(n=>t.includes(n))}const T=5e3,L=1e4,W=6e4,_=2*36e5,U=1500,H=9e4;export class OrchestrationEngine{deps;runtime=new Map;opening=new Map;startedByOrchestration=new Map;forkJudge;constructor(e){this.deps=e,this.forkJudge=createForkConditionJudge({supports:t=>e.supportsExtract?.(t)??!1,extract:t=>e.extract?.(t)??Promise.resolve(null)})}async start(e,t,n,s){const r=this.deps.orchestrations.getById(e);if(!r)return{ok:!1,status:404,error:"Orchestration not found"};const i=k(r);if(!i.ok)return{ok:!1,status:409,error:i.error};const{entries:d}=m(r.nodes,r.edges),u=s?d.filter(a=>s.includes(a.id)):d.filter(a=>a.kind==="session");if(u.length===0)return{ok:!1,status:409,error:"No matching entry node"};const c=this.activeOf(e);if(c)return await Promise.allSettled(u.map(a=>a.kind==="session"?this.deliver(c,{from:"",to:a.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(c,a.id,n??""))),this.maybeDone(c),{ok:!0,runId:c.id};const o={id:this.deps.runs.insert({orchestrationId:r.id,orchestrationName:r.name,projectId:r.projectId,trigger:t}).id,orchestrationId:r.id,trigger:t,name:r.name,nodes:r.nodes,edges:r.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};return this.runtime.set(o.id,o),this.emitRun(o,"running"),await Promise.allSettled(u.map(a=>a.kind==="session"?this.deliver(o,{from:"",to:a.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(o,a.id,n??""))),this.maybeDone(o),{ok:!0,runId:o.id}}cancel(e){const t=this.runtime.get(e);return t?this.finish(t,"cancelled"):!1}onEvent(e){try{if(!(this.deps.surfaceFor?.(e.source)??S(e.source)).idleSignals.includes(e.eventType))return;const t=this.hasPendingAnywhere(e.sessionId);for(const n of[...this.runtime.values()]){const s=n.state.pending[e.sessionId];!n.running||!s||s.length===0||(s.shift(),this.persist(n),this.fireEdges(n,e.sessionId))}if(!t){const n=Date.now(),s=this.startedByOrchestration.get(e.sessionId);s!==void 0&&n-s<W?this.startedByOrchestration.delete(e.sessionId):(this.startedByOrchestration.delete(e.sessionId),this.maybeAutoFire(e.sessionId))}}catch{}}hasPendingAnywhere(e){return[...this.runtime.values()].some(t=>(t.state.pending[e]?.length??0)>0)}maybeAutoFire(e){const t=Date.now();for(const n of this.entryIndex().get(e)??[]){if(!n.enabled||this.activeOf(n.id))continue;const s=`${n.id}:${e}`;if(t-(this.lastAutoFireAt.get(s)??0)<T)continue;const r=n.nodes.find(i=>i.id===e&&i.kind==="session");!r||!n.edges.some(i=>i.from===r.id)||(this.lastAutoFireAt.set(s,t),this.fireFromEntry(n,r.id))}}async fireFromEntry(e,t){if(!k(e).ok)return;const n={id:this.deps.runs.insert({orchestrationId:e.id,orchestrationName:e.name,projectId:e.projectId,trigger:"manual"}).id,orchestrationId:e.id,trigger:"manual",name:e.name,nodes:e.nodes,edges:e.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(n.id,n),this.emitRun(n,"running"),await this.fireEdges(n,t),this.maybeDone(n)}entryIndexCache=null;lastAutoFireAt=new Map;entryIndex(){if(this.entryIndexCache&&Date.now()-this.entryIndexCache.at<L)return this.entryIndexCache.map;const e=new Map;for(const t of this.deps.orchestrations.list()){if(!t.enabled)continue;const n=new Set(m(t.nodes,t.edges).entries.map(s=>s.id));for(const s of t.nodes){if(s.kind!=="session"||!n.has(s.id)&&!s.autoFire)continue;const r=e.get(s.id)??[];r.push(t),e.set(s.id,r)}}return this.entryIndexCache={at:Date.now(),map:e},e}cronTick(e=new Date){let t=0;try{const n=$(e);for(const s of this.deps.orchestrations.list()){if(!s.enabled||!s.cron||s.lastCronAt===n)continue;const r=F(s.cron);if(!r||!C(r,e))continue;const{entries:i}=m(s.nodes,s.edges);i.some(d=>d.kind==="session")&&(this.deps.orchestrations.setCronFired(s.id,n),!this.activeOf(s.id)&&(this.start(s.id,"cron"),t++))}}catch{}return t}rearm(){try{for(const e of this.deps.runs.listRunning()){const t=this.deps.orchestrations.getById(e.orchestrationId);if(!(t?k(t):{ok:!1}).ok){this.deps.runs.finish(e.id,"interrupted","daemon restarted \u2014 definition gone");continue}const n={id:e.id,orchestrationId:e.orchestrationId,trigger:e.trigger,name:e.orchestrationName,nodes:t.nodes,edges:t.edges,state:e.state,deliveries:e.deliveries,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(n.id,n),this.emitRun(n,"running")}}catch{}try{this.deps.runs.prune()}catch{}}sweepTerminated(){let e=0;try{const t=this.deps.livenessOf?.()??I(),n=new Map(this.deps.sessions.listWithCounts().map(r=>[r.sessionId,r])),s=Date.now();for(const r of[...this.runtime.values()])if(r.running)for(const[i,d]of Object.entries(r.state.pending)){if(d.length===0)continue;const u=n.get(i);if(u&&y(u,t)!==!1){const c=Date.parse(d[0].at);Number.isFinite(c)&&s-c>_&&(this.staleOut(r,i,d[0].at),e++);continue}this.reviveOrDrop(r,i),e++}}catch{return e}return e}staleOut(e,t,n){const s=((Date.now()-Date.parse(n))/36e5).toFixed(1);this.dropPending(e,t,`pending stale ${s}h (oldest ${n}) \u2014 target alive but never turned; run failed to release the single-run gate`),this.finish(e,"failed",`pending stale on ${t} (${s}h) \u2014 run aborted`)}ensureOpenOnce(e){const t=this.opening.get(e);if(t)return t;const n=(this.deps.ensureOpen?.(e)??Promise.resolve({ok:!0})).finally(()=>this.opening.delete(e));return this.opening.set(e,n),n}async reviveOrDrop(e,t){const n=await this.ensureOpen(t);n.ok||!e.running||(this.dropPending(e,t,`pending dropped \u2014 session is not running: ${n.error}`),this.maybeDone(e))}async fireEdges(e,t,n=""){const s=e.edges.filter(o=>o.from===t);if(s.length===0){this.maybeDone(e);return}const r=n||(this.deps.deliverer.lastTurnOutput?.(t)?.output??null),i=r?r.length>x?`${r.slice(0,x)}\u2026`:r:null,d=r?P(r):{text:null,truncated:!1},u=this.deps.sessions.getBySessionId(t)?.title||t,c=new Map;if(!n){const o=s.filter(a=>a.condition?.trim()&&!(a.when?.trim()&&!matchWhen(a.when,d.text)));if(o.length>0){const a=await this.evaluateConditionsBatch(e,t,o,d.text,d.truncated);for(const[f,l]of a)c.set(f,l)}}await Promise.allSettled(s.map(async o=>{if(n){const l=O(o.text,{upstream:n,summary:n,session:t}),b=o.text.includes("{upstream}")?l:j(l,n);return this.deliver(e,{from:t,to:o.to,edgeId:o.id,text:b})}let a=null;if(o.extract?.trim()&&this.takeFork(e)&&(a=this.deps.supportsExtract?.(t)?await this.deps.extract?.({sessionId:t,prompt:o.extract.trim()})??null:null),o.when?.trim()&&!matchWhen(o.when,d.text)){this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,stage:"condition",error:"pre-filter no match \u2014 upstream output lacks all keywords"});return}if(o.condition?.trim()){const l=c.get(o.id);if(l!==!0){l===void 0&&this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return}}const f=O(o.text,{upstream:i,summary:a??i,session:u});if(M.test(f)){this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,error:"unresolved template variable \u2014 no upstream output and no extract result"});return}return this.deliver(e,{from:t,to:o.to,edgeId:o.id,text:f})})),this.maybeDone(e)}async evaluateConditionsBatch(e,t,n,s,r){const i=new Map,d=this.deps.conditionJudge??this.forkJudge;if(!this.takeFork(e)){for(const u of n)this.record(e,{from:t,to:u.to,edgeId:u.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return i}if(d.judgeBatch&&n.length>1)try{const u=await d.judgeBatch({sessionId:t,items:n.map(c=>({key:c.id,condition:c.condition.trim()})),upstream:s});return n.forEach((c,o)=>{const a=u[o];a&&(i.set(c.id,a.ok),this.record(e,{from:t,to:c.to,edgeId:c.id,ok:a.ok,stage:"condition",...a.ok?{}:{error:a.reason??"condition not satisfied \u2014 delivery blocked"},...a.source?{source:a.source}:{},...this.conditionDetail(a.detail,r)}))}),i}catch{}for(const u of n)i.set(u.id,await this.evaluateCondition(e,t,u,s,r));return i}conditionDetail(e,t){const n=[e,t?`state truncated to ${g} chars`:null].filter(Boolean);return n.length>0?{detail:n.join(" \u2014 ")}:{}}async evaluateCondition(e,t,n,s,r=!1){const i=o=>(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!1,stage:"condition",error:o,...d?{source:d}:{},...this.conditionDetail(u,r)}),!1);let d,u,c;try{c=await(this.deps.conditionJudge??this.forkJudge).judge({sessionId:t,condition:n.condition.trim(),upstream:s}),d=c.source,u=c.detail}catch(o){return i(`condition judge failed \u2014 delivery blocked: ${o instanceof Error?o.message:String(o)}`)}return c.ok?(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!0,stage:"condition",...d?{source:d}:{},...this.conditionDetail(u,r)}),!0):i(c.reason??"condition not satisfied \u2014 delivery blocked")}async deliver(e,t){const n=await this.deliverOnce(e,t);return n||!e.running?n:(await new Promise(s=>setTimeout(s,this.deps.retryDelayMs??U)),e.running?this.deliverOnce(e,t):!1)}async deliverOnce(e,t){e.inflight++;try{if(!e.running)return!1;const n=e.nodes.find(i=>i.id===t.to);if(!n)return this.record(e,{...t,ok:!1,error:"target node is not in the snapshot"}),!1;if(n.kind==="webhook"){const i=await(this.deps.postJsonImpl??E)(n.url??"",n.secret,{orchestrationName:e.name,runId:e.id,from:t.from,text:t.text,at:new Date().toISOString()});return e.running?(e.deliveries++,this.record(e,{...t,ok:i.ok,...i.ok?{}:{error:i.error}}),this.checkBudget(e),i.ok):!1}if(!t.text.trim())return this.record(e,{...t,ok:!1,error:"edge has no message"}),!1;if(this.deps.deferWhenUserPresent&&this.userPresent(t.to)){const i=e.state.pending[t.to]??[];return i.push({messageId:`defer-${D()}`,at:new Date().toISOString()}),e.state.pending[t.to]=i,this.record(e,{from:t.from,to:t.to,edgeId:t.edgeId,ok:!0,stage:"defer"}),!0}if(this.aliveOf(t.to)===!1){const i=Date.now(),d=await this.ensureOpenOnce(t.to);if(!e.running)return!1;if(this.record(e,{from:"",to:t.to,edgeId:t.edgeId,ok:d.ok,stage:"ensure",ms:Date.now()-i,...d.ok?{}:{error:d.error}}),!d.ok)return this.record(e,{...t,ok:!1,error:`target session is not open: ${d.error}`}),!1;if(this.startedByOrchestration.set(t.to,Date.now()),await this.deps.deliverer.awaitInboxReady?.(t.to,A),!e.running)return!1}const s=await this.deps.deliverer.send({toSessionId:t.to,text:t.text,mode:"prompt",fromKind:"dashboard"});if(!e.running)return!1;if(!s.ok)return this.record(e,{...t,ok:!1,error:s.error}),!1;if(s.status==="failed"){const i=s.message;return this.record(e,{...t,ok:!1,error:i.error??(i.reason==="offline"?"target session is offline":"delivery failed")}),!1}const r=e.state.pending[t.to]??[];return r.push({messageId:s.messageId,at:new Date().toISOString()}),e.state.pending[t.to]=r,e.deliveries++,this.record(e,{...t,ok:!0}),this.checkBudget(e),!0}catch(n){return this.record(e,{...t,ok:!1,error:n instanceof Error?n.message:String(n)}),!1}finally{e.inflight--}}checkBudget(e){e.deliveries>=(this.deps.maxDeliveries??w)&&this.finish(e,"failed",`delivery budget exceeded (${w})`)}takeFork(e){return e.forks>=p?!1:(e.forks++,!0)}record(e,t){if(!e.running)return;const n={at:new Date().toISOString(),from:t.from,to:t.to,edgeId:t.edgeId,ok:t.ok,...t.error?{error:t.error}:{},...t.stage?{stage:t.stage}:{},...t.ms===void 0?{}:{ms:t.ms},...t.source?{source:t.source}:{},...t.detail?{detail:t.detail}:{}};e.state.events.push(n),e.state.events.length>200&&e.state.events.splice(0,e.state.events.length-200),this.persist(e),this.deps.bus.emit({kind:"orchestration.delivery",orchestrationId:e.orchestrationId,runId:e.id,edgeId:t.edgeId,from:t.from,to:t.to,ok:t.ok,...t.error?{error:t.error}:{},deliveries:e.deliveries,pendingCounts:v(e.state),at:n.at})}maybeDone(e){if(!e.running||e.finishing||e.inflight>0||Object.values(e.state.pending).some(s=>s.length>0))return;e.finishing=!0;const t=e.state.events.some(s=>s.ok&&s.stage===void 0);if(!t&&e.state.events.length>0&&e.state.events.every(s=>s.stage==="condition")){this.finish(e,"done");return}const n=[...e.state.events].reverse().find(s=>!s.ok)?.error??null;this.finish(e,t?"done":"failed",t?null:n??"no delivery succeeded")}finish(e,t,n=null){if(!e.running||(e.running=!1,!this.deps.runs.finish(e.id,t,n,e.state)))return!1;this.runtime.delete(e.id),this.emitRun(e,t);try{this.deps.runs.prune()}catch{}return!0}persist(e){this.deps.runs.updateState(e.id,e.state,e.deliveries),this.emitRun(e,"running")}emitRun(e,t){this.deps.bus.emit({kind:"orchestration.run",orchestrationId:e.orchestrationId,runId:e.id,status:t,trigger:e.trigger,deliveries:e.deliveries,pendingCounts:v(e.state),at:new Date().toISOString()})}dropPending(e,t,n){delete e.state.pending[t],this.record(e,{from:"",to:t,edgeId:"",ok:!1,error:n})}activeOf(e){return[...this.runtime.values()].find(t=>t.running&&t.orchestrationId===e)}aliveOf(e){const t=this.deps.sessions.listWithCounts().find(s=>s.sessionId===e);if(!t)return!1;const n=this.deps.livenessOf?.()??I();return y(t,n)}userPresent(e){if(this.deps.sessions.turnOpenOf(e))return!1;const t=this.deps.sessions.listWithCounts().find(s=>s.sessionId===e);if(!t)return!1;const n=Date.parse(t.lastSeenAt);return Number.isFinite(n)&&Date.now()-n<H}async ensureOpen(e){if(!this.deps.ensureOpen)return{ok:!1,error:"terminal auto-open unavailable"};try{return await this.deps.ensureOpen(e)}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{graphDirections as
|
|
1
|
+
import{graphDirections as g}from"../repositories/orchestrations.js";export const ORCH_MAX_NODES=24,ORCH_MAX_EDGES=64,ORCH_MAX_DELIVERIES=200,ORCH_MAX_FORKS=50;export function validateOrchestration(f){const{nodes:n,edges:r}=f;if(n.length===0)return{ok:!1,error:"At least one node is required"};if(n.length>ORCH_MAX_NODES)return{ok:!1,error:`At most ${ORCH_MAX_NODES} nodes per orchestration`};const i=new Set;for(const o of n){if(i.has(o.id))return{ok:!1,error:`Duplicate node ${o.id}`};if(i.add(o.id),o.kind==="webhook"&&!o.id.startsWith("w:"))return{ok:!1,error:`Webhook node id must start with "w:": ${o.id}`};if(o.kind==="trigger"&&!o.id.startsWith("t:"))return{ok:!1,error:`Trigger node id must start with "t:": ${o.id}`}}if(r.length>ORCH_MAX_EDGES)return{ok:!1,error:`At most ${ORCH_MAX_EDGES} edges per orchestration`};const s=new Set,a=new Set;for(const o of r){if(s.has(o.id))return{ok:!1,error:`Duplicate edge id ${o.id}`};if(s.add(o.id),!i.has(o.from)||!i.has(o.to))return{ok:!1,error:`Edge ${o.id} references a node outside the node set`};if(o.from===o.to)return{ok:!1,error:`Self-loop on ${o.from}`};const u=`${o.from}->${o.to}`;if(a.has(u))return{ok:!1,error:`Duplicate edge ${o.from}\u2192${o.to}`};a.add(u)}const{entries:e}=g(n,r),t=new Set(r.map(o=>o.to)),d=new Set(r.map(o=>o.from)),c=new Set(e.filter(o=>o.kind==="webhook").map(o=>o.id)),k=r.find(o=>!o.text.trim()&&!c.has(o.from)&&!o.extract?.trim());if(k)return{ok:!1,error:`Edge ${k.from}\u2192${k.to} has no message`};for(const o of r)if(c.has(o.from)&&(o.condition?.trim()||o.when?.trim()))return{ok:!1,error:`Edge ${o.from}\u2192${o.to} cannot have a condition/pre-filter (webhook entries have no session to ask)`};for(const o of n)if(o.kind==="webhook"&&o.autoFire)return{ok:!1,error:`Webhook node ${o.id} cannot have autoFire`};for(const o of n)if(o.kind==="webhook"){if(t.has(o.id)&&d.has(o.id))return{ok:!1,error:`Webhook node ${o.id} cannot have both inbound and outbound edges`};if(!t.has(o.id)&&!d.has(o.id))return{ok:!1,error:`Webhook node ${o.id} is not connected`}}for(const o of n)if(o.kind==="trigger"){if(t.has(o.id))return{ok:!1,error:`Trigger node ${o.id} cannot have inbound edges`};if(!d.has(o.id))return{ok:!1,error:`Trigger node ${o.id} is not connected`}}for(const o of n){if(o.kind!=="webhook"||!t.has(o.id))continue;const u=o.url??"";let h=null;try{h=new URL(u)}catch{h=null}if(!h||h.protocol!=="http:"&&h.protocol!=="https:")return{ok:!1,error:`Webhook node ${o.id} needs a valid http(s) URL`}}const p=findCycle(n,r);return p?{ok:!1,error:`Cycle detected: ${p.join(" \u2192 ")}`}:{ok:!0}}export function findCycle(f,n){const r=new Map;for(const e of f)r.set(e.id,[]);for(const e of n){const t=r.get(e.from);t&&t.push(e.to)}const i=new Map,s=[],a=e=>{i.set(e,1),s.push(e);for(const t of r.get(e)??[]){const d=i.get(t)??0;if(d===1)return[...s.slice(s.indexOf(t)),t];if(d===0){const c=a(t);if(c)return c}}return s.pop(),i.set(e,2),null};for(const e of f)if((i.get(e.id)??0)===0){const t=a(e.id);if(t)return t}return null}export function ranksOf(f,n){const r=new Map(f.map(e=>[e.id,0])),i=new Map(f.map(e=>[e.id,[]]));for(const e of n)i.get(e.from)?.push(e.to),r.set(e.to,(r.get(e.to)??0)+1);const s=new Map(f.map(e=>[e.id,0])),a=f.filter(e=>(r.get(e.id)??0)===0).map(e=>e.id);for(let e=0;e<a.length;e++){const t=a[e];for(const d of i.get(t)??[]){s.set(d,Math.max(s.get(d)??0,(s.get(t)??0)+1));const c=(r.get(d)??0)-1;r.set(d,c),c===0&&a.push(d)}}return s}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{cp as
|
|
2
|
-
`,"utf8")}async function
|
|
3
|
-
`,"utf8")}export async function searchPlugins(
|
|
1
|
+
import{cp as x,mkdir as p,readFile as E,readdir as C,rm as m,writeFile as j}from"node:fs/promises";import{existsSync as F,readdirSync as N,rmSync as O}from"node:fs";import s from"node:path";import{spawn as T}from"node:child_process";import{WEAVE_PLUGIN_MANIFEST as h,WeavePluginManifestSchema as I}from"@weavecode/core";import{getPluginsDir as J,getTmpDir as $}from"../db/paths.js";export function globalPluginRoot(){return J()}export function pruneInstallTmp(){const r=$();let t;try{t=N(r)}catch{return}for(const n of t)if(n.startsWith("install-"))try{O(s.join(r,n),{recursive:!0,force:!0})}catch{}}function A(r){return s.join(r??globalPluginRoot(),"installed.json")}async function D(r){try{const t=JSON.parse(await E(A(r),"utf8"));return Array.isArray(t)?t:[]}catch{return[]}}async function P(r,t){const n=t??globalPluginRoot();await p(n,{recursive:!0}),await j(A(t),JSON.stringify(r,null,2)+`
|
|
2
|
+
`,"utf8")}async function S(r){try{const t=JSON.parse(await E(s.join(r,h),"utf8"));return I.safeParse(t).success?t:null}catch{return null}}async function W(r){const t=[],n=await S(r);if(n)return[{dir:r,manifest:n}];let i;try{i=await C(r)}catch{return t}for(const u of i){const e=s.join(r,u),o=await S(e);o&&t.push({dir:e,manifest:o})}return t}function _(r,t,n,i=6e4){return new Promise((u,e)=>{const o=T(r,t,{cwd:n,windowsHide:!0,stdio:["ignore","pipe","pipe"]});let a="";const l=setTimeout(()=>{o.kill(),e(new Error(`${r} ${t.join(" ")} \u8D85\u65F6\uFF08${i}ms\uFF09`))},i);o.stderr?.on("data",c=>a+=c.toString()),o.on("error",c=>{clearTimeout(l),e(c)}),o.on("close",c=>{clearTimeout(l),c===0?u():e(new Error(`${r} \u9000\u51FA\u7801 ${c}: ${a.slice(0,500)}`))})})}export function isGitSource(r){return/^(https?:\/\/|git@|ssh:\/\/|git:\/\/)/.test(r)||r.endsWith(".git")}export async function installPlugin(r,t){const n=[];let i,u;if(isGitSource(r)){n.push(`\u4ECE ${r} \u5B89\u88C5\u7684\u63D2\u4EF6\u672A\u7ECF\u6C99\u7BB1\u9694\u79BB\uFF0C\u8BF7\u786E\u8BA4\u6765\u6E90\u53EF\u4FE1`);const e=s.join($(),`install-${Date.now()}`);await p(e,{recursive:!0}),await _("git",["clone","--depth","1",r,s.join(e,"repo")]),i=s.join(e,"repo"),u=()=>m(e,{recursive:!0,force:!0})}else if(i=s.resolve(r),!F(i))throw new Error(`\u672C\u5730\u8DEF\u5F84\u4E0D\u5B58\u5728: ${i}`);try{const e=await W(i);if(e.length===0)throw new Error(`\u672A\u627E\u5230 ${h}\uFF08src \u6216\u5176\u4E00\u7EA7\u5B50\u76EE\u5F55\uFF09`);const o=t?.root??globalPluginRoot();await p(o,{recursive:!0});const a=await D(t?.root),l=[];for(const{dir:c,manifest:y}of e){const f=String(y.id),g=s.join(o,f);s.resolve(g).startsWith(s.resolve(o)+s.sep)&&(await m(g,{recursive:!0,force:!0}),await x(c,g,{recursive:!0,filter:w=>!w.includes("node_modules")&&!w.includes(`${s.sep}.git`)}));const d={id:f,name:String(y.name??f),version:String(y.version??"0.0.0"),source:r,dir:f,installedAt:new Date().toISOString()},v=a.findIndex(w=>w.id===f);v>=0?a[v]=d:a.push(d),l.push({id:f,name:d.name,version:d.version,dir:f})}return await P(a,t?.root),{installed:l,warnings:n}}finally{u&&await u()}}export async function uninstallPlugin(r,t){const n=t?.root??globalPluginRoot(),i=await D(t?.root),u=i.find(o=>o.id===r),e=u?s.join(n,u.dir):s.join(n,r);return F(e)?(await m(e,{recursive:!0,force:!0}),u&&await P(i.filter(o=>o.id!==r),t?.root),!0):!1}export async function exportPlugin(r,t,n){const i=s.join(n?.root??globalPluginRoot(),r);if(!F(i))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728: ${i}`);if(!await S(i))throw new Error(`\u63D2\u4EF6\u7F3A\u5C11\u5408\u6CD5 ${h}: ${r}`);const u=s.join(s.resolve(t),r);return await m(u,{recursive:!0,force:!0}),await x(i,u,{recursive:!0,filter:e=>!e.includes("node_modules")&&!e.includes(`${s.sep}.git`)}),u}function B(r){return s.join(r??globalPluginRoot(),"sources.json")}export function parseSources(r){if(Array.isArray(r))return{indexes:r.filter(t=>typeof t=="string")};if(r&&typeof r=="object"){const t=r.indexes;return{indexes:Array.isArray(t)?t.filter(n=>typeof n=="string"):[]}}return{indexes:[]}}export async function readSourcesFile(r){try{return parseSources(JSON.parse(await E(B(r),"utf8")))}catch{return{indexes:[]}}}export async function writeSourcesFile(r,t){const n=t??globalPluginRoot();await p(n,{recursive:!0}),await j(B(t),JSON.stringify(r,null,2)+`
|
|
3
|
+
`,"utf8")}export async function searchPlugins(r){const{indexes:t}=await readSourcesFile(),n=[];for(const i of t)try{const u=await fetch(i,{signal:AbortSignal.timeout(1e4)});if(!u.ok)continue;const e=await u.json();for(const o of e.plugins??[]){const a=`${o.id} ${o.name} ${o.description??""}`.toLowerCase();(!r||a.includes(r.toLowerCase()))&&n.push(o)}}catch{}return n}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as j}from"node:fs";import{readFile as $,readdir as C}from"node:fs/promises";import d from"node:path";import{pathToFileURL as D}from"node:url";import{watch as P}from"chokidar";import{builtinRulesDir as W}from"../market/builtin.js";import{HARNESS_EVENT_UNION as I,HookRuleSchema as B,PluginRuleEntrySchema as T,WEAVE_PLUGIN_MANIFEST as A,WeavePluginManifestSchema as k}from"@weavecode/core";import{getDataRoot as O,getPluginsDir as M}from"../db/paths.js";import{marketLibraryRoots as N}from"../market/resolve.js";import{validateHandler as x}from"./registry.js";import{builtinToolkitRoot as H,discoverToolkitSources as U,discoverWeavePackDirs as L}from"./toolkit-scan.js";export function createPluginLogger(u){return{debug:e=>console.debug(`[plugin:${u}] ${e}`),info:e=>console.info(`[plugin:${u}] ${e}`),warn:e=>console.warn(`[plugin:${u}] ${e}`),error:e=>console.error(`[plugin:${u}] ${e}`)}}const R="@file:";function _(){return d.resolve(H())}export class WeavePluginLoader{deps;handlers=new Map;configs=new Map;plugins=new Map;subscribers=new Map;roots=new Map;watchStop;constructor(e){this.deps=e}list(){return[...this.plugins.values()]}getHandler(e,s){return this.handlers.get(`${e}:${s}`)}getConfig(e){return this.configs.get(e)??{}}async loadRoot(e,s,n){const i=d.resolve(e);this.roots.set(i,{scope:s,projectId:n});let o;try{o=await C(i)}catch{return[]}const t=this.priorIdsUnder(i),c=[];for(const p of o){const l=d.join(i,p);if(this.roots.has(d.resolve(l))||d.resolve(l)===_())continue;const g=await this.loadOne(l,s,n,p);this.plugins.set(g.id,g),c.push(g)}return this.finalizeScan(t,c)}async loadToolkitRoot(e,s,n){const i=d.resolve(e);this.roots.set(i,{scope:s,projectId:n,deep:!0});const o=await L(i),t=this.priorIdsUnder(i),c=[];for(const p of o){await this.ensureToolkitDefaultDisabled(p);const l=await this.loadOne(p,s,n,d.basename(p));this.plugins.set(l.id,l),c.push(l)}return this.finalizeScan(t,c)}async ensureToolkitDefaultDisabled(e){try{const s=JSON.parse(await $(d.join(e,A),"utf8"));typeof s.id=="string"&&!this.deps.states.get(s.id)&&this.deps.states.setEnabled(s.id,!1)}catch{}}priorIdsUnder(e){const s=[...this.roots.keys()].filter(n=>n!==e&&n.startsWith(e+d.sep));return new Set([...this.plugins.values()].filter(n=>n.dir.startsWith(e+d.sep)?!s.some(i=>n.dir.startsWith(i+d.sep)):!1).map(n=>n.id))}finalizeScan(e,s){const n=new Set(s.map(o=>o.id));let i=!1;for(const o of e)n.has(o)||(this.deps.rules.removeByPlugin(o),this.unloadHandlers(o),this.configs.delete(o),this.plugins.delete(o),i=!0,this.emitReload({pluginId:o,status:"rejected",ruleCount:0,removed:!0}));(i||s.length>0)&&this.deps.registry.load();for(const o of s)this.emitReload({pluginId:o.id,status:o.status,ruleCount:o.ruleCount,at:new Date().toISOString()});return s}watchRoots(e=1e3){if(this.watchStop)return this.watchStop;const s=new Map,n=[...this.roots.entries()].filter(([i])=>j(i)).map(([i,o])=>{const t=o.deep?6:o.projectId!==null?3:2,c=P(i,{ignoreInitial:!0,depth:t});return c.on("all",()=>{const p=s.get(i);p&&clearTimeout(p),s.set(i,setTimeout(()=>{s.delete(i);const l=this.roots.get(i);l&&(l.deep?this.loadToolkitRoot(i,l.scope,l.projectId):this.loadRoot(i,l.scope,l.projectId)).catch(()=>{})},e))}),c.on("error",()=>{}),c});return this.watchStop=()=>{for(const i of s.values())clearTimeout(i);s.clear();for(const i of n)i.close();this.watchStop=void 0},this.watchStop}async reloadAll(){for(const[e,s]of[...this.roots])await(s.deep?this.loadToolkitRoot(e,s.scope,s.projectId):this.loadRoot(e,s.scope,s.projectId)).catch(()=>{})}stopWatching(){this.watchStop?.()}async rescanRoots(e,s){await registerPluginRoots(this,{libraries:s},e),this.stopWatching(),await this.reloadAll(),this.watchRoots()}setPluginEnabled(e,s){const n=this.plugins.get(e);if(!n)return!1;this.deps.states.setEnabled(e,s);for(const o of this.deps.rules.listByPlugin(e))this.deps.rules.setEnabled(o.id,s);this.deps.registry.load();const i=s?n.error?"rejected":"active":"disabled";return this.plugins.set(e,{...n,status:i}),this.deps.bus?.emit({kind:"plugin.toggled",pluginId:e,enabled:s,at:new Date().toISOString()}),!0}unloadHandlers(e){for(const s of[...this.handlers.keys()])s.startsWith(`${e}:`)&&this.handlers.delete(s);this.subscribers.delete(e)}notifyEvent(e,s,n){for(const[i,o]of this.subscribers){if(!o.events.has(e))continue;const t=this.configs.get(i)??{};(async()=>{await o.sub.onEvent({eventType:e,payload:s,sessionId:n,config:t,logger:createPluginLogger(i)})})().catch(()=>{})}}emitReload(e){this.deps.bus?.emit({kind:"plugin.reloaded",at:new Date().toISOString(),...e})}async loadOne(e,s,n,i){const o=(r,a,h=i,y="0.0.0")=>{const w=this.plugins.get(r);return w&&w.dir===e&&(this.deps.rules.removeByPlugin(r),this.unloadHandlers(r),this.configs.delete(r)),{id:r,name:h,version:y,dir:e,scope:s,projectId:n,status:"rejected",error:a,ruleCount:0}};let t;try{const r=JSON.parse(await $(d.join(e,A),"utf8")),a=k.safeParse(r);if(!a.success)return o(i,`manifest \u6821\u9A8C\u5931\u8D25: ${a.error.issues[0]?.message??""}`);t=a.data}catch(r){return o(i,`manifest \u8BFB\u53D6\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}if(s!=="builtin"&&t.id.startsWith("weave-"))return o(t.id,"id \u4EE5 weave- \u5F00\u5934\u4E3A\u5185\u7F6E\u9884\u8BBE\u547D\u540D\u7A7A\u95F4\u4FDD\u7559",t.name,t.version);const c=this.plugins.get(t.id);if(c&&c.status!=="rejected"&&c.dir!==e)return o(t.id,`\u91CD\u590D\u7684\u63D2\u4EF6 id\uFF08\u5DF2\u7531 ${c.dir} \u6CE8\u518C\uFF09`,t.name,t.version);const p=(t.requires?.events??[]).filter(r=>!I.includes(r));if(p.length>0)return o(t.id,`requires.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${p.join(", ")}`,t.name,t.version);const l=[];for(const r of t.rules)try{const a=JSON.parse(await $(this.resolveWithin(e,r),"utf8"));if(!Array.isArray(a))throw new Error(`${r} \u4E0D\u662F\u6570\u7EC4`);l.push(...a)}catch(a){return o(t.id,`\u89C4\u5219\u6587\u4EF6 ${r}: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}const g=new Map;for(const r of t.handlers)try{const a=this.resolveWithin(e,r.entry),h=(await import(`${D(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.execute!="function")throw new Error(`${r.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 execute \u51FD\u6570`);if(h.type!==r.type)throw new Error(`${r.entry} \u5BFC\u51FA type="${h.type}" \u4E0E manifest \u58F0\u660E "${r.type}" \u4E0D\u7B26`);g.set(`${t.id}:${r.type}`,h)}catch(a){return o(t.id,`handler ${r.type} \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}let F;if(t.subscribe){const r=t.subscribe.events.filter(a=>!I.includes(a));if(r.length>0)return o(t.id,`subscribe.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${r.join(", ")}`,t.name,t.version);try{const a=this.resolveWithin(e,t.subscribe.entry),h=(await import(`${D(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.onEvent!="function")throw new Error(`${t.subscribe.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 onEvent \u51FD\u6570`);F={events:new Set(t.subscribe.events),sub:h}}catch(a){return o(t.id,`subscriber \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}}const S=[];for(let r=0;r<l.length;r++){const a=l[r],h=typeof a=="object"&&a!==null&&"handler"in a?{...a,handler:z(a.handler,t.id)}:a,y=T.safeParse(h);if(!y.success)return o(t.id,`\u89C4\u5219 #${r} \u6821\u9A8C\u5931\u8D25: ${y.error.issues[0]?.message??""}`,t.name,t.version);const w=y.data;let f=w.handler;if(f.type==="plugin"&&!g.has(`${t.id}:${f.handlerType}`))return o(t.id,`\u89C4\u5219 #${r} \u5F15\u7528\u672A\u58F0\u660E\u7684 handler "${f.handlerType}"`,t.name,t.version);if((f.type==="inject"||f.type==="manual")&&f.template.startsWith(R)){const v=f.template.slice(R.length);try{const b=await $(this.resolveWithin(e,v),"utf8");f={...f,template:b}}catch(b){return o(t.id,`\u89C4\u5219 #${r} \u6A21\u677F ${v}: ${b instanceof Error?b.message:String(b)}`,t.name,t.version)}}let E;try{E=B.parse({...w,handler:f,id:`plugin:${t.id}:${r}`,projectId:n,enabled:w.enabled??!0,priority:w.priority??0,origin:s==="builtin"?"builtin":"plugin",pluginId:t.id}),x(E.source,E.handler)}catch(v){return o(t.id,`\u89C4\u5219 #${r}: ${v instanceof Error?v.message:String(v)}`,t.name,t.version)}S.push(E)}const m=this.deps.states.get(t.id);try{for(const r of S)this.deps.rules.upsertPluginRule(r)}catch(r){return this.deps.rules.removeByPlugin(t.id),o(t.id,`\u89C4\u5219\u5165\u5E93\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`,t.name,t.version)}if(m&&!m.enabled)for(const r of this.deps.rules.listByPlugin(t.id))this.deps.rules.setEnabled(r.id,!1);for(const[r,a]of g)this.handlers.set(r,a);return this.configs.set(t.id,{...t.config??{},...m?.config??{}}),F&&!(m&&!m.enabled)&&this.subscribers.set(t.id,F),{id:t.id,name:t.name,version:t.version,dir:e,scope:s,projectId:n,status:m&&!m.enabled?"disabled":"active",ruleCount:S.length}}resolveWithin(e,s){const n=d.resolve(e),i=d.resolve(n,s);if(i!==n&&!i.startsWith(n+d.sep))throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u63D2\u4EF6\u76EE\u5F55: ${s}`);return i}}function z(u,e){if(typeof u!="object"||u===null)return u;const s=u;return s.type!=="plugin"||s.pluginId!==void 0?u:{...s,pluginId:e}}export async function registerPluginRoots(u,e,s){const n=[],i=U();if(e.libraries)for(const t of N(e.libraries))i.push({root:t,provenance:"market"});const o=new Set;for(const t of i){const c=d.resolve(t.root);o.has(c)||(o.add(c),n.push(...await u.loadToolkitRoot(t.root,t.provenance==="builtin"?"builtin":"user",null)))}n.push(...await u.loadRoot(W(O()),"builtin",null)),n.push(...await u.loadRoot(M(),"user",null));for(const t of s)n.push(...await u.loadRoot(d.join(t.path,".weave","plugins"),"project",t.id));return n}export async function loadAllPlugins(u,e){const s=new WeavePluginLoader(u),n=await registerPluginRoots(s,u,e);return{loader:s,loaded:n}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function pluginsStateOf(
|
|
1
|
+
export function pluginsStateOf(r){const t={syncedAt:null,enabled:{}};if(r==null)return t;try{const n=JSON.parse(r);if(!n||typeof n!="object"||Array.isArray(n))return t;const e=n.plugins;if(!e||typeof e!="object"||Array.isArray(e))return t;const o=e,c=o.enabled,s={};if(c&&typeof c=="object"&&!Array.isArray(c))for(const[l,a]of Object.entries(c))typeof a=="boolean"&&(s[l]=a);return{syncedAt:typeof o.syncedAt=="string"?o.syncedAt:null,enabled:s}}catch{return t}}export function effective(r,t,n){const e=pluginsStateOf(r.meta);return Object.hasOwn(e.enabled,t)?e.enabled[t]:e.syncedAt!==null?!1:n.states.get(t)?.enabled??n.defaultEnabled??!0}export function setProjectEnabled(r,t,n,e){const o=pluginsStateOf(r.meta);e.projects.setMeta(r.id,{plugins:{syncedAt:o.syncedAt,enabled:{...o.enabled,[t]:n}}})}export function syncPlugins(r,t,n){const e={...pluginsStateOf(r.meta).enabled};for(const c of t)Object.hasOwn(e,c)||(e[c]=!1);const o=n.now??new Date().toISOString();return n.projects.setMeta(r.id,{plugins:{syncedAt:o,enabled:e}}),o}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PROMPT_FLUSH_INTERVAL_MS=15e3;export function startPromptFlusher(
|
|
1
|
+
export const PROMPT_FLUSH_INTERVAL_MS=15e3;export function startPromptFlusher(e){const t=setInterval(()=>{e.flushAll()},15e3);return t.unref?.(),()=>clearInterval(t)}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{mkdirSync as g,readFileSync as u,readdirSync as
|
|
2
|
-
`))if(
|
|
3
|
-
`).filter(
|
|
1
|
+
import{mkdirSync as g,readFileSync as u,readdirSync as y,renameSync as m,writeFileSync as h}from"node:fs";import{join as f}from"node:path";import{hookShardId as l}from"./mirror.js";export const PROMPTBOX_MAX_LINES=200;export function promptboxPathOf(e,r){return f(e,"promptbox",`${r}.jsonl`)}function d(e){const r=[];for(const s of e.split(`
|
|
2
|
+
`))if(s.trim())try{const t=JSON.parse(s);if(typeof t.id=="string"&&typeof t.sessionId=="string"&&typeof t.text=="string"){const n=t.images,c=(Array.isArray(t.attachments)?t.attachments:Array.isArray(n)?n:[]).filter(i=>{const o=i;return typeof o?.id=="string"&&typeof o?.name=="string"&&typeof o?.mediaType=="string"&&typeof o?.path=="string"});r.push({id:t.id,sessionId:t.sessionId,text:t.text,oneWay:t.oneWay===!0,...t.forceTerminal===!0?{forceTerminal:!0}:{},...c.length>0?{attachments:c}:{},at:typeof t.at=="string"?t.at:""})}}catch{}return r}export function appendPromptbox(e,r,s){if(s.length!==0)try{const t=promptboxPathOf(e,l(r));g(f(e,"promptbox"),{recursive:!0});let n=[];try{n=u(t,"utf8").split(`
|
|
3
|
+
`).filter(a=>a.trim())}catch{n=[]}const c=new Date().toISOString();for(const a of s)n.push(JSON.stringify({...a,at:c}));const i=n.slice(-PROMPTBOX_MAX_LINES),o=`${t}.tmp`;h(o,i.length?i.join(`
|
|
4
4
|
`)+`
|
|
5
|
-
`:""),
|
|
6
|
-
`).filter(
|
|
5
|
+
`:""),m(o,t)}catch{}}export function readPromptbox(e,r){try{return d(u(promptboxPathOf(e,l(r)),"utf8"))}catch{return[]}}export function removePromptboxEntries(e,r,s){if(s.size!==0)try{const t=promptboxPathOf(e,l(r));let n;try{n=u(t,"utf8").split(`
|
|
6
|
+
`).filter(o=>o.trim())}catch{return}const c=n.filter(o=>{try{return!s.has(JSON.parse(o).id??"")}catch{return!1}}),i=`${t}.tmp`;h(i,c.length?c.join(`
|
|
7
7
|
`)+`
|
|
8
|
-
`:""),
|
|
9
|
-
`).filter(
|
|
8
|
+
`:""),m(i,t)}catch{}}export function readAllPromptbox(e){const r=f(e,"promptbox");let s;try{s=y(r)}catch{return[]}const t=[];for(const n of s)if(n.endsWith(".jsonl"))try{t.push(...d(u(f(r,n),"utf8")))}catch{continue}return t}export function scanQueuedSessionIds(e){return new Set(readAllPromptbox(e).map(r=>r.sessionId))}export function removePromptboxBySession(e,r){const s=f(e,"promptbox");let t;try{t=y(s)}catch{return 0}let n=0;for(const c of t){if(!c.endsWith(".jsonl"))continue;const i=f(s,c);let o;try{o=u(i,"utf8").split(`
|
|
9
|
+
`).filter(p=>p.trim())}catch{continue}const a=o.filter(p=>{try{return JSON.parse(p).sessionId!==r}catch{return!1}});if(a.length!==o.length){n+=o.length-a.length;try{const p=`${i}.tmp`;h(p,a.length?a.join(`
|
|
10
10
|
`)+`
|
|
11
|
-
`:""),
|
|
11
|
+
`:""),m(p,i)}catch{}}}return n}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),d(
|
|
1
|
+
import{chmodSync as r,existsSync as c,mkdirSync as p,readFileSync as l,renameSync as d,writeFileSync as u}from"node:fs";import y from"node:path";import n from"web-push";import{getPushKeysPath as h}from"../db/paths.js";import{watchReasonPhrase as f}from"./watch-engine.js";export class PushNotifier{deps;vapid;constructor(e){this.deps=e,this.vapid=m(e.keysPath??h()),e.bus.subscribe(i=>this.onBus(i))}publicKey(){return this.vapid.publicKey}onBus(e){const i=this.payloadFor(e);if(!i)return;const s=this.deps.subscriptions.list();s.length!==0&&this.pushAll(s,JSON.stringify(i))}payloadFor(e){return e.kind==="watch.fired"?e.watcherSessionId!==null?null:{title:"weave",body:`Session ${this.labelOf(e.targetSessionId)} ${f(e.reason)}`,tag:`weave-watch-${e.targetSessionId}`,url:"/"}:e.kind==="question.pending"?{title:"weave",body:`Session ${this.labelOf(e.sessionId)} is waiting for your answer`,tag:`weave-question-${e.sessionId}`,url:"/"}:null}labelOf(e){return this.deps.sessions.getBySessionId(e)?.title??e.slice(0,8)}async pushAll(e,i){for(const s of e)try{await(this.deps.send??b)(s,i,this.vapid)}catch(o){const a=o.statusCode;(a===404||a===410)&&this.deps.subscriptions.deleteByEndpoint(s.endpoint)}}}async function b(t,e,i){n.setVapidDetails("mailto:weave@localhost",i.publicKey,i.privateKey),await n.sendNotification({endpoint:t.endpoint,keys:{p256dh:t.p256dh,auth:t.auth}},e,{TTL:3600})}function m(t){if(c(t))try{const s=JSON.parse(l(t,"utf8"));if(typeof s.publicKey=="string"&&s.publicKey&&typeof s.privateKey=="string"&&s.privateKey)return{publicKey:s.publicKey,privateKey:s.privateKey}}catch{}const e=n.generateVAPIDKeys();p(y.dirname(t),{recursive:!0});const i=`${t}.tmp`;u(i,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),d(i,t);try{r(t,384)}catch{}return e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isHarness as
|
|
1
|
+
import{isHarness as h}from"@weavecode/core";import{permissionModeOf as c}from"@weavecode/harness";import{blockingPromptFor as f}from"../surfaces.js";const g=12;export class QuestionTracker{deps;pending=new Map;lastPreTool=new Map;permissionMode=new Map;seeding=!1;constructor(e){this.deps=e}specOf(e){return h(e)?this.deps.surfaceFor?.(e)??f(e):null}onEvent(e){const s=e.payload;if(!s)return;const n=this.specOf(e.source);if(!n)return;const t=e.sessionId,o=typeof s.toolName=="string"?s.toolName:null,d=c(s.raw);if(d&&this.permissionMode.set(t,d),s.eventType==="PreToolUse"){if(o&&this.lastPreTool.set(t,{toolName:o,toolInput:s.toolInput}),o&&n.blockingTools.includes(o)){const l=this.pending.get(t),r={sessionId:t,harness:this.harnessOf(e.source),kind:"question",questions:n.parseQuestions(o,s.toolInput),at:new Date().toISOString()};this.pending.set(t,r),!this.seeding&&l?.kind!=="question"&&this.deps.onPending?.(r)}return}if(s.eventType==="Notification"){if(n.permissionNotificationType&&I(s.raw)===n.permissionNotificationType){const l=this.permissionMode.get(t);if(l!=null&&n.silentPermissionModes.includes(l))return;const r=this.lastPreTool.get(t);if(this.pending.get(t)?.kind==="question"&&r!=null&&n.blockingTools.includes(r.toolName))return;const a=this.lastPreTool.get(t)??{toolName:null,toolInput:null};this.pending.set(t,{sessionId:t,harness:this.harnessOf(e.source),kind:"permission",questions:[n.permissionQuestion({...a,message:m(s.raw),permissionMode:l??null})],at:new Date().toISOString()})}return}const p=n.eventQuestion(s.eventType,{raw:s.raw,toolName:o,toolInput:s.toolInput});if(p){const l=this.pending.get(t),r={sessionId:t,harness:this.harnessOf(e.source),kind:"switch",questions:[p],at:new Date().toISOString()};this.pending.set(t,r),!this.seeding&&l?.kind!=="switch"&&this.deps.onPending?.(r);return}const u=this.pending.get(t);if(u){if(u.kind!=="question"){this.pending.delete(t),this.lastPreTool.delete(t);return}(s.eventType==="PostToolUse"&&o!=null&&n.blockingTools.includes(o)||s.eventType==="UserPromptSubmit"||s.eventType==="Stop")&&(this.pending.delete(t),this.lastPreTool.delete(t))}}seedFromDb(){this.seeding=!0;try{for(const e of this.deps.sessions.list())for(const s of this.deps.hookEvents.listBySession(e.sessionId,g)){let n=null;try{n=JSON.parse(s.payload)}catch{n=null}this.onEvent({sessionId:e.sessionId,source:s.source,payload:n})}}finally{this.seeding=!1}}snapshot(){return[...this.pending.values()].filter(e=>!this.dropIfInterrupted(e)).sort((e,s)=>e.at<s.at?1:-1)}get(e){const s=this.pending.get(e);return s?this.dropIfInterrupted(s)?null:s:null}dropIfInterrupted(e){return this.deps.interruptedAt?.(e.sessionId)==null?!1:(this.pending.delete(e.sessionId),!0)}markAnswered(e){this.pending.delete(e)}forgetSession(e){this.pending.delete(e),this.lastPreTool.delete(e),this.permissionMode.delete(e)}harnessOf(e){return e}}function m(i){if(!i||typeof i!="object")return null;const e=i.message;return typeof e=="string"&&e.trim()?e:null}function I(i){if(!i||typeof i!="object")return null;const e=i.notification_type;return typeof e=="string"&&e?e:null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{INJECTABLE_EVENTS as
|
|
1
|
+
import{INJECTABLE_EVENTS as a,hookSourceHarness as c,normalizeHookRuleSource as s}from"@weavecode/core";export class HookRuleRegistry{repo;byEvent=new Map;all=[];onChange;constructor(e){this.repo=e,this.load()}load(){this.all=this.repo.list().map(e=>({...e,source:s(e.source)})),this.byEvent=new Map;for(const e of this.all){if(e.source.kind!=="hook-event")continue;const t=this.byEvent.get(e.source.event);t?t.push(e):this.byEvent.set(e.source.event,[e])}this.onChange?.()}list(e){return(e===void 0?this.all:this.repo.list(e)).map(t=>({...t,source:s(t.source)}))}get(e){return this.all.find(t=>t.id===e)}candidates(e,t){const n=this.byEvent.get(e)??[];return t?.includeDisabled?[...n]:n.filter(o=>o.enabled)}create(e){const t=s(e.source);validateHandler(t,e.handler);const n=this.repo.create({...e,source:t});return this.load(),n}update(e,t){const n=this.get(e);if(!n)return;const o=t.source?s(t.source):n.source;validateHandler(o,t.handler??n.handler);const i=this.repo.update(e,t.source?{...t,source:o}:t);return i&&this.load(),i}setEnabled(e,t){const n=this.repo.setEnabled(e,t);return n&&this.load(),n}remove(e){const t=this.repo.remove(e);return t&&this.load(),t}}export function validateHandler(r,e){const t=c(r);if(e.type==="inject"){if(t===null||t==="any")throw new Error('inject handler requires source.kind = "hook-event" with a concrete harness (legacy "claude-event" accepted; "any" rejected)');const n=a[t],o=r.kind==="claude-event"||r.kind==="hook-event"?r.event:"";if(!n.includes(o))throw new Error(`inject handler is not supported on event "${o}" (allowed: ${n.join(", ")})`);return}if(e.type==="plugin"&&t===null)throw new Error('plugin handler requires source.kind = "hook-event"')}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CLAUDE_RESUME as
|
|
1
|
+
import{CLAUDE_RESUME as a}from"@weavecode/harness";import{HeadlessRunner as o}from"./headless-runner.js";export class ResumeRunner{deps;headless;claudeBin;resumeSpec;timeoutMs;constructor(s){this.deps=s,this.headless=s.headless??new o({spawnImpl:s.spawnImpl,killImpl:s.killImpl}),this.resumeSpec=s.resumeSpec??a,this.claudeBin=s.claudeBin??process.env.WEAVE_CLAUDE_BIN??this.resumeSpec.bin,this.timeoutMs=s.timeoutMs}async run(s,e){const t=this.deps.dispatches.getById(s);if(!t)return{ok:!1,status:404,error:"Dispatch not found"};if(t.status!=="pending"&&t.status!=="injected")return{ok:!1,status:409,error:`Dispatch is ${t.status}`};const i=this.deps.sessions.getBySessionId(e);if(!i)return{ok:!1,status:404,error:"Session not found"};if(i.projectId==null)return{ok:!1,status:400,error:"Session has no project"};const u=this.deps.projects.getById(i.projectId);if(!u)return{ok:!1,status:400,error:"Project not found for session"};if(this.headless.isBusy(e))return{ok:!1,status:409,error:"Session already has a running dispatch"};const n={settled:!1};try{this.deps.dispatches.updateStatus(s,{status:"running"}),this.deps.bus?.emit({kind:"dispatch.started",ruleId:t.ruleId,dispatchId:s,sessionId:e,at:new Date().toISOString()}),this.headless.run({sessionId:e,cwd:u.path,prompt:t.prompt,spec:this.resumeSpec,bin:this.claudeBin,timeoutMs:this.timeoutMs,onSettle:r=>this.settle(t,e,n,r)})||this.settle(t,e,n,{status:"failed",output:null,error:"Session already has a running dispatch"})}catch(r){this.settle(t,e,n,{status:"failed",output:null,error:r instanceof Error?r.message:String(r)})}return{ok:!0,dispatchId:s}}settle(s,e,t,i){if(!t.settled){t.settled=!0;try{this.deps.dispatches.updateStatus(s.id,{status:i.status,output:i.output,error:i.error,finished:!0}),this.deps.bus?.emit({kind:"dispatch.finished",ruleId:s.ruleId,dispatchId:s.id,status:i.status,sessionId:e,at:new Date().toISOString()})}catch{}}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function purgeSession(e,
|
|
1
|
+
export function purgeSession(e,s){const n=e.events.deleteBySession(s);e.uploads?.pruneUnreferenced();const o=e.dispatches?.deleteBySession(s)??0,i=e.deliverer?.forgetSession(s)??0;return e.watches?.deleteBySession(s),e.orchestrations?.deleteMentioningSession(s),e.questions?.forgetSession(s),e.sideQuestions?.deleteBySession(s),e.probe?.forget(s),e.sessions.remove(s),{events:n,dispatches:o,messages:i}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isHarness as
|
|
1
|
+
import{isHarness as p}from"@weavecode/core";import{messagingSurfaceFor as I}from"../surfaces.js";export const SIDE_ANSWER_WINDOW_MS=10*6e4,SIDE_SETTLE_WINDOW_MS=3e4;const c=/\p{Script=Han}/u;function l(n){const e=n.toLowerCase().replace(/\s+/g,""),s=new Set;for(let t=0;t<e.length-1;t++)s.add(e.slice(t,t+2));return s}function g(n,e){const s=l(n),t=l(e);if(s.size===0||t.size===0)return 0;let r=0;for(const o of s)t.has(o)&&r++;return 2*r/(s.size+t.size)}export function answerScore(n,e){let s=0;return c.test(n)===c.test(e)&&(s+=2),e.length>=120&&(s+=1),g(n,e)>=.15&&(s+=1),s}const w=new Map;function f(n,e,s){const t=w.get(e.id);t&&clearTimeout(t),setTimeout(()=>{w.delete(e.id);const r=n.repo.getById(e.id);r?.status==="answered"&&r.answerEventId===e.answerEventId&&n.settle?.(r)},Math.max(0,s+SIDE_SETTLE_WINDOW_MS-(n.now?.()??Date.now()))).unref?.()}export function claimSideAnswer(n,e){if(!p(e.source))return null;const s=(n.surfaceFor?.(e.source)??I(e.source)).sideQuestion?.answerOf(e.eventType,e.payload);if(!s)return null;const t=n.now?.()??Date.now(),r=new Date(t-SIDE_ANSWER_WINDOW_MS).toISOString(),o=n.repo.claim(e.sessionId,s,e.eventId,r);if(o)return S(n,o),f(n,o,t),o;const u=new Date(t-SIDE_SETTLE_WINDOW_MS).toISOString(),i=n.repo.list(e.sessionId,{limit:5}).find(d=>d.status==="answered"&&(d.answeredAt??"")>=u);if(!i||i.answer==null||answerScore(i.question,s)<=answerScore(i.question,i.answer))return null;const a=n.repo.supersede(i.id,s,e.eventId,u);return a?(S(n,a),f(n,a,t),a):null}function S(n,e){n.bus?.emit({kind:"sideQuestion.answered",sessionId:e.sessionId,sideQuestionId:e.id,at:e.answeredAt??new Date().toISOString()})}export function readSideQuestions(n,e,s){return n.repo.expirePending(new Date((n.now?.()??Date.now())-SIDE_ANSWER_WINDOW_MS).toISOString()),n.repo.list(e,s)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as
|
|
1
|
+
import{randomUUID as r}from"node:crypto";const o=30*6e4,e=new Map;export function registerSyntheticSession(t=`sx-${r()}`){return e.set(t,Date.now()+o),t}export function isSyntheticSession(t){if(!t)return!1;const n=e.get(t);return n===void 0?!1:n<Date.now()?(e.delete(t),!1):!0}export function syntheticSessionIds(){return[...e.keys()]}export function replaceSyntheticSessions(t){e.clear();for(const n of t)e.set(n,Date.now()+o)}
|