@weavecode/weave 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/.editorconfig +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/CHANGELOG.md +45 -22
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/README.md +26 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/dist/qs.js +27 -27
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/eslint.config.mjs +61 -50
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/formats.js +7 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/parse.js +13 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/stringify.js +5 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/lib/utils.js +15 -7
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express/node_modules/qs/package.json +6 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/dist/common.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/express-rate-limit/node_modules/ip-address/package.json +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/README.md +2 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/helper/css/common.js +8 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/helper/css/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/helper/route/index.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/jsx/base.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +8 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/middleware/serve-static/index.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/router/trie-router/node.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/cjs/utils/url.js +11 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/helper/css/common.js +8 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/helper/css/index.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/helper/route/index.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/jsx/base.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/bearer-auth/index.js +8 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/middleware/serve-static/index.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/router/trie-router/node.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/aws-lambda/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/bun/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/bun/ssg.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/cloudflare-pages/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/cloudflare-workers/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/deno/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/deno/ssg.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/lambda-edge/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/netlify/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/adapter/vercel/conninfo.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/helper/testing/index.d.ts +2 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/hono-base.d.ts +21 -9
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/index.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/jsx/components.d.ts +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/jsx/context.d.ts +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/jsx/dom/components.d.ts +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/jsx/dom/css.d.ts +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/jsx/streaming.d.ts +4 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/middleware/bearer-auth/index.d.ts +2 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/middleware/ip-restriction/index.d.ts +3 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +3 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/types/utils/ipaddr.d.ts +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/dist/utils/url.js +11 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/hono/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 +2 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +14 -0
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +4 -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 +3 -3
- package/node_modules/@weavecode/cli/dist/init/executor.d.ts +5 -4
- package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
- package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
- package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
- package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/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.d.ts +25 -0
- package/node_modules/@weavecode/cli/dist/init/provision.js +1 -0
- package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
- package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
- package/node_modules/@weavecode/cli/dist/parser.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
- package/node_modules/@weavecode/cli/package.json +5 -5
- package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
- package/node_modules/@weavecode/core/dist/harness.d.ts +13 -1
- package/node_modules/@weavecode/core/dist/harness.js +1 -1
- package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
- package/node_modules/@weavecode/core/dist/index.js +1 -1
- package/node_modules/@weavecode/core/dist/platform.js +1 -1
- package/node_modules/@weavecode/core/dist/types.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
- package/node_modules/@weavecode/core/package.json +1 -1
- package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -4
- package/node_modules/@weavecode/harness/dist/claude/capture.js +9 -9
- package/node_modules/@weavecode/harness/dist/claude/commands.js +3 -3
- package/node_modules/@weavecode/harness/dist/claude/config.d.ts +9 -0
- 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.d.ts +2 -0
- package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/images.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/index.d.ts +4 -2
- package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/liveness.d.ts +64 -0
- package/node_modules/@weavecode/harness/dist/claude/liveness.js +1 -0
- 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.d.ts +4 -0
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/narration.d.ts +13 -0
- package/node_modules/@weavecode/harness/dist/claude/narration.js +1 -0
- 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/settings-gen.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/side-question.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +14 -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.d.ts +13 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript.js +7 -6
- package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/capture.d.ts +1 -2
- 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.d.ts +10 -0
- 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.d.ts +1 -1
- package/node_modules/@weavecode/harness/dist/codex/event-source.js +2 -2
- package/node_modules/@weavecode/harness/dist/codex/images.d.ts +2 -0
- package/node_modules/@weavecode/harness/dist/codex/images.js +1 -0
- package/node_modules/@weavecode/harness/dist/codex/index.d.ts +13 -2
- package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/liveness.d.ts +38 -0
- package/node_modules/@weavecode/harness/dist/codex/liveness.js +1 -0
- package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/messaging.d.ts +7 -3
- package/node_modules/@weavecode/harness/dist/codex/messaging.js +3 -3
- package/node_modules/@weavecode/harness/dist/codex/narration.d.ts +10 -0
- package/node_modules/@weavecode/harness/dist/codex/narration.js +1 -0
- 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.d.ts +12 -0
- package/node_modules/@weavecode/harness/dist/codex/provision.js +1 -0
- package/node_modules/@weavecode/harness/dist/codex/questions.d.ts +9 -0
- package/node_modules/@weavecode/harness/dist/codex/questions.js +2 -0
- package/node_modules/@weavecode/harness/dist/codex/resume.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/rollout.d.ts +8 -5
- package/node_modules/@weavecode/harness/dist/codex/rollout.js +5 -5
- package/node_modules/@weavecode/harness/dist/codex/side-question.d.ts +12 -0
- package/node_modules/@weavecode/harness/dist/codex/side-question.js +4 -0
- package/node_modules/@weavecode/harness/dist/codex/titles.d.ts +8 -0
- package/node_modules/@weavecode/harness/dist/codex/titles.js +4 -0
- 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 +162 -8
- package/node_modules/@weavecode/harness/dist/driver.js +1 -1
- package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
- package/node_modules/@weavecode/harness/dist/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
- package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
- package/node_modules/@weavecode/harness/dist/install.d.ts +9 -0
- package/node_modules/@weavecode/harness/dist/install.js +1 -0
- 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/dist/zcode/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -3
- package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -2
- package/node_modules/@weavecode/harness/package.json +2 -2
- package/node_modules/@weavecode/server/dist/config/dotted.js +1 -1
- package/node_modules/@weavecode/server/dist/config/profiles.d.ts +10 -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 +6 -6
- package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/claude-liveness.d.ts +4 -55
- package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/config-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/cron.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/dashboard-pusher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/decision-config.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +2 -0
- 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.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/daemon/liveness.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/mcp-orchestration.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/narration-watcher.d.ts +28 -0
- package/node_modules/@weavecode/server/dist/daemon/narration-watcher.js +2 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-ghostty.d.ts +16 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-ghostty.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-iterm.d.ts +20 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-iterm.js +12 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-konsole.d.ts +23 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-konsole.js +2 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-terminal-app.d.ts +19 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-terminal-app.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wezterm.d.ts +87 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wezterm.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wt.d.ts +45 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend-wt.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend.d.ts +115 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/backend.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/opener/launch.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/pty-terminals.js +4 -4
- package/node_modules/@weavecode/server/dist/daemon/opener/shared.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/wezterm-mux.d.ts +8 -5
- package/node_modules/@weavecode/server/dist/daemon/opener/wezterm-mux.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/opener/wt.js +3 -3
- package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +23 -120
- package/node_modules/@weavecode/server/dist/daemon/opener.js +1 -13
- package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/project-files.d.ts +17 -2
- package/node_modules/@weavecode/server/dist/daemon/project-files.js +2 -1
- package/node_modules/@weavecode/server/dist/daemon/project-harnesses.d.ts +2 -0
- package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/prompt-images.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/hooks-admin.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/market.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/orchestration.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/path-refs.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/project-files.d.ts +6 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/project-files.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/projects.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/routes/search.d.ts +38 -0
- package/node_modules/@weavecode/server/dist/daemon/routes/search.js +1 -0
- 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/watches.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/server.d.ts +8 -2
- package/node_modules/@weavecode/server/dist/daemon/server.js +8 -8
- package/node_modules/@weavecode/server/dist/daemon/session-open.d.ts +10 -1
- 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.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
- package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/upload-sessions.js +1 -1
- package/node_modules/@weavecode/server/dist/db/db.js +5 -2
- package/node_modules/@weavecode/server/dist/db/layout.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +10 -0
- package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/dashboard-rate.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/decision-judge.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/ack-gate.d.ts +20 -0
- 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.d.ts +7 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/keys.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/queue.d.ts +4 -4
- 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.d.ts +3 -1
- package/node_modules/@weavecode/server/dist/hooks/delivery/views.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/dispatcher.d.ts +5 -0
- 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.d.ts +15 -0
- package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
- package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +64 -6
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
- package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
- package/node_modules/@weavecode/server/dist/hooks/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.d.ts +5 -0
- 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/session-sweeper.d.ts +2 -0
- package/node_modules/@weavecode/server/dist/hooks/session-sweeper.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 -0
- 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.js +2 -2
- package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
- package/node_modules/@weavecode/server/dist/install/installer.js +1 -1
- package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
- package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
- package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
- package/node_modules/@weavecode/server/dist/install/project-config.js +1 -1
- package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
- package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
- package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
- package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
- package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
- package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
- package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
- package/node_modules/@weavecode/server/dist/market/import.js +2 -2
- package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
- package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
- package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
- package/node_modules/@weavecode/server/dist/registry.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
- package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +19 -1
- package/node_modules/@weavecode/server/dist/repositories/hook-events.js +9 -3
- package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
- package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
- package/node_modules/@weavecode/server/dist/repositories/orchestrations.js +7 -7
- package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
- package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
- package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +12 -2
- package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/repositories/side-questions.js +8 -5
- package/node_modules/@weavecode/server/dist/repositories/uploads.js +11 -11
- package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -3
- package/node_modules/@weavecode/server/dist/surfaces.d.ts +8 -1
- package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
- package/node_modules/@weavecode/server/dist/version.d.ts +1 -11
- package/node_modules/@weavecode/server/dist/version.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-etRkSvQM.js → abnfDiagram-WEYOIA3C-DA-K085F.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{arc-FxRZALAZ.js → arc-BI1jnmdZ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{architectureDiagram-ZHVYKT53-5OxZ-ffz.js → architectureDiagram-ZHVYKT53-DbdBgric.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{blockDiagram-RJAE7QA3-C-CgMF0O.js → blockDiagram-RJAE7QA3-BPRBmzb-.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{c4Diagram-XDPPPE54-B6TqN1Pw.js → c4Diagram-XDPPPE54-C4D5sRs1.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/channel-DcCJrvon.js +1 -0
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2E7WHVMD-Bdzr5RRj.js → chunk-2E7WHVMD-9ZSKiNU3.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-2Q5K7J3B-gBZASjAC.js → chunk-2Q5K7J3B-i0AOjw_8.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-4EMNKR2T-DSlUhKMw.js → chunk-4EMNKR2T-DTpLfX1H.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-55XCU76K-BDQ6zpGR.js → chunk-55XCU76K-COQYRD4q.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-5VM5RSS4-DPnewKbl.js → chunk-5VM5RSS4-VsftEbvo.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-JWPE2WC7-DagmT8Cc.js → chunk-JWPE2WC7-DonektJN.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-VQ5W62QI-Da_2PxfM.js → chunk-VQ5W62QI-CaKUwuul.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-XXDRQBXY-Cdaysois.js → chunk-XXDRQBXY-DXH3D_MT.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{chunk-ZCHMQSOR-CvgYfbjU.js → chunk-ZCHMQSOR-COwyAuGn.js} +2 -2
- package/node_modules/@weavecode/server/web/dist/assets/{classDiagram-v2-4MYWR3UA-ahplYD2h.js → classDiagram-v2-4MYWR3UA-DEvMZ6mX.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cose-bilkent-JH36ORCC-DFyUfgKj.js → cose-bilkent-JH36ORCC-6JBJHfH6.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cynefin-EF2NZ3EQ-mr2qRwod.js → cynefin-EF2NZ3EQ-C4GM4sjT.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{cynefinDiagram-WF24UDRP-BC26VqNp.js → cynefinDiagram-WF24UDRP-Cqgi0MBP.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{dagre-NK4GIZVX-DoKn_P1x.js → dagre-NK4GIZVX-CljrnkCY.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-CBK3MWTC-C9WfEmt3.js → diagram-CBK3MWTC-C3PyOj5J.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-I5XIIV2D-D4Ibieda.js → diagram-I5XIIV2D-I5brQlaZ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-ODIL2UCW-wsLbYLi0.js → diagram-ODIL2UCW-BX9uFNbU.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-PFBEJUXE-DBioMmDk.js → diagram-PFBEJUXE-y7D-VmqJ.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-RJA3I4VV-Cl5gKsWm.js → diagram-RJA3I4VV-DLUL8W42.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{diagram-TYUNFSNR-BSXOaZic.js → diagram-TYUNFSNR-DLCC3ILi.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ebnfDiagram-V4P3TTPT-CJIGOag6.js → ebnfDiagram-V4P3TTPT-D7vALia7.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{elk-QONTBCTQ-D6nd2OVX.js → elk-QONTBCTQ-Ct2_hatz.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{erDiagram-KYQIGQAA-gmXjWsuF.js → erDiagram-KYQIGQAA-DxLai58T.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{flowDiagram-IUGLLWBU-DWAiZ43K.js → flowDiagram-IUGLLWBU-AWn2IHrF.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ganttDiagram-R7GPNTJY-De4v6Wtt.js → ganttDiagram-R7GPNTJY-DmRHd4Wz.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{gitGraphDiagram-PDYL7XHY-CouLBWOB.js → gitGraphDiagram-PDYL7XHY-Ccj-t3zg.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/index-BSxzia7U.js +1031 -0
- package/node_modules/@weavecode/server/web/dist/assets/index-CEpJpR7P.css +11 -0
- package/node_modules/@weavecode/server/web/dist/assets/{infoDiagram-MVDRKAX5-CeMCdduD.js → infoDiagram-MVDRKAX5-BHquFlQa.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{ishikawaDiagram-HPEHV2GE-DK6hETwg.js → ishikawaDiagram-HPEHV2GE-CVogEbdm.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{journeyDiagram-BOSHW7O7-BcgwTlST.js → journeyDiagram-BOSHW7O7-DC9XG9oh.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{kanban-definition-FNSA4HC5-CTVMJNz2.js → kanban-definition-FNSA4HC5-C_eu7DC_.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{linear-CqQf5eWO.js → linear-keTbWHJ-.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{mermaid.core-B6KZaljU.js → mermaid.core-4sbg0MnY.js} +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/{mindmap-definition-6OY57UG3-cpKvrQTI.js → mindmap-definition-6OY57UG3-kMQS0S2l.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{pegDiagram-ECIUJNBX-Bv2bNqMZ.js → pegDiagram-ECIUJNBX-DcUFoEwP.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{pieDiagram-GNMPY74T-CXOnA429.js → pieDiagram-GNMPY74T-BQJ7WDCx.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{quadrantDiagram-D57K4MC3-BFDUpWZb.js → quadrantDiagram-D57K4MC3-C7Oi1-sq.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{railroadDiagram-Y72NRBL7-BHoDSO0D.js → railroadDiagram-Y72NRBL7-CEF2QbOF.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{requirementDiagram-EQYSW5RA-B8JGji7q.js → requirementDiagram-EQYSW5RA-CTjjFS7X.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sankeyDiagram-SY24JHO5-BbE2-6ZM.js → sankeyDiagram-SY24JHO5-j0S5kubS.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sequenceDiagram-BLEHNHQU-DwK4X2MT.js → sequenceDiagram-BLEHNHQU-B76EsZp4.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{sizeCapture-INFHLROL-CY10zRMe.js → sizeCapture-INFHLROL-r0DZuqAy.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{stateDiagram-v2-A6IESKWZ-32t4Zx8b.js → stateDiagram-v2-A6IESKWZ-B4DR9LHz.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{swimlanes-B3ENRKFQ-CZlYQ8_g.js → swimlanes-B3ENRKFQ-Dbcl85ro.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-CZ_6SSBd.js +8 -0
- package/node_modules/@weavecode/server/web/dist/assets/{timeline-definition-JXYKGLGB-8VsB-Jwg.js → timeline-definition-JXYKGLGB-BlBXXRNf.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{usecaseDiagram-WPOLBNNX-CKOTONay.js → usecaseDiagram-WPOLBNNX-Ck1M0dpc.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{vennDiagram-Q3Y3IDCW-BzrNjxtm.js → vennDiagram-Q3Y3IDCW-N8B-ohWk.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{wardleyDiagram-IVAIDKWA-CrSd-v8I.js → wardleyDiagram-IVAIDKWA-DX-AMXq_.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/assets/{xychartDiagram-4URNHDU4-t9cV9_9b.js → xychartDiagram-4URNHDU4-4fgL48Yl.js} +1 -1
- package/node_modules/@weavecode/server/web/dist/index.html +5 -4
- package/node_modules/@weavecode/templates/package.json +2 -2
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/@peculiar/asn1-x509-attr/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/package.json +4 -4
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/@peculiar/asn1-pfx/package.json +5 -5
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/@peculiar/asn1-pkcs8/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/@peculiar/asn1-x509-attr/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/package.json +7 -7
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/package.json +3 -3
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/package.json +1 -1
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/build/cjs/time.js +1 -1
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/build/es2015/time.js +1 -1
- package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/package.json +2 -2
- package/package.json +6 -6
- package/node_modules/@weavecode/server/web/dist/assets/channel-Dv4QUMOJ.js +0 -1
- package/node_modules/@weavecode/server/web/dist/assets/index-BXhLerZ4.js +0 -1008
- package/node_modules/@weavecode/server/web/dist/assets/index-BYRxC-Zz.css +0 -11
- package/node_modules/@weavecode/server/web/dist/assets/swimlanesDiagram-AYQRV4AK-BlIxQLON.js +0 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`)}catch{return[]}const
|
|
1
|
+
import{existsSync as v,readdirSync as I,readFileSync as w,renameSync as g,unlinkSync as S,writeFileSync as T}from"node:fs";import{join as f}from"node:path";import{isMainThread as E,parentPort as h,Worker as x,workerData as k}from"node:worker_threads";import{createRuntimeRegistry as M,effortLevelOf as O,frameFacts as P,permissionModeOf as D,startedModelOf as A,switchedModelOf as L}from"@weavecode/harness";import{HARNESS_LIFECYCLE as W,isHarness as m}from"@weavecode/core";import{getLogsDir as _}from"../db/paths.js";import{projectHarnessIds as C}from"../daemon/project-harnesses.js";import{openDatabase as F}from"../db/db.js";import{HookEventRepository as R}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(n,o=new Map){const e=f(n.hooksDir,"inbox");let i;try{i=I(e)}catch{return[]}const s=[];for(const c of i)c.endsWith(INBOX_FAILED_SUFFIX)||c.endsWith(".tmp")||c.endsWith(INBOX_CLAIM_SUFFIX)||c.endsWith(".jsonl")&&s.push(c);const r=[];for(const c of i)c.endsWith(INBOX_CLAIM_SUFFIX)&&r.push(...j(n,f(e,c),o));for(const c of s){const p=f(e,`${c.slice(0,-6)}${INBOX_CLAIM_SUFFIX}`);if(!v(p)){try{g(f(e,c),p)}catch{continue}r.push(...j(n,p,o))}}return r}function j(n,o,e){let i;try{i=w(o,"utf8").split(`
|
|
2
|
+
`)}catch{return[]}const s=new Map;for(const u of i){const a=u.trim();if(!a)continue;const t=z(a);if(!t)continue;const l=s.get(t.token)??{lines:[],inputs:[],delivered:[],terminals:[],messaging:[]};if(l.lines.push(a),l.project||(l.project=n.projects.getByToken(t.token),s.set(t.token,l)),!l.project||l.project.archivedAt)continue;const y=t.report&&typeof t.report=="object"?n.adapters.find(d=>d.source===t.report.source):void 0;if(!(!y||!t.report.eventType))try{const d=y.normalize(t.report,l.project.id);if(H(d.sessionId))continue;l.inputs.push(d),l.delivered.push(t.report.deliveredTitle??null),l.terminals.push(t.terminalEnv),l.messaging.push(t.messaging)}catch{}}const r=[],c=[];for(const u of s.values())if(!(!u.project||u.inputs.length===0))try{const a=b(n,u.project,u.inputs);for(let t=0;t<u.inputs.length;t++)r.push({eventId:a[t],projectId:u.project.id,input:u.inputs[t],deliveredTitle:u.delivered[t]??null,messaging:u.messaging[t]??null,terminalEnv:u.terminals[t]??null})}catch{c.push(...u.lines)}if(c.length===0){e.delete(o);try{S(o)}catch{}return r}const p=(e.get(o)??0)+1;if(e.set(o,p),p>=$){e.delete(o);try{g(o,o.replace(INBOX_CLAIM_SUFFIX,INBOX_FAILED_SUFFIX))}catch{}return r}try{T(o,c.join(`
|
|
3
3
|
`)+`
|
|
4
|
-
`)}catch{}return
|
|
4
|
+
`)}catch{}return r}function b(n,o,e){const i=n.hookEvents.insertMany(e),s=new Map;for(const r of e){if(!r.sessionId)continue;const c=s.get(r.sessionId),p=r.createdAt;(!s.has(r.sessionId)||p&&(!c||p>c))&&s.set(r.sessionId,p)}for(const[r,c]of s)n.hookSessions.touch(r,o.id,c);return i}export const LOGS_TICK_MS=1e3;export async function pollLogsOnce(n){if(n.sources.length===0)return[];const o=new Map;for(const i of n.projects.list()){const s=await C(i.path);n.sources.some(r=>s.includes(r.harness))&&o.set(i.path,i)}if(o.size===0)return[];const e=[];for(const i of n.sources){const s=n.adapters.find(p=>p.source===i.harness);if(!s)continue;let r;try{r=await i.poll({stateDir:f(n.logsDir,i.harness),cwdWhitelist:[...o.keys()]})}catch{continue}const c=new Map;for(const p of r){const u=p.report.cwd?o.get(p.report.cwd):void 0;if(u)try{const a=s.normalize(p.report,u.id);a.createdAt=p.at;const t=c.get(u);t?t.push(a):c.set(u,[a])}catch{}}for(const[p,u]of c)try{const a=b(n,p,u);for(let t=0;t<u.length;t++)e.push({eventId:a[t],projectId:p.id,input:u[t]})}catch(a){console.error("[weave] log ingest failed:",a)}}return e}function z(n){try{const o=JSON.parse(n);if(!o||typeof o.token!="string"||!o.token||!o.report||typeof o.report!="object")return null;const e=o.messaging?.socket,i=typeof e=="string"&&e?{socket:e,token:typeof o.messaging?.token=="string"?o.messaging.token:null}:null;return{token:o.token,report:o.report,messaging:i,terminalEnv:K(o.terminal)}}catch{return null}}function K(n){if(typeof n!="object"||n===null)return null;const o={};for(const[e,i]of Object.entries(n))typeof i=="string"&&i&&(o[e]=i);return Object.keys(o).length>0?o:null}export function unparkFailedInbox(n){const o=f(n,"inbox");let e;try{e=I(o)}catch{return 0}let i=0;for(const s of e){if(!s.endsWith(INBOX_FAILED_SUFFIX))continue;const r=f(o,`${s.slice(0,-INBOX_FAILED_SUFFIX.length)}${INBOX_CLAIM_SUFFIX}`);if(!v(r))try{g(f(o,s),r),i++}catch{}}return i}export function handleIngestedRecords(n,o){for(const e of o){const i=n.projects.getById(e.projectId);if(!i)continue;n.dashboardRate?.record();let s=null;try{s=JSON.parse(e.input.payload)}catch{s=null}if(n.bus?.emit({kind:"event.ingested",eventId:e.eventId,projectId:i.id,sessionId:e.input.sessionId??null,eventType:e.input.eventType,...P(s),at:e.input.createdAt??new Date().toISOString()}),e.input.sessionId){n.questionTracker?.onEvent({sessionId:e.input.sessionId,source:e.input.source,payload:s}),n.sideQuestions?.onEvent({sessionId:e.input.sessionId,source:e.input.source,eventType:e.input.eventType,payload:s,eventId:e.eventId}),n.watchEngine?.onEvent({sessionId:e.input.sessionId,eventType:e.input.eventType,source:e.input.source}),n.orchestrationEngine?.onEvent({sessionId:e.input.sessionId,eventType:e.input.eventType,source:e.input.source}),e.messaging&&n.messagePipe?.noteInboxSocket?.(e.input.sessionId,e.messaging),n.sessionProbe?.noteTranscript(e.input.sessionId,s?.transcriptPath??null);const r=L(e.input.eventType,s?.raw);r&&n.sessionProbe?.noteModel?.(e.input.sessionId,r.to);const c=A(e.input.eventType,s?.raw);c&&n.sessionProbe?.sessionStarted?.(e.input.sessionId,c.model);const p=O(s?.raw);p&&n.sessionProbe?.noteEffort?.(e.input.sessionId,p);const u=D(s?.raw);if(u&&n.sessionProbe?.noteMode?.(e.input.sessionId,u),e.terminalEnv||m(e.input.source)){const t=e.input.source;m(t)&&n.paneEnvSource?.(t)==="launch"?n.messagePipe?.claimPendingOrigin?.(e.input.sessionId,t,e.projectId):e.terminalEnv&&n.messagePipe?.notePaneEnv?.(e.input.sessionId,e.terminalEnv)}if(e.input.eventType==="UserPromptSubmit"){const t=n.messagePipe?.onSessionPrompt?.(e.input.sessionId,J(s)??"",e.eventId)??[];t.length>0&&n.uploads?.linkToEvent(e.eventId,t)}else n.messagePipe?.noteActivity?.(e.input.sessionId);const a=m(e.input.source)?W[e.input.source].sessionExit:null;a!==null&&e.input.eventType===a&&(n.messagePipe?.sessionExited?.(e.input.sessionId),n.terminalTopologyKick?.()),n.messagePipe?.hasQueued(e.input.sessionId)&&n.messagePipe.flushSession(e.input.sessionId)}n.dispatcher&&n.dispatcher.onIngest({eventId:e.eventId,project:i,sessionId:e.input.sessionId??null,payload:s??{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(n.hooksDir,i.token,[{sessionId:e.input.sessionId,text:r.deferred}])}).catch(()=>{})}}function J(n){const o=n?.raw;return typeof o?.prompt=="string"&&o.prompt?o.prompt:null}export function startInboxWorker(n){return new x(new URL(import.meta.url),{workerData:{inboxWorker:!0,...n}})}if(!E&&k?.inboxWorker===!0){const n=k,o=F(n.dbPath),e=M(),i=new N(o),s={hooksDir:n.hooksDir,projects:i,hookEvents:new R(o),hookSessions:new B(o),adapters:e.byCapability("events").flatMap(t=>t.events??[])};h?.on("message",t=>{t?.type==="synthetic-sessions"&&Array.isArray(t.ids)&&U(t.ids)});const r=new Map,c=()=>{try{const t=drainInboxOnce(s,r);t.length>0&&h?.postMessage(t)}catch(t){console.error("[weave] inbox drain failed:",t)}};c(),setInterval(c,n.tickMs??INBOX_TICK_MS);const p={projects:i,hookEvents:s.hookEvents,hookSessions:s.hookSessions,adapters:s.adapters,logsDir:_(),sources:e.byCapability("logs").flatMap(t=>t.logs??[])};let u=!1;const a=()=>{u||(u=!0,pollLogsOnce(p).then(t=>{t.length>0&&h?.postMessage(t)}).catch(t=>console.error("[weave] log poll failed:",t)).finally(()=>{u=!1}))};p.sources.length>0&&(a(),setInterval(a,LOGS_TICK_MS))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import f from"node:path";export const DISPATCH_MARKER="<!--weave-dispatch-->";const s=e=>process.platform==="win32"?e.toLowerCase():e;export function normalizePosix(e){return e.replace(/\\/g,"/")}function a(e){return/[.+^${}()|[\]\\]/.test(e)?`\\${e}`:e}const l=new Map;export function globToRegex(e){const r=l.get(e);if(r)return r;let t="";for(let n=0;n<e.length;n++){const c=e[n];c==="*"?e[n+1]==="*"?(n++,e[n+1]==="/"?(n++,t+="(?:.*/)?"):t+=".*"):t+="[^/]*":c==="?"?t+="[^/]":t+=a(c)}const o=new RegExp(`^${t}$`,"i");return l.set(e,o),o}export function matchGlob(e,r){return globToRegex(r).test(normalizePosix(e))}export function extractFilePath(e){if(typeof e!="object"||e===null)return null;const r=e;for(const t of["file_path","notebook_path","filePath"]){const o=r[t];if(typeof o=="string"&&o.length>0)return o}return null}function i(e,r){const t=s(normalizePosix(e)),o=s(normalizePosix(r).replace(/\/+$/,""));return t===o||t.startsWith(`${o}/`)}export function isCrossProjectPath(e,r,t){const o=s(normalizePosix(r));return i(e,r)?!1:t.some(n=>s(normalizePosix(n))!==o&&i(e,n))}export function renderTemplate(e,r){return e.replace(/\{(\w+)\}/g,(t,o)=>{const n=r[o];return n==null?t:String(n)})}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,r){return r.some(t=>matchGlob(e,t))}export function projectLabel(e){return f.basename(normalizePosix(e).replace(/\/+$/,""))||e}
|
|
@@ -112,6 +112,11 @@ export interface PromptTerminal {
|
|
|
112
112
|
sendText(paneId: string, text: string): Promise<void>;
|
|
113
113
|
/** 裸键序注入(作答的选项键 / 中断的 ESC:模态框只吃键盘,不吃粘贴文本)。 */
|
|
114
114
|
sendKeys(paneId: string, keys: string): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* 读 pane 可视屏文本(旁路会话读屏通道用);可缺省(无读屏能力的装配 = 恒
|
|
117
|
+
* null,侧问入口对读屏 harness 置灰)。
|
|
118
|
+
*/
|
|
119
|
+
getPaneText?(paneId: string): Promise<string | null>;
|
|
115
120
|
/** 关掉这个 pane(会话生命周期收尾);无通道的后端明确拒绝。 */
|
|
116
121
|
closePane(paneId: string): Promise<void>;
|
|
117
122
|
}
|
|
@@ -158,9 +163,14 @@ export interface MessageDelivererDeps {
|
|
|
158
163
|
* 模态框在场时层② 的文本与回车会被它吃掉:投出去只换来一条「已发出却没回执」
|
|
159
164
|
* 的假送达,回车还可能替用户按下某个选项。缺省 = 不判(测试与无 tracker 装配)。 */
|
|
160
165
|
blockedByQuestion?: (sessionId: string) => boolean;
|
|
161
|
-
/**
|
|
162
|
-
*
|
|
166
|
+
/** 会话存活图(测试注入);缺省合并图(claude 注册表 + codex 锁探针缓存)——
|
|
167
|
+
* 同两个引擎(watch/sequence)的取法:判不动的会话一律「查不到」,不猜。 */
|
|
163
168
|
livenessOf?: () => Map<string, boolean>;
|
|
169
|
+
/** 读屏通道的回答落库(codex 侧问):按 (sessionId, question) 找到待答行直更。
|
|
170
|
+
* 缺省 = 无落库(读屏取到的回答只发帧不存档)。 */
|
|
171
|
+
sideAnswerStore?: {
|
|
172
|
+
answerById(sessionId: string, question: string, answer: string): void;
|
|
173
|
+
};
|
|
164
174
|
}
|
|
165
175
|
/** send() 入参(路由层已做 zod 形状校验)。 */
|
|
166
176
|
export interface SendInput {
|
|
@@ -240,6 +250,8 @@ export declare class MessageDeliverer {
|
|
|
240
250
|
private readonly deps;
|
|
241
251
|
private readonly headless;
|
|
242
252
|
private readonly hooksDir;
|
|
253
|
+
/** 读屏通道的回答落库(codex = /side;缺省无——回答只发帧不存档)。 */
|
|
254
|
+
private readonly sideAnswerStore?;
|
|
243
255
|
/** 内存态注册表(pending 之后的生命周期)。 */
|
|
244
256
|
private readonly memory;
|
|
245
257
|
/** 有队列行的会话(ingest 冲洗守卫 + 刷新器探活索引;构造时从磁盘重建)。 */
|
|
@@ -253,8 +265,22 @@ export declare class MessageDeliverer {
|
|
|
253
265
|
* 长时间没动静的会话根本等不到,于是从终端分组里掉出去。
|
|
254
266
|
*/
|
|
255
267
|
private readonly paneEnvs;
|
|
268
|
+
/**
|
|
269
|
+
* 定位已撤销的会话(会话退出):pane env 已删、这轮扫描也探不到它,而拓扑
|
|
270
|
+
* 合并契约是「缺席 = 保留上次分块」——不显式报 null,旧分块会永远留在快照里。
|
|
271
|
+
* sessionTerminals() 报完即焚;会话再发事件(resume)会重新 notePaneEnv。
|
|
272
|
+
*/
|
|
273
|
+
private readonly revokedPaneEnvs;
|
|
256
274
|
/** 上次落盘的 pane env(hook 每次事件都上报,值没变就不重写盘)。 */
|
|
257
275
|
private persistedPaneEnvs;
|
|
276
|
+
/**
|
|
277
|
+
* 起点候选(weave 起会话的 spawn 回执)。paneEnvSource='launch' 的 harness
|
|
278
|
+
* (codex)hook env 系统性失真,pane 定位改信这里——sessionId 事后才知道
|
|
279
|
+
* (宿主自己生成),先按 (harness, projectId) 排队,ingest 侧认领(FIFO)。
|
|
280
|
+
* 落盘同 pane-envs:只解 daemon 自己的重启。
|
|
281
|
+
*/
|
|
282
|
+
private pendingOrigins;
|
|
283
|
+
private persistedPendingOrigins;
|
|
258
284
|
/** 已排自续冲洗的会话(防重复排拍)。 */
|
|
259
285
|
private readonly flushScheduled;
|
|
260
286
|
/**
|
|
@@ -345,8 +371,24 @@ export declare class MessageDeliverer {
|
|
|
345
371
|
* resume 到新窗口后,下一次事件就把定位改过来,与 inbox 凭据同一自愈口径)。
|
|
346
372
|
*/
|
|
347
373
|
notePaneEnv(sessionId: string, env: Record<string, string>): void;
|
|
374
|
+
/**
|
|
375
|
+
* 记一条起点候选(weave 起会话的 spawn 回执)。只为 paneEnvSource='launch'
|
|
376
|
+
* 的 harness 而来(调用侧闸):'hook' 的 harness env 精确,起点只会引入过期源。
|
|
377
|
+
*/
|
|
378
|
+
notePendingOrigin(origin: {
|
|
379
|
+
harness: Harness;
|
|
380
|
+
projectId: number;
|
|
381
|
+
env: Record<string, string>;
|
|
382
|
+
}): void;
|
|
383
|
+
/**
|
|
384
|
+
* 认领起点候选:首个 (harness, projectId) 匹配的 FIFO 条目即该会话的 pane 定位
|
|
385
|
+
* (notePaneEnv 全语义——分组、层② 定位同一份数据)。没有匹配 no-op:手动开的
|
|
386
|
+
* 会话没有起点,不分组(与现状持平,不猜)。
|
|
387
|
+
*/
|
|
388
|
+
claimPendingOrigin(sessionId: string, harness: Harness, projectId: number): void;
|
|
348
389
|
/** 原子写(临时文件 + rename)+ 0600;失败静默(内存态照常能定位,下次再落)。 */
|
|
349
390
|
private persistPaneEnvs;
|
|
391
|
+
private persistPendingOrigins;
|
|
350
392
|
/**
|
|
351
393
|
* 会话退出(`SessionEnd` 到达):旁路事实随进程作废——inbox 凭据出盘(旧 socket
|
|
352
394
|
* 已死,留着只会让下一次投递白试一轮)、pane 定位清(窗口随会话关)。**会话行与
|
|
@@ -382,6 +424,13 @@ export declare class MessageDeliverer {
|
|
|
382
424
|
* 对应气泡上(见 `PipeMessage.ackedEventId`)。
|
|
383
425
|
*/
|
|
384
426
|
onSessionPrompt(sessionId: string, prompt: string, eventId?: number): string[];
|
|
427
|
+
/**
|
|
428
|
+
* 活动旁证:该会话来了任何 hook 事件 = 宿主活着且在干活。内建命令(`/compact`
|
|
429
|
+
* 之类)没有 UPS 回执,命令行「已发出」的翻牌就靠它——宿主受理命令后的第一笔
|
|
430
|
+
* 事件(PreCompact…)及时把行翻成已回执(5s 短窗口只是兜底)。普通文本行有
|
|
431
|
+
* UPS 正路,不掺和。
|
|
432
|
+
*/
|
|
433
|
+
noteActivity(sessionId: string): void;
|
|
385
434
|
/** 未回执闸布防(判定与计时在 delivery/ack-gate.ts)。 */
|
|
386
435
|
private armAckWatch;
|
|
387
436
|
/** 斜杠命令的回执收尾(短窗口;内建命令不发 UPS)。 */
|
|
@@ -450,10 +499,11 @@ export declare class MessageDeliverer {
|
|
|
450
499
|
*/
|
|
451
500
|
setEffort(sessionId: string, level: string): Promise<AnswerResult>;
|
|
452
501
|
/**
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
502
|
+
* 旁路会话:问句经层② 终端打进会话 pane。两条通道按能力面分流——
|
|
503
|
+
* - **事件认领**(claude = `/btw`):宿主的侧问只活在 TUI 里,也不落任何文件,
|
|
504
|
+
* 终端击键是唯一通道;回答是之后的一条采集事件(认领见 `hooks/side-questions.ts`)。
|
|
505
|
+
* - **读屏**(codex = `/side`):宿主侧边会话 ephemeral(零落盘、零 hook 事件),
|
|
506
|
+
* 开面板 → 发问句 → 轮询读屏 → 关面板,回答同步取回(`pollScreenAnswer`)。
|
|
457
507
|
*
|
|
458
508
|
* 返回归一化后的问句(已过 harness 的形态校验):调用方据此落历史行。
|
|
459
509
|
*/
|
|
@@ -465,6 +515,14 @@ export declare class MessageDeliverer {
|
|
|
465
515
|
status: 400 | 404 | 409;
|
|
466
516
|
error: string;
|
|
467
517
|
}>;
|
|
518
|
+
/**
|
|
519
|
+
* 读屏通道的执行体(fire-and-forget:POST 先回、行先落 pending,回答到了经
|
|
520
|
+
* `sideQuestion.answered` 帧推给前端)。时序全部实测钉死(2026-10-27):
|
|
521
|
+
* 开面板的 CR 常被吃 → 发完验屏、没开成补一发再验;**收尾前必须确认面板还
|
|
522
|
+
* 开着**——用户中途关掉后,closeKey 落主线程语境(忙 = 中断确认菜单、闲 =
|
|
523
|
+
* 退出 TUI),盲打比不收尾糟得多,面板不在就什么都不发。
|
|
524
|
+
*/
|
|
525
|
+
private pollScreenAnswer;
|
|
468
526
|
private sessionKeysTarget;
|
|
469
527
|
/** bus 可选 → 必选形状(delivery 模块的入参)。 */
|
|
470
528
|
private busSafe;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),x(t,e),T(e,384),this.persistedPaneEnvs=s}catch{}}sessionExited(s){this.inboxSockets.forget(s),this.paneEnvs.delete(s),this.persistPaneEnvs(),this.awaitingAck.delete(s);const e=this.deps.sessions.getBySessionId(s),t=e?.projectId==null?null:this.deps.projects.getById(e.projectId);if(!t)return;const i=p(this.hooksDir,t.token).filter(n=>n.sessionId===s);this.failQueuedOffline(s,i.filter(n=>!this.dismissedIds.has(n.id)))}async sessionTerminals(){return cs(this.deps,this.terminalChannel(),this.paneEnvs,()=>this.persistPaneEnvs())}diagnose(s){const e=this.surfaceOfSession(s),t=this.deps.sessions.livenessRowOf(s),i=t?B(t,this.deps.livenessOf?.()??I()):null,n=e?.promptInbox??null,r=this.inboxSockets.get(s),u=n?r?n.requiresAuthOn(process.platform)&&!r.token?{status:"unavailable",reason:"auth-token-required"}:{status:"ready",reason:null}:{status:"unavailable",reason:"no-credentials"}:{status:"unavailable",reason:"no-mechanism"},a=e?.queuedPrompt?{status:"ready",reason:null}:{status:"unavailable",reason:"no-mechanism"},o=e?.prompt?.resolve(s)??null,l=e?.prompt?o?{status:"ready",reason:null}:{status:"unavailable",reason:"no-peer-name"}:{status:"unavailable",reason:"no-mechanism"},h=this.paneEnvs.has(s),d=this.terminalChannel()?h?{status:"ready",reason:null}:{status:"unknown",reason:"no-pane-env"}:{status:"unavailable",reason:"no-backend"},m=this.deps.sessions.getBySessionId(s),y=m?.projectId==null?null:this.deps.projects.getById(m.projectId),b=y?p(this.hooksDir,y.token).filter(E=>E.sessionId===s).length:0;return{alive:i,inbox:u,queue:a,relay:l,terminal:d,paneEnvReported:h,pending:b,stalled:this.gate.isStalled(s)}}onSessionPrompt(s,e,t){const i=this.gate.acknowledge(s,e,t,{ackMinText:vs});return this.gate.hitLast&&this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s),i}armAckWatch(s){this.gate.armAckWatch(s)}armCommandAck(s){this.gate.armCommandAck(s,e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)})}stall(s,e,t){this.gate.stall(s,e,t)}async answer(s,e){if(e.length===0||!S.test(e[0])||e.some(i=>!S.test(i)&&!G.test(i)))return{ok:!1,status:400,error:"Invalid answer keys"};const t=await this.sessionKeysTarget(s);if(!t.ok)return t;try{for(const[i,n]of e.entries())i>0&&await Ts(N),await t.terminal.sendKeys(t.paneId,n);return{ok:!0}}catch(i){return{ok:!1,status:409,error:i instanceof Error?i.message:String(i)}}}async interrupt(s,e="both",t){const i=await this.sessionKeysTarget(s,"\u51FB\u952E",e);if(!i.ok)return i;if(t!=null&&i.paneId===t)return{ok:!0,paneId:i.paneId,sent:!1};try{return await i.terminal.sendKeys(i.paneId,H),{ok:!0,paneId:i.paneId,sent:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async closePane(s){const e=await this.sessionKeysTarget(s,"\u5173\u95ED");if(!e.ok)return e;try{return await e.terminal.closePane(e.paneId),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async cycleMode(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,z),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressEnter(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,L),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async pressCtrlC(s){const e=await this.sessionKeysTarget(s);if(!e.ok)return e;try{return await e.terminal.sendKeys(e.paneId,J),{ok:!0}}catch(t){return{ok:!1,status:409,error:t instanceof Error?t.message:String(t)}}}async setModel(s,e){const t=e.trim();if(!$.test(t))return{ok:!1,status:400,error:"\u6A21\u578B\u540D\u5F62\u6001\u4E0D\u5408\u6CD5\uFF08\u4E0D\u542B\u7A7A\u767D\u4E0E\u63A7\u5236\u5B57\u7B26\uFF0C\u2264128 \u5B57\u7B26\uFF09"};const i=await this.sessionKeysTarget(s);if(!i.ok)return i;try{return await i.terminal.sendText(i.paneId,Z(t)),{ok:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async setEffort(s,e){const t=e.trim(),i=await this.sessionKeysTarget(s);if(!i.ok)return i;const n=U(this.deps.hookEvents,s);if(!n.includes(t))return{ok:!1,status:400,error:`\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\u4E0D\u5408\u6CD5\uFF08\u53EF\u9009\uFF1A${n.join(" / ")||"\u65E0"}\uFF09`};try{return await i.terminal.sendText(i.paneId,V(t)),{ok:!0}}catch(r){return{ok:!1,status:409,error:r instanceof Error?r.message:String(r)}}}async askSideQuestion(s,e){if(!this.deps.sessions.getBySessionId(s))return{ok:!1,status:404,error:"Session not found"};const t=this.surfaceOfSession(s),i=t?.sideQuestion??null;if(!i)return{ok:!1,status:409,error:t?.unsupportedReasons?.sideQuestion??"\u8FD9\u4E2A harness \u6CA1\u6709\u65C1\u8DEF\u4F1A\u8BDD\u901A\u9053"};const n=i.validate(e);if(!n.ok)return{ok:!1,status:400,error:n.error};const r=await this.sessionKeysTarget(s,"\u53D1\u8D77\u65C1\u8DEF\u4F1A\u8BDD");if(!r.ok)return r;try{return await r.terminal.sendText(r.paneId,i.command(n.text)),{ok:!0,question:n.text}}catch(u){return{ok:!1,status:409,error:u instanceof Error?u.message:String(u)}}}async sessionKeysTarget(s,e="\u51FB\u952E",t="both"){return Y(this.keysDeps(),s,e,t)}busSafe(){return{emit:s=>this.bus(s)}}channelDeps(){return{setMemory:s=>this.memory.set(s.id,s),deleteMemory:s=>this.memory.delete(s),awaitAck:(s,e)=>this.gate.await(s,e),isSlashCommand,armAckWatch:s=>this.gate.armAckWatch(s),armCommandAck:s=>this.gate.armCommandAck(s,e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)}),emit:s=>this.bus(s),...this.deps.spawnImpl?{spawnImpl:this.deps.spawnImpl}:{}}}wireTextOfEntry(s){return ts(s,e=>this.surfaceOfSession(e))}hasImagesEntry(s){return ss(s)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(s,e,t)=>this.terminalPaneFor(s,e,t)}}async resend(s){const e=this.memory.get(s);if(!e)return{ok:!1,status:404,error:"Message not found"};if(!(e.channel==="prompt"&&(e.status==="failed"||e.status==="delivered"&&!e.acked)))return{ok:!1,status:409,error:"Message is not resendable"};const t=this.deps.sessions.getBySessionId(e.sessionId);if(!t)return{ok:!1,status:404,error:"Session not found"};if(t.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const i=this.deps.projects.getById(t.projectId);if(!i)return{ok:!1,status:404,error:"Project not found"};const n=this.surfaceOfSession(e.sessionId);if(!n)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};if(this.gate.clearStall(e.sessionId,s),e.status==="delivered"&&e.via==="terminal"&&this.terminalChannel()){const a=await this.terminalPaneFor(t,i);if(a)return this.memory.set(s,{...e,status:"delivering",stalled:!1,settledAt:null}),this.runTerminalSubmit(s,a.id),this.bus({kind:"message.created",messageId:s,sessionId:e.sessionId,mode:e.mode,at:new Date().toISOString()}),{ok:!0,messageId:s,status:"delivering",message:this.memory.get(s)}}this.memory.delete(s);const r={...e,status:"pending",stalled:!1,acked:!1,settledAt:null,reason:void 0,error:null},u=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()}),u}dismiss(s,e){const t=this.memory.get(e);if(t){if(t.status==="running")return{ok:!1,status:409,error:"Message is still in flight"};t.status==="delivering"&&this.gate.headOf(t.sessionId)===e&&this.flushing.delete(t.sessionId),this.memory.delete(e),this.gate.clearStall(t.sessionId,e),this.gate.release(t.sessionId,e),this.queuedSessions.has(t.sessionId)&&this.scheduleFlushContinuation(t.sessionId)}else if(!this.dropQueued(s,e))return{ok:!1,status:404,error:"Message not found"};return this.bus({kind:"message.dismissed",messageId:e,sessionId:s,at:new Date().toISOString()}),{ok:!0}}dropQueued(s,e){const t=this.deps.sessions.getBySessionId(s);if(t?.projectId==null)return!1;const i=this.deps.projects.getById(t.projectId);if(!i)return!1;const n=p(this.hooksDir,i.token);if(!n.some(r=>r.id===e&&r.sessionId===s))return!1;for(f(this.hooksDir,i.token,new Set([e])),this.dismissedIds.add(e);this.dismissedIds.size>Es;){const r=this.dismissedIds.values().next().value;if(r===void 0)break;this.dismissedIds.delete(r)}return n.some(r=>r.sessionId===s&&r.id!==e)||this.queuedSessions.delete(s),!0}async flushSession(s){if(this.stalled.has(s)||this.flushing.has(s)||!this.queuedSessions.has(s))return;const e=Symbol(s);this.flushing.set(s,e);try{await this.flushSessionInner(s)}catch{}finally{this.flushing.get(s)===e&&this.flushing.delete(s)}}async flushSessionInner(s){if(!this.ackGateOpen(s))return;const e=this.deps.sessions.getBySessionId(s);if(e?.projectId==null)return;const t=this.deps.projects.getById(e.projectId);if(!t)return;const i=p(this.hooksDir,t.token).filter(a=>a.sessionId===s);if(i.length===0){this.queuedSessions.delete(s);return}if(this.sessionJudgedDead(s)){this.failQueuedOffline(s,i.filter(a=>!this.dismissedIds.has(a.id)));return}const n=this.surfaceOfSession(s),r=n?.prompt??null,u=this.modalBlocked(s);for(const a of i){if(this.stalled.has(s))return;if(this.dismissedIds.has(a.id))continue;const o={id:a.id,sessionId:s,text:a.text,...a.attachments&&a.attachments.length>0?{attachments:a.attachments}:{},mode:"prompt",oneWay:a.oneWay===!0,...a.forceTerminal===!0?{forceTerminal:!0}:{},via:"socket",channel:"prompt",status:"pending",at:a.at};if(!u&&this.hasImagesEntry(o)&&this.terminalChannel()){const d=await this.terminalPaneFor(e,t);if(d){f(this.hooksDir,t.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(s,o.id),await this.runTerminalPrompt(o.id,d.id,this.wireTextOfEntry(o)),this.settleQueueIndex(s,t.token);return}}if(n&&await this.tryQueuedDeliver(o,n)){f(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(s,t.token);return}if(n&&await this.tryInboxDeliver(o,n)){f(this.hooksDir,t.token,new Set([a.id])),this.settleQueueIndex(s,t.token);return}const l=r?.resolve(s)??null,h=o.forceTerminal===!0?["terminal"]:o.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const d of h){if(d==="relay"&&r&&l){if(this.memory.set(o.id,{...o,status:"delivering",via:"relay"}),!this.runRelay(o,r,l.name)){this.memory.delete(o.id);return}this.awaitingAck.set(s,o.id),f(this.hooksDir,t.token,new Set([a.id]));break}if(d==="terminal"&&!u&&this.terminalChannel()){const m=await this.terminalPaneFor(e,t);if(m){f(this.hooksDir,t.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(s,o.id),await this.runTerminalPrompt(o.id,m.id,this.wireTextOfEntry(o));break}}}if(this.awaitingAck.get(s)===o.id){this.settleQueueIndex(s,t.token);return}return}this.settleQueueIndex(s,t.token)}settleQueueIndex(s,e){p(this.hooksDir,e).every(t=>t.sessionId!==s)&&this.queuedSessions.delete(s)}async flushAll(){for(const s of[...this.queuedSessions])await this.flushSession(s)}forgetSession(s){let e=0;for(const[t,i]of this.memory)i.sessionId===s&&(this.memory.delete(t),e++);return e+=fs(this.hooksDir,s),this.queuedSessions.delete(s),this.gate.clearStall(s),this.gate.release(s),this.inboxSockets.forget(s),this.paneEnvs.delete(s),this.persistPaneEnvs(),e}forgetProject(s){let e=0;for(const[t,i]of this.memory)this.deps.sessions.getBySessionId(i.sessionId)?.projectId===s&&(this.memory.delete(t),this.inboxSockets.forget(i.sessionId),this.paneEnvs.delete(i.sessionId),this.gate.clearStall(i.sessionId),this.gate.release(i.sessionId),e++);for(const t of[...this.queuedSessions])this.deps.sessions.getBySessionId(t)?.projectId===s&&(e+=this.forgetSession(t));return this.persistPaneEnvs(),e}surfaceOfSession(s){const e=this.deps.hookEvents.listBySession(s,1),t=e[e.length-1]?.source;return P(t)?this.deps.surfaceFor?.(t)??M(t):null}resolveChannel(s,e,t){return rs(this.deps.sessions,()=>this.terminalChannel()!=null,s,e,t)}async terminalPaneFor(s,e,t="both"){return X(this.terminalChannel(),this.paneEnvs,s,e,t)}terminalChannel(){const s=this.deps.terminal;return s&&s.available()?s:null}modalBlocked(s){return this.deps.blockedByQuestion?.(s)===!0}async deliverPrompt(s,e,t,i){if(this.sessionJudgedDead(s.sessionId))return{ok:!0,messageId:s.id,status:"failed",message:this.failOffline(s)};const n=this.modalBlocked(s.sessionId);if(!n&&this.hasImagesEntry(s)&&this.terminalChannel()){const d=await this.terminalPaneFor(e,t);if(d)return this.memory.set(s.id,{...s,status:"delivering",via:"terminal"}),this.awaitingAck.set(s.sessionId,s.id),this.runTerminalPrompt(s.id,d.id,this.wireTextOfEntry(s)),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)}}const r=await this.tryQueuedDeliver(s,i);if(r)return{ok:!0,messageId:s.id,status:"delivered",message:r};const u=await this.tryInboxDeliver(s,i);if(u)return{ok:!0,messageId:s.id,status:"delivered",message:u};const a=i.prompt,o=a?.resolve(s.sessionId)??null,l=s.forceTerminal===!0?["terminal"]:s.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const d of l){if(d==="relay"&&a&&o){if(this.memory.set(s.id,{...s,status:"delivering",via:"relay"}),this.runRelay(s,a,o.name))return this.awaitingAck.set(s.sessionId,s.id),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)};this.memory.delete(s.id)}if(d==="terminal"&&!n&&this.terminalChannel()){const m=await this.terminalPaneFor(e,t);if(m)return this.memory.set(s.id,{...s,status:"delivering",via:"terminal"}),this.awaitingAck.set(s.sessionId,s.id),this.runTerminalPrompt(s.id,m.id,this.wireTextOfEntry(s)),{ok:!0,messageId:s.id,status:"delivering",message:this.memory.get(s.id)}}}if(this.sessionJudgedDead(s.sessionId))return{ok:!0,messageId:s.id,status:"failed",message:this.failOffline(s)};this.queueEntry(s,t.token);const h={...s,status:"pending"};return{ok:!0,messageId:s.id,status:"pending",message:h}}async tryQueuedDeliver(s,e){const t=e.queuedPrompt;if(!t||this.hasImagesEntry(s))return null;const{bin:i,args:n}=t.command(s.sessionId,this.wireTextOfEntry(s));this.memory.set(s.id,{...s,status:"delivering",via:"queue"});try{await es(i,n,t.timeoutMs??3e4,this.deps.spawnImpl)}catch{return this.memory.delete(s.id),null}return v(this.channelDeps(),{...s,via:"queue"},"queue")}async tryInboxDeliver(s,e){const t=e.promptInbox,i=this.inboxSockets.get(s.sessionId);if(!t||!i||s.forceTerminal===!0)return null;this.memory.set(s.id,{...s,status:"delivering",via:"socket"});try{await W(t,i,this.wireTextOfEntry(s))}catch{return this.memory.delete(s.id),null}return v(this.channelDeps(),s,"socket")}queueEntry(s,e){as(this.hooksDir,e,s),this.queuedSessions.add(s.sessionId)}sessionJudgedDead(s,e=this.deps.livenessOf?.()??I()){return ds(this.deps.sessions,s,e)}failOffline(s){return os(this.memory,e=>this.bus(e),s)}failQueuedOffline(s,e){us(this.deps,this.hooksDir,this.memory,t=>this.bus(t),s,e),this.queuedSessions.delete(s)}relayDeps(){return{headless:this.headless,getMemory:s=>this.memory.get(s)??null,setMemory:s=>this.memory.set(s.id,s),awaitAck:(s,e)=>this.gate.await(s,e),stall:(s,e,t)=>this.gate.stall(s,e,t),isSlashCommand,armAckWatch:s=>this.gate.armAckWatch(s),armCommandAck:(s,e)=>this.gate.armCommandAck(s,t=>{e(t),this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)}),onReleased:s=>{this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)},emit:s=>this.bus(s),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.relayTimeoutMs===void 0?{}:{relayTimeoutMs:this.deps.relayTimeoutMs}}}runRelay(s,e,t){return hs(this.relayDeps(),s,e,t,this.wireTextOfEntry(s))}async runTerminalPrompt(s,e,t){await this.runTerminal(s,i=>i.sendText(e,t))}async runTerminalSubmit(s,e){await this.runTerminal(s,t=>t.sendKeys(e,"\r"))}async runTerminal(s,e){const t=this.memory.get(s);if(!t)return;const i=this.terminalChannel();if(i)try{await e(i);const n=this.memory.get(s);if(!n)return;const r={...n,status:"delivered",settledAt:new Date().toISOString()};this.memory.set(s,r),isSlashCommand(n.text)?this.armCommandAck(s):this.armAckWatch(r),this.bus({kind:"message.delivered",messageId:s,sessionId:t.sessionId,at:new Date().toISOString()})}catch(n){const r=this.memory.get(s);if(!r)return;if(r.acked===!0){const a=new Date().toISOString();this.memory.set(s,{...r,status:"delivered",settledAt:a}),this.bus({kind:"message.delivered",messageId:s,sessionId:r.sessionId,at:a});return}const u={...r,status:"failed",error:n instanceof Error?n.message:String(n),settledAt:new Date().toISOString()};this.memory.set(s,u),this.stall(t.sessionId,u,"failed"),this.bus({kind:"message.finished",messageId:s,sessionId:t.sessionId,status:"failed",at:new Date().toISOString()})}}deliverInject(s,e,t,i){return ns({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},s,e,t,i,this.wireTextOfEntry(s))}deliverHeadless(s,e,t,i){return is({memory:this.memory,headless:this.headless,bus:this.busSafe(),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.timeoutMs===void 0?{}:{timeoutMs:this.deps.timeoutMs}},s,e,t,i,this.wireTextOfEntry(s))}bus(s){try{this.deps.bus?.emit(s)}catch{}}}
|
|
1
|
+
import{randomUUID as R}from"node:crypto";import{chmodSync as y,mkdirSync as w,readFileSync as v,renameSync as O,writeFileSync as b}from"node:fs";import{dirname as I,join as g}from"node:path";import{isHarness as E}from"@weavecode/core";import{turnOutputOf as B}from"@weavecode/harness";import{isImageMediaType as T}from"../repositories/uploads.js";import{messagingSurfaceFor as L}from"../surfaces.js";import{pidAliveOf as F}from"../daemon/claude-liveness.js";import{combinedLivenessOf as A}from"../daemon/liveness.js";import{HeadlessRunner as N}from"./headless-runner.js";import{hooksRoot as Q}from"./mirror.js";import{INBOX_TARGETS_FILE as G,InboxSocketRegistry as W,deliverViaInboxSocket as J}from"./inbox-socket.js";import{AckGate as H}from"./delivery/ack-gate.js";import{ANSWER_ATOM as D,ANSWER_ATOM_GAP_MS as U,ANSWER_TEXT as V,CTRL_C as $,ENTER as X,ESC as z,MODEL_NAME as Z,SHIFT_TAB as Y,effortCommand as ee,effortLevelsOf as te,locateTerminalPane as se,modelCommand as ie,sessionKeysTarget as ne}from"./delivery/keys.js";import{hasImages as re,settleDelivered as P,spawnOnce as ae,wireTextOf as oe}from"./delivery/channels.js";import{deliverHeadless as le,deliverInject as ue,resolveChannel as he}from"./delivery/send.js";import{appendQueueEntry as de,failOffline as ce,failQueuedOffline as me,sessionJudgedDead as fe}from"./delivery/queue.js";import{runRelay as pe}from"./delivery/relay.js";import{listInflightCounts as ge,listVisible as ke,sessionTerminals as Se}from"./delivery/views.js";import{readPromptbox as k,removePromptboxBySession as ye,removePromptboxEntries as f,scanQueuedSessionIds as we}from"./promptbox.js";const ve=1e3,Oe=6e4,be=3e4,Ie=9e4,Ee=5e3,Te=8,Ae=250,De=5,Pe=200;export function isSlashCommand(m){return/^\/[A-Za-z][A-Za-z0-9:_-]*(\s|$)/.test(m.trim())}const x="pane-envs.json",_="pending-origins.json",M=15*6e4;function xe(m){try{const e=JSON.parse(v(m,"utf8"));if(!Array.isArray(e))return[];const t=[];for(const s of e){if(typeof s!="object"||s===null)continue;const i=s;if(!E(i.harness)||typeof i.projectId!="number"||typeof i.env!="object"||i.env===null||typeof i.at!="string")continue;const n={};for(const[r,l]of Object.entries(i.env))typeof l=="string"&&l&&(n[r]=l);Object.keys(n).length!==0&&t.push({harness:i.harness,projectId:i.projectId,env:n,at:i.at})}return t.filter(s=>Date.now()-Date.parse(s.at)<M)}catch{return[]}}function _e(m){try{const e=JSON.parse(v(m,"utf8"));if(typeof e!="object"||e===null)return{};const t={};for(const[s,i]of Object.entries(e)){if(typeof i!="object"||i===null)continue;const n={};for(const[r,l]of Object.entries(i))typeof l=="string"&&l&&(n[r]=l);Object.keys(n).length>0&&(t[s]=n)}return t}catch{return{}}}const p=m=>new Promise(e=>setTimeout(e,m)),j=300,C=1500,Me=1e3,je=12e4;export class MessageDeliverer{deps;headless;hooksDir;sideAnswerStore;memory=new Map;queuedSessions;inboxSockets;paneEnvs;revokedPaneEnvs=new Set;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 N({spawnImpl:e.spawnImpl,killImpl:e.killImpl}),this.hooksDir=e.hooksDir??Q(),this.sideAnswerStore=e.sideAnswerStore,this.inboxSockets=new W(g(this.hooksDir,G));const t=_e(g(this.hooksDir,x));this.paneEnvs=new Map(Object.entries(t)),this.persistedPaneEnvs=JSON.stringify(t),this.pendingOrigins=xe(g(this.hooksDir,_)),this.persistedPendingOrigins=JSON.stringify(this.pendingOrigins),this.queuedSessions=we(this.hooksDir),this.gate=new H({awaitingAck:this.awaitingAck,stalled:this.stalled,memory:this.memory},{ackStallMs:e.ackStallMs??be,ackStallReleaseMs:e.ackStallReleaseMs??Ie,commandAckGraceMs:e.commandAckGraceMs??Ee},{emit:s=>this.bus(s)}),this.gate.onAutoRelease=s=>this.scheduleFlushContinuation(s)}async send(e){const t=this.deps.sessions.getBySessionId(e.toSessionId);if(!t)return{ok:!1,status:404,error:"Session not found"};const s=this.surfaceOfSession(e.toSessionId);if(!s)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(!s.attach)return{ok:!1,status:409,error:"This harness cannot receive attachments"};if(i.some(h=>T(h.mediaType))&&!s.attach.kinds.includes("image"))return{ok:!1,status:409,error:"This harness cannot receive images"};if(i.some(h=>!T(h.mediaType))&&!s.attach.kinds.includes("file"))return{ok:!1,status:409,error:"This harness cannot receive file attachments"}}const n=this.resolveChannel(e.mode,e.toSessionId,s);if(typeof n!="string")return{ok:!1,status:409,error:n.reason};if(t.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const r=this.deps.projects.getById(t.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 l={fromLabel:e.fromKind==="session"?`session ${e.fromSessionId??"unknown"}`:e.fromKind,at:new Date().toISOString(),mode:n},a={id:R(),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:l.at},o=n==="prompt"&&this.blockedAhead(a.sessionId);o&&(this.queueEntry(a,r.token),this.scheduleFlushContinuation(a.sessionId));const c=o?{ok:!0,messageId:a.id,status:"pending",message:a}:n==="inject"?this.deliverInject(a,r.token,l,s):n==="headless"?this.deliverHeadless(a,r.path,l,s):await this.deliverPrompt(a,t,r,s);return this.bus({kind:"message.created",messageId:a.id,sessionId:a.sessionId,mode:a.mode,at:a.at}),c}getMessage(e){return this.memory.get(e)??null}listVisible(e){return ke(this.deps,this.hooksDir,this.memory,e,this.deps.visibleTtlMs??Oe)}hasQueued(e){return this.queuedSessions.has(e)}listInflightCounts(){return ge(this.hooksDir,this.memory)}hasTerminalChannel(){return this.terminalChannel()!=null}scheduleFlushContinuation(e){if(this.flushScheduled.has(e))return;this.flushScheduled.add(e),setTimeout(()=>{this.flushScheduled.delete(e),this.flushSession(e)},this.deps.flushGapMs??ve).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,t){this.inboxSockets.set(e,t)}async awaitInboxReady(e,t){const s=this.surfaceOfSession(e)?.promptInbox??null;if(!s)return!1;const i=()=>{const r=this.inboxSockets.get(e);return!!r&&(!s.requiresAuthOn(process.platform)||!!r.token)},n=Date.now()+t;for(;!i();){if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,Ae))}return!0}lastTurnOutput(e){const t=this.deps.hookEvents.listBySession(e,De);for(let s=t.length-1;s>=0;s--){const i=t[s];let n=null;try{n=JSON.parse(i.payload)}catch{continue}const r=B(n?.raw);if(r)return{output:r,at:i.createdAt}}return null}notePaneEnv(e,t){this.paneEnvs.set(e,t),this.revokedPaneEnvs.delete(e),this.persistPaneEnvs()}notePendingOrigin(e){this.pendingOrigins=this.pendingOrigins.filter(t=>Date.now()-Date.parse(t.at)<M),this.pendingOrigins.push({...e,at:new Date().toISOString()}),this.persistPendingOrigins()}claimPendingOrigin(e,t,s){const i=this.pendingOrigins.findIndex(r=>r.harness===t&&r.projectId===s);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 t=g(this.hooksDir,x);try{w(I(t),{recursive:!0});const s=`${t}.tmp`;b(s,`${e}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),O(s,t),y(t,384),this.persistedPaneEnvs=e}catch{}}persistPendingOrigins(){const e=JSON.stringify(this.pendingOrigins);if(e===this.persistedPendingOrigins)return;const t=g(this.hooksDir,_);try{w(I(t),{recursive:!0});const s=`${t}.tmp`;b(s,`${e}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),O(s,t),y(t,384),this.persistedPendingOrigins=e}catch{}}sessionExited(e){this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.revokedPaneEnvs.add(e),this.persistPaneEnvs(),this.awaitingAck.delete(e);const t=this.deps.sessions.getBySessionId(e),s=t?.projectId==null?null:this.deps.projects.getById(t.projectId);if(!s)return;const i=k(this.hooksDir,s.token).filter(n=>n.sessionId===e);this.failQueuedOffline(e,i.filter(n=>!this.dismissedIds.has(n.id)))}async sessionTerminals(){return Se(this.deps,this.terminalChannel(),this.paneEnvs,()=>this.persistPaneEnvs(),this.revokedPaneEnvs)}diagnose(e){const t=this.surfaceOfSession(e),s=this.deps.sessions.livenessRowOf(e),i=s?F(s,this.deps.livenessOf?.()??A()):null,n=t?.promptInbox??null,r=this.inboxSockets.get(e),l=n?r?n.requiresAuthOn(process.platform)&&!r.token?{status:"unavailable",reason:"auth-token-required"}:{status:"ready",reason:null}:{status:"unavailable",reason:"no-credentials"}:{status:"unavailable",reason:"no-mechanism"},a=t?.queuedPrompt?{status:"ready",reason:null}:{status:"unavailable",reason:"no-mechanism"},o=t?.prompt?.resolve(e)??null,c=t?.prompt?o?{status:"ready",reason:null}:{status:"unavailable",reason:"no-peer-name"}:{status:"unavailable",reason:"no-mechanism"},h=this.paneEnvs.has(e),u=this.terminalChannel()?h?{status:"ready",reason:null}:{status:"unknown",reason:"no-pane-env"}:{status:"unavailable",reason:"no-backend"},d=this.deps.sessions.getBySessionId(e),S=d?.projectId==null?null:this.deps.projects.getById(d.projectId),q=S?k(this.hooksDir,S.token).filter(K=>K.sessionId===e).length:0;return{alive:i,inbox:l,queue:a,relay:c,terminal:u,paneEnvReported:h,pending:q,stalled:this.gate.isStalled(e)}}onSessionPrompt(e,t,s){const i=this.gate.acknowledge(e,t,s,{ackMinText:Te});return this.gate.hitLast&&this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e),i}noteActivity(e){this.gate.noteActivity(e)&&this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)}armAckWatch(e){this.gate.armAckWatch(e)}armCommandAck(e){this.gate.armCommandAck(e,t=>{this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)})}stall(e,t,s){this.gate.stall(e,t,s)}async answer(e,t){if(t.length===0||!D.test(t[0])||t.some(i=>!D.test(i)&&!V.test(i)))return{ok:!1,status:400,error:"Invalid answer keys"};const s=await this.sessionKeysTarget(e);if(!s.ok)return s;try{for(const[i,n]of t.entries())i>0&&await p(U),await s.terminal.sendKeys(s.paneId,n);return{ok:!0}}catch(i){return{ok:!1,status:409,error:i instanceof Error?i.message:String(i)}}}async interrupt(e,t="both",s){const i=await this.sessionKeysTarget(e,"\u51FB\u952E",t);if(!i.ok)return i;if(s!=null&&i.paneId===s)return{ok:!0,paneId:i.paneId,sent:!1};try{return await i.terminal.sendKeys(i.paneId,z),{ok:!0,paneId:i.paneId,sent:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async closePane(e){const t=await this.sessionKeysTarget(e,"\u5173\u95ED");if(!t.ok)return t;try{return await t.terminal.closePane(t.paneId),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async cycleMode(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,Y),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async pressEnter(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,X),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async pressCtrlC(e){const t=await this.sessionKeysTarget(e);if(!t.ok)return t;try{return await t.terminal.sendKeys(t.paneId,$),{ok:!0}}catch(s){return{ok:!1,status:409,error:s instanceof Error?s.message:String(s)}}}async setModel(e,t){const s=t.trim();if(!Z.test(s))return{ok:!1,status:400,error:"\u6A21\u578B\u540D\u5F62\u6001\u4E0D\u5408\u6CD5\uFF08\u4E0D\u542B\u7A7A\u767D\u4E0E\u63A7\u5236\u5B57\u7B26\uFF0C\u2264128 \u5B57\u7B26\uFF09"};const i=await this.sessionKeysTarget(e);if(!i.ok)return i;try{return await i.terminal.sendText(i.paneId,ie(s)),{ok:!0}}catch(n){return{ok:!1,status:409,error:n instanceof Error?n.message:String(n)}}}async setEffort(e,t){const s=t.trim(),i=await this.sessionKeysTarget(e);if(!i.ok)return i;const n=te(this.deps.hookEvents,e);if(!n.includes(s))return{ok:!1,status:400,error:`\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\u4E0D\u5408\u6CD5\uFF08\u53EF\u9009\uFF1A${n.join(" / ")||"\u65E0"}\uFF09`};try{return await i.terminal.sendText(i.paneId,ee(s)),{ok:!0}}catch(r){return{ok:!1,status:409,error:r instanceof Error?r.message:String(r)}}}async askSideQuestion(e,t){if(!this.deps.sessions.getBySessionId(e))return{ok:!1,status:404,error:"Session not found"};const s=this.surfaceOfSession(e),i=s?.sideQuestion??null;if(!i)return{ok:!1,status:409,error:s?.unsupportedReasons?.sideQuestion??"\u8FD9\u4E2A harness \u6CA1\u6709\u65C1\u8DEF\u4F1A\u8BDD\u901A\u9053"};const n=i.validate(t);if(!n.ok)return{ok:!1,status:400,error:n.error};if(i.prerequisite&&this.deps.sessions.hasRunOf(e)!==!0)return{ok:!1,status:409,error:i.prerequisite};const r=await this.sessionKeysTarget(e,"\u53D1\u8D77\u65C1\u8DEF\u4F1A\u8BDD");if(!r.ok)return r;try{return i.screen?(this.pollScreenAnswer(e,r.terminal,r.paneId,i,n.text),{ok:!0,question:n.text}):(await r.terminal.sendText(r.paneId,i.command(n.text)),{ok:!0,question:n.text})}catch(l){return{ok:!1,status:409,error:l instanceof Error?l.message:String(l)}}}pollScreenAnswer(e,t,s,i,n){const r=i.screen,l=async()=>await t.getPaneText?.(s).catch(()=>null)??null;(async()=>{const a=await l()??"";await t.sendKeys(s,r.openKeys).catch(()=>{}),await p(j),await t.sendKeys(s,r.submitKey).catch(()=>{}),await p(C);let o=await l();if((!o||!r.panelOpen(o))&&(await t.sendKeys(s,r.submitKey).catch(()=>{}),await p(C),o=await l(),!o||!r.panelOpen(o)))return;await t.sendText(s,n).catch(()=>{}),await p(j),await t.sendKeys(s,r.submitKey).catch(()=>{});const c=Date.now()+je;let h=null;for(;Date.now()<c;){if(await p(Me),o=await l(),o==null)return;const d=r.extractAnswer(n,a,o);if(d.done){h=d.answer;break}}h!=null&&(this.sideAnswerStore?.answerById(e,n,h),this.bus({kind:"sideQuestion.answered",sessionId:e,at:new Date().toISOString()}));const u=await l();u&&r.panelOpen(u)&&await t.sendKeys(s,r.closeKey).catch(()=>{})})()}async sessionKeysTarget(e,t="\u51FB\u952E",s="both"){return ne(this.keysDeps(),e,t,s)}busSafe(){return{emit:e=>this.bus(e)}}channelDeps(){return{setMemory:e=>this.memory.set(e.id,e),deleteMemory:e=>this.memory.delete(e),awaitAck:(e,t)=>this.gate.await(e,t),isSlashCommand,armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:e=>this.gate.armCommandAck(e,t=>{this.queuedSessions.has(t)&&this.scheduleFlushContinuation(t)}),emit:e=>this.bus(e),...this.deps.spawnImpl?{spawnImpl:this.deps.spawnImpl}:{}}}wireTextOfEntry(e){return oe(e,t=>this.surfaceOfSession(t))}hasImagesEntry(e){return re(e)}keysDeps(){return{sessions:this.deps.sessions,projects:this.deps.projects,hookEvents:this.deps.hookEvents,terminalChannel:()=>this.terminalChannel(),terminalPaneFor:(e,t,s)=>this.terminalPaneFor(e,t,s)}}async resend(e){const t=this.memory.get(e);if(!t)return{ok:!1,status:404,error:"Message not found"};if(!(t.channel==="prompt"&&(t.status==="failed"||t.status==="delivered"&&!t.acked)))return{ok:!1,status:409,error:"Message is not resendable"};const i=this.deps.sessions.getBySessionId(t.sessionId);if(!i)return{ok:!1,status:404,error:"Session not found"};if(i.projectId==null)return{ok:!1,status:400,error:"Session is not bound to a project"};const n=this.deps.projects.getById(i.projectId);if(!n)return{ok:!1,status:404,error:"Project not found"};const r=this.surfaceOfSession(t.sessionId);if(!r)return{ok:!1,status:400,error:"Session has no hook events to determine its harness"};if(this.gate.clearStall(t.sessionId,e),t.status==="delivered"&&t.via==="terminal"&&this.terminalChannel()){const o=await this.terminalPaneFor(i,n);if(o)return this.memory.set(e,{...t,status:"delivering",stalled:!1,settledAt:null}),this.runTerminalSubmit(e,o.id),this.bus({kind:"message.created",messageId:e,sessionId:t.sessionId,mode:t.mode,at:new Date().toISOString()}),{ok:!0,messageId:e,status:"delivering",message:this.memory.get(e)}}this.memory.delete(e);const l={...t,status:"pending",stalled:!1,acked:!1,settledAt:null,reason:void 0,error:null},a=await this.deliverPrompt(l,i,n,r);return this.bus({kind:"message.created",messageId:l.id,sessionId:l.sessionId,mode:l.mode,at:new Date().toISOString()}),a}dismiss(e,t){const s=this.memory.get(t);if(s){if(s.status==="running")return{ok:!1,status:409,error:"Message is still in flight"};s.status==="delivering"&&this.gate.headOf(s.sessionId)===t&&this.flushing.delete(s.sessionId),this.memory.delete(t),this.gate.clearStall(s.sessionId,t),this.gate.release(s.sessionId,t),this.queuedSessions.has(s.sessionId)&&this.scheduleFlushContinuation(s.sessionId)}else if(!this.dropQueued(e,t))return{ok:!1,status:404,error:"Message not found"};return this.bus({kind:"message.dismissed",messageId:t,sessionId:e,at:new Date().toISOString()}),{ok:!0}}dropQueued(e,t){const s=this.deps.sessions.getBySessionId(e);if(s?.projectId==null)return!1;const i=this.deps.projects.getById(s.projectId);if(!i)return!1;const n=k(this.hooksDir,i.token);if(!n.some(r=>r.id===t&&r.sessionId===e))return!1;for(f(this.hooksDir,i.token,new Set([t])),this.dismissedIds.add(t);this.dismissedIds.size>Pe;){const r=this.dismissedIds.values().next().value;if(r===void 0)break;this.dismissedIds.delete(r)}return n.some(r=>r.sessionId===e&&r.id!==t)||this.queuedSessions.delete(e),!0}async flushSession(e){if(this.stalled.has(e)||this.flushing.has(e)||!this.queuedSessions.has(e))return;const t=Symbol(e);this.flushing.set(e,t);try{await this.flushSessionInner(e)}catch{}finally{this.flushing.get(e)===t&&this.flushing.delete(e)}}async flushSessionInner(e){if(!this.ackGateOpen(e))return;const t=this.deps.sessions.getBySessionId(e);if(t?.projectId==null)return;const s=this.deps.projects.getById(t.projectId);if(!s)return;const i=k(this.hooksDir,s.token).filter(a=>a.sessionId===e);if(i.length===0){this.queuedSessions.delete(e);return}if(this.sessionJudgedDead(e)){this.failQueuedOffline(e,i.filter(a=>!this.dismissedIds.has(a.id)));return}const n=this.surfaceOfSession(e),r=n?.prompt??null,l=this.modalBlocked(e);for(const a of i){if(this.stalled.has(e))return;if(this.dismissedIds.has(a.id))continue;const o={id:a.id,sessionId:e,text:a.text,...a.attachments&&a.attachments.length>0?{attachments:a.attachments}:{},mode:"prompt",oneWay:a.oneWay===!0,...a.forceTerminal===!0?{forceTerminal:!0}:{},via:"socket",channel:"prompt",status:"pending",at:a.at};if(!l&&this.hasImagesEntry(o)&&this.terminalChannel()){const u=await this.terminalPaneFor(t,s);if(u){f(this.hooksDir,s.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(e,o.id),await this.runTerminalPrompt(o.id,u.id,this.wireTextOfEntry(o)),this.settleQueueIndex(e,s.token);return}}if(n&&await this.tryQueuedDeliver(o,n)){f(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}if(n&&await this.tryInboxDeliver(o,n)){f(this.hooksDir,s.token,new Set([a.id])),this.settleQueueIndex(e,s.token);return}const c=r?.resolve(e)??null,h=o.forceTerminal===!0?["terminal"]:o.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of h){if(u==="relay"&&r&&c){if(this.memory.set(o.id,{...o,status:"delivering",via:"relay"}),!this.runRelay(o,r,c.name)){this.memory.delete(o.id);return}this.awaitingAck.set(e,o.id),f(this.hooksDir,s.token,new Set([a.id]));break}if(u==="terminal"&&!l&&this.terminalChannel()){const d=await this.terminalPaneFor(t,s);if(d){f(this.hooksDir,s.token,new Set([a.id])),this.memory.set(o.id,{...o,via:"terminal",status:"delivering"}),this.awaitingAck.set(e,o.id),await this.runTerminalPrompt(o.id,d.id,this.wireTextOfEntry(o));break}}}if(this.awaitingAck.get(e)===o.id){this.settleQueueIndex(e,s.token);return}return}this.settleQueueIndex(e,s.token)}settleQueueIndex(e,t){k(this.hooksDir,t).every(s=>s.sessionId!==e)&&this.queuedSessions.delete(e)}async flushAll(){for(const e of[...this.queuedSessions])await this.flushSession(e)}forgetSession(e){let t=0;for(const[s,i]of this.memory)i.sessionId===e&&(this.memory.delete(s),t++);return t+=ye(this.hooksDir,e),this.queuedSessions.delete(e),this.gate.clearStall(e),this.gate.release(e),this.inboxSockets.forget(e),this.paneEnvs.delete(e),this.revokedPaneEnvs.add(e),this.persistPaneEnvs(),t}forgetProject(e){const t=this.pendingOrigins.length;this.pendingOrigins=this.pendingOrigins.filter(i=>i.projectId!==e),this.pendingOrigins.length!==t&&this.persistPendingOrigins();let s=0;for(const[i,n]of this.memory)this.deps.sessions.getBySessionId(n.sessionId)?.projectId===e&&(this.memory.delete(i),this.inboxSockets.forget(n.sessionId),this.paneEnvs.delete(n.sessionId),this.gate.clearStall(n.sessionId),this.gate.release(n.sessionId),s++);for(const i of[...this.queuedSessions])this.deps.sessions.getBySessionId(i)?.projectId===e&&(s+=this.forgetSession(i));return this.persistPaneEnvs(),s}surfaceOfSession(e){const t=this.deps.hookEvents.listBySession(e,1),s=t[t.length-1]?.source;return E(s)?this.deps.surfaceFor?.(s)??L(s):null}resolveChannel(e,t,s){return he(this.deps.sessions,()=>this.terminalChannel()!=null,e,t,s)}async terminalPaneFor(e,t,s="both"){return se(this.terminalChannel(),this.paneEnvs,e,t,s)}terminalChannel(){const e=this.deps.terminal;return e&&e.available()?e:null}modalBlocked(e){return this.deps.blockedByQuestion?.(e)===!0}async deliverPrompt(e,t,s,i){if(this.sessionJudgedDead(e.sessionId))return{ok:!0,messageId:e.id,status:"failed",message:this.failOffline(e)};const n=this.modalBlocked(e.sessionId);if(!n&&this.hasImagesEntry(e)&&this.terminalChannel()){const u=await this.terminalPaneFor(t,s);if(u)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,u.id,this.wireTextOfEntry(e)),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)}}const r=await this.tryQueuedDeliver(e,i);if(r)return{ok:!0,messageId:e.id,status:"delivered",message:r};const l=await this.tryInboxDeliver(e,i);if(l)return{ok:!0,messageId:e.id,status:"delivered",message:l};const a=i.prompt,o=a?.resolve(e.sessionId)??null,c=e.forceTerminal===!0?["terminal"]:e.oneWay===!0?["terminal","relay"]:["relay","terminal"];for(const u of c){if(u==="relay"&&a&&o){if(this.memory.set(e.id,{...e,status:"delivering",via:"relay"}),this.runRelay(e,a,o.name))return this.awaitingAck.set(e.sessionId,e.id),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)};this.memory.delete(e.id)}if(u==="terminal"&&!n&&this.terminalChannel()){const d=await this.terminalPaneFor(t,s);if(d)return this.memory.set(e.id,{...e,status:"delivering",via:"terminal"}),this.awaitingAck.set(e.sessionId,e.id),this.runTerminalPrompt(e.id,d.id,this.wireTextOfEntry(e)),{ok:!0,messageId:e.id,status:"delivering",message:this.memory.get(e.id)}}}if(this.sessionJudgedDead(e.sessionId))return{ok:!0,messageId:e.id,status:"failed",message:this.failOffline(e)};this.queueEntry(e,s.token);const h={...e,status:"pending"};return{ok:!0,messageId:e.id,status:"pending",message:h}}async tryQueuedDeliver(e,t){const s=t.queuedPrompt;if(!s||this.hasImagesEntry(e))return null;const{bin:i,args:n}=s.command(e.sessionId,this.wireTextOfEntry(e));this.memory.set(e.id,{...e,status:"delivering",via:"queue"});try{await ae(i,n,s.timeoutMs??3e4,this.deps.spawnImpl)}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),{...e,via:"queue"},"queue")}async tryInboxDeliver(e,t){const s=t.promptInbox,i=this.inboxSockets.get(e.sessionId);if(!s||!i||e.forceTerminal===!0)return null;this.memory.set(e.id,{...e,status:"delivering",via:"socket"});try{await J(s,i,this.wireTextOfEntry(e))}catch{return this.memory.delete(e.id),null}return P(this.channelDeps(),e,"socket")}queueEntry(e,t){de(this.hooksDir,t,e),this.queuedSessions.add(e.sessionId)}sessionJudgedDead(e,t=this.deps.livenessOf?.()??A()){return fe(this.deps.sessions,e,t)}failOffline(e){return ce(this.memory,t=>this.bus(t),e)}failQueuedOffline(e,t){me(this.deps,this.hooksDir,this.memory,s=>this.bus(s),e,t),this.queuedSessions.delete(e)}relayDeps(){return{headless:this.headless,getMemory:e=>this.memory.get(e)??null,setMemory:e=>this.memory.set(e.id,e),awaitAck:(e,t)=>this.gate.await(e,t),stall:(e,t,s)=>this.gate.stall(e,t,s),isSlashCommand,armAckWatch:e=>this.gate.armAckWatch(e),armCommandAck:(e,t)=>this.gate.armCommandAck(e,s=>{t(s),this.queuedSessions.has(s)&&this.scheduleFlushContinuation(s)}),onReleased:e=>{this.queuedSessions.has(e)&&this.scheduleFlushContinuation(e)},emit:e=>this.bus(e),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.relayTimeoutMs===void 0?{}:{relayTimeoutMs:this.deps.relayTimeoutMs}}}runRelay(e,t,s){return pe(this.relayDeps(),e,t,s,this.wireTextOfEntry(e))}async runTerminalPrompt(e,t,s){await this.runTerminal(e,i=>i.sendText(t,s))}async runTerminalSubmit(e,t){await this.runTerminal(e,s=>s.sendKeys(t,"\r"))}async runTerminal(e,t){const s=this.memory.get(e);if(!s)return;const i=this.terminalChannel();if(i)try{await t(i);const n=this.memory.get(e);if(!n)return;const r={...n,status:"delivered",settledAt:new Date().toISOString()};this.memory.set(e,r),isSlashCommand(n.text)?this.armCommandAck(e):this.armAckWatch(r),this.bus({kind:"message.delivered",messageId:e,sessionId:s.sessionId,at:new Date().toISOString()})}catch(n){const r=this.memory.get(e);if(!r)return;if(r.acked===!0){const a=new Date().toISOString();this.memory.set(e,{...r,status:"delivered",settledAt:a}),this.bus({kind:"message.delivered",messageId:e,sessionId:r.sessionId,at:a});return}const l={...r,status:"failed",error:n instanceof Error?n.message:String(n),settledAt:new Date().toISOString()};this.memory.set(e,l),this.stall(s.sessionId,l,"failed"),this.bus({kind:"message.finished",messageId:e,sessionId:s.sessionId,status:"failed",at:new Date().toISOString()})}}deliverInject(e,t,s,i){return ue({hooksDir:this.hooksDir,memory:this.memory,bus:this.busSafe()},e,t,s,i,this.wireTextOfEntry(e))}deliverHeadless(e,t,s,i){return le({memory:this.memory,headless:this.headless,bus:this.busSafe(),...this.deps.bin?{bin:this.deps.bin}:{},...this.deps.timeoutMs===void 0?{}:{timeoutMs:this.deps.timeoutMs}},e,t,s,i,this.wireTextOfEntry(e))}bus(e){try{this.deps.bus?.emit(e)}catch{}}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createHash as
|
|
2
|
-
`,{flag:"a"})}export function appendOutbox(
|
|
3
|
-
`).filter(c=>c.trim())}catch{t=[]}for(const c of
|
|
1
|
+
import{createHash as l}from"node:crypto";import{mkdirSync as a,readFileSync as h,renameSync as f,writeFileSync as p}from"node:fs";import{join as n}from"node:path";import{hookSourceHarness as u}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(i){return l("sha256").update(i).digest("hex").slice(0,16)}export function hooksRoot(i){return y(i)}export function mirrorPathOf(i,r){return n(i,"mirror",`${r}.json`)}export function outboxPathOf(i,r){return n(i,"outbox",`${r}.jsonl`)}export function buildMirrorDoc(i,r,e){const o=r.filter(t=>!(t.source.kind!=="hook-event"||t.handler.type!=="inject"||!t.enabled||t.projectId!==null&&t.projectId!==i.id||t.filter.crossProjectOnly)).sort((t,s)=>s.priority-t.priority).map(t=>({id:t.id,name:t.name,harness:u(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(i.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(n(hooksRoot(this.dataDir),"mirror"),{recursive:!0});const t=`${o}.tmp`;p(t,JSON.stringify(e)),f(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(i,r,e){const o=n(i,"inbox");a(o,{recursive:!0}),p(n(o,`${hookShardId(r)}.jsonl`),JSON.stringify({v:1,token:r,report:e})+`
|
|
2
|
+
`,{flag:"a"})}export function appendOutbox(i,r,e){if(e.length!==0)try{const o=outboxPathOf(i,hookShardId(r));a(n(i,"outbox"),{recursive:!0});let t=[];try{t=h(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 s=t.slice(-OUTBOX_MAX_LINES),d=`${o}.tmp`;p(d,s.length?s.join(`
|
|
4
4
|
`)+`
|
|
5
|
-
`:""),d
|
|
5
|
+
`:""),f(d,o)}catch{}}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{randomUUID as
|
|
1
|
+
import{randomUUID as S}from"node:crypto";import{graphDirections as m,pendingCountsOf as v}from"../repositories/orchestrations.js";import{messagingSurfaceFor as _}from"../surfaces.js";import{matchesMinute as b,minuteKey as E,parseCron as A}from"../daemon/cron.js";import{pidAliveOf as y}from"../daemon/claude-liveness.js";import{combinedLivenessOf as w}from"../daemon/liveness.js";import{postJson as C}from"./handlers/webhook.js";import{renderTemplate as R}from"./match.js";import{ORCH_MAX_DELIVERIES as I,ORCH_MAX_FORKS as p,validateOrchestration as k}from"./orchestration-graph.js";const N=5e3;function $(l,e){const t=l.trim();return t?`${t}
|
|
2
2
|
|
|
3
|
-
${e}`:e}const
|
|
4
|
-
\u2026[weave: ${
|
|
5
|
-
${
|
|
3
|
+
${e}`:e}const O=4e3,g=32e3;function T(l){if(l.length<=g)return{text:l,truncated:!1};const e=g/2;return{text:`${l.slice(0,e)}
|
|
4
|
+
\u2026[weave: ${l.length-g} chars truncated]\u2026
|
|
5
|
+
${l.slice(-e)}`,truncated:!0}}function x(l,e){return R(l,{upstream:e.upstream,summary:e.summary,session:e.session})}const M=/\{(upstream|summary|session)\}/,F=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(l){const t=((l??"").trim().toLowerCase().split(/\s+/)[0]??"").replace(/[.。!!??]/g,"");return F.has(t)?!0:j.has(t)?!1:null}export function createForkConditionJudge(l){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(!l.supports(t))return{ok:!1,source:"fork",reason:"condition not evaluable \u2014 harness has no context sub-agent face"};const s=await l.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(!l.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((o,d)=>`${d+1}. key=${o.key}: ${o.condition}`).join(`
|
|
8
|
+
`),r=await l.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=N(r,n.map(d=>d.key));return i?n.map(d=>{const u=i.get(d.key);return e(u===void 0?null:u)}):n.map(()=>e(null))}}}function N(h,e){if(!h)return null;const t=h.match(/\{[\s\S]*\}/);if(!t)return null;try{const n=JSON.parse(t[0]),s=new Map;for(const r of e){const i=n[r];if(typeof i!="boolean")return null;s.set(r,i)}return s}catch{return null}}export function matchWhen(h,e){const t=(e??"").toLowerCase();return h.split(/[,,\n;;]/).map(n=>n.trim().toLowerCase()).filter(n=>n.length>0).some(n=>t.includes(n))}const T=5e3,L=1e4,W=6e4,_=2*36e5,U=1500,H=9e4;export class OrchestrationEngine{deps;runtime=new Map;opening=new Map;startedByOrchestration=new Map;forkJudge;constructor(e){this.deps=e,this.forkJudge=createForkConditionJudge({supports:t=>e.supportsExtract?.(t)??!1,extract:t=>e.extract?.(t)??Promise.resolve(null)})}async start(e,t,n,s){const r=this.deps.orchestrations.getById(e);if(!r)return{ok:!1,status:404,error:"Orchestration not found"};const i=k(r);if(!i.ok)return{ok:!1,status:409,error:i.error};const{entries:d}=m(r.nodes,r.edges),u=s?d.filter(a=>s.includes(a.id)):d.filter(a=>a.kind==="session");if(u.length===0)return{ok:!1,status:409,error:"No matching entry node"};const c=this.activeOf(e);if(c)return await Promise.allSettled(u.map(a=>a.kind==="session"?this.deliver(c,{from:"",to:a.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(c,a.id,n??""))),this.maybeDone(c),{ok:!0,runId:c.id};const o={id:this.deps.runs.insert({orchestrationId:r.id,orchestrationName:r.name,projectId:r.projectId,trigger:t}).id,orchestrationId:r.id,trigger:t,name:r.name,nodes:r.nodes,edges:r.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};return this.runtime.set(o.id,o),this.emitRun(o,"running"),await Promise.allSettled(u.map(a=>a.kind==="session"?this.deliver(o,{from:"",to:a.id,edgeId:"",text:n?.trim()||r.startText.trim()||r.name}):this.fireEdges(o,a.id,n??""))),this.maybeDone(o),{ok:!0,runId:o.id}}cancel(e){const t=this.runtime.get(e);return t?this.finish(t,"cancelled"):!1}onEvent(e){try{if(!(this.deps.surfaceFor?.(e.source)??S(e.source)).idleSignals.includes(e.eventType))return;const t=this.hasPendingAnywhere(e.sessionId);for(const n of[...this.runtime.values()]){const s=n.state.pending[e.sessionId];!n.running||!s||s.length===0||(s.shift(),this.persist(n),this.fireEdges(n,e.sessionId))}if(!t){const n=Date.now(),s=this.startedByOrchestration.get(e.sessionId);s!==void 0&&n-s<W?this.startedByOrchestration.delete(e.sessionId):(this.startedByOrchestration.delete(e.sessionId),this.maybeAutoFire(e.sessionId))}}catch{}}hasPendingAnywhere(e){return[...this.runtime.values()].some(t=>(t.state.pending[e]?.length??0)>0)}maybeAutoFire(e){const t=Date.now();for(const n of this.entryIndex().get(e)??[]){if(!n.enabled||this.activeOf(n.id))continue;const s=`${n.id}:${e}`;if(t-(this.lastAutoFireAt.get(s)??0)<T)continue;const r=n.nodes.find(i=>i.id===e&&i.kind==="session");!r||!n.edges.some(i=>i.from===r.id)||(this.lastAutoFireAt.set(s,t),this.fireFromEntry(n,r.id))}}async fireFromEntry(e,t){if(!k(e).ok)return;const n={id:this.deps.runs.insert({orchestrationId:e.id,orchestrationName:e.name,projectId:e.projectId,trigger:"manual"}).id,orchestrationId:e.id,trigger:"manual",name:e.name,nodes:e.nodes,edges:e.edges,state:{pending:{},events:[]},deliveries:0,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(n.id,n),this.emitRun(n,"running"),await this.fireEdges(n,t),this.maybeDone(n)}entryIndexCache=null;lastAutoFireAt=new Map;entryIndex(){if(this.entryIndexCache&&Date.now()-this.entryIndexCache.at<L)return this.entryIndexCache.map;const e=new Map;for(const t of this.deps.orchestrations.list()){if(!t.enabled)continue;const n=new Set(m(t.nodes,t.edges).entries.map(s=>s.id));for(const s of t.nodes){if(s.kind!=="session"||!n.has(s.id)&&!s.autoFire)continue;const r=e.get(s.id)??[];r.push(t),e.set(s.id,r)}}return this.entryIndexCache={at:Date.now(),map:e},e}cronTick(e=new Date){let t=0;try{const n=$(e);for(const s of this.deps.orchestrations.list()){if(!s.enabled||!s.cron||s.lastCronAt===n)continue;const r=F(s.cron);if(!r||!C(r,e))continue;const{entries:i}=m(s.nodes,s.edges);i.some(d=>d.kind==="session")&&(this.deps.orchestrations.setCronFired(s.id,n),!this.activeOf(s.id)&&(this.start(s.id,"cron"),t++))}}catch{}return t}rearm(){try{for(const e of this.deps.runs.listRunning()){const t=this.deps.orchestrations.getById(e.orchestrationId);if(!(t?k(t):{ok:!1}).ok){this.deps.runs.finish(e.id,"interrupted","daemon restarted \u2014 definition gone");continue}const n={id:e.id,orchestrationId:e.orchestrationId,trigger:e.trigger,name:e.orchestrationName,nodes:t.nodes,edges:t.edges,state:e.state,deliveries:e.deliveries,forks:0,inflight:0,running:!0,finishing:!1};this.runtime.set(n.id,n),this.emitRun(n,"running")}}catch{}try{this.deps.runs.prune()}catch{}}sweepTerminated(){let e=0;try{const t=this.deps.livenessOf?.()??y(),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&&I(u,t)!==!1){const c=Date.parse(d[0].at);Number.isFinite(c)&&s-c>_&&(this.staleOut(r,i,d[0].at),e++);continue}this.reviveOrDrop(r,i),e++}}catch{return e}return e}staleOut(e,t,n){const s=((Date.now()-Date.parse(n))/36e5).toFixed(1);this.dropPending(e,t,`pending stale ${s}h (oldest ${n}) \u2014 target alive but never turned; run failed to release the single-run gate`),this.finish(e,"failed",`pending stale on ${t} (${s}h) \u2014 run aborted`)}ensureOpenOnce(e){const t=this.opening.get(e);if(t)return t;const n=(this.deps.ensureOpen?.(e)??Promise.resolve({ok:!0})).finally(()=>this.opening.delete(e));return this.opening.set(e,n),n}async reviveOrDrop(e,t){const n=await this.ensureOpen(t);n.ok||!e.running||(this.dropPending(e,t,`pending dropped \u2014 session is not running: ${n.error}`),this.maybeDone(e))}async fireEdges(e,t,n=""){const s=e.edges.filter(o=>o.from===t);if(s.length===0){this.maybeDone(e);return}const r=n||(this.deps.deliverer.lastTurnOutput?.(t)?.output??null),i=r?r.length>x?`${r.slice(0,x)}\u2026`:r:null,d=r?P(r):{text:null,truncated:!1},u=this.deps.sessions.getBySessionId(t)?.title||t,c=new Map;if(!n){const o=s.filter(a=>a.condition?.trim()&&!(a.when?.trim()&&!matchWhen(a.when,d.text)));if(o.length>0){const a=await this.evaluateConditionsBatch(e,t,o,d.text,d.truncated);for(const[f,l]of a)c.set(f,l)}}await Promise.allSettled(s.map(async o=>{if(n){const l=O(o.text,{upstream:n,summary:n,session:t}),b=o.text.includes("{upstream}")?l:j(l,n);return this.deliver(e,{from:t,to:o.to,edgeId:o.id,text:b})}let a=null;if(o.extract?.trim()&&this.takeFork(e)&&(a=this.deps.supportsExtract?.(t)?await this.deps.extract?.({sessionId:t,prompt:o.extract.trim()})??null:null),o.when?.trim()&&!matchWhen(o.when,d.text)){this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,stage:"condition",error:"pre-filter no match \u2014 upstream output lacks all keywords"});return}if(o.condition?.trim()){const l=c.get(o.id);if(l!==!0){l===void 0&&this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return}}const f=O(o.text,{upstream:i,summary:a??i,session:u});if(M.test(f)){this.record(e,{from:t,to:o.to,edgeId:o.id,ok:!1,error:"unresolved template variable \u2014 no upstream output and no extract result"});return}return this.deliver(e,{from:t,to:o.to,edgeId:o.id,text:f})})),this.maybeDone(e)}async evaluateConditionsBatch(e,t,n,s,r){const i=new Map,d=this.deps.conditionJudge??this.forkJudge;if(!this.takeFork(e)){for(const u of n)this.record(e,{from:t,to:u.to,edgeId:u.id,ok:!1,stage:"condition",error:`fork budget exhausted (${p}) \u2014 condition not evaluated`});return i}if(d.judgeBatch&&n.length>1)try{const u=await d.judgeBatch({sessionId:t,items:n.map(c=>({key:c.id,condition:c.condition.trim()})),upstream:s});return n.forEach((c,o)=>{const a=u[o];a&&(i.set(c.id,a.ok),this.record(e,{from:t,to:c.to,edgeId:c.id,ok:a.ok,stage:"condition",...a.ok?{}:{error:a.reason??"condition not satisfied \u2014 delivery blocked"},...a.source?{source:a.source}:{},...this.conditionDetail(a.detail,r)}))}),i}catch{}for(const u of n)i.set(u.id,await this.evaluateCondition(e,t,u,s,r));return i}conditionDetail(e,t){const n=[e,t?`state truncated to ${g} chars`:null].filter(Boolean);return n.length>0?{detail:n.join(" \u2014 ")}:{}}async evaluateCondition(e,t,n,s,r=!1){const i=o=>(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!1,stage:"condition",error:o,...d?{source:d}:{},...this.conditionDetail(u,r)}),!1);let d,u,c;try{c=await(this.deps.conditionJudge??this.forkJudge).judge({sessionId:t,condition:n.condition.trim(),upstream:s}),d=c.source,u=c.detail}catch(o){return i(`condition judge failed \u2014 delivery blocked: ${o instanceof Error?o.message:String(o)}`)}return c.ok?(this.record(e,{from:t,to:n.to,edgeId:n.id,ok:!0,stage:"condition",...d?{source:d}:{},...this.conditionDetail(u,r)}),!0):i(c.reason??"condition not satisfied \u2014 delivery blocked")}async deliver(e,t){const n=await this.deliverOnce(e,t);return n||!e.running?n:(await new Promise(s=>setTimeout(s,this.deps.retryDelayMs??U)),e.running?this.deliverOnce(e,t):!1)}async deliverOnce(e,t){e.inflight++;try{if(!e.running)return!1;const n=e.nodes.find(i=>i.id===t.to);if(!n)return this.record(e,{...t,ok:!1,error:"target node is not in the snapshot"}),!1;if(n.kind==="webhook"){const i=await(this.deps.postJsonImpl??B)(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?.()??y();return I(t,n)}userPresent(e){if(this.deps.sessions.turnOpenOf(e))return!1;const t=this.deps.sessions.listWithCounts().find(s=>s.sessionId===e);if(!t)return!1;const n=Date.parse(t.lastSeenAt);return Number.isFinite(n)&&Date.now()-n<H}async ensureOpen(e){if(!this.deps.ensureOpen)return{ok:!1,error:"terminal auto-open unavailable"};try{return await this.deps.ensureOpen(e)}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}}}
|
|
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)}}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{graphDirections as
|
|
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(d){const{nodes:n,edges:t}=d;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 s=new Set;for(const e of n){if(s.has(e.id))return{ok:!1,error:`Duplicate node ${e.id}`};if(s.add(e.id),e.kind==="webhook"&&!e.id.startsWith("w:"))return{ok:!1,error:`Webhook node id must start with "w:": ${e.id}`};if(e.kind==="trigger"&&!e.id.startsWith("t:"))return{ok:!1,error:`Trigger node id must start with "t:": ${e.id}`}}if(t.length>ORCH_MAX_EDGES)return{ok:!1,error:`At most ${ORCH_MAX_EDGES} edges per orchestration`};const i=new Set,a=new Set;for(const e of t){if(i.has(e.id))return{ok:!1,error:`Duplicate edge id ${e.id}`};if(i.add(e.id),!s.has(e.from)||!s.has(e.to))return{ok:!1,error:`Edge ${e.id} references a node outside the node set`};if(e.from===e.to)return{ok:!1,error:`Self-loop on ${e.from}`};const h=`${e.from}->${e.to}`;if(a.has(h))return{ok:!1,error:`Duplicate edge ${e.from}\u2192${e.to}`};a.add(h)}const{entries:o}=p(n,t),r=new Set(t.map(e=>e.to)),f=new Set(t.map(e=>e.from)),c=new Set(o.filter(e=>e.kind==="webhook").map(e=>e.id)),l=t.find(e=>!e.text.trim()&&!c.has(e.from)&&!e.extract?.trim());if(l)return{ok:!1,error:`Edge ${l.from}\u2192${l.to} has no message`};for(const e of t)if(c.has(e.from)&&(e.condition?.trim()||e.when?.trim()))return{ok:!1,error:`Edge ${e.from}\u2192${e.to} cannot have a condition/pre-filter (webhook entries have no session to ask)`};for(const e of n)if(e.kind==="webhook"&&e.autoFire)return{ok:!1,error:`Webhook node ${e.id} cannot have autoFire`};for(const e of n)if(e.kind==="webhook"){if(r.has(e.id)&&f.has(e.id))return{ok:!1,error:`Webhook node ${e.id} cannot have both inbound and outbound edges`};if(!r.has(e.id)&&!f.has(e.id))return{ok:!1,error:`Webhook node ${e.id} is not connected`}}for(const e of n)if(e.kind==="trigger"){if(r.has(e.id))return{ok:!1,error:`Trigger node ${e.id} cannot have inbound edges`};if(!f.has(e.id))return{ok:!1,error:`Trigger node ${e.id} is not connected`}}for(const e of n){if(e.kind!=="webhook"||!r.has(e.id))continue;const h=e.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 ${e.id} needs a valid http(s) URL`}}const k=findCycle(n,t);return k?{ok:!1,error:`Cycle detected: ${k.join(" \u2192 ")}`}:{ok:!0}}export function findCycle(d,n){const t=new Map;for(const o of d)t.set(o.id,[]);for(const o of n){const r=t.get(o.from);r&&r.push(o.to)}const s=new Map,i=[],a=o=>{s.set(o,1),i.push(o);for(const r of t.get(o)??[]){const f=s.get(r)??0;if(f===1)return[...i.slice(i.indexOf(r)),r];if(f===0){const c=a(r);if(c)return c}}return i.pop(),s.set(o,2),null};for(const o of d)if((s.get(o.id)??0)===0){const r=a(o.id);if(r)return r}return null}export function ranksOf(d,n){const t=new Map(d.map(o=>[o.id,0])),s=new Map(d.map(o=>[o.id,[]]));for(const o of n)s.get(o.from)?.push(o.to),t.set(o.to,(t.get(o.to)??0)+1);const i=new Map(d.map(o=>[o.id,0])),a=d.filter(o=>(t.get(o.id)??0)===0).map(o=>o.id);for(let o=0;o<a.length;o++){const r=a[o];for(const f of s.get(r)??[]){i.set(f,Math.max(i.get(f)??0,(i.get(r)??0)+1));const c=(t.get(f)??0)-1;t.set(f,c),c===0&&a.push(f)}}return i}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export declare function globalPluginRoot(): string;
|
|
2
|
+
/**
|
|
3
|
+
* 清掉 git 安装崩溃残留的 `install-<ts>` 临时目录(clone 后、cleanup 前进程死了
|
|
4
|
+
* 就没人删)。daemon 启动时清一次:tmp 区归 daemon 单进程所有,此刻必无人占用。
|
|
5
|
+
*/
|
|
6
|
+
export declare function pruneInstallTmp(): void;
|
|
2
7
|
/** src 为本地路径(存在目录/含 manifest 的父目录)或 git URL(https:// 或 git@ 或 *.git 结尾)。 */
|
|
3
8
|
export declare function isGitSource(src: string): boolean;
|
|
4
9
|
export interface InstallResult {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{cp as
|
|
2
|
-
`,"utf8")}async function
|
|
3
|
-
`,"utf8")}export async function searchPlugins(
|
|
1
|
+
import{cp as j,mkdir as p,readFile as g,readdir as _,rm as m,writeFile as P}from"node:fs/promises";import{existsSync as v,readdirSync as D,rmSync as F}from"node:fs";import s from"node:path";import{spawn as J}from"node:child_process";import{WEAVE_PLUGIN_MANIFEST as S,WeavePluginManifestSchema as W}from"@weavecode/core";import{getPluginsDir as b,getTmpDir as A}from"../db/paths.js";export function globalPluginRoot(){return b()}export function pruneInstallTmp(){const t=A();let r;try{r=D(t)}catch{return}for(const e of r)if(e.startsWith("install-"))try{F(s.join(t,e),{recursive:!0,force:!0})}catch{}}function E(t){return s.join(t??globalPluginRoot(),"installed.json")}async function N(t){try{const r=JSON.parse(await g(E(t),"utf8"));return Array.isArray(r)?r:[]}catch{return[]}}async function O(t,r){const e=r??globalPluginRoot();await p(e,{recursive:!0}),await P(E(r),JSON.stringify(t,null,2)+`
|
|
2
|
+
`,"utf8")}async function x(t){try{const r=JSON.parse(await g(s.join(t,S),"utf8"));return W.safeParse(r).success?r:null}catch{return null}}async function k(t){const r=[],e=await x(t);if(e)return[{dir:t,manifest:e}];let o;try{o=await _(t)}catch{return r}for(const a of o){const n=s.join(t,a),i=await x(n);i&&r.push({dir:n,manifest:i})}return r}function I(t,r,e,o=6e4){return new Promise((a,n)=>{const i=J(t,r,{cwd:e,windowsHide:!0,stdio:["ignore","pipe","pipe"]});let c="";const l=setTimeout(()=>{i.kill(),n(new Error(`${t} ${r.join(" ")} \u8D85\u65F6\uFF08${o}ms\uFF09`))},o);i.stderr?.on("data",u=>c+=u.toString()),i.on("error",u=>{clearTimeout(l),n(u)}),i.on("close",u=>{clearTimeout(l),u===0?a():n(new Error(`${t} \u9000\u51FA\u7801 ${u}: ${c.slice(0,500)}`))})})}export function isGitSource(t){return/^(https?:\/\/|git@|ssh:\/\/|git:\/\/)/.test(t)||t.endsWith(".git")}export async function installPlugin(t,r){const e=[];let o,a;if(isGitSource(t)){e.push(`\u4ECE ${t} \u5B89\u88C5\u7684\u63D2\u4EF6\u672A\u7ECF\u6C99\u7BB1\u9694\u79BB\uFF0C\u8BF7\u786E\u8BA4\u6765\u6E90\u53EF\u4FE1`);const n=s.join(A(),`install-${Date.now()}`);await p(n,{recursive:!0}),await I("git",["clone","--depth","1",t,s.join(n,"repo")]),o=s.join(n,"repo"),a=()=>m(n,{recursive:!0,force:!0})}else if(o=s.resolve(t),!v(o))throw new Error(`\u672C\u5730\u8DEF\u5F84\u4E0D\u5B58\u5728: ${o}`);try{const n=await k(o);if(n.length===0)throw new Error(`\u672A\u627E\u5230 ${S}\uFF08src \u6216\u5176\u4E00\u7EA7\u5B50\u76EE\u5F55\uFF09`);const i=r?.root??globalPluginRoot();await p(i,{recursive:!0});const c=await N(r?.root),l=[];for(const{dir:u,manifest:y}of n){const f=String(y.id),h=s.join(i,f);s.resolve(h).startsWith(s.resolve(i)+s.sep)&&(await m(h,{recursive:!0,force:!0}),await j(u,h,{recursive:!0,filter:w=>!w.includes("node_modules")&&!w.includes(`${s.sep}.git`)}));const d={id:f,name:String(y.name??f),version:String(y.version??"0.0.0"),source:t,dir:f,installedAt:new Date().toISOString()},$=c.findIndex(w=>w.id===f);$>=0?c[$]=d:c.push(d),l.push({id:f,name:d.name,version:d.version,dir:f})}return await O(c,r?.root),{installed:l,warnings:e}}finally{a&&await a()}}export async function uninstallPlugin(t,r){const e=r?.root??globalPluginRoot(),o=await N(r?.root),a=o.find(i=>i.id===t),n=a?s.join(e,a.dir):s.join(e,t);return v(n)?(await m(n,{recursive:!0,force:!0}),a&&await O(o.filter(i=>i.id!==t),r?.root),!0):!1}export async function exportPlugin(t,r,e){const o=s.join(e?.root??globalPluginRoot(),t);if(!v(o))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728: ${o}`);if(!await x(o))throw new Error(`\u63D2\u4EF6\u7F3A\u5C11\u5408\u6CD5 ${S}: ${t}`);const n=s.join(s.resolve(r),t);return await m(n,{recursive:!0,force:!0}),await j(o,n,{recursive:!0,filter:i=>!i.includes("node_modules")&&!i.includes(`${s.sep}.git`)}),n}function T(t){return s.join(t??globalPluginRoot(),"sources.json")}export function parseSources(t){if(Array.isArray(t))return{indexes:t.filter(r=>typeof r=="string")};if(t&&typeof t=="object"){const r=t.indexes;return{indexes:Array.isArray(r)?r.filter(e=>typeof e=="string"):[]}}return{indexes:[]}}export async function readSourcesFile(t){try{return parseSources(JSON.parse(await g(T(t),"utf8")))}catch{return{indexes:[]}}}export async function writeSourcesFile(t,r){const e=r??globalPluginRoot();await p(e,{recursive:!0}),await P(T(r),JSON.stringify(t,null,2)+`
|
|
3
|
+
`,"utf8")}export async function searchPlugins(t){const{indexes:r}=await readSourcesFile(),e=[];for(const o of r)try{const a=await fetch(o,{signal:AbortSignal.timeout(1e4)});if(!a.ok)continue;const n=await a.json();for(const i of n.plugins??[]){const c=`${i.id} ${i.name} ${i.description??""}`.toLowerCase();(!t||c.includes(t.toLowerCase()))&&e.push(i)}}catch{}return e}
|