@weavecode/weave 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/dist/index.cjs +31 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/dist/index.mjs +31 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.cjs +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/dist/index.mjs +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/README.md +39 -39
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/dist/ipv6.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/adapter/bun/websocket.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/context.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/helper/css/common.js +3 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/hono-base.js +4 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/hono.js +0 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/basic-auth/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/csrf/index.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/mount/index.js +4 -4
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +13 -11
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/router/reg-exp-router/prepared-router.js +4 -4
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +39 -51
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +15 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/utils/jwt/jwt.js +2 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/utils/mount.js +35 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/utils/url.js +10 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/validator/validator.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/context.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/helper/css/common.js +3 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/hono-base.js +4 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/hono.js +0 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/basic-auth/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/bearer-auth/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/csrf/index.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/jwk/jwk.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/jwt/jwt.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/language/language.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/mount/index.js +4 -4
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/router/reg-exp-router/node.js +13 -11
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/router/reg-exp-router/prepared-router.js +5 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/router/reg-exp-router/router.js +40 -52
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/router/reg-exp-router/trie.js +15 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/middleware/mount/index.d.ts +1 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +3 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/utils/mount.d.ts +4 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/utils/url.d.ts +1 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/utils/jwt/jwt.js +2 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/utils/mount.js +34 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/utils/url.js +10 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/validator/validator.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/remote.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/deflate.js +2 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +2 -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.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/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 +3 -3
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +7 -0
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +3 -3
- 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 +5 -5
- 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/git-exclude.d.ts +20 -0
- package/node_modules/@weavecode/cli/dist/init/git-exclude.js +7 -0
- 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-files.d.ts +14 -0
- package/node_modules/@weavecode/cli/dist/init/instruction-files.js +1 -0
- 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/package.json +5 -5
- package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
- package/node_modules/@weavecode/core/dist/harness.d.ts +115 -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.d.ts +4 -4
- 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/package.json +1 -1
- package/node_modules/@weavecode/harness/dist/claude/assets.js +3 -3
- package/node_modules/@weavecode/harness/dist/claude/capture.js +9 -9
- package/node_modules/@weavecode/harness/dist/claude/commands.d.ts +2 -0
- package/node_modules/@weavecode/harness/dist/claude/commands.js +3 -2
- 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.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.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.js +1 -1
- 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.d.ts +6 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +21 -14
- 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.js +2 -2
- 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 +6 -0
- 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.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 +3 -3
- 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/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 +2 -2
- 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/pty-terminals.js +1 -1
- 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.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/pet-seed.d.ts +4 -0
- package/node_modules/@weavecode/server/dist/daemon/pet-seed.js +2 -0
- package/node_modules/@weavecode/server/dist/daemon/pet-window.d.ts +17 -0
- package/node_modules/@weavecode/server/dist/daemon/pet-window.js +2 -0
- package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/project-files.d.ts +1 -1
- 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/installations.d.ts +29 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/installations.js +1 -0
- 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/pets.d.ts +3 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/pets.js +1 -0
- 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.js +2 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/watches.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/server.d.ts +4 -0
- 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.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +21 -0
- 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.d.ts +4 -1
- package/node_modules/@weavecode/server/dist/db/db.js +2 -2
- package/node_modules/@weavecode/server/dist/db/layout.d.ts +5 -0
- package/node_modules/@weavecode/server/dist/db/layout.js +2 -1
- package/node_modules/@weavecode/server/dist/db/paths.d.ts +9 -0
- package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/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.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/channels.js +1 -1
- 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.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/send.js +2 -2
- 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.js +5 -5
- 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/index.d.ts +1 -1
- package/node_modules/@weavecode/server/dist/index.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.d.ts +0 -9
- 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 +4 -4
- package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +6 -0
- package/node_modules/@weavecode/server/dist/repositories/hook-events.js +8 -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 +1 -1
- 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.js +2 -2
- 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.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-S1lL1V_n.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{arc-CRZTRyjb.js → arc-CoTNHyHV.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/architectureDiagram-ZHVYKT53-C6ttfnzW.js +36 -0
- package/node_modules/@weavecode/server/web/dist/assets/{blockDiagram-RJAE7QA3-BIH8mSIZ.js → blockDiagram-RJAE7QA3-CYr3Cpu9.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{c4Diagram-XDPPPE54-5YoKWFOD.js → c4Diagram-XDPPPE54-BFS7PhLD.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/channel-DxQHp3Yc.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2E7WHVMD-B653kMXt.js → chunk-2E7WHVMD-DJ7X_Shu.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2Q5K7J3B-f_A4_eDz.js → chunk-2Q5K7J3B-B8nr2rdz.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-4EMNKR2T-v5j5qNGj.js → chunk-4EMNKR2T-DmnZmUMU.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/chunk-55XCU76K-Xz9a8dmp.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-5VM5RSS4-BeROhLXN.js → chunk-5VM5RSS4-Dg9mg7pf.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-JWPE2WC7-D6dXb_jr.js → chunk-JWPE2WC7-CmjTZO8o.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-VQ5W62QI-CnHdSEMi.js → chunk-VQ5W62QI-D3YDdJ3E.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/chunk-XXDRQBXY-s1OG9sqW.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/chunk-ZCHMQSOR-C3hINQU3.js +2 -0
- package/node_modules/@weavecode/server/web/dist/assets/{classDiagram-v2-4MYWR3UA-DQe1b_k8.js → classDiagram-v2-4MYWR3UA-BTsbYrVl.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/cose-bilkent-JH36ORCC-C0W8Y-jI.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{cynefin-EF2NZ3EQ-OZotFKUu.js → cynefin-EF2NZ3EQ-stAu4Rh-.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/cynefinDiagram-WF24UDRP-CqYibiiv.js +62 -0
- package/node_modules/@weavecode/server/web/dist/assets/dagre-NK4GIZVX-qqcoJAqB.js +4 -0
- package/node_modules/@weavecode/server/web/dist/assets/diagram-CBK3MWTC-D0YTopb7.js +24 -0
- package/node_modules/@weavecode/server/web/dist/assets/diagram-I5XIIV2D-Csvw6aYr.js +24 -0
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-ODIL2UCW-D9A6W8oB.js → diagram-ODIL2UCW-Dl0tYLkF.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-PFBEJUXE-PeI-eyu2.js → diagram-PFBEJUXE-BCPSWZPe.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/diagram-RJA3I4VV-ETg-BrAJ.js +41 -0
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-TYUNFSNR-D5KieEw5.js → diagram-TYUNFSNR-_M6ZxBG7.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/ebnfDiagram-V4P3TTPT-C-e_W7qx.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{elk-QONTBCTQ-D3xrVg0U.js → elk-QONTBCTQ-B5TBharB.js} +3 -3
- package/node_modules/@weavecode/server/web/dist/assets/{erDiagram-KYQIGQAA-y_V1cor7.js → erDiagram-KYQIGQAA-D08rj2pv.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{flowDiagram-IUGLLWBU-BJ8Z0MkF.js → flowDiagram-IUGLLWBU-BALTxsKh.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/ganttDiagram-R7GPNTJY-Cts193jT.js +292 -0
- package/node_modules/@weavecode/server/web/dist/assets/gitGraphDiagram-PDYL7XHY-L9qYUX0v.js +106 -0
- package/node_modules/@weavecode/server/web/dist/assets/infoDiagram-MVDRKAX5-Bv47rgU0.js +2 -0
- package/node_modules/@weavecode/server/web/dist/assets/{ishikawaDiagram-HPEHV2GE-ChEnND76.js → ishikawaDiagram-HPEHV2GE-Da8_s6cs.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{journeyDiagram-BOSHW7O7-DHcNtpYF.js → journeyDiagram-BOSHW7O7-Bj3CjZOf.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{kanban-definition-FNSA4HC5-Dft7qpW5.js → kanban-definition-FNSA4HC5-D1hicmMu.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/linear-CWQg2iA1.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/main-XLn3EZFh.css +11 -0
- package/node_modules/@weavecode/server/web/dist/assets/main-bsb0lQoL.js +1096 -0
- package/node_modules/@weavecode/server/web/dist/assets/{mermaid.core-D_Dp_Kl2.js → mermaid.core-C-wP0Zg2.js} +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/{mindmap-definition-6OY57UG3-CM6OAd_-.js → mindmap-definition-6OY57UG3-Dk0VKqre.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/modulepreload-polyfill-B5Qt9EMX.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/pegDiagram-ECIUJNBX-Bp1K_F9z.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/pet-J6izA90s.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/pieDiagram-GNMPY74T-BZ4rGy3t.js +39 -0
- package/node_modules/@weavecode/server/web/dist/assets/{quadrantDiagram-D57K4MC3-D8pQ_PU2.js → quadrantDiagram-D57K4MC3-B4N5KRsR.js} +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/railroadDiagram-Y72NRBL7-C8nx8oHf.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{requirementDiagram-EQYSW5RA-C90DU5Ny.js → requirementDiagram-EQYSW5RA-VSH57d0d.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{sankeyDiagram-SY24JHO5-B_poYGgJ.js → sankeyDiagram-SY24JHO5-jUb1hcya.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{sequenceDiagram-BLEHNHQU-DDW7b2Dn.js → sequenceDiagram-BLEHNHQU-E2BioCNi.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/sizeCapture-INFHLROL-BdKrbRmI.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{stateDiagram-v2-A6IESKWZ-CkVMAyxG.js → stateDiagram-v2-A6IESKWZ-tFz7uNM7.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/swimlanes-B3ENRKFQ-B9BAPDWw.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-DQ2NPLl9.js +8 -0
- package/node_modules/@weavecode/server/web/dist/assets/{timeline-definition-JXYKGLGB-DnhkRGLb.js → timeline-definition-JXYKGLGB-CofNnFTK.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{usecaseDiagram-WPOLBNNX-_TdIjC6Z.js → usecaseDiagram-WPOLBNNX-DOvjhJjJ.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{vennDiagram-Q3Y3IDCW-FzgsymXB.js → vennDiagram-Q3Y3IDCW-BcFHWnhS.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{wardleyDiagram-IVAIDKWA-BwqimStC.js → wardleyDiagram-IVAIDKWA-Bz2aqRAs.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{xychartDiagram-4URNHDU4-CFjjVPIV.js → xychartDiagram-4URNHDU4-DpNF6Vsq.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/index.html +3 -2
- package/node_modules/@weavecode/server/web/dist/pet.html +130 -0
- package/node_modules/@weavecode/templates/dist/index.d.ts +2 -0
- package/node_modules/@weavecode/templates/dist/index.js +1 -1
- package/node_modules/@weavecode/templates/dist/resources/pets/weave-spider/pet.json +7 -0
- package/node_modules/@weavecode/templates/dist/resources/pets/weave-spider/spritesheet.png +0 -0
- package/node_modules/@weavecode/templates/dist/resources/weave-market/.claude-plugin/marketplace.json +6 -0
- package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-pet-hatcher/.claude-plugin/plugin.json +8 -0
- package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-pet-hatcher/skills/weave-pet-hatcher/SKILL.md +121 -0
- package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-pet-hatcher/skills/weave-pet-hatcher/scripts/assemble-pet.mjs +308 -0
- package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-pet-hatcher/weave.json +4 -0
- package/node_modules/@weavecode/templates/package.json +2 -2
- package/package.json +11 -7
- package/scripts/preinstall.mjs +108 -0
- package/node_modules/@weavecode/server/web/dist/assets/abnfDiagram-WEYOIA3C-DDeQkTf5.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/architectureDiagram-ZHVYKT53-Dj54DE3O.js +0 -36
- package/node_modules/@weavecode/server/web/dist/assets/channel-5VM93AJ8.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/chunk-55XCU76K-CgEqeP7j.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/chunk-XXDRQBXY-BkG_e6PE.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/chunk-ZCHMQSOR-DxR-fxzs.js +0 -2
- package/node_modules/@weavecode/server/web/dist/assets/cose-bilkent-JH36ORCC-DThrA8S5.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/cynefinDiagram-WF24UDRP-DJjq2hfT.js +0 -62
- package/node_modules/@weavecode/server/web/dist/assets/dagre-NK4GIZVX-C2vH93HT.js +0 -4
- package/node_modules/@weavecode/server/web/dist/assets/diagram-CBK3MWTC-DrF_ScM-.js +0 -24
- package/node_modules/@weavecode/server/web/dist/assets/diagram-I5XIIV2D-D1qoUJ4t.js +0 -24
- package/node_modules/@weavecode/server/web/dist/assets/diagram-RJA3I4VV-DITY0Rd8.js +0 -41
- package/node_modules/@weavecode/server/web/dist/assets/ebnfDiagram-V4P3TTPT-DDylK-gz.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/ganttDiagram-R7GPNTJY-C0q-CS1T.js +0 -292
- package/node_modules/@weavecode/server/web/dist/assets/gitGraphDiagram-PDYL7XHY-BYTComiB.js +0 -106
- package/node_modules/@weavecode/server/web/dist/assets/index-BKxAxaVG.js +0 -1091
- package/node_modules/@weavecode/server/web/dist/assets/index-C0Sd4MH7.css +0 -11
- package/node_modules/@weavecode/server/web/dist/assets/infoDiagram-MVDRKAX5-DtixgjLP.js +0 -2
- package/node_modules/@weavecode/server/web/dist/assets/linear-DEo11t-X.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/pegDiagram-ECIUJNBX-_QkY0h8Q.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/pieDiagram-GNMPY74T-ZGr5vtDj.js +0 -39
- package/node_modules/@weavecode/server/web/dist/assets/railroadDiagram-Y72NRBL7-DUIo-WmA.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/sizeCapture-INFHLROL-CmKoqX6K.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/swimlanes-B3ENRKFQ-Dm_Omzky.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-Bjj8ZA4d.js +0 -8
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{appendOutbox as
|
|
1
|
+
import{appendOutbox as p}from"../mirror.js";export function resolveChannel(e,t,n,o,s){if(n==="prompt")return s.prompt||s.queuedPrompt||t()?"prompt":{reason:s.unsupportedReasons?.prompt??`Harness "${s.harness}" has no native prompt channel and the configured terminal cannot inject text`};if(n==="inject"||n==="headless")return(n==="inject"?s.inject:s.headless)?n:{reason:unsupportedReason(s,n)};const i=e.turnOpenOf(o)?"inject":"headless";return(i==="inject"?s.inject:s.headless)?i:{reason:unsupportedReason(s,i)}}export function unsupportedReason(e,t){return e.unsupportedReasons?.[t]??`Harness "${e.harness}" does not support the ${t} messaging channel`}export function renderEnvelope(e,t,n){return n.renderEnvelope?.(e,t)??`[weave message] from=${t.fromLabel} at=${t.at} mode=${t.mode}
|
|
2
2
|
|
|
3
|
-
${e}`}export function deliverInject(e,t,
|
|
3
|
+
${e}`}export function deliverInject(e,t,n,o,s,i){const d=renderEnvelope(i,o,s);p(e.hooksDir,n,[{sessionId:t.sessionId,text:d}]);const r={...t,status:"injected",settledAt:new Date().toISOString()};return e.memory.set(r.id,r),e.bus.emit({kind:"message.delivered",messageId:r.id,sessionId:t.sessionId,at:new Date().toISOString()}),{ok:!0,messageId:r.id,status:"injected",message:r}}export function deliverHeadless(e,t,n,o,s,i){const d=s.headless,r={...t,status:"running"};e.memory.set(r.id,r);const u={settled:!1};try{e.headless.run({sessionId:r.sessionId,cwd:n,prompt:renderEnvelope(i,o,s),spec:d,bin:e.bin??process.env.WEAVE_CLAUDE_BIN??d.bin,timeoutMs:e.timeoutMs,onSettle:a=>m(e,r,u,a)})||m(e,r,u,{status:"failed",output:null,error:"Session already has a running run"})}catch(a){m(e,r,u,{status:"failed",output:null,error:a instanceof Error?a.message:String(a)})}return{ok:!0,messageId:r.id,status:"running",message:e.memory.get(r.id)}}function m(e,t,n,o){if(n.settled)return;n.settled=!0;const s=e.memory.get(t.id);if(s)try{e.memory.set(t.id,{...s,status:o.status,output:o.output,error:o.error,settledAt:new Date().toISOString()}),e.bus.emit({kind:"message.finished",messageId:t.id,sessionId:t.sessionId,status:o.status,at:new Date().toISOString()})}catch{}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{combinedLivenessOf as
|
|
1
|
+
import{combinedLivenessOf as p}from"../../daemon/liveness.js";import{readAllPromptbox as m,readPromptbox as g}from"../promptbox.js";import{sessionJudgedDead as h}from"./queue.js";function I(n,e){return{id:e.id,sessionId:n,text:e.text,...e.attachments&&e.attachments.length>0?{attachments:e.attachments}:{},mode:"prompt",oneWay:e.oneWay===!0,...e.forceTerminal===!0?{forceTerminal:!0}:{},channel:"prompt",status:"pending",at:e.at}}export function listVisible(n,e,o,a,s,u=()=>!1){const l=Date.now(),r=[],i=n.sessions.getBySessionId(a);if(i?.projectId!=null){const t=n.projects.getById(i.projectId);if(t)for(const c of g(e,t.token))c.sessionId===a&&r.push(I(a,c))}for(const t of o.values()){if(t.sessionId!==a)continue;if(t.stalled===!0||t.status==="delivering"||t.status==="running"){r.push(t);continue}if(t.status==="failed"||t.status==="timeout"){r.push(t);continue}const c=t.settledAt?Date.parse(t.settledAt):NaN,d=t.status==="delivered"&&t.acked!==!0,f=t.status==="delivered"&&t.acked===!0&&t.ackedEventId==null&&u(t.text);(d||f||!Number.isNaN(c)&&l-c<s)&&r.push(t)}return r.sort((t,c)=>t.at<c.at?-1:1)}export function listInflightCounts(n,e){const o=new Map,a=s=>{o.set(s,(o.get(s)??0)+1)};for(const s of m(n))a(s.sessionId);for(const s of e.values())(s.status==="delivering"||s.status==="running")&&a(s.sessionId);return o}export async function sessionTerminals(n,e,o,a,s){const u={};if(s&&s.size>0){for(const i of s)u[i]=null;s.clear()}if(!e?.locateScreens||o.size===0)return u;const l={},r=n.livenessOf?.()??p();for(const[i,t]of o){if(h(n.sessions,i,r)){o.delete(i),a(),u[i]=null;continue}l[i]=t}return{...u,...await e.locateScreens(l)}}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{INJECTABLE_EVENTS as b,TITLE_EFFECTIVE_EVENTS as S,hookSourceHarness as w}from"@weavecode/core";import{createPluginLogger as P}from"./plugin-loader.js";import{readHooksEnabled as k}from"../daemon/settings.js";import{effective as v,pluginsStateOf as
|
|
2
|
-
${
|
|
3
|
-
${
|
|
1
|
+
import{INJECTABLE_EVENTS as b,TITLE_EFFECTIVE_EVENTS as S,hookSourceHarness as w}from"@weavecode/core";import{createPluginLogger as P}from"./plugin-loader.js";import{readHooksEnabled as k}from"../daemon/settings.js";import{effective as v,pluginsStateOf as j}from"./plugin-project-state.js";import{postJson as D,runWebhook as T}from"./handlers/webhook.js";import{DISPATCH_MARKER as I,extractFilePath as h,isCrossProjectPath as W,matchesAnyGlob as C,projectLabel as O,renderTemplate as E,templateVars as A}from"./match.js";function $(c){if(!c)return null;const e=c.match(/\{[\s\S]*\}/);if(e)try{const i=JSON.parse(e[0]);if(typeof i.label=="string"&&i.label.trim())return i.label.trim()}catch{}const s=/label\s*[:=]\s*"?([A-Za-z0-9_-]+)/i.exec(c);return s?s[1]:null}const y=6e4,N=10*6e4,x=4,H=4,L=3e3;export class HookDispatcher{deps;runningWebhooks=new Set;lastClassifyAt=new Map;recentPool=new Map;activeWebhooks=0;pendingWebhooks=[];activePlugins=0;pendingPlugins=[];constructor(e){this.deps=e}async onIngest(e){try{if(!k())return{};this.deps.plugins?.notifyEvent?.(e.payload.eventType,e.payload,e.sessionId);const s={};if(e.sessionId){const t=_(e.payload);let n=null;if(t===null&&this.deps.sessionTitleOf)try{n=await this.deps.sessionTitleOf(e.sessionId)}catch{}const r=t??n;r!==null&&this.deps.sessions.applyReportedTitle(e.sessionId,r)&&this.deps.bus.emit({kind:"session.renamed",sessionId:e.sessionId,title:r,at:new Date().toISOString()});const d=this.deps.sessions.getBySessionId(e.sessionId)?.pendingTitle;if(d){s.sessionTitle=d;const p=S[e.source].includes(e.payload.eventType);(e.deliveredTitle===d&&p||t!==null)&&this.deps.sessions.confirmPendingTitle(e.sessionId,d)&&this.deps.bus.emit({kind:"session.renamed",sessionId:e.sessionId,title:d,at:new Date().toISOString()})}}const i=this.match(e);if(i.length===0)return s;const a=[],o=[],l=Date.now(),u=l+L;for(const t of i)if(this.deps.bus.emit({kind:"rule.matched",ruleId:t.id,eventId:e.eventId,sessionId:e.sessionId,at:new Date(l).toISOString()}),t.handler.type!=="log"){if(t.handler.type==="manual"||t.handler.type==="inject"){if(this.dedupe(t,e,l))continue;const n=E(t.handler.template,A({event:e.payload.eventType,tool:e.payload.toolName,filePath:h(e.payload.toolInput),cwd:e.payload.cwd,session:e.sessionId,project:O(e.project.path),rule:t.name}))+`
|
|
2
|
+
${I}`,r=t.handler.type==="inject"?"injected":"pending";this.createDispatch(t,e,{prompt:n,status:r,mode:t.handler.type==="inject"?"auto":"manual"}),t.handler.type==="inject"&&(t.filter.crossProjectOnly?o.push(n):a.push(n));continue}if(t.handler.type==="webhook"){if(this.runningWebhooks.has(t.id))continue;this.runningWebhooks.add(t.id);const n=this.createDispatch(t,e,{prompt:`webhook ${t.handler.url}`,status:"running",mode:"auto"});this.deps.bus.emit({kind:"dispatch.started",ruleId:t.id,dispatchId:n.id,sessionId:e.sessionId,at:new Date().toISOString()}),this.runWebhookAsync(t,this.summary(t,e),n.id);continue}if(t.handler.type==="classify"){const n=this.turnText(e);if(!n)continue;const r=t.handler,d=n.toLowerCase();if(r.prefilter&&r.prefilter.length>0&&!r.prefilter.some(m=>d.includes(m.toLowerCase())))continue;const p=`classify:${t.id}`,f=r.cooldownMs??N;if(l-(this.lastClassifyAt.get(p)??0)<f||this.runningWebhooks.has(p))continue;this.lastClassifyAt.set(p,l),this.runningWebhooks.add(p);const g=this.createDispatch(t,e,{prompt:`classify \u2192 ${r.routes.map(m=>m.label).join("/")}`,status:"running",mode:"auto"});this.deps.bus.emit({kind:"dispatch.started",ruleId:t.id,dispatchId:g.id,sessionId:e.sessionId,at:new Date().toISOString()}),this.runClassifyAsync(t,e,g.id,n);continue}if(t.handler.type==="plugin"){const n=this.deps.plugins;if(!n)continue;const r=n.getHandler(t.handler.pluginId,t.handler.handlerType);if(!r||this.dedupe(t,e,l))continue;if(!this.injectable(e)){this.runPluginDetached(t,e,n,r);continue}const d=u-Date.now();if(d<=0)continue;const p=await this.runPluginHandler(t,e,n,r,d);if(!p)continue;p.prompt&&this.createDispatch(t,e,{prompt:p.prompt+`
|
|
3
|
+
${I}`,status:"pending",mode:"auto"}),p.additionalContext&&o.push(p.additionalContext)}}return(a.length>0||o.length>0)&&(s.additionalContext=[...a,...o].join(`
|
|
4
4
|
|
|
5
5
|
`)),o.length>0&&(s.deferred=o.join(`
|
|
6
6
|
|
|
7
|
-
`)),s}catch{return{}}}createDispatch(e,s,
|
|
8
|
-
${
|
|
7
|
+
`)),s}catch{return{}}}createDispatch(e,s,i){const a=this.deps.dispatches.insert({ruleId:e.id,eventId:s.eventId,sessionId:s.sessionId,...i});return this.deps.bus.emit({kind:"dispatch.created",ruleId:e.id,dispatchId:a.id,status:i.status,mode:a.mode,sessionId:s.sessionId,at:a.startedAt}),a}dedupe(e,s,i){const a=`${e.id}:${s.sessionId??""}`,o=this.recentPool.get(a);return o!==void 0&&i-o<y?!0:(this.recentPool.set(a,i),this.trimDedupe(i),!1)}match(e){const s=this.deps.pluginStates,i=s?j(e.project.meta).enabled:null;let a=null;return this.deps.registry.candidates(e.payload.eventType,s?{includeDisabled:!0}:void 0).filter(o=>{const l=w(o.source);if(l!==null&&l!=="any"&&l!==e.source||o.projectId!==null&&o.projectId!==e.project.id)return!1;if(o.pluginId!==null){if(!o.enabled&&i?.[o.pluginId]!==!0||s&&!v(e.project,o.pluginId,{states:s}))return!1}else if(!o.enabled)return!1;const u=o.filter;if(u.toolNames?.length&&(!e.payload.toolName||!u.toolNames.includes(e.payload.toolName)))return!1;if(u.pathGlobs?.length){const t=h(e.payload.toolInput);if(!t||!C(t,u.pathGlobs))return!1}if(u.crossProjectOnly){const t=h(e.payload.toolInput)??e.payload.cwd;if(!t||(a??=this.deps.projects.list().map(n=>n.path).filter(n=>n!==e.project.path),!W(t,e.project.path,a)))return!1}return!0})}injectable(e){const s=e.payload.eventType;return s!==null&&b[e.source].includes(s)}async runPluginHandler(e,s,i,a,o){if(e.handler.type!=="plugin")return;const{pluginId:l}=e.handler,u=P(l),t=o===void 0?e.timeoutMs:Math.min(e.timeoutMs,o);let n;try{const r=(async()=>{await this.acquirePluginSlot();try{return await a.execute({event:s.payload,rule:e,config:i.getConfig(l),logger:u})}finally{this.releasePluginSlot()}})(),d=await Promise.race([r,new Promise((p,f)=>{n=setTimeout(()=>f(new Error("plugin handler timeout")),t)})]);return d&&typeof d=="object"?d:void 0}catch{return}finally{n&&clearTimeout(n)}}async runPluginDetached(e,s,i,a){try{const o=await this.runPluginHandler(e,s,i,a);if(!o?.prompt)return;this.createDispatch(e,s,{prompt:o.prompt+`
|
|
8
|
+
${I}`,status:"pending",mode:"auto"})}catch{}}summary(e,s){return{ruleId:e.id,ruleName:e.name,projectId:s.project.id,sessionId:s.sessionId,event:s.payload.eventType,toolName:s.payload.toolName,filePath:h(s.payload.toolInput),cwd:s.payload.cwd,at:new Date().toISOString()}}turnText(e){const s=e.payload.raw?.last_assistant_message;return typeof s=="string"?s.trim():""}async runClassifyAsync(e,s,i,a){const o=e.handler;if(o.type!=="classify")return;const l=`classify:${e.id}`;try{const u=await this.deps.classify?.({sessionId:s.sessionId??"",prompt:`${o.prompt}
|
|
9
9
|
|
|
10
10
|
\u672C\u8F6E\u6700\u7EC8\u8F93\u51FA\uFF1A
|
|
11
|
-
${a.slice(0,8e3)}`}),t
|
|
11
|
+
${a.slice(0,8e3)}`}),t=$(u),n=t?o.routes.find(d=>d.label.toLowerCase()===t.toLowerCase()):void 0;if(!n){this.deps.dispatches.updateStatus(i,{status:"succeeded",output:t?`label=${t} (no route)`:"no label",finished:!0}),this.deps.bus.emit({kind:"dispatch.finished",ruleId:e.id,dispatchId:i,status:"succeeded",sessionId:s.sessionId,at:new Date().toISOString()});return}const r=await D(n.url,n.secret,{...this.summary(e,s),label:t,verdict:u?.slice(0,500)},this.deps.fetchImpl);this.deps.dispatches.updateStatus(i,{status:r.status,output:`label=${t} ${r.output??""}`.trim(),error:r.error??null,finished:!0}),this.deps.bus.emit({kind:"dispatch.finished",ruleId:e.id,dispatchId:i,status:r.status,sessionId:s.sessionId,at:new Date().toISOString()})}catch(u){this.deps.dispatches.updateStatus(i,{status:"failed",error:String(u),finished:!0}),this.deps.bus.emit({kind:"dispatch.finished",ruleId:e.id,dispatchId:i,status:"failed",sessionId:s.sessionId,at:new Date().toISOString()})}finally{this.runningWebhooks.delete(l)}}async runWebhookAsync(e,s,i){await this.acquireWebhookSlot();try{const a=await T(e,s,this.deps.fetchImpl);this.deps.dispatches.updateStatus(i,{status:a.status,output:a.output??null,error:a.error??null,finished:!0}),this.deps.bus.emit({kind:"dispatch.finished",ruleId:e.id,dispatchId:i,status:a.status,sessionId:s.sessionId,at:new Date().toISOString()})}catch(a){this.deps.dispatches.updateStatus(i,{status:"failed",error:String(a),finished:!0}),this.deps.bus.emit({kind:"dispatch.finished",ruleId:e.id,dispatchId:i,status:"failed",sessionId:s.sessionId,at:new Date().toISOString()})}finally{this.runningWebhooks.delete(e.id),this.releaseWebhookSlot()}}acquireWebhookSlot(){return this.activeWebhooks<x?(this.activeWebhooks++,Promise.resolve()):new Promise(e=>{this.pendingWebhooks.push(()=>{this.activeWebhooks++,e()})})}releaseWebhookSlot(){this.activeWebhooks--;const e=this.pendingWebhooks.shift();e&&e()}acquirePluginSlot(){return this.activePlugins<H?(this.activePlugins++,Promise.resolve()):new Promise(e=>{this.pendingPlugins.push(()=>{this.activePlugins++,e()})})}releasePluginSlot(){this.activePlugins--;const e=this.pendingPlugins.shift();e&&e()}trimDedupe(e){if(!(this.recentPool.size<1e3))for(const[s,i]of this.recentPool)e-i>=y&&this.recentPool.delete(s)}}function _(c){const e=c.raw;if(typeof e!="object"||e===null)return null;const s=e.session_title;return typeof s=="string"&&s.length>0?s:null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isSyntheticSession as
|
|
1
|
+
import{isSyntheticSession as S,registerSyntheticSession as f,syntheticSessionIds as g}from"./synthetic-sessions.js";const y=8e3;export function createEdgeExtract(e){const d=e.concurrency??4;let o=0;return{supports(t){const r=e.harnessOf(t);return r?e.surfaceFor(r).headless?.extractArgs!=null:!1},run({sessionId:t,prompt:r}){if(o>=d)return Promise.resolve(null);const i=e.harnessOf(t),c=e.sessions.getBySessionId(t);if(!i||!c?.projectId)return Promise.resolve(null);const u=e.projects.getById(c.projectId),n=e.surfaceFor(i).headless,l=process.env.WEAVE_CLAUDE_BIN??n?.bin;if(!u||!n?.extractArgs||!l)return Promise.resolve(null);const h=f();return e.onSyntheticChange(),o++,new Promise(m=>{let a=!1;const p=s=>{a||(a=!0,o--,m(s))};e.headless.run({sessionId:h,cwd:u.path,prompt:r,spec:n,bin:l,argsOf:s=>n.extractArgs(t,s),timeoutMs:e.timeoutMs??12e4,onSettle:s=>{p(s.status==="succeeded"&&s.output?.trim()?s.output.trim().slice(0,y):null)}})||p(null)})}}}export{S as isSyntheticSession,g as syntheticSessionIds};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHmac as l}from"node:crypto";const c=5e3,
|
|
1
|
+
import{createHmac as l}from"node:crypto";const c=5e3,d=4096;export async function postJson(e,s,n,o=fetch){let r;try{r=new URL(e)}catch{return{ok:!1,status:"failed",error:`invalid url: ${e}`}}if(r.protocol!=="http:"&&r.protocol!=="https:")return{ok:!1,status:"failed",error:`unsupported protocol: ${r.protocol}`};const u=JSON.stringify(n),i={"content-type":"application/json","user-agent":"weave-daemon"};s&&(i["x-weave-signature"]=`sha256=${l("sha256",s).update(u).digest("hex")}`);try{const t=await o(r,{method:"POST",headers:i,body:u,signal:AbortSignal.timeout(c)}),a=(await t.text()).slice(0,d);return t.ok?{ok:!0,status:"succeeded",output:a||`HTTP ${t.status}`}:{ok:!1,status:"failed",error:`HTTP ${t.status}`,output:a}}catch(t){const a=t instanceof Error&&(t.name==="TimeoutError"||t.name==="AbortError");return{ok:!1,status:a?"timeout":"failed",error:a?`webhook timed out after ${c}ms`:String(t)}}}export async function runWebhook(e,s,n=fetch){const o=e.handler;return o.type!=="webhook"?{ok:!1,status:"failed",error:`rule ${e.id} is not a webhook handler`}:postJson(o.url,o.secret,s,n)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{spawn as k}from"node:child_process";const
|
|
2
|
-
${
|
|
1
|
+
import{spawn as k}from"node:child_process";const T=3e5,y=32*1024,P=2e3;export class HeadlessRunner{spawnImpl;killImpl;active=new Set;livePids=new Map;constructor(t={}){this.spawnImpl=t.spawnImpl??k,this.killImpl=t.killImpl??defaultKill}isBusy(t){return this.active.has(t)}killAll(){let t=0;for(const e of this.livePids.values())try{this.killImpl(e),t++}catch{}return this.livePids.clear(),t}run(t){if(this.active.has(t.sessionId))return!1;this.active.add(t.sessionId);const e={settled:!1};try{this.watch(t,e)}catch(r){this.settle(t,e,{status:"failed",output:null,error:E(r)})}return!0}watch(t,e){const r=t.timeoutMs??T,a=t.spec.promptStdin===!0,f=t.argsOf?t.argsOf(t.sessionId):t.spec.args(t.sessionId,a?"":t.prompt),d=a&&process.platform==="win32"&&!/[\s"\\/]/.test(t.bin),H=(t.detached??!0)&&!d,m={cwd:t.cwd,detached:H,windowsHide:!0,shell:d,stdio:[a?"pipe":"ignore","pipe","pipe"],env:(()=>{const s={...process.env,WEAVE_HOOK_DISPATCH:"1"};return delete s.CLAUDE_CODE_CHILD_SESSION,s})()},i=d?this.spawnImpl([t.bin,...f].join(" "),[],m):this.spawnImpl(t.bin,f,m);if(i.pid!==void 0&&this.livePids.set(t.sessionId,i.pid),a){i.stdin?.on("error",()=>{});try{i.stdin?.write(t.prompt),i.stdin?.end()}catch{}}const I=[],p=[];let w=0,v=0;const g=(s,o,l)=>{if(o>=y)return o;const c=y-o;return s.push(l.length>c?l.subarray(0,c):l),o+Math.min(l.length,c)},h=()=>Buffer.concat([...I,...p]).toString("utf8"),L=()=>{const s=Buffer.concat(p).toString("utf8");return s.length>P?s.slice(-P):s};i.stdout?.on("data",s=>{w=g(I,w,s)}),i.stderr?.on("data",s=>{v=g(p,v,s)});const u=r>0?setTimeout(()=>{if(i.pid!==void 0)try{this.killImpl(i.pid)}catch{}this.settle(t,e,{status:"timeout",output:h(),error:`Timeout after ${r}ms`})},r):null;i.on("error",s=>{u!==null&&clearTimeout(u),this.settle(t,e,{status:"failed",output:h(),error:E(s)})}),i.on("exit",(s,o)=>{u!==null&&clearTimeout(u);const l=h();if(s===0){this.settle(t,e,{status:"succeeded",output:l,error:null});return}const c=s!==null?`exit ${s}`:`exit signal ${o??"unknown"}`,S=L();this.settle(t,e,{status:"failed",output:l,error:S?`${c}
|
|
2
|
+
${S}`:c})})}settle(t,e,r){if(!e.settled){e.settled=!0,this.active.delete(t.sessionId),this.livePids.delete(t.sessionId);try{t.onSettle(r)}catch{}}}}export function defaultKill(n){if(process.platform==="win32"){try{k("taskkill",["/PID",String(n),"/T","/F"],{windowsHide:!0,stdio:"ignore"}).on("error",()=>{})}catch{}return}try{process.kill(-n,"SIGKILL")}catch{try{process.kill(n,"SIGKILL")}catch{}}}function E(n){return n instanceof Error?n.message:String(n)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`,{encoding:"utf8",mode:384}),
|
|
1
|
+
import k from"node:net";import{chmodSync as l,mkdirSync as y,readFileSync as S,renameSync as b,writeFileSync as d}from"node:fs";import{dirname as g}from"node:path";export function inboxSocketPathOf(s){return s.startsWith("uds:")?s.slice(4):s}export function deliverViaInboxSocket(s,t,e,o={}){const c=o.platform??process.platform,i=o.timeoutMs??3e3,p=inboxSocketPathOf(t.socket);return s.requiresAuthOn(c)&&!t.token?Promise.reject(new Error(`inbox delivery requires a token on platform "${c}"`)):new Promise((u,m)=>{const a=s.frame({token:t.token,text:e});let f=!1;const h=r=>{f||(f=!0,n.destroy(),m(r))},n=k.connect(p);n.setTimeout(i),n.on("timeout",()=>h(new Error(`inbox socket timeout after ${i}ms`))),n.on("error",r=>h(r)),n.on("connect",()=>{n.write(a,r=>{r?h(r):n.end()})}),n.on("close",()=>{f||(f=!0,u())})})}export const INBOX_TARGETS_FILE="inbox-targets.json";function x(s){try{const t=JSON.parse(S(s,"utf8"));if(typeof t!="object"||t===null)return{};const e={};for(const[o,c]of Object.entries(t)){const i=c;typeof i?.socket!="string"||!i.socket||(e[o]={socket:i.socket,token:typeof i.token=="string"&&i.token?i.token:null})}return e}catch{return{}}}export class InboxSocketRegistry{file;bySession;persisted;constructor(t){this.file=t;const e=t?x(t):{};this.bySession=new Map(Object.entries(e)),this.persisted=JSON.stringify(e)}set(t,e){const o=this.bySession.get(t);if(!e?.socket){o&&(this.bySession.delete(t),this.persist());return}o&&o.socket===e.socket&&o.token===e.token||(this.bySession.set(t,e),this.persist())}get(t){return this.bySession.get(t)}forget(t){this.bySession.delete(t)&&this.persist()}persist(){if(!this.file)return;const t=JSON.stringify(Object.fromEntries(this.bySession));if(t!==this.persisted)try{y(g(this.file),{recursive:!0});const e=`${this.file}.tmp`;d(e,`${t}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),b(e,this.file),l(this.file,384),this.persisted=t}catch{}}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`)}catch{return[]}const
|
|
1
|
+
import{existsSync as I,readdirSync as v,readFileSync as j,renameSync as h,unlinkSync as b,writeFileSync as E}from"node:fs";import{join as d}from"node:path";import{isMainThread as T,parentPort as m,Worker as P,workerData as k}from"node:worker_threads";import{createRuntimeRegistry as x,effortLevelOf as M,frameFacts as O,permissionModeOf as D,startedModelOf as W,switchedModelOf as A}from"@weavecode/harness";import{HARNESS_LIFECYCLE as F,isHarness as g}from"@weavecode/core";import{getLogsDir as R}from"../db/paths.js";import{projectHarnessIds as L}from"../daemon/project-harnesses.js";import{openDatabase as _}from"../db/db.js";import{HookEventRepository as C}from"../repositories/hook-events.js";import{ProjectRepository as N}from"../repositories/projects.js";import{SessionRepository as B}from"../repositories/sessions.js";import{appendOutbox as X}from"./mirror.js";import{isSyntheticSession as H,replaceSyntheticSessions as U}from"./synthetic-sessions.js";export const INBOX_TICK_MS=200,INBOX_CLAIM_SUFFIX=".claim.jsonl",INBOX_FAILED_SUFFIX=".failed.jsonl";const $=5;export function drainInboxOnce(s,t=new Map){const e=d(s.hooksDir,"inbox");let i;try{i=v(e)}catch{return[]}const o=[];for(const c of i)c.endsWith(INBOX_FAILED_SUFFIX)||c.endsWith(".tmp")||c.endsWith(INBOX_CLAIM_SUFFIX)||c.endsWith(".jsonl")&&o.push(c);const r=[];for(const c of i)c.endsWith(INBOX_CLAIM_SUFFIX)&&r.push(...w(s,d(e,c),t));for(const c of o){const p=d(e,`${c.slice(0,-6)}${INBOX_CLAIM_SUFFIX}`);if(!I(p)){try{h(d(e,c),p)}catch{continue}r.push(...w(s,p,t))}}return r}function w(s,t,e){let i;try{i=j(t,"utf8").split(`
|
|
2
|
+
`)}catch{return[]}const o=new Map;for(const a of i){const u=a.trim();if(!u)continue;const n=z(u);if(!n)continue;const l=o.get(n.token)??{lines:[],inputs:[],delivered:[],terminals:[],messaging:[]};if(l.lines.push(u),l.project||(l.project=s.projects.getByToken(n.token),o.set(n.token,l)),!l.project||l.project.archivedAt)continue;const y=n.report&&typeof n.report=="object"?s.adapters.find(f=>f.source===n.report.source):void 0;if(!(!y||!n.report.eventType))try{const f=y.normalize(n.report,l.project.id);if(H(f.sessionId))continue;l.inputs.push(f),l.delivered.push(n.report.deliveredTitle??null),l.terminals.push(n.terminalEnv),l.messaging.push(n.messaging)}catch{}}const r=[],c=[];for(const a of o.values())if(!(!a.project||a.inputs.length===0))try{const u=S(s,a.project,a.inputs);for(let n=0;n<a.inputs.length;n++)r.push({eventId:u[n],projectId:a.project.id,input:a.inputs[n],deliveredTitle:a.delivered[n]??null,messaging:a.messaging[n]??null,terminalEnv:a.terminals[n]??null})}catch{c.push(...a.lines)}if(c.length===0){e.delete(t);try{b(t)}catch{}return r}const p=(e.get(t)??0)+1;if(e.set(t,p),p>=$){e.delete(t);try{h(t,t.replace(INBOX_CLAIM_SUFFIX,INBOX_FAILED_SUFFIX))}catch{}return r}try{E(t,c.join(`
|
|
3
3
|
`)+`
|
|
4
|
-
`)}catch{}return r}function
|
|
4
|
+
`)}catch{}return r}function S(s,t,e){const i=s.hookEvents.insertMany(e),o=new Map;for(const r of e){if(!r.sessionId)continue;const c=o.get(r.sessionId),p=r.createdAt;(!o.has(r.sessionId)||p&&(!c||p>c))&&o.set(r.sessionId,p)}for(const[r,c]of o)s.hookSessions.touch(r,t.id,c);return i}export const LOGS_TICK_MS=1e3;export async function pollLogsOnce(s){if(s.sources.length===0)return[];const t=new Map;for(const i of s.projects.list()){const o=await L(i.path);s.sources.some(r=>o.includes(r.harness))&&t.set(i.path,i)}if(t.size===0)return[];const e=[];for(const i of s.sources){const o=s.adapters.find(p=>p.source===i.harness);if(!o)continue;let r;try{r=await i.poll({stateDir:d(s.logsDir,i.harness),cwdWhitelist:[...t.keys()]})}catch{continue}const c=new Map;for(const p of r){const a=p.report.cwd?t.get(p.report.cwd):void 0;if(a)try{const u=o.normalize(p.report,a.id);u.createdAt=p.at;const n=c.get(a);n?n.push(u):c.set(a,[u])}catch{}}for(const[p,a]of c)try{const u=S(s,p,a);for(let n=0;n<a.length;n++)e.push({eventId:u[n],projectId:p.id,input:a[n]})}catch(u){console.error("[weave] log ingest failed:",u)}}return e}function z(s){try{const t=JSON.parse(s);if(!t||typeof t.token!="string"||!t.token||!t.report||typeof t.report!="object")return null;const e=t.messaging?.socket,i=typeof e=="string"&&e?{socket:e,token:typeof t.messaging?.token=="string"?t.messaging.token:null}:null;return{token:t.token,report:t.report,messaging:i,terminalEnv:K(t.terminal)}}catch{return null}}function K(s){if(typeof s!="object"||s===null)return null;const t={};for(const[e,i]of Object.entries(s))typeof i=="string"&&i&&(t[e]=i);return Object.keys(t).length>0?t:null}export function unparkFailedInbox(s){const t=d(s,"inbox");let e;try{e=v(t)}catch{return 0}let i=0;for(const o of e){if(!o.endsWith(INBOX_FAILED_SUFFIX))continue;const r=d(t,`${o.slice(0,-INBOX_FAILED_SUFFIX.length)}${INBOX_CLAIM_SUFFIX}`);if(!I(r))try{h(d(t,o),r),i++}catch{}}return i}export function handleIngestedRecords(s,t){for(const e of t){const i=s.projects.getById(e.projectId);if(!i)continue;s.dashboardRate?.record();let o=null;try{o=JSON.parse(e.input.payload)}catch{o=null}if(s.bus?.emit({kind:"event.ingested",eventId:e.eventId,projectId:i.id,sessionId:e.input.sessionId??null,eventType:e.input.eventType,...O(o),at:e.input.createdAt??new Date().toISOString()}),e.input.sessionId){s.questionTracker?.onEvent({sessionId:e.input.sessionId,source:e.input.source,payload:o}),s.sideQuestions?.onEvent({sessionId:e.input.sessionId,source:e.input.source,eventType:e.input.eventType,payload:o,eventId:e.eventId}),s.watchEngine?.onEvent({sessionId:e.input.sessionId,eventType:e.input.eventType,source:e.input.source}),s.orchestrationEngine?.onEvent({sessionId:e.input.sessionId,eventType:e.input.eventType,source:e.input.source}),e.messaging&&s.messagePipe?.noteInboxSocket?.(e.input.sessionId,e.messaging),s.sessionProbe?.noteTranscript(e.input.sessionId,o?.transcriptPath??null);const r=A(e.input.eventType,o?.raw);r&&s.sessionProbe?.noteModel?.(e.input.sessionId,r.to);const c=W(e.input.eventType,o?.raw);c&&s.sessionProbe?.sessionStarted?.(e.input.sessionId,c.model);const p=M(o?.raw);p&&s.sessionProbe?.noteEffort?.(e.input.sessionId,p);const a=D(o?.raw);if(a&&s.sessionProbe?.noteMode?.(e.input.sessionId,a),e.terminalEnv||g(e.input.source)){const n=e.input.source;g(n)&&s.paneEnvSource?.(n)==="launch"?s.messagePipe?.claimPendingOrigin?.(e.input.sessionId,n,e.projectId):e.terminalEnv&&s.messagePipe?.notePaneEnv?.(e.input.sessionId,e.terminalEnv)}if(e.input.eventType==="UserPromptSubmit"){const n=s.messagePipe?.onSessionPrompt?.(e.input.sessionId,J(o)??"",e.eventId)??[];n.length>0&&s.uploads?.linkToEvent(e.eventId,n)}else s.messagePipe?.noteActivity?.(e.input.sessionId);const u=g(e.input.source)?F[e.input.source].sessionExit:null;u!==null&&e.input.eventType===u&&(s.messagePipe?.sessionExited?.(e.input.sessionId),s.terminalTopologyKick?.()),s.messagePipe?.hasQueued(e.input.sessionId)&&s.messagePipe.flushSession(e.input.sessionId)}s.dispatcher&&s.dispatcher.onIngest({eventId:e.eventId,project:i,sessionId:e.input.sessionId??null,payload:o??{eventType:e.input.eventType,toolName:null,toolInput:null,toolResponse:null,cwd:null,transcriptPath:null,raw:null},source:e.input.source,deliveredTitle:e.deliveredTitle??null}).then(r=>{r.deferred&&e.input.sessionId&&X(s.hooksDir,i.token,[{sessionId:e.input.sessionId,text:r.deferred}])}).catch(()=>{})}}function J(s){const t=s?.raw;return typeof t?.prompt=="string"&&t.prompt?t.prompt:null}export function startInboxWorker(s){return new P(new URL(import.meta.url),{workerData:{inboxWorker:!0,...s}})}if(!T&&k?.inboxWorker===!0){const s=k,t=_(s.dbPath),e=x(),i=new N(t),o={hooksDir:s.hooksDir,projects:i,hookEvents:new C(t),hookSessions:new B(t),adapters:e.byCapability("events").flatMap(n=>n.events??[])};m?.on("message",n=>{n?.type==="synthetic-sessions"&&Array.isArray(n.ids)&&U(n.ids)});const r=new Map,c=()=>{try{const n=drainInboxOnce(o,r);n.length>0&&m?.postMessage(n)}catch(n){console.error("[weave] inbox drain failed:",n)}};c(),setInterval(c,s.tickMs??INBOX_TICK_MS);const p={projects:i,hookEvents:o.hookEvents,hookSessions:o.hookSessions,adapters:o.adapters,logsDir:R(),sources:e.byCapability("logs").flatMap(n=>n.logs??[])};let a=!1;const u=()=>{a||(a=!0,pollLogsOnce(p).then(n=>{n.length>0&&m?.postMessage(n)}).catch(n=>console.error("[weave] log poll failed:",n)).finally(()=>{a=!1}))};p.sources.length>0&&(u(),setInterval(u,LOGS_TICK_MS))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import i from"node:path";export const DISPATCH_MARKER="<!--weave-dispatch-->";const c=e=>process.platform==="win32"?e.toLowerCase():e;export function normalizePosix(e){return e.replace(/\\/g,"/")}function p(e){return/[.+^${}()|[\]\\]/.test(e)?`\\${e}`:e}const s=new Map;export function globToRegex(e){const t=s.get(e);if(t)return t;let n="";for(let r=0;r<e.length;r++){const l=e[r];l==="*"?e[r+1]==="*"?(r++,e[r+1]==="/"?(r++,n+="(?:.*/)?"):n+=".*"):n+="[^/]*":l==="?"?n+="[^/]":n+=p(l)}const o=new RegExp(`^${n}$`,"i");return s.set(e,o),o}export function matchGlob(e,t){return globToRegex(t).test(normalizePosix(e))}export function extractFilePath(e){if(typeof e!="object"||e===null)return null;const t=e;for(const n of["file_path","notebook_path","filePath"]){const o=t[n];if(typeof o=="string"&&o.length>0)return o}return null}function u(e,t){const n=c(normalizePosix(e)),o=c(normalizePosix(t).replace(/\/+$/,""));return n===o||n.startsWith(`${o}/`)}export function isCrossProjectPath(e,t,n){const o=c(normalizePosix(t));return u(e,t)?!1:n.some(r=>c(normalizePosix(r))!==o&&u(e,r))}export function renderTemplate(e,t){return e.replace(/\{(\w+)\}/g,(n,o)=>{const r=t[o];return r==null?n:String(r)})}export function templateVars(e){return{event:e.event,tool:e.tool,file:e.filePath?normalizePosix(e.filePath):null,cwd:e.cwd?normalizePosix(e.cwd):null,session:e.session,project:e.project,rule:e.rule}}export function matchesAnyGlob(e,t){return t.some(n=>matchGlob(e,n))}export function projectLabel(e){return i.basename(normalizePosix(e).replace(/\/+$/,""))||e}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{randomUUID as K}from"node:crypto";import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),O(s
|
|
3
|
-
`,{encoding:"utf8",mode:384}),O(s
|
|
4
|
-
`).slice(-
|
|
5
|
-
`);return xe.test(a)||je.test(a)},n=this.deps.interruptVerifyMs??Ce;let r=!1;for(const[l,a]of Ne.entries()){try{await t.terminal.sendKeys(t.paneId,a)}catch(h){if(l===0)return{ok:!1,status:409,error:h instanceof Error?h.message:String(h)};break}await m(l===0?n:Ke);const o=await s();if(o===null)return{ok:!0,paneId:t.paneId,sent:!0,confirmed:!0};if(i(o)){r=!0;break}}return{ok:!0,paneId:t.paneId,sent:!0,confirmed:r}}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,ie),{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,Z),{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,z),{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(!se.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,oe(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=re(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,ne(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 m(x),await t.sendKeys(s,r.submitKey).catch(()=>{}),await m(j);let o=await l();if((!o||!r.panelOpen(o))&&(await t.sendKeys(s,r.submitKey).catch(()=>{}),await m(j),o=await l(),!o||!r.panelOpen(o)))return;await t.sendText(s,n).catch(()=>{}),await m(x),await t.sendKeys(s,r.submitKey).catch(()=>{});const h=Date.now()+We;let d=null;for(;Date.now()<h;){if(await m(Ge),o=await l(),o==null)return;const c=r.extractAnswer(n,a,o);if(c.done){d=c.answer;break}}d!=null&&(this.sideAnswerStore?.answerById(e,n,d),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"){return le(this.keysDeps(),e,t)}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),commandModeOf:(e,t)=>this.commandModeOf(t,e),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 de(e,t=>this.surfaceOfSession(t))}hasImagesEntry(e){return ue(e)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(e,t)=>this.terminalPaneFor(e,t),paneEnvConflictOf:e=>this.paneEnvConflictOf(e)}}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(p(this.hooksDir,i.token,new Set([t])),this.dismissedIds.add(t);this.dismissedIds.size>Le;){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){p(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)){p(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}if(n&&await this.tryInboxDeliver(o,n)){p(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}const h=r?.resolve(e)??null,d=o.forceTerminal===!0?["terminal"]:o.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of d){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(e,o.id),p(this.hooksDir,s.token,new Set([a.id]));break}if(u==="terminal"&&!l&&this.terminalChannel()){const c=await this.terminalPaneFor(t,s);if(c){p(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,c.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+=Oe(this.hooksDir,e),this.queuedSessions.delete(e),this.gate.clearStall(e),this.gate.release(e),this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.paneEnvConflicts.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 S(s)?this.deps.surfaceFor?.(s)??F(s):null}commandModeOf(e,t){const s=this.deps.hookEvents.listBySession(e,1),i=s[s.length-1]?.source;if(!S(i))return null;const n=this.deps.commandsFor?.(i)??L(i);return n?q(t,n.inputModes):null}resolveChannel(e,t,s){return fe(this.deps.sessions,()=>this.terminalChannel()!=null,e,t,s)}async terminalPaneFor(e,t){return this.paneEnvConflicts.has(e.sessionId)?null:ae(this.terminalChannel(),this.paneEnvs,e,t)}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,h=e.forceTerminal===!0?["terminal"]:e.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of h){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 c=await this.terminalPaneFor(t,s);if(c)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,c.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 d={...e,status:"pending"};return{ok:!0,messageId:e.id,status:"pending",message:d}}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 he(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 V(s,i,this.wireTextOfEntry(e))}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),e,"socket")}queueEntry(e,t){pe(this.hooksDir,t,e),this.queuedSessions.add(e.sessionId)}sessionJudgedDead(e,t=this.deps.livenessOf?.()??A()){return Se(this.deps.sessions,e,t)}failOffline(e){return ge(this.memory,t=>this.bus(t),e)}failQueuedOffline(e,t){ke(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),commandModeOf:(e,t)=>this.commandModeOf(t,e),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 ye(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),this.commandModeOf(n.sessionId,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 me({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},e,t,s,i,this.wireTextOfEntry(e))}deliverHeadless(e,t,s,i){return ce({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 J}from"../daemon/claude-liveness.js";import{combinedLivenessOf as T}from"../daemon/liveness.js";import{HeadlessRunner as _}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 ee,ESC_KITTY as se,MODEL_NAME as te,SHIFT_TAB as ie,effortCommand as ne,effortLevelsOf as re,locateTerminalPane as ae,modelCommand as oe,sessionKeysTarget as de}from"./delivery/keys.js";import{hasImages as ue,settleDelivered as P,spawnOnce as he,wireTextOf as le}from"./delivery/channels.js";import{deliverHeadless as ce,deliverInject as me,resolveChannel as fe}from"./delivery/send.js";import{appendQueueEntry as pe,failOffline as ge,failQueuedOffline as ye,sessionJudgedDead as ke}from"./delivery/queue.js";import{runRelay as Ie}from"./delivery/relay.js";import{listInflightCounts as Se,listVisible as ve,sessionTerminals as we}from"./delivery/views.js";import{readPromptbox as y,removePromptboxBySession as Oe,removePromptboxEntries as p,scanQueuedSessionIds as Ee}from"./promptbox.js";const be=1e3,De=6e4,Te=3e4,Ae=9e4,Pe=5e3,xe=8,Ce=12e4,je=1200,Me=/interrupted/i,Fe=/· done/,Be=12,qe=[se,ee,X],Ke=600,Qe=250,Re=5,Ne=200,x="pane-envs.json",C="pending-origins.json",j=15*6e4;function We(f){try{const e=JSON.parse(w(f,"utf8"));if(!Array.isArray(e))return[];const s=[];for(const t of e){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&&s.push({harness:i.harness,projectId:i.projectId,env:n,at:i.at})}return s.filter(t=>Date.now()-Date.parse(t.at)<j)}catch{return[]}}function Je(f){try{const e=JSON.parse(w(f,"utf8"));if(typeof e!="object"||e===null)return{};const s={};for(const[t,i]of Object.entries(e)){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&&(s[t]=n)}return s}catch{return{}}}const m=f=>new Promise(e=>setTimeout(e,f)),M=300,F=1500,_e=1e3,Ge=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(e){this.deps=e,this.headless=e.headless??new _({spawnImpl:e.spawnImpl,killImpl:e.killImpl}),this.hooksDir=e.hooksDir??G(),this.sideAnswerStore=e.sideAnswerStore,this.inboxSockets=new H(g(this.hooksDir,L));const s=Je(g(this.hooksDir,x));this.paneEnvs=new Map(Object.entries(s)),this.persistedPaneEnvs=JSON.stringify(s),this.pendingOrigins=We(g(this.hooksDir,C)),this.persistedPendingOrigins=JSON.stringify(this.pendingOrigins),this.queuedSessions=Ee(this.hooksDir),this.gate=new V({awaitingAck:this.awaitingAck,stalled:this.stalled,memory:this.memory},{ackStallMs:e.ackStallMs??Te,ackStallReleaseMs:e.ackStallReleaseMs??Ae,commandAckGraceMs:e.commandAckGraceMs??Pe},{emit:t=>this.bus(t)},(t,i)=>this.commandModeOf(t,i)!==null),this.gate.onAutoRelease=t=>this.scheduleFlushContinuation(t)}async send(e){const s=this.deps.sessions.getBySessionId(e.toSessionId);if(!s)return{ok:!1,status:404,error:"Session not found"};const t=this.surfaceOfSession(e.toSessionId);if(!t)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};const i=e.attachments?[...e.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(e.mode,e.toSessionId,t);if(typeof n!="string")return{ok:!1,status:409,error:n.reason};if(s.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const r=this.deps.projects.getById(s.projectId);if(!r)return{ok:!1,status:404,error:"Project not found"};if(n==="headless"&&this.headless.isBusy(e.toSessionId))return{ok:!1,status:409,error:"Session already has a running run"};const d={fromLabel:e.fromKind==="session"?`session ${e.fromSessionId??"unknown"}`:e.fromKind,at:new Date().toISOString(),mode:n},a={id:K(),sessionId:e.toSessionId,text:e.text,...i.length>0?{attachments:i}:{},mode:e.mode,oneWay:e.oneWay===!0,...e.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,s,r,t);return this.bus({kind:"message.created",messageId:a.id,sessionId:a.sessionId,mode:a.mode,at:a.at}),h}getMessage(e){return this.memory.get(e)??null}listVisible(e){return ve(this.deps,this.hooksDir,this.memory,e,this.deps.visibleTtlMs??De,s=>this.commandModeOf(e,s)!==null)}hasQueued(e){return this.queuedSessions.has(e)}listInflightCounts(){return Se(this.hooksDir,this.memory)}hasTerminalChannel(){return this.terminalChannel()!=null}scheduleFlushContinuation(e){this.flushScheduled.has(e)||(this.flushScheduled.add(e),setTimeout(()=>{this.flushScheduled.delete(e),this.flushSession(e)},this.deps.flushGapMs??be).unref?.())}ackGateOpen(e){return this.gate.open(e)}blockedAhead(e){return this.ackGateOpen(e)?this.queuedSessions.has(e)||this.flushing.has(e):!0}noteInboxSocket(e,s){this.inboxSockets.set(e,s)}async awaitInboxReady(e,s){const t=this.surfaceOfSession(e)?.promptInbox??null;if(!t)return!1;const i=()=>{const r=this.inboxSockets.get(e);return!!r&&(!t.requiresAuthOn(process.platform)||!!r.token)},n=Date.now()+s;for(;!i();){if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,Qe))}return!0}lastTurnOutput(e){const s=this.deps.hookEvents.listBySession(e,Re);for(let t=s.length-1;t>=0;t--){const i=s[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(e,s){const t=JSON.stringify(s);for(const[i,n]of this.paneEnvs){if(i===e||JSON.stringify(n)!==t)continue;const r=this.deps.sessions.getBySessionId(i)?.lastSeenAt;if((r?Date.now()-Date.parse(r):Number.POSITIVE_INFINITY)<Ce){this.paneEnvs.delete(e),this.paneEnvConflicts.set(e,i),this.persistPaneEnvs();return}this.paneEnvs.delete(i),this.revokedPaneEnvs.add(i)}this.paneEnvConflicts.delete(e),this.paneEnvs.set(e,s),this.revokedPaneEnvs.delete(e),this.persistPaneEnvs()}paneEnvConflictOf(e){return this.paneEnvConflicts.get(e)??null}notePendingOrigin(e){this.pendingOrigins=this.pendingOrigins.filter(s=>Date.now()-Date.parse(s.at)<j),this.pendingOrigins.push({...e,at:new Date().toISOString()}),this.persistPendingOrigins()}claimPendingOrigin(e,s,t){const i=this.pendingOrigins.findIndex(r=>r.harness===s&&r.projectId===t);if(i<0)return;const[n]=this.pendingOrigins.splice(i,1);this.notePaneEnv(e,n.env),this.persistPendingOrigins()}persistPaneEnvs(){const e=JSON.stringify(Object.fromEntries(this.paneEnvs));if(e===this.persistedPaneEnvs)return;const s=g(this.hooksDir,x);try{v(b(s),{recursive:!0});const t=`${s}.tmp`;E(t,`${e}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),O(t,s),S(s,384),this.persistedPaneEnvs=e}catch{}}persistPendingOrigins(){const e=JSON.stringify(this.pendingOrigins);if(e===this.persistedPendingOrigins)return;const s=g(this.hooksDir,C);try{v(b(s),{recursive:!0});const t=`${s}.tmp`;E(t,`${e}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),O(t,s),S(s,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 s=this.deps.sessions.getBySessionId(e),t=s?.projectId==null?null:this.deps.projects.getById(s.projectId);if(!t)return;const i=y(this.hooksDir,t.token).filter(n=>n.sessionId===e);this.failQueuedOffline(e,i.filter(n=>!this.dismissedIds.has(n.id)))}async sessionTerminals(){return we(this.deps,this.terminalChannel(),this.paneEnvs,()=>this.persistPaneEnvs(),this.revokedPaneEnvs)}diagnose(e){const s=this.surfaceOfSession(e),t=this.deps.sessions.livenessRowOf(e),i=t?J(t,this.deps.livenessOf?.()??T()):null,n=s?.promptInbox??null,r=this.inboxSockets.get(e),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=s?.queuedPrompt?{status:"ready",reason:null}:{status:"unavailable",reason:"no-mechanism"},o=s?.prompt?.resolve(e)??null,h=s?.prompt?o?{status:"ready",reason:null}:{status:"unavailable",reason:"no-peer-name"}:{status:"unavailable",reason:"no-mechanism"},l=this.paneEnvs.has(e),u=this.terminalChannel()?l?{status:"ready",reason:null}:this.paneEnvConflicts.has(e)?{status:"unavailable",reason:"pane-env-conflict"}:{status:"unknown",reason:"no-pane-env"}:{status:"unavailable",reason:"no-backend"},c=this.deps.sessions.getBySessionId(e),I=c?.projectId==null?null:this.deps.projects.getById(c.projectId),B=I?y(this.hooksDir,I.token).filter(q=>q.sessionId===e).length:0;return{alive:i,inbox:d,queue:a,relay:h,terminal:u,paneEnvReported:l,pending:B,stalled:this.gate.isStalled(e)}}onSessionPrompt(e,s,t){const i=this.gate.acknowledge(e,s,t,{ackMinText:xe});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,s=>{this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)})}stall(e,s,t){this.gate.stall(e,s,t)}async answer(e,s){if(s.length===0||!A.test(s[0])||s.some(i=>!A.test(i)&&!U.test(i)))return{ok:!1,status:400,error:"Invalid answer keys"};const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{for(const[i,n]of s.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(e){const s=await this.sessionKeysTarget(e,"\u51FB\u952E");if(!s.ok)return s;const t=async()=>{try{return await s.terminal.getPaneText?.(s.paneId)??null}catch{return null}},i=d=>{const a=d.split(`
|
|
4
|
+
`).slice(-Be).join(`
|
|
5
|
+
`);return Me.test(a)||Fe.test(a)},n=this.deps.interruptVerifyMs??je;let r=!1;for(const[d,a]of qe.entries()){try{await s.terminal.sendKeys(s.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:Ke);const o=await t();if(o===null)return{ok:!0,paneId:s.paneId,sent:!0,confirmed:!0};if(i(o)){r=!0;break}}return{ok:!0,paneId:s.paneId,sent:!0,confirmed:r}}async closePane(e){const s=await this.sessionKeysTarget(e,"\u5173\u95ED");if(!s.ok)return s;try{return await s.terminal.closePane(s.paneId),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async cycleMode(e){const s=await this.sessionKeysTarget(e);if(!s.ok)return s;try{return await s.terminal.sendKeys(s.paneId,ie),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressEnter(e){const s=await this.sessionKeysTarget(e);if(!s.ok)return s;try{return await s.terminal.sendKeys(s.paneId,Z),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressCtrlC(e){const s=await this.sessionKeysTarget(e);if(!s.ok)return s;try{return await s.terminal.sendKeys(s.paneId,z),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async setModel(e,s){const t=s.trim();if(!te.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(e);if(!i.ok)return i;try{return await i.terminal.sendText(i.paneId,oe(t)),{ok:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async setEffort(e,s){const t=s.trim(),i=await this.sessionKeysTarget(e);if(!i.ok)return i;const n=re(this.deps.hookEvents,e);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,ne(t)),{ok:!0}}catch(r){return{ok:!1,status:409,error:r instanceof Error?r.message:String(r)}}}async askSideQuestion(e,s){if(!this.deps.sessions.getBySessionId(e))return{ok:!1,status:404,error:"Session not found"};const t=this.surfaceOfSession(e),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(s);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(d){return{ok:!1,status:409,error:d instanceof Error?d.message:String(d)}}}pollScreenAnswer(e,s,t,i,n){const r=i.screen,d=async()=>await s.getPaneText?.(t).catch(()=>null)??null;(async()=>{const a=await d()??"";await s.sendKeys(t,r.openKeys).catch(()=>{}),await m(M),await s.sendKeys(t,r.submitKey).catch(()=>{}),await m(F);let o=await d();if((!o||!r.panelOpen(o))&&(await s.sendKeys(t,r.submitKey).catch(()=>{}),await m(F),o=await d(),!o||!r.panelOpen(o)))return;await s.sendText(t,n).catch(()=>{}),await m(M),await s.sendKeys(t,r.submitKey).catch(()=>{});const h=Date.now()+Ge;let l=null;for(;Date.now()<h;){if(await m(_e),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(e,n,l),this.bus({kind:"sideQuestion.answered",sessionId:e,at:new Date().toISOString()}));const u=await d();u&&r.panelOpen(u)&&await s.sendKeys(t,r.closeKey).catch(()=>{})})()}async sessionKeysTarget(e,s="\u51FB\u952E"){return de(this.keysDeps(),e,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,s)=>this.gate.await(e,s),commandModeOf:(e,s)=>this.commandModeOf(s,e),armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:e=>this.gate.armCommandAck(e,s=>{this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)}),emit:e=>this.bus(e),...this.deps.spawnImpl?{spawnImpl:this.deps.spawnImpl}:{}}}wireTextOfEntry(e){return le(e,s=>this.surfaceOfSession(s))}hasImagesEntry(e){return ue(e)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(e,s)=>this.terminalPaneFor(e,s),paneEnvConflictOf:e=>this.paneEnvConflictOf(e)}}async resend(e){const s=this.memory.get(e);if(!s)return{ok:!1,status:404,error:"Message not found"};if(!(s.channel==="prompt"&&(s.status==="failed"||s.status==="delivered"&&!s.acked)))return{ok:!1,status:409,error:"Message is not resendable"};const t=this.deps.sessions.getBySessionId(s.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(s.sessionId);if(!n)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};if(this.gate.clearStall(s.sessionId,e),s.status==="delivered"&&s.via==="terminal"&&this.terminalChannel()){const a=await this.terminalPaneFor(t,i);if(a)return this.memory.set(e,{...s,status:"delivering",stalled:!1,settledAt:null}),this.runTerminalSubmit(e,a.id),this.bus({kind:"message.created",messageId:e,sessionId:s.sessionId,mode:s.mode,at:new Date().toISOString()}),{ok:!0,messageId:e,status:"delivering",message:this.memory.get(e)}}this.memory.delete(e);const r={...s,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(e,s){const t=this.memory.get(s);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)===s&&this.flushing.delete(t.sessionId),this.memory.delete(s),this.gate.clearStall(t.sessionId,s),this.gate.release(t.sessionId,s),this.queuedSessions.has(t.sessionId)&&this.scheduleFlushContinuation(t.sessionId)}else if(!this.dropQueued(e,s))return{ok:!1,status:404,error:"Message not found"};return this.bus({kind:"message.dismissed",messageId:s,sessionId:e,at:new Date().toISOString()}),{ok:!0}}dropQueued(e,s){const t=this.deps.sessions.getBySessionId(e);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===s&&r.sessionId===e))return!1;for(p(this.hooksDir,i.token,new Set([s])),this.dismissedIds.add(s);this.dismissedIds.size>Ne;){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!==s)||this.queuedSessions.delete(e),!0}async flushSession(e){if(this.stalled.has(e)||this.flushing.has(e)||!this.queuedSessions.has(e))return;const s=Symbol(e);this.flushing.set(e,s);try{await this.flushSessionInner(e)}catch{}finally{this.flushing.get(e)===s&&this.flushing.delete(e)}}async flushSessionInner(e){if(!this.ackGateOpen(e))return;const s=this.deps.sessions.getBySessionId(e);if(s?.projectId==null)return;const t=this.deps.projects.getById(s.projectId);if(!t)return;const i=y(this.hooksDir,t.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,d=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(!d&&this.hasImagesEntry(o)&&this.terminalChannel()){const u=await this.terminalPaneFor(s,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(e,o.id),await this.runTerminalPrompt(o.id,u.id,this.wireTextOfEntry(o)),this.settleQueueIndex(e,t.token);return}}if(n&&await this.tryQueuedDeliver(o,n)){p(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(e,t.token);return}if(n&&await this.tryInboxDeliver(o,n)){p(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(e,t.token);return}const h=r?.resolve(e)??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(e,o.id),p(this.hooksDir,t.token,new Set([a.id]));break}if(u==="terminal"&&!d&&this.terminalChannel()){const c=await this.terminalPaneFor(s,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(e,o.id),await this.runTerminalPrompt(o.id,c.id,this.wireTextOfEntry(o));break}}}if(this.awaitingAck.get(e)===o.id){this.settleQueueIndex(e,t.token);return}return}this.settleQueueIndex(e,t.token)}settleQueueIndex(e,s){y(this.hooksDir,s).every(t=>t.sessionId!==e)&&this.queuedSessions.delete(e)}async flushAll(){for(const e of[...this.queuedSessions])await this.flushSession(e)}forgetSession(e){let s=0;for(const[t,i]of this.memory)i.sessionId===e&&(this.memory.delete(t),s++);return s+=Oe(this.hooksDir,e),this.queuedSessions.delete(e),this.gate.clearStall(e),this.gate.release(e),this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.paneEnvConflicts.delete(e),this.revokedPaneEnvs.add(e),this.persistPaneEnvs(),s}forgetProject(e){const s=this.pendingOrigins.length;this.pendingOrigins=this.pendingOrigins.filter(i=>i.projectId!==e),this.pendingOrigins.length!==s&&this.persistPendingOrigins();let t=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),t++);for(const i of[...this.queuedSessions])this.deps.sessions.getBySessionId(i)?.projectId===e&&(t+=this.forgetSession(i));return this.persistPaneEnvs(),t}surfaceOfSession(e){const s=this.deps.hookEvents.listBySession(e,1),t=s[s.length-1]?.source;return k(t)?this.deps.surfaceFor?.(t)??W(t):null}commandModeOf(e,s){const t=this.deps.hookEvents.listBySession(e,1),i=t[t.length-1]?.source;if(!k(i))return null;const n=this.deps.commandsFor?.(i)??N(i);return n?Q(s,n.inputModes):null}resolveChannel(e,s,t){return fe(this.deps.sessions,()=>this.terminalChannel()!=null,e,s,t)}async terminalPaneFor(e,s){return this.paneEnvConflicts.has(e.sessionId)?null:ae(this.terminalChannel(),this.paneEnvs,e,s)}terminalChannel(){const e=this.deps.terminal;return e&&e.available()?e:null}modalBlocked(e){return this.deps.blockedByQuestion?.(e)===!0}async deliverPrompt(e,s,t,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(s,t);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 d=await this.tryInboxDeliver(e,i);if(d)return{ok:!0,messageId:e.id,status:"delivered",message:d};const a=i.prompt,o=a?.resolve(e.sessionId)??null,h=e.forceTerminal===!0?["terminal"]:e.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of h){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 c=await this.terminalPaneFor(s,t);if(c)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,c.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,t.token);const l={...e,status:"pending"};return{ok:!0,messageId:e.id,status:"pending",message:l}}async tryQueuedDeliver(e,s){const t=s.queuedPrompt;if(!t||this.hasImagesEntry(e))return null;const{bin:i,args:n}=t.command(e.sessionId,this.wireTextOfEntry(e));this.memory.set(e.id,{...e,status:"delivering",via:"queue"});try{await he(i,n,t.timeoutMs??3e4,this.deps.spawnImpl)}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),{...e,via:"queue"},"queue")}async tryInboxDeliver(e,s){const t=s.promptInbox,i=this.inboxSockets.get(e.sessionId);if(!t||!i||e.forceTerminal===!0)return null;this.memory.set(e.id,{...e,status:"delivering",via:"socket"});try{await $(t,i,this.wireTextOfEntry(e))}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),e,"socket")}queueEntry(e,s){pe(this.hooksDir,s,e),this.queuedSessions.add(e.sessionId)}sessionJudgedDead(e,s=this.deps.livenessOf?.()??T()){return ke(this.deps.sessions,e,s)}failOffline(e){return ge(this.memory,s=>this.bus(s),e)}failQueuedOffline(e,s){ye(this.deps,this.hooksDir,this.memory,t=>this.bus(t),e,s),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,s)=>this.gate.await(e,s),stall:(e,s,t)=>this.gate.stall(e,s,t),commandModeOf:(e,s)=>this.commandModeOf(s,e),armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:(e,s)=>this.gate.armCommandAck(e,t=>{s(t),this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)}),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,s,t){return Ie(this.relayDeps(),e,s,t,this.wireTextOfEntry(e))}async runTerminalPrompt(e,s,t){await this.runTerminal(e,i=>i.sendText(s,t))}async runTerminalSubmit(e,s){await this.runTerminal(e,t=>t.sendKeys(s,"\r"))}async runTerminal(e,s){const t=this.memory.get(e);if(!t)return;const i=this.terminalChannel();if(i)try{await s(i);const n=this.memory.get(e);if(!n)return;const r={...n,status:"delivered",settledAt:new Date().toISOString()};this.memory.set(e,r),this.commandModeOf(n.sessionId,n.text)?this.armCommandAck(e):this.armAckWatch(r),this.bus({kind:"message.delivered",messageId:e,sessionId:t.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 d={...r,status:"failed",error:n instanceof Error?n.message:String(n),settledAt:new Date().toISOString()};this.memory.set(e,d),this.stall(t.sessionId,d,"failed"),this.bus({kind:"message.finished",messageId:e,sessionId:t.sessionId,status:"failed",at:new Date().toISOString()})}}deliverInject(e,s,t,i){return me({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},e,s,t,i,this.wireTextOfEntry(e))}deliverHeadless(e,s,t,i){return ce({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,s,t,i,this.wireTextOfEntry(e))}bus(e){try{this.deps.bus?.emit(e)}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 e)t.push(JSON.stringify({...c,at:new Date().toISOString()}));const
|
|
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,r){return i(s,"mirror",`${r}.json`)}export function outboxPathOf(s,r){return i(s,"outbox",`${r}.jsonl`)}export function buildMirrorDoc(s,r,e){const o=r.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:e,rules:o}}export class MirrorWriter{deps;dataDir;constructor(r){this.deps=r,this.dataDir=r.dataDir??m()}syncAll(){for(const r of this.deps.projects.list())this.syncProject(r.id)}syncProject(r){const e=this.deps.projects.getById(r);if(!e||e.archivedAt)return;const o={};for(const t of this.deps.sessions.list(r))t.pendingTitle&&(o[t.sessionId]=t.pendingTitle);this.write(e.token,buildMirrorDoc(e,this.deps.rules.list(),o))}write(r,e){try{const o=mirrorPathOf(hooksRoot(this.dataDir),hookShardId(r));a(i(hooksRoot(this.dataDir),"mirror"),{recursive:!0});const t=`${o}.tmp`;l(t,JSON.stringify(e)),d(t,o)}catch{}}attachToBus(r){r.subscribe(e=>{if(e.kind!=="session.renamed"||!e.sessionId)return;const o=this.deps.sessions.getBySessionId(e.sessionId);o?.projectId!=null&&this.syncProject(o.projectId)})}}export function appendInbox(s,r,e){const o=i(s,"inbox");a(o,{recursive:!0}),l(i(o,`${hookShardId(r)}.jsonl`),JSON.stringify({v:1,token:r,report:e})+`
|
|
2
|
+
`,{flag:"a"})}export function appendOutbox(s,r,e){if(e.length!==0)try{const o=outboxPathOf(s,hookShardId(r));a(i(s,"outbox"),{recursive:!0});let t=[];try{t=u(o,"utf8").split(`
|
|
3
|
+
`).filter(c=>c.trim())}catch{t=[]}for(const c of e)t.push(JSON.stringify({...c,at:new Date().toISOString()}));const n=t.slice(-OUTBOX_MAX_LINES),p=`${o}.tmp`;l(p,n.length?n.join(`
|
|
4
4
|
`)+`
|
|
5
|
-
`:""),
|
|
5
|
+
`:""),d(p,o)}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,H=1500,U=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??H)),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<U}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 p}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(
|
|
1
|
+
import{graphDirections as p}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:t}=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(t.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 t){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 h=`${o.from}->${o.to}`;if(a.has(h))return{ok:!1,error:`Duplicate edge ${o.from}\u2192${o.to}`};a.add(h)}const{entries:e}=p(n,t),r=new Set(t.map(o=>o.to)),d=new Set(t.map(o=>o.from)),c=new Set(e.filter(o=>o.kind==="webhook").map(o=>o.id)),k=t.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 t)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(r.has(o.id)&&d.has(o.id))return{ok:!1,error:`Webhook node ${o.id} cannot have both inbound and outbound edges`};if(!r.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(r.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"||!r.has(o.id))continue;const h=o.url??"";let u=null;try{u=new URL(h)}catch{u=null}if(!u||u.protocol!=="http:"&&u.protocol!=="https:")return{ok:!1,error:`Webhook node ${o.id} needs a valid http(s) URL`}}const g=findCycle(n,t);return g?{ok:!1,error:`Cycle detected: ${g.join(" \u2192 ")}`}:{ok:!0}}export function findCycle(f,n){const t=new Map;for(const e of f)t.set(e.id,[]);for(const e of n){const r=t.get(e.from);r&&r.push(e.to)}const i=new Map,s=[],a=e=>{i.set(e,1),s.push(e);for(const r of t.get(e)??[]){const d=i.get(r)??0;if(d===1)return[...s.slice(s.indexOf(r)),r];if(d===0){const c=a(r);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 r=a(e.id);if(r)return r}return null}export function ranksOf(f,n){const t=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),t.set(e.to,(t.get(e.to)??0)+1);const s=new Map(f.map(e=>[e.id,0])),a=f.filter(e=>(t.get(e.id)??0)===0).map(e=>e.id);for(let e=0;e<a.length;e++){const r=a[e];for(const d of i.get(r)??[]){s.set(d,Math.max(s.get(d)??0,(s.get(r)??0)+1));const c=(t.get(d)??0)-1;t.set(d,c),c===0&&a.push(d)}}return s}
|