@poolzin/pool-bot 2026.2.25 → 2026.2.26
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/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +7 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +93 -11
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +2 -2
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +4 -3
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +4 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +9 -1
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +2 -2
- package/dist/browser/server-context.js +7 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +2 -1
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/cli/banner.js +1 -1
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-media-utils.js +7 -2
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +34 -41
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/command-registry.js +2 -11
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +11 -7
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +22 -2
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +30 -16
- package/dist/config/config-paths.js +9 -11
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-vars.js +37 -8
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +97 -12
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +4 -0
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.js +148 -13
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/discord/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +34 -10
- package/dist/gateway/call.js +4 -16
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/net.js +54 -12
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +1 -0
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/protocol/index.js +4 -3
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +16 -7
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/chat.js +10 -6
- package/dist/gateway/server-methods/config.js +12 -14
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-runtime-config.js +34 -13
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +6 -5
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +108 -29
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +122 -0
- package/dist/infra/exec-approvals-analysis.js +34 -3
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +53 -45
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +93 -2
- package/dist/security/audit-extra.async.js +159 -5
- package/dist/security/audit-extra.js +1 -1
- package/dist/security/audit-extra.sync.js +85 -6
- package/dist/security/audit.js +40 -4
- package/dist/security/dm-policy-shared.js +44 -0
- package/dist/security/external-content.js +26 -6
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +8 -3
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +155 -90
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +14 -1
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/theme.js +12 -12
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +41 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +58 -6
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +123 -16
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import readline from "node:readline";
|
|
|
6
6
|
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
|
7
7
|
import { resolveStateDir } from "../config/paths.js";
|
|
8
8
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
9
|
+
import { isFileMissingError, statRegularFile } from "./fs-utils.js";
|
|
9
10
|
import { deriveQmdScopeChannel, deriveQmdScopeChatType, isQmdScopeAllowed } from "./qmd-scope.js";
|
|
10
11
|
import { listSessionFilesForAgent, buildSessionEntry, } from "./session-files.js";
|
|
11
12
|
import { requireNodeSqlite } from "./sqlite.js";
|
|
@@ -15,6 +16,23 @@ const SNIPPET_HEADER_RE = /@@\s*-([0-9]+),([0-9]+)/;
|
|
|
15
16
|
const SEARCH_PENDING_UPDATE_WAIT_MS = 500;
|
|
16
17
|
const MAX_QMD_OUTPUT_CHARS = 200_000;
|
|
17
18
|
const NUL_MARKER_RE = /(?:\^@|\\0|\\x00|\\u0000|null\s*byte|nul\s*byte)/i;
|
|
19
|
+
const QMD_EMBED_BACKOFF_BASE_MS = 60_000;
|
|
20
|
+
const QMD_EMBED_BACKOFF_MAX_MS = 60 * 60 * 1000;
|
|
21
|
+
let qmdEmbedQueueTail = Promise.resolve();
|
|
22
|
+
async function runWithQmdEmbedLock(task) {
|
|
23
|
+
const previous = qmdEmbedQueueTail;
|
|
24
|
+
let release;
|
|
25
|
+
qmdEmbedQueueTail = new Promise((resolve) => {
|
|
26
|
+
release = resolve;
|
|
27
|
+
});
|
|
28
|
+
await previous.catch(() => undefined);
|
|
29
|
+
try {
|
|
30
|
+
return await task();
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
release?.();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
18
36
|
export class QmdMemoryManager {
|
|
19
37
|
static async create(params) {
|
|
20
38
|
const resolved = params.resolved.qmd;
|
|
@@ -50,6 +68,8 @@ export class QmdMemoryManager {
|
|
|
50
68
|
db = null;
|
|
51
69
|
lastUpdateAt = null;
|
|
52
70
|
lastEmbedAt = null;
|
|
71
|
+
embedBackoffUntil = null;
|
|
72
|
+
embedFailureCount = 0;
|
|
53
73
|
attemptedNullByteCollectionRepair = false;
|
|
54
74
|
constructor(params) {
|
|
55
75
|
this.cfg = params.cfg;
|
|
@@ -179,6 +199,7 @@ export class QmdMemoryManager {
|
|
|
179
199
|
catch {
|
|
180
200
|
// ignore; older qmd versions might not support list --json.
|
|
181
201
|
}
|
|
202
|
+
await this.migrateLegacyUnscopedCollections(existing);
|
|
182
203
|
for (const collection of this.qmd.collections) {
|
|
183
204
|
const listed = existing.get(collection.name);
|
|
184
205
|
if (listed && !this.shouldRebindCollection(collection, listed)) {
|
|
@@ -208,6 +229,52 @@ export class QmdMemoryManager {
|
|
|
208
229
|
}
|
|
209
230
|
}
|
|
210
231
|
}
|
|
232
|
+
async migrateLegacyUnscopedCollections(existing) {
|
|
233
|
+
for (const collection of this.qmd.collections) {
|
|
234
|
+
if (existing.has(collection.name)) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const legacyName = this.deriveLegacyCollectionName(collection.name);
|
|
238
|
+
if (!legacyName) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const listedLegacy = existing.get(legacyName);
|
|
242
|
+
if (!listedLegacy) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (!this.canMigrateLegacyCollection(collection, listedLegacy)) {
|
|
246
|
+
log.debug(`qmd legacy collection migration skipped for ${legacyName} (path/pattern mismatch)`);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
await this.removeCollection(legacyName);
|
|
251
|
+
existing.delete(legacyName);
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
255
|
+
if (!this.isCollectionMissingError(message)) {
|
|
256
|
+
log.warn(`qmd collection remove failed for ${legacyName}: ${message}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
deriveLegacyCollectionName(scopedName) {
|
|
262
|
+
const agentSuffix = `-${this.sanitizeCollectionNameSegment(this.agentId)}`;
|
|
263
|
+
if (!scopedName.endsWith(agentSuffix)) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
const legacyName = scopedName.slice(0, -agentSuffix.length).trim();
|
|
267
|
+
return legacyName || null;
|
|
268
|
+
}
|
|
269
|
+
canMigrateLegacyCollection(collection, listedLegacy) {
|
|
270
|
+
if (listedLegacy.path && !this.pathsMatch(listedLegacy.path, collection.path)) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (typeof listedLegacy.pattern === "string" && listedLegacy.pattern !== collection.pattern) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
211
278
|
async ensureCollectionPath(collection) {
|
|
212
279
|
if (!this.isDirectoryGlobPattern(collection.pattern)) {
|
|
213
280
|
return;
|
|
@@ -238,8 +305,8 @@ export class QmdMemoryManager {
|
|
|
238
305
|
shouldRebindCollection(collection, listed) {
|
|
239
306
|
if (!listed.path) {
|
|
240
307
|
// Older qmd versions may only return names from `collection list --json`.
|
|
241
|
-
//
|
|
242
|
-
return
|
|
308
|
+
// Rebind managed collections so stale path bindings cannot survive upgrades.
|
|
309
|
+
return true;
|
|
243
310
|
}
|
|
244
311
|
if (!this.pathsMatch(listed.path, collection.path)) {
|
|
245
312
|
return true;
|
|
@@ -312,11 +379,40 @@ export class QmdMemoryManager {
|
|
|
312
379
|
log.warn("qmd query skipped: no managed collections configured");
|
|
313
380
|
return [];
|
|
314
381
|
}
|
|
315
|
-
const qmdSearchCommand = this.qmd.searchMode
|
|
382
|
+
const qmdSearchCommand = this.qmd.searchMode;
|
|
383
|
+
const mcporterEnabled = this.qmd.mcporter.enabled;
|
|
316
384
|
let parsed;
|
|
317
385
|
try {
|
|
318
|
-
if (
|
|
319
|
-
|
|
386
|
+
if (mcporterEnabled) {
|
|
387
|
+
const tool = qmdSearchCommand === "search"
|
|
388
|
+
? "search"
|
|
389
|
+
: qmdSearchCommand === "vsearch"
|
|
390
|
+
? "vector_search"
|
|
391
|
+
: "deep_search";
|
|
392
|
+
const minScore = opts?.minScore ?? 0;
|
|
393
|
+
if (collectionNames.length > 1) {
|
|
394
|
+
parsed = await this.runMcporterAcrossCollections({
|
|
395
|
+
tool,
|
|
396
|
+
query: trimmed,
|
|
397
|
+
limit,
|
|
398
|
+
minScore,
|
|
399
|
+
collectionNames,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
parsed = await this.runQmdSearchViaMcporter({
|
|
404
|
+
mcporter: this.qmd.mcporter,
|
|
405
|
+
tool,
|
|
406
|
+
query: trimmed,
|
|
407
|
+
limit,
|
|
408
|
+
minScore,
|
|
409
|
+
collection: collectionNames[0],
|
|
410
|
+
timeoutMs: this.qmd.limits.timeoutMs,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else if (collectionNames.length > 1) {
|
|
415
|
+
parsed = await this.runQueryAcrossCollections(trimmed, limit, collectionNames, qmdSearchCommand);
|
|
320
416
|
}
|
|
321
417
|
else {
|
|
322
418
|
const args = this.buildSearchArgs(qmdSearchCommand, trimmed, limit);
|
|
@@ -328,11 +424,13 @@ export class QmdMemoryManager {
|
|
|
328
424
|
}
|
|
329
425
|
}
|
|
330
426
|
catch (err) {
|
|
331
|
-
if (
|
|
427
|
+
if (!mcporterEnabled &&
|
|
428
|
+
qmdSearchCommand !== "query" &&
|
|
429
|
+
this.isUnsupportedQmdOptionError(err)) {
|
|
332
430
|
log.warn(`qmd ${qmdSearchCommand} does not support configured flags; retrying search with qmd query`);
|
|
333
431
|
try {
|
|
334
432
|
if (collectionNames.length > 1) {
|
|
335
|
-
parsed = await this.runQueryAcrossCollections(trimmed, limit, collectionNames);
|
|
433
|
+
parsed = await this.runQueryAcrossCollections(trimmed, limit, collectionNames, "query");
|
|
336
434
|
}
|
|
337
435
|
else {
|
|
338
436
|
const fallbackArgs = this.buildSearchArgs("query", trimmed, limit);
|
|
@@ -349,13 +447,17 @@ export class QmdMemoryManager {
|
|
|
349
447
|
}
|
|
350
448
|
}
|
|
351
449
|
else {
|
|
352
|
-
|
|
450
|
+
const label = mcporterEnabled ? "mcporter/qmd" : `qmd ${qmdSearchCommand}`;
|
|
451
|
+
log.warn(`${label} failed: ${String(err)}`);
|
|
353
452
|
throw err instanceof Error ? err : new Error(String(err));
|
|
354
453
|
}
|
|
355
454
|
}
|
|
356
455
|
const results = [];
|
|
357
456
|
for (const entry of parsed) {
|
|
358
|
-
const doc = await this.resolveDocLocation(entry.docid
|
|
457
|
+
const doc = await this.resolveDocLocation(entry.docid, {
|
|
458
|
+
preferredCollection: entry.collection,
|
|
459
|
+
preferredFile: entry.file,
|
|
460
|
+
});
|
|
359
461
|
if (!doc) {
|
|
360
462
|
continue;
|
|
361
463
|
}
|
|
@@ -375,7 +477,7 @@ export class QmdMemoryManager {
|
|
|
375
477
|
source: doc.source,
|
|
376
478
|
});
|
|
377
479
|
}
|
|
378
|
-
return this.clampResultsByInjectedChars(
|
|
480
|
+
return this.clampResultsByInjectedChars(this.diversifyResultsBySource(results, limit));
|
|
379
481
|
}
|
|
380
482
|
async sync(params) {
|
|
381
483
|
if (params?.progress) {
|
|
@@ -395,19 +497,25 @@ export class QmdMemoryManager {
|
|
|
395
497
|
if (!absPath.endsWith(".md")) {
|
|
396
498
|
throw new Error("path required");
|
|
397
499
|
}
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
|
|
500
|
+
const statResult = await statRegularFile(absPath);
|
|
501
|
+
if (statResult.missing) {
|
|
502
|
+
return { text: "", path: relPath };
|
|
401
503
|
}
|
|
402
504
|
if (params.from !== undefined || params.lines !== undefined) {
|
|
403
|
-
const
|
|
404
|
-
|
|
505
|
+
const partial = await this.readPartialText(absPath, params.from, params.lines);
|
|
506
|
+
if (partial.missing) {
|
|
507
|
+
return { text: "", path: relPath };
|
|
508
|
+
}
|
|
509
|
+
return { text: partial.text, path: relPath };
|
|
510
|
+
}
|
|
511
|
+
const full = await this.readFullText(absPath);
|
|
512
|
+
if (full.missing) {
|
|
513
|
+
return { text: "", path: relPath };
|
|
405
514
|
}
|
|
406
|
-
const content = await fs.readFile(absPath, "utf-8");
|
|
407
515
|
if (!params.from && !params.lines) {
|
|
408
|
-
return { text:
|
|
516
|
+
return { text: full.text, path: relPath };
|
|
409
517
|
}
|
|
410
|
-
const lines =
|
|
518
|
+
const lines = full.text.split("\n");
|
|
411
519
|
const start = Math.max(1, params.from ?? 1);
|
|
412
520
|
const count = Math.max(1, params.lines ?? lines.length);
|
|
413
521
|
const slice = lines.slice(start - 1, start - 1 + count);
|
|
@@ -491,26 +599,18 @@ export class QmdMemoryManager {
|
|
|
491
599
|
if (this.sessionExporter) {
|
|
492
600
|
await this.exportSessions();
|
|
493
601
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
catch (err) {
|
|
498
|
-
if (!(await this.tryRepairNullByteCollections(err, reason))) {
|
|
499
|
-
throw err;
|
|
500
|
-
}
|
|
501
|
-
await this.runQmd(["update"], { timeoutMs: this.qmd.update.updateTimeoutMs });
|
|
502
|
-
}
|
|
503
|
-
const embedIntervalMs = this.qmd.update.embedIntervalMs;
|
|
504
|
-
const shouldEmbed = Boolean(force) ||
|
|
505
|
-
this.lastEmbedAt === null ||
|
|
506
|
-
(embedIntervalMs > 0 && Date.now() - this.lastEmbedAt > embedIntervalMs);
|
|
507
|
-
if (shouldEmbed) {
|
|
602
|
+
await this.runQmdUpdateWithRetry(reason);
|
|
603
|
+
if (this.shouldRunEmbed(force)) {
|
|
508
604
|
try {
|
|
509
|
-
await
|
|
605
|
+
await runWithQmdEmbedLock(async () => {
|
|
606
|
+
await this.runQmd(["embed"], { timeoutMs: this.qmd.update.embedTimeoutMs });
|
|
607
|
+
});
|
|
510
608
|
this.lastEmbedAt = Date.now();
|
|
609
|
+
this.embedBackoffUntil = null;
|
|
610
|
+
this.embedFailureCount = 0;
|
|
511
611
|
}
|
|
512
612
|
catch (err) {
|
|
513
|
-
|
|
613
|
+
this.noteEmbedFailure(reason, err);
|
|
514
614
|
}
|
|
515
615
|
}
|
|
516
616
|
this.lastUpdateAt = Date.now();
|
|
@@ -521,6 +621,62 @@ export class QmdMemoryManager {
|
|
|
521
621
|
});
|
|
522
622
|
await this.pendingUpdate;
|
|
523
623
|
}
|
|
624
|
+
async runQmdUpdateWithRetry(reason) {
|
|
625
|
+
const isBootRun = reason === "boot" || reason.startsWith("boot:");
|
|
626
|
+
const maxAttempts = isBootRun ? 3 : 1;
|
|
627
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
628
|
+
try {
|
|
629
|
+
await this.runQmdUpdateOnce(reason);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
catch (err) {
|
|
633
|
+
if (attempt >= maxAttempts || !this.isRetryableUpdateError(err)) {
|
|
634
|
+
throw err;
|
|
635
|
+
}
|
|
636
|
+
const delayMs = 500 * 2 ** (attempt - 1);
|
|
637
|
+
log.warn(`qmd update retry ${attempt}/${maxAttempts - 1} after failure (${reason}): ${String(err)}`);
|
|
638
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async runQmdUpdateOnce(reason) {
|
|
643
|
+
try {
|
|
644
|
+
await this.runQmd(["update"], { timeoutMs: this.qmd.update.updateTimeoutMs });
|
|
645
|
+
}
|
|
646
|
+
catch (err) {
|
|
647
|
+
if (!(await this.tryRepairNullByteCollections(err, reason))) {
|
|
648
|
+
throw err;
|
|
649
|
+
}
|
|
650
|
+
await this.runQmd(["update"], { timeoutMs: this.qmd.update.updateTimeoutMs });
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
isRetryableUpdateError(err) {
|
|
654
|
+
if (this.isSqliteBusyError(err)) {
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
658
|
+
const normalized = message.toLowerCase();
|
|
659
|
+
return normalized.includes("timed out");
|
|
660
|
+
}
|
|
661
|
+
shouldRunEmbed(force) {
|
|
662
|
+
if (this.qmd.searchMode === "search") {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
const now = Date.now();
|
|
666
|
+
if (this.embedBackoffUntil !== null && now < this.embedBackoffUntil) {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
const embedIntervalMs = this.qmd.update.embedIntervalMs;
|
|
670
|
+
return (Boolean(force) ||
|
|
671
|
+
this.lastEmbedAt === null ||
|
|
672
|
+
(embedIntervalMs > 0 && now - this.lastEmbedAt > embedIntervalMs));
|
|
673
|
+
}
|
|
674
|
+
noteEmbedFailure(reason, err) {
|
|
675
|
+
this.embedFailureCount += 1;
|
|
676
|
+
const delayMs = Math.min(QMD_EMBED_BACKOFF_MAX_MS, QMD_EMBED_BACKOFF_BASE_MS * 2 ** Math.max(0, this.embedFailureCount - 1));
|
|
677
|
+
this.embedBackoffUntil = Date.now() + delayMs;
|
|
678
|
+
log.warn(`qmd embed failed (${reason}): ${String(err)}; backing off for ${Math.ceil(delayMs / 1000)}s`);
|
|
679
|
+
}
|
|
524
680
|
enqueueForcedUpdate(reason) {
|
|
525
681
|
this.queuedForcedRuns += 1;
|
|
526
682
|
if (!this.queuedForcedUpdate) {
|
|
@@ -650,10 +806,144 @@ export class QmdMemoryManager {
|
|
|
650
806
|
});
|
|
651
807
|
});
|
|
652
808
|
}
|
|
809
|
+
async ensureMcporterDaemonStarted(mcporter) {
|
|
810
|
+
if (!mcporter.enabled) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (!mcporter.startDaemon) {
|
|
814
|
+
const g = globalThis;
|
|
815
|
+
if (!g.__poolbotMcporterColdStartWarned) {
|
|
816
|
+
g.__poolbotMcporterColdStartWarned = true;
|
|
817
|
+
log.warn("mcporter qmd bridge enabled but startDaemon=false; each query may cold-start QMD MCP. Consider setting memory.qmd.mcporter.startDaemon=true to keep it warm.");
|
|
818
|
+
}
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const g = globalThis;
|
|
822
|
+
if (!g.__poolbotMcporterDaemonStart) {
|
|
823
|
+
g.__poolbotMcporterDaemonStart = (async () => {
|
|
824
|
+
try {
|
|
825
|
+
await this.runMcporter(["daemon", "start"], { timeoutMs: 10_000 });
|
|
826
|
+
}
|
|
827
|
+
catch (err) {
|
|
828
|
+
log.warn(`mcporter daemon start failed: ${String(err)}`);
|
|
829
|
+
// Allow future searches to retry daemon start on transient failures.
|
|
830
|
+
delete g.__poolbotMcporterDaemonStart;
|
|
831
|
+
}
|
|
832
|
+
})();
|
|
833
|
+
}
|
|
834
|
+
await g.__poolbotMcporterDaemonStart;
|
|
835
|
+
}
|
|
836
|
+
async runMcporter(args, opts) {
|
|
837
|
+
return await new Promise((resolve, reject) => {
|
|
838
|
+
const child = spawn("mcporter", args, {
|
|
839
|
+
// Keep mcporter and direct qmd commands on the same agent-scoped XDG state.
|
|
840
|
+
env: this.env,
|
|
841
|
+
cwd: this.workspaceDir,
|
|
842
|
+
});
|
|
843
|
+
let stdout = "";
|
|
844
|
+
let stderr = "";
|
|
845
|
+
let stdoutTruncated = false;
|
|
846
|
+
let stderrTruncated = false;
|
|
847
|
+
const timer = opts?.timeoutMs
|
|
848
|
+
? setTimeout(() => {
|
|
849
|
+
child.kill("SIGKILL");
|
|
850
|
+
reject(new Error(`mcporter ${args.join(" ")} timed out after ${opts.timeoutMs}ms`));
|
|
851
|
+
}, opts.timeoutMs)
|
|
852
|
+
: null;
|
|
853
|
+
child.stdout.on("data", (data) => {
|
|
854
|
+
const next = appendOutputWithCap(stdout, data.toString("utf8"), this.maxQmdOutputChars);
|
|
855
|
+
stdout = next.text;
|
|
856
|
+
stdoutTruncated = stdoutTruncated || next.truncated;
|
|
857
|
+
});
|
|
858
|
+
child.stderr.on("data", (data) => {
|
|
859
|
+
const next = appendOutputWithCap(stderr, data.toString("utf8"), this.maxQmdOutputChars);
|
|
860
|
+
stderr = next.text;
|
|
861
|
+
stderrTruncated = stderrTruncated || next.truncated;
|
|
862
|
+
});
|
|
863
|
+
child.on("error", (err) => {
|
|
864
|
+
if (timer) {
|
|
865
|
+
clearTimeout(timer);
|
|
866
|
+
}
|
|
867
|
+
reject(err);
|
|
868
|
+
});
|
|
869
|
+
child.on("close", (code) => {
|
|
870
|
+
if (timer) {
|
|
871
|
+
clearTimeout(timer);
|
|
872
|
+
}
|
|
873
|
+
if (stdoutTruncated || stderrTruncated) {
|
|
874
|
+
reject(new Error(`mcporter ${args.join(" ")} produced too much output (limit ${this.maxQmdOutputChars} chars)`));
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (code === 0) {
|
|
878
|
+
resolve({ stdout, stderr });
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
reject(new Error(`mcporter ${args.join(" ")} failed (code ${code}): ${stderr || stdout}`));
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
async runQmdSearchViaMcporter(params) {
|
|
887
|
+
await this.ensureMcporterDaemonStarted(params.mcporter);
|
|
888
|
+
const selector = `${params.mcporter.serverName}.${params.tool}`;
|
|
889
|
+
const callArgs = {
|
|
890
|
+
query: params.query,
|
|
891
|
+
limit: params.limit,
|
|
892
|
+
minScore: params.minScore,
|
|
893
|
+
};
|
|
894
|
+
if (params.collection) {
|
|
895
|
+
callArgs.collection = params.collection;
|
|
896
|
+
}
|
|
897
|
+
const result = await this.runMcporter([
|
|
898
|
+
"call",
|
|
899
|
+
selector,
|
|
900
|
+
"--args",
|
|
901
|
+
JSON.stringify(callArgs),
|
|
902
|
+
"--output",
|
|
903
|
+
"json",
|
|
904
|
+
"--timeout",
|
|
905
|
+
String(Math.max(0, params.timeoutMs)),
|
|
906
|
+
], { timeoutMs: Math.max(params.timeoutMs + 2_000, 5_000) });
|
|
907
|
+
const parsedUnknown = JSON.parse(result.stdout);
|
|
908
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
909
|
+
const structured = isRecord(parsedUnknown) && isRecord(parsedUnknown.structuredContent)
|
|
910
|
+
? parsedUnknown.structuredContent
|
|
911
|
+
: parsedUnknown;
|
|
912
|
+
const results = isRecord(structured) && Array.isArray(structured.results)
|
|
913
|
+
? structured.results
|
|
914
|
+
: Array.isArray(structured)
|
|
915
|
+
? structured
|
|
916
|
+
: [];
|
|
917
|
+
const out = [];
|
|
918
|
+
for (const item of results) {
|
|
919
|
+
if (!isRecord(item)) {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
const docidRaw = item.docid;
|
|
923
|
+
const docid = typeof docidRaw === "string" ? docidRaw.replace(/^#/, "").trim() : "";
|
|
924
|
+
if (!docid) {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
const scoreRaw = item.score;
|
|
928
|
+
const score = typeof scoreRaw === "number" ? scoreRaw : Number(scoreRaw);
|
|
929
|
+
const snippet = typeof item.snippet === "string" ? item.snippet : "";
|
|
930
|
+
out.push({ docid, score: Number.isFinite(score) ? score : 0, snippet });
|
|
931
|
+
}
|
|
932
|
+
return out;
|
|
933
|
+
}
|
|
653
934
|
async readPartialText(absPath, from, lines) {
|
|
654
935
|
const start = Math.max(1, from ?? 1);
|
|
655
936
|
const count = Math.max(1, lines ?? Number.POSITIVE_INFINITY);
|
|
656
|
-
|
|
937
|
+
let handle;
|
|
938
|
+
try {
|
|
939
|
+
handle = await fs.open(absPath);
|
|
940
|
+
}
|
|
941
|
+
catch (err) {
|
|
942
|
+
if (isFileMissingError(err)) {
|
|
943
|
+
return { missing: true };
|
|
944
|
+
}
|
|
945
|
+
throw err;
|
|
946
|
+
}
|
|
657
947
|
const stream = handle.createReadStream({ encoding: "utf-8" });
|
|
658
948
|
const rl = readline.createInterface({
|
|
659
949
|
input: stream,
|
|
@@ -677,7 +967,19 @@ export class QmdMemoryManager {
|
|
|
677
967
|
rl.close();
|
|
678
968
|
await handle.close();
|
|
679
969
|
}
|
|
680
|
-
return selected.slice(0, count).join("\n");
|
|
970
|
+
return { missing: false, text: selected.slice(0, count).join("\n") };
|
|
971
|
+
}
|
|
972
|
+
async readFullText(absPath) {
|
|
973
|
+
try {
|
|
974
|
+
const text = await fs.readFile(absPath, "utf-8");
|
|
975
|
+
return { missing: false, text };
|
|
976
|
+
}
|
|
977
|
+
catch (err) {
|
|
978
|
+
if (isFileMissingError(err)) {
|
|
979
|
+
return { missing: true };
|
|
980
|
+
}
|
|
981
|
+
throw err;
|
|
982
|
+
}
|
|
681
983
|
}
|
|
682
984
|
ensureDb() {
|
|
683
985
|
if (this.db) {
|
|
@@ -762,7 +1064,7 @@ export class QmdMemoryManager {
|
|
|
762
1064
|
const trimmed = lower.replace(/^-+|-+$/g, "");
|
|
763
1065
|
return trimmed || "agent";
|
|
764
1066
|
}
|
|
765
|
-
async resolveDocLocation(docid) {
|
|
1067
|
+
async resolveDocLocation(docid, hints) {
|
|
766
1068
|
if (!docid) {
|
|
767
1069
|
return null;
|
|
768
1070
|
}
|
|
@@ -770,21 +1072,21 @@ export class QmdMemoryManager {
|
|
|
770
1072
|
if (!normalized) {
|
|
771
1073
|
return null;
|
|
772
1074
|
}
|
|
773
|
-
const
|
|
1075
|
+
const cacheKey = `${hints?.preferredCollection ?? "*"}:${normalized}`;
|
|
1076
|
+
const cached = this.docPathCache.get(cacheKey);
|
|
774
1077
|
if (cached) {
|
|
775
1078
|
return cached;
|
|
776
1079
|
}
|
|
777
1080
|
const db = this.ensureDb();
|
|
778
|
-
let
|
|
1081
|
+
let rows = [];
|
|
779
1082
|
try {
|
|
780
|
-
|
|
781
|
-
.prepare("SELECT collection, path FROM documents WHERE hash = ? AND active = 1
|
|
782
|
-
.
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
.
|
|
787
|
-
.get(`${normalized}%`);
|
|
1083
|
+
rows = db
|
|
1084
|
+
.prepare("SELECT collection, path FROM documents WHERE hash = ? AND active = 1")
|
|
1085
|
+
.all(normalized);
|
|
1086
|
+
if (rows.length === 0) {
|
|
1087
|
+
rows = db
|
|
1088
|
+
.prepare("SELECT collection, path FROM documents WHERE hash LIKE ? AND active = 1")
|
|
1089
|
+
.all(`${normalized}%`);
|
|
788
1090
|
}
|
|
789
1091
|
}
|
|
790
1092
|
catch (err) {
|
|
@@ -794,16 +1096,49 @@ export class QmdMemoryManager {
|
|
|
794
1096
|
}
|
|
795
1097
|
throw err;
|
|
796
1098
|
}
|
|
797
|
-
if (
|
|
1099
|
+
if (rows.length === 0) {
|
|
798
1100
|
return null;
|
|
799
1101
|
}
|
|
800
|
-
const location = this.
|
|
1102
|
+
const location = this.pickDocLocation(rows, hints);
|
|
801
1103
|
if (!location) {
|
|
802
1104
|
return null;
|
|
803
1105
|
}
|
|
804
|
-
this.docPathCache.set(
|
|
1106
|
+
this.docPathCache.set(cacheKey, location);
|
|
805
1107
|
return location;
|
|
806
1108
|
}
|
|
1109
|
+
pickDocLocation(rows, hints) {
|
|
1110
|
+
if (hints?.preferredCollection) {
|
|
1111
|
+
for (const row of rows) {
|
|
1112
|
+
if (row.collection !== hints.preferredCollection) {
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
const location = this.toDocLocation(row.collection, row.path);
|
|
1116
|
+
if (location) {
|
|
1117
|
+
return location;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (hints?.preferredFile) {
|
|
1122
|
+
const preferred = path.normalize(hints.preferredFile);
|
|
1123
|
+
for (const row of rows) {
|
|
1124
|
+
const rowPath = path.normalize(row.path);
|
|
1125
|
+
if (rowPath !== preferred && !rowPath.endsWith(path.sep + preferred)) {
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
const location = this.toDocLocation(row.collection, row.path);
|
|
1129
|
+
if (location) {
|
|
1130
|
+
return location;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
for (const row of rows) {
|
|
1135
|
+
const location = this.toDocLocation(row.collection, row.path);
|
|
1136
|
+
if (location) {
|
|
1137
|
+
return location;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
807
1142
|
extractSnippetLines(snippet) {
|
|
808
1143
|
const match = SNIPPET_HEADER_RE.exec(snippet);
|
|
809
1144
|
if (match) {
|
|
@@ -962,6 +1297,48 @@ export class QmdMemoryManager {
|
|
|
962
1297
|
}
|
|
963
1298
|
return clamped;
|
|
964
1299
|
}
|
|
1300
|
+
diversifyResultsBySource(results, limit) {
|
|
1301
|
+
const target = Math.max(0, limit);
|
|
1302
|
+
if (target <= 0) {
|
|
1303
|
+
return [];
|
|
1304
|
+
}
|
|
1305
|
+
if (results.length <= 1) {
|
|
1306
|
+
return results.slice(0, target);
|
|
1307
|
+
}
|
|
1308
|
+
const bySource = new Map();
|
|
1309
|
+
for (const entry of results) {
|
|
1310
|
+
const list = bySource.get(entry.source) ?? [];
|
|
1311
|
+
list.push(entry);
|
|
1312
|
+
bySource.set(entry.source, list);
|
|
1313
|
+
}
|
|
1314
|
+
const hasSessions = bySource.has("sessions");
|
|
1315
|
+
const hasMemory = bySource.has("memory");
|
|
1316
|
+
if (!hasSessions || !hasMemory) {
|
|
1317
|
+
return results.slice(0, target);
|
|
1318
|
+
}
|
|
1319
|
+
const sourceOrder = Array.from(bySource.entries())
|
|
1320
|
+
.toSorted((a, b) => (b[1][0]?.score ?? 0) - (a[1][0]?.score ?? 0))
|
|
1321
|
+
.map(([source]) => source);
|
|
1322
|
+
const diversified = [];
|
|
1323
|
+
while (diversified.length < target) {
|
|
1324
|
+
let emitted = false;
|
|
1325
|
+
for (const source of sourceOrder) {
|
|
1326
|
+
const next = bySource.get(source)?.shift();
|
|
1327
|
+
if (!next) {
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
diversified.push(next);
|
|
1331
|
+
emitted = true;
|
|
1332
|
+
if (diversified.length >= target) {
|
|
1333
|
+
break;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (!emitted) {
|
|
1337
|
+
break;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
return diversified;
|
|
1341
|
+
}
|
|
965
1342
|
shouldSkipUpdate(force) {
|
|
966
1343
|
if (force) {
|
|
967
1344
|
return false;
|
|
@@ -1003,14 +1380,50 @@ export class QmdMemoryManager {
|
|
|
1003
1380
|
new Promise((resolve) => setTimeout(resolve, SEARCH_PENDING_UPDATE_WAIT_MS)),
|
|
1004
1381
|
]);
|
|
1005
1382
|
}
|
|
1006
|
-
async runQueryAcrossCollections(query, limit, collectionNames) {
|
|
1007
|
-
log.debug(`qmd
|
|
1383
|
+
async runQueryAcrossCollections(query, limit, collectionNames, command) {
|
|
1384
|
+
log.debug(`qmd ${command} multi-collection workaround active (${collectionNames.length} collections)`);
|
|
1008
1385
|
const bestByDocId = new Map();
|
|
1009
1386
|
for (const collectionName of collectionNames) {
|
|
1010
|
-
const args = this.buildSearchArgs(
|
|
1387
|
+
const args = this.buildSearchArgs(command, query, limit);
|
|
1011
1388
|
args.push("-c", collectionName);
|
|
1012
1389
|
const result = await this.runQmd(args, { timeoutMs: this.qmd.limits.timeoutMs });
|
|
1013
1390
|
const parsed = parseQmdQueryJson(result.stdout, result.stderr);
|
|
1391
|
+
for (const entry of parsed) {
|
|
1392
|
+
const normalizedDocId = typeof entry.docid === "string" && entry.docid.trim().length > 0
|
|
1393
|
+
? entry.docid
|
|
1394
|
+
: undefined;
|
|
1395
|
+
if (!normalizedDocId) {
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
const withCollection = {
|
|
1399
|
+
...entry,
|
|
1400
|
+
docid: normalizedDocId,
|
|
1401
|
+
collection: entry.collection ?? collectionName,
|
|
1402
|
+
};
|
|
1403
|
+
const prev = bestByDocId.get(normalizedDocId);
|
|
1404
|
+
const prevScore = typeof prev?.score === "number" ? prev.score : Number.NEGATIVE_INFINITY;
|
|
1405
|
+
const nextScore = typeof withCollection.score === "number"
|
|
1406
|
+
? withCollection.score
|
|
1407
|
+
: Number.NEGATIVE_INFINITY;
|
|
1408
|
+
if (!prev || nextScore > prevScore) {
|
|
1409
|
+
bestByDocId.set(normalizedDocId, withCollection);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return [...bestByDocId.values()].toSorted((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
1414
|
+
}
|
|
1415
|
+
async runMcporterAcrossCollections(params) {
|
|
1416
|
+
const bestByDocId = new Map();
|
|
1417
|
+
for (const collectionName of params.collectionNames) {
|
|
1418
|
+
const parsed = await this.runQmdSearchViaMcporter({
|
|
1419
|
+
mcporter: this.qmd.mcporter,
|
|
1420
|
+
tool: params.tool,
|
|
1421
|
+
query: params.query,
|
|
1422
|
+
limit: params.limit,
|
|
1423
|
+
minScore: params.minScore,
|
|
1424
|
+
collection: collectionName,
|
|
1425
|
+
timeoutMs: this.qmd.limits.timeoutMs,
|
|
1426
|
+
});
|
|
1014
1427
|
for (const entry of parsed) {
|
|
1015
1428
|
if (typeof entry.docid !== "string" || !entry.docid.trim()) {
|
|
1016
1429
|
continue;
|