@poolzin/pool-bot 2026.1.39 → 2026.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/chrome-extension/README.md +3 -3
- package/assets/chrome-extension/background.js +5 -5
- package/assets/chrome-extension/manifest.json +3 -3
- package/assets/chrome-extension/options.html +4 -4
- package/assets/chrome-extension/options.js +1 -1
- package/dist/acp/client.js +3 -3
- package/dist/acp/types.js +1 -1
- package/dist/agents/agent-paths.js +3 -3
- package/dist/agents/auth-profiles/paths.js +3 -3
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +10 -12
- package/dist/agents/cli-runner.js +2 -2
- package/dist/agents/cloudflare-ai-gateway.js +31 -0
- package/dist/agents/compaction.js +16 -2
- package/dist/agents/context-window-guard.js +13 -10
- package/dist/agents/context.js +4 -4
- package/dist/agents/docs-path.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/minimax-vlm.js +1 -1
- package/dist/agents/model-auth.js +12 -1
- package/dist/agents/model-catalog.js +4 -4
- package/dist/agents/model-selection.js +31 -4
- package/dist/agents/models-config.js +3 -3
- package/dist/agents/models-config.providers.js +147 -39
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers/openai.js +1 -1
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +9 -8
- package/dist/agents/pi-embedded-runner/model.js +63 -4
- package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
- package/dist/agents/pi-embedded-runner/run.js +203 -50
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
- package/dist/agents/pi-embedded-runner/utils.js +1 -1
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-model-discovery.js +10 -0
- package/dist/agents/pi-tool-definition-adapter.js +50 -9
- package/dist/agents/pi-tools.before-tool-call.js +67 -0
- package/dist/agents/pi-tools.js +20 -10
- package/dist/agents/pi-tools.read.js +2 -2
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-file-repair.js +83 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/session-transcript-repair.js +68 -0
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills/frontmatter.js +1 -1
- package/dist/agents/skills/workspace.js +2 -2
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/system-prompt.js +28 -4
- package/dist/agents/together-models.js +127 -0
- package/dist/agents/tool-images.js +1 -1
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +25 -1
- package/dist/agents/tools/browser-tool.js +3 -3
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +2 -2
- package/dist/agents/tools/memory-tool.js +93 -5
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/commands-registry.data.js +1 -1
- package/dist/auto-reply/envelope.js +50 -72
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +3 -2
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/commands-session.js +2 -2
- package/dist/auto-reply/reply/get-reply-run.js +16 -5
- package/dist/auto-reply/reply/groups.js +1 -1
- package/dist/auto-reply/reply/inbound-context.js +9 -1
- package/dist/auto-reply/reply/inbound-meta.js +130 -0
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/reply/untrusted-context.js +15 -0
- package/dist/auto-reply/status.js +1 -1
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +51 -8
- package/dist/browser/config.js +2 -11
- package/dist/browser/extension-relay.js +104 -43
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui.js +3 -3
- package/dist/channels/plugins/catalog.js +2 -2
- package/dist/channels/plugins/onboarding/imessage.js +1 -1
- package/dist/channels/plugins/onboarding/signal.js +1 -1
- package/dist/channels/plugins/onboarding/slack.js +4 -4
- package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
- package/dist/channels/plugins/pairing-message.js +1 -1
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/browser-cli-extension.js +2 -2
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/docs-cli.js +1 -1
- package/dist/cli/gateway-cli/dev.js +1 -1
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +30 -20
- package/dist/cli/nodes-cli/register.canvas.js +1 -1
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/plugins-cli.js +1 -1
- package/dist/cli/run-main.js +2 -2
- package/dist/cli/security-cli.js +1 -1
- package/dist/cli/tagline.js +1 -1
- package/dist/cli/update-cli.js +173 -52
- package/dist/cli/webhooks-cli.js +5 -5
- package/dist/commands/agent.js +1 -0
- package/dist/commands/agents.commands.add.js +1 -1
- package/dist/commands/auth-choice.apply.api-providers.js +305 -17
- package/dist/commands/auth-choice.apply.js +4 -1
- package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
- package/dist/commands/auth-choice.apply.xai.js +63 -0
- package/dist/commands/auth-choice.preferred-provider.js +7 -1
- package/dist/commands/configure.wizard.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-gateway-services.js +3 -3
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/doctor-update.js +3 -3
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.probe.js +2 -2
- package/dist/commands/models/list.registry.js +4 -4
- package/dist/commands/models/list.status-command.js +44 -24
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-auth.config-core.js +366 -28
- package/dist/commands/onboard-auth.credentials.js +71 -9
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +26 -24
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/commands/status-all/report-lines.js +1 -1
- package/dist/commands/status.command.js +1 -1
- package/dist/commands/uninstall.js +3 -3
- package/dist/compat/legacy-names.js +1 -1
- package/dist/config/defaults.js +3 -2
- package/dist/config/io.js +3 -3
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +3 -3
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/types.memory.js +1 -0
- package/dist/config/version.js +4 -4
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +171 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/daemon/constants.js +7 -7
- package/dist/daemon/inspect.js +6 -6
- package/dist/daemon/systemd-unit.js +1 -1
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/live-image-probe.js +1 -66
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/openai-http.js +2 -2
- package/dist/gateway/openresponses-http.js +4 -4
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +110 -12
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +7 -3
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/hooks/frontmatter.js +1 -1
- package/dist/hooks/hooks-status.js +1 -1
- package/dist/hooks/install.js +2 -2
- package/dist/hooks/loader.js +1 -1
- package/dist/hooks/workspace.js +3 -3
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/index.js +2 -2
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/bonjour.js +3 -3
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/provider-usage.fetch.minimax.js +1 -1
- package/dist/infra/restart.js +1 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/tailscale.js +1 -1
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/macos/relay.js +2 -2
- package/dist/media/fetch.js +81 -58
- package/dist/media/input-files.js +1 -1
- package/dist/media/mime.js +4 -0
- package/dist/media/png-encode.js +74 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +4 -4
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/backend-config.js +207 -0
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +29 -17
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +155 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/memory/types.js +1 -0
- package/dist/node-host/runner.js +36 -26
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/pairing/pairing-messages.js +1 -1
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/discovery.js +1 -1
- package/dist/plugins/install.js +2 -2
- package/dist/plugins/source-display.js +51 -0
- package/dist/plugins/update.js +1 -1
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/audit.js +2 -2
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/text/reasoning-tags.js +52 -7
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +145 -0
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +38 -11
- package/dist/telegram/bot-message-dispatch.js +48 -15
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/test-helpers/workspace.js +11 -0
- package/dist/test-utils/channel-plugins.js +82 -0
- package/dist/test-utils/ports.js +73 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/shell-argv.js +61 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +55 -14
- package/dist/version.js +42 -5
- package/dist/web/qr-image.js +1 -61
- package/dist/wizard/onboarding.finalize.js +7 -7
- package/dist/wizard/onboarding.js +3 -3
- package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
- package/docs/_config.yml +2 -2
- package/docs/_layouts/default.html +9 -9
- package/docs/concepts/typebox.md +1 -1
- package/docs/docs.json +1 -1
- package/docs/northflank.mdx +7 -7
- package/docs/railway.mdx +3 -3
- package/docs/render.mdx +5 -5
- package/docs/start/lore.md +2 -2
- package/extensions/bluebubbles/index.ts +2 -2
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/bluebubbles/src/accounts.ts +8 -8
- package/extensions/bluebubbles/src/actions.test.ts +22 -22
- package/extensions/bluebubbles/src/actions.ts +5 -5
- package/extensions/bluebubbles/src/attachments.ts +2 -2
- package/extensions/bluebubbles/src/channel.ts +16 -16
- package/extensions/bluebubbles/src/chat.ts +2 -2
- package/extensions/bluebubbles/src/media-send.ts +2 -2
- package/extensions/bluebubbles/src/monitor.test.ts +46 -46
- package/extensions/bluebubbles/src/monitor.ts +5 -5
- package/extensions/bluebubbles/src/onboarding.ts +7 -7
- package/extensions/bluebubbles/src/reactions.ts +2 -2
- package/extensions/bluebubbles/src/send.ts +2 -2
- package/extensions/copilot-proxy/README.md +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/diagnostics-otel/src/service.ts +3 -3
- package/extensions/discord/index.ts +2 -2
- package/extensions/discord/package.json +1 -1
- package/extensions/google-antigravity-auth/README.md +1 -1
- package/extensions/google-antigravity-auth/index.ts +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/README.md +1 -1
- package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/index.ts +3 -3
- package/extensions/googlechat/package.json +1 -1
- package/extensions/googlechat/src/accounts.ts +8 -8
- package/extensions/googlechat/src/actions.ts +6 -6
- package/extensions/googlechat/src/channel.ts +21 -21
- package/extensions/googlechat/src/monitor.ts +8 -8
- package/extensions/googlechat/src/onboarding.ts +10 -10
- package/extensions/imessage/index.ts +2 -2
- package/extensions/imessage/package.json +1 -1
- package/extensions/line/index.ts +2 -2
- package/extensions/line/package.json +1 -1
- package/extensions/line/src/card-command.ts +2 -2
- package/extensions/line/src/channel.logout.test.ts +4 -4
- package/extensions/line/src/channel.sendPayload.test.ts +8 -8
- package/extensions/line/src/channel.ts +3 -3
- package/extensions/llm-task/README.md +3 -3
- package/extensions/llm-task/index.ts +2 -2
- package/extensions/llm-task/package.json +1 -1
- package/extensions/llm-task/src/llm-task-tool.ts +4 -4
- package/extensions/lobster/README.md +6 -6
- package/extensions/lobster/index.ts +2 -2
- package/extensions/lobster/src/lobster-tool.test.ts +4 -4
- package/extensions/lobster/src/lobster-tool.ts +2 -2
- package/extensions/matrix/index.ts +2 -2
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/client/config.ts +1 -1
- package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
- package/extensions/matrix/src/onboarding.ts +1 -1
- package/extensions/mattermost/index.ts +2 -2
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
- package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
- package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
- package/extensions/mattermost/src/onboarding.ts +2 -2
- package/extensions/memory-core/index.ts +2 -2
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/index.ts +3 -3
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/msteams/index.ts +2 -2
- package/extensions/msteams/package.json +1 -1
- package/extensions/msteams/src/channel.directory.test.ts +2 -2
- package/extensions/msteams/src/channel.ts +2 -2
- package/extensions/msteams/src/graph-upload.ts +4 -4
- package/extensions/msteams/src/monitor-handler.ts +2 -2
- package/extensions/msteams/src/monitor.ts +2 -2
- package/extensions/msteams/src/onboarding.ts +9 -9
- package/extensions/msteams/src/reply-dispatcher.ts +2 -2
- package/extensions/msteams/src/send-context.ts +2 -2
- package/extensions/msteams/src/send.ts +4 -4
- package/extensions/nextcloud-talk/index.ts +2 -2
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nextcloud-talk/src/channel.ts +7 -7
- package/extensions/nextcloud-talk/src/inbound.ts +7 -7
- package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
- package/extensions/nostr/README.md +2 -2
- package/extensions/nostr/index.ts +5 -5
- package/extensions/nostr/package.json +1 -1
- package/extensions/nostr/src/types.ts +4 -4
- package/extensions/open-prose/index.ts +2 -2
- package/extensions/qwen-portal-auth/README.md +1 -1
- package/extensions/signal/index.ts +2 -2
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/index.ts +2 -2
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/index.ts +2 -2
- package/extensions/telegram/package.json +1 -1
- package/extensions/telegram/src/channel.ts +2 -2
- package/extensions/tlon/README.md +2 -2
- package/extensions/tlon/index.ts +2 -2
- package/extensions/tlon/package.json +1 -1
- package/extensions/tlon/src/channel.ts +13 -13
- package/extensions/tlon/src/monitor/index.ts +3 -3
- package/extensions/tlon/src/onboarding.ts +3 -3
- package/extensions/tlon/src/types.ts +3 -3
- package/extensions/twitch/README.md +1 -1
- package/extensions/twitch/index.ts +2 -2
- package/extensions/twitch/package.json +1 -1
- package/extensions/twitch/src/config.ts +3 -3
- package/extensions/twitch/src/monitor.ts +3 -3
- package/extensions/twitch/src/onboarding.ts +9 -9
- package/extensions/twitch/src/outbound.test.ts +2 -2
- package/extensions/twitch/src/plugin.test.ts +2 -2
- package/extensions/twitch/src/plugin.ts +8 -8
- package/extensions/twitch/src/send.test.ts +2 -2
- package/extensions/twitch/src/send.ts +4 -4
- package/extensions/twitch/src/token.test.ts +8 -8
- package/extensions/twitch/src/token.ts +3 -3
- package/extensions/twitch/src/twitch-client.ts +3 -3
- package/extensions/twitch/src/types.ts +3 -3
- package/extensions/twitch/src/utils/markdown.ts +1 -1
- package/extensions/voice-call/README.md +3 -3
- package/extensions/voice-call/package.json +1 -1
- package/extensions/voice-call/src/core-bridge.ts +2 -2
- package/extensions/voice-call/src/response-generator.ts +1 -1
- package/extensions/whatsapp/index.ts +2 -2
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/README.md +1 -1
- package/extensions/zalo/index.ts +2 -2
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalo/src/accounts.ts +8 -8
- package/extensions/zalo/src/actions.ts +4 -4
- package/extensions/zalo/src/channel.directory.test.ts +2 -2
- package/extensions/zalo/src/channel.ts +18 -18
- package/extensions/zalo/src/monitor.ts +9 -9
- package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
- package/extensions/zalo/src/onboarding.ts +24 -24
- package/extensions/zalo/src/send.ts +2 -2
- package/extensions/zalouser/README.md +2 -2
- package/extensions/zalouser/index.ts +2 -2
- package/extensions/zalouser/package.json +1 -1
- package/extensions/zalouser/src/accounts.ts +9 -9
- package/extensions/zalouser/src/channel.ts +24 -24
- package/extensions/zalouser/src/monitor.ts +4 -4
- package/extensions/zalouser/src/onboarding.ts +28 -28
- package/package.json +13 -251
- package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
- package/skills/tmux/scripts/find-sessions.sh +1 -1
- package/CHANGELOG.md +0 -102
- package/README-header.png +0 -0
- package/git-hooks/pre-commit +0 -4
- package/scripts/format-staged.js +0 -148
- package/scripts/postinstall.js +0 -300
- package/scripts/setup-git-hooks.js +0 -96
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const TOOL_CALL_TYPES = new Set(["toolCall", "toolUse", "functionCall"]);
|
|
1
2
|
function extractToolCallsFromAssistant(msg) {
|
|
2
3
|
const content = msg.content;
|
|
3
4
|
if (!Array.isArray(content))
|
|
@@ -18,6 +19,18 @@ function extractToolCallsFromAssistant(msg) {
|
|
|
18
19
|
}
|
|
19
20
|
return toolCalls;
|
|
20
21
|
}
|
|
22
|
+
function isToolCallBlock(block) {
|
|
23
|
+
if (!block || typeof block !== "object") {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const type = block.type;
|
|
27
|
+
return typeof type === "string" && TOOL_CALL_TYPES.has(type);
|
|
28
|
+
}
|
|
29
|
+
function hasToolCallInput(block) {
|
|
30
|
+
const hasInput = "input" in block ? block.input !== undefined && block.input !== null : false;
|
|
31
|
+
const hasArguments = "arguments" in block ? block.arguments !== undefined && block.arguments !== null : false;
|
|
32
|
+
return hasInput || hasArguments;
|
|
33
|
+
}
|
|
21
34
|
function extractToolResultId(msg) {
|
|
22
35
|
const toolCallId = msg.toolCallId;
|
|
23
36
|
if (typeof toolCallId === "string" && toolCallId)
|
|
@@ -43,6 +56,51 @@ function makeMissingToolResult(params) {
|
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
58
|
export { makeMissingToolResult };
|
|
59
|
+
export function repairToolCallInputs(messages) {
|
|
60
|
+
let droppedToolCalls = 0;
|
|
61
|
+
let droppedAssistantMessages = 0;
|
|
62
|
+
let changed = false;
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const msg of messages) {
|
|
65
|
+
if (!msg || typeof msg !== "object") {
|
|
66
|
+
out.push(msg);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
70
|
+
out.push(msg);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const nextContent = [];
|
|
74
|
+
let droppedInMessage = 0;
|
|
75
|
+
for (const block of msg.content) {
|
|
76
|
+
if (isToolCallBlock(block) && !hasToolCallInput(block)) {
|
|
77
|
+
droppedToolCalls += 1;
|
|
78
|
+
droppedInMessage += 1;
|
|
79
|
+
changed = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
nextContent.push(block);
|
|
83
|
+
}
|
|
84
|
+
if (droppedInMessage > 0) {
|
|
85
|
+
if (nextContent.length === 0) {
|
|
86
|
+
droppedAssistantMessages += 1;
|
|
87
|
+
changed = true;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
out.push({ ...msg, content: nextContent });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
out.push(msg);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
messages: changed ? out : messages,
|
|
97
|
+
droppedToolCalls,
|
|
98
|
+
droppedAssistantMessages,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export function sanitizeToolCallInputs(messages) {
|
|
102
|
+
return repairToolCallInputs(messages).messages;
|
|
103
|
+
}
|
|
46
104
|
export function sanitizeToolUseResultPairing(messages) {
|
|
47
105
|
return repairToolUseResultPairing(messages).messages;
|
|
48
106
|
}
|
|
@@ -92,6 +150,16 @@ export function repairToolUseResultPairing(messages) {
|
|
|
92
150
|
continue;
|
|
93
151
|
}
|
|
94
152
|
const assistant = msg;
|
|
153
|
+
// Skip tool call extraction for aborted or errored assistant messages.
|
|
154
|
+
// When stopReason is "error" or "aborted", the tool_use blocks may be incomplete
|
|
155
|
+
// (e.g., partialJson: true) and should not have synthetic tool_results created.
|
|
156
|
+
// Creating synthetic results for incomplete tool calls causes API 400 errors:
|
|
157
|
+
// "unexpected tool_use_id found in tool_result blocks"
|
|
158
|
+
const stopReason = assistant.stopReason;
|
|
159
|
+
if (stopReason === "error" || stopReason === "aborted") {
|
|
160
|
+
out.push(msg);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
95
163
|
const toolCalls = extractToolCallsFromAssistant(assistant);
|
|
96
164
|
if (toolCalls.length === 0) {
|
|
97
165
|
out.push(msg);
|
|
@@ -53,6 +53,57 @@ function resolveShellFromPath(name) {
|
|
|
53
53
|
}
|
|
54
54
|
return undefined;
|
|
55
55
|
}
|
|
56
|
+
function normalizeShellName(value) {
|
|
57
|
+
const trimmed = value.trim();
|
|
58
|
+
if (!trimmed) {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
return path
|
|
62
|
+
.basename(trimmed)
|
|
63
|
+
.replace(/\.(exe|cmd|bat)$/i, "")
|
|
64
|
+
.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
65
|
+
}
|
|
66
|
+
export function detectRuntimeShell() {
|
|
67
|
+
const overrideShell = process.env.CLAWDBOT_SHELL?.trim();
|
|
68
|
+
if (overrideShell) {
|
|
69
|
+
const name = normalizeShellName(overrideShell);
|
|
70
|
+
if (name) {
|
|
71
|
+
return name;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (process.platform === "win32") {
|
|
75
|
+
if (process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {
|
|
76
|
+
return "pwsh";
|
|
77
|
+
}
|
|
78
|
+
return "powershell";
|
|
79
|
+
}
|
|
80
|
+
const envShell = process.env.SHELL?.trim();
|
|
81
|
+
if (envShell) {
|
|
82
|
+
const name = normalizeShellName(envShell);
|
|
83
|
+
if (name) {
|
|
84
|
+
return name;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {
|
|
88
|
+
return "pwsh";
|
|
89
|
+
}
|
|
90
|
+
if (process.env.BASH_VERSION) {
|
|
91
|
+
return "bash";
|
|
92
|
+
}
|
|
93
|
+
if (process.env.ZSH_VERSION) {
|
|
94
|
+
return "zsh";
|
|
95
|
+
}
|
|
96
|
+
if (process.env.FISH_VERSION) {
|
|
97
|
+
return "fish";
|
|
98
|
+
}
|
|
99
|
+
if (process.env.KSH_VERSION) {
|
|
100
|
+
return "ksh";
|
|
101
|
+
}
|
|
102
|
+
if (process.env.NU_VERSION || process.env.NUSHELL_VERSION) {
|
|
103
|
+
return "nu";
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
56
107
|
export function sanitizeBinaryOutput(text) {
|
|
57
108
|
const scrubbed = text.replace(/[\p{Format}\p{Surrogate}]/gu, "");
|
|
58
109
|
if (!scrubbed)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { loadSkillsFromDir } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
3
|
+
import { resolveBundledSkillsDir } from "./bundled-dir.js";
|
|
4
|
+
const skillsLogger = createSubsystemLogger("skills");
|
|
5
|
+
let hasWarnedMissingBundledDir = false;
|
|
6
|
+
export function resolveBundledSkillsContext(opts = {}) {
|
|
7
|
+
const dir = resolveBundledSkillsDir(opts);
|
|
8
|
+
const names = new Set();
|
|
9
|
+
if (!dir) {
|
|
10
|
+
if (!hasWarnedMissingBundledDir) {
|
|
11
|
+
hasWarnedMissingBundledDir = true;
|
|
12
|
+
skillsLogger.warn("Bundled skills directory could not be resolved; built-in skills may be missing.");
|
|
13
|
+
}
|
|
14
|
+
return { dir, names };
|
|
15
|
+
}
|
|
16
|
+
const result = loadSkillsFromDir({ dir, source: "poolbot-bundled" });
|
|
17
|
+
for (const skill of result.skills) {
|
|
18
|
+
if (skill.name.trim()) {
|
|
19
|
+
names.add(skill.name);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { dir, names };
|
|
23
|
+
}
|
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
4
|
+
function looksLikeSkillsDir(dir) {
|
|
5
|
+
try {
|
|
6
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
7
|
+
for (const entry of entries) {
|
|
8
|
+
if (entry.name.startsWith(".")) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
const fullPath = path.join(dir, entry.name);
|
|
12
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
if (fs.existsSync(path.join(fullPath, "SKILL.md"))) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
export function resolveBundledSkillsDir(opts = {}) {
|
|
5
28
|
const override = process.env.CLAWDBOT_BUNDLED_SKILLS_DIR?.trim();
|
|
6
29
|
if (override)
|
|
7
30
|
return override;
|
|
8
31
|
// bun --compile: ship a sibling `skills/` next to the executable.
|
|
9
32
|
try {
|
|
10
|
-
const
|
|
33
|
+
const execPath = opts.execPath ?? process.execPath;
|
|
34
|
+
const execDir = path.dirname(execPath);
|
|
11
35
|
const sibling = path.join(execDir, "skills");
|
|
12
36
|
if (fs.existsSync(sibling))
|
|
13
37
|
return sibling;
|
|
@@ -17,11 +41,21 @@ export function resolveBundledSkillsDir() {
|
|
|
17
41
|
}
|
|
18
42
|
// npm/dev: resolve `<packageRoot>/skills` relative to this module.
|
|
19
43
|
try {
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
44
|
+
const moduleUrl = opts.moduleUrl ?? import.meta.url;
|
|
45
|
+
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
|
|
46
|
+
// Walk up from this module to find the package root containing skills/
|
|
47
|
+
let current = moduleDir;
|
|
48
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
49
|
+
const candidate = path.join(current, "skills");
|
|
50
|
+
if (looksLikeSkillsDir(candidate)) {
|
|
51
|
+
return candidate;
|
|
52
|
+
}
|
|
53
|
+
const next = path.dirname(current);
|
|
54
|
+
if (next === current) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
current = next;
|
|
58
|
+
}
|
|
25
59
|
}
|
|
26
60
|
catch {
|
|
27
61
|
// ignore
|
|
@@ -67,7 +67,7 @@ function parseFrontmatterBool(value, fallback) {
|
|
|
67
67
|
const parsed = parseBooleanValue(value);
|
|
68
68
|
return parsed === undefined ? fallback : parsed;
|
|
69
69
|
}
|
|
70
|
-
export function
|
|
70
|
+
export function resolvePoolbotMetadata(frontmatter) {
|
|
71
71
|
const raw = getFrontmatterValue(frontmatter, "metadata");
|
|
72
72
|
if (!raw)
|
|
73
73
|
return undefined;
|
|
@@ -5,7 +5,7 @@ import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
|
5
5
|
import { CONFIG_DIR, resolveUserPath } from "../../utils.js";
|
|
6
6
|
import { resolveBundledSkillsDir } from "./bundled-dir.js";
|
|
7
7
|
import { shouldIncludeSkill } from "./config.js";
|
|
8
|
-
import { parseFrontmatter,
|
|
8
|
+
import { parseFrontmatter, resolvePoolbotMetadata, resolveSkillInvocationPolicy, } from "./frontmatter.js";
|
|
9
9
|
import { resolvePluginSkillDirs } from "./plugin-skills.js";
|
|
10
10
|
import { serializeByKey } from "./serialize.js";
|
|
11
11
|
const fsp = fs.promises;
|
|
@@ -129,7 +129,7 @@ function loadSkillEntries(workspaceDir, opts) {
|
|
|
129
129
|
return {
|
|
130
130
|
skill,
|
|
131
131
|
frontmatter,
|
|
132
|
-
metadata:
|
|
132
|
+
metadata: resolvePoolbotMetadata(frontmatter),
|
|
133
133
|
invocation: resolveSkillInvocationPolicy(frontmatter),
|
|
134
134
|
};
|
|
135
135
|
});
|
|
@@ -3,10 +3,45 @@ import path from "node:path";
|
|
|
3
3
|
import { Readable } from "node:stream";
|
|
4
4
|
import { pipeline } from "node:stream/promises";
|
|
5
5
|
import { resolveBrewExecutable } from "../infra/brew.js";
|
|
6
|
+
import { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
|
6
7
|
import { runCommandWithTimeout } from "../process/exec.js";
|
|
8
|
+
import { scanDirectoryWithSummary } from "../security/skill-scanner.js";
|
|
7
9
|
import { CONFIG_DIR, ensureDir, resolveUserPath } from "../utils.js";
|
|
8
10
|
import { hasBinary, loadWorkspaceSkillEntries, resolveSkillsInstallPreferences, } from "./skills.js";
|
|
9
11
|
import { resolveSkillKey } from "./skills/frontmatter.js";
|
|
12
|
+
function withWarnings(result, warnings) {
|
|
13
|
+
if (warnings.length === 0)
|
|
14
|
+
return result;
|
|
15
|
+
return { ...result, warnings };
|
|
16
|
+
}
|
|
17
|
+
function formatScanFindingDetail(finding) {
|
|
18
|
+
const severity = finding.severity.toUpperCase();
|
|
19
|
+
const loc = finding.line ? `${finding.file}:${finding.line}` : finding.file;
|
|
20
|
+
return `[${severity}] ${loc} — ${finding.message}`;
|
|
21
|
+
}
|
|
22
|
+
async function collectSkillInstallScanWarnings(entry) {
|
|
23
|
+
const skillDir = entry.skill.filePath ? path.dirname(entry.skill.filePath) : undefined;
|
|
24
|
+
if (!skillDir)
|
|
25
|
+
return [];
|
|
26
|
+
try {
|
|
27
|
+
const summary = await scanDirectoryWithSummary(skillDir);
|
|
28
|
+
if (summary.findings.length === 0)
|
|
29
|
+
return [];
|
|
30
|
+
const warnings = [];
|
|
31
|
+
const header = summary.critical > 0
|
|
32
|
+
? `⚠️ Security scan found ${summary.critical} critical finding(s).`
|
|
33
|
+
: `Security scan found ${summary.warn} warning(s).`;
|
|
34
|
+
warnings.push(header);
|
|
35
|
+
for (const finding of summary.findings) {
|
|
36
|
+
warnings.push(formatScanFindingDetail(finding));
|
|
37
|
+
}
|
|
38
|
+
warnings.push('Run "poolbot security audit --deep" for a full report.');
|
|
39
|
+
return warnings;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
10
45
|
function isNodeReadableStream(value) {
|
|
11
46
|
return Boolean(value && typeof value.pipe === "function");
|
|
12
47
|
}
|
|
@@ -110,10 +145,11 @@ function resolveArchiveType(spec, filename) {
|
|
|
110
145
|
return undefined;
|
|
111
146
|
}
|
|
112
147
|
async function downloadFile(url, destPath, timeoutMs) {
|
|
113
|
-
const
|
|
114
|
-
|
|
148
|
+
const { response, release } = await fetchWithSsrFGuard({
|
|
149
|
+
url,
|
|
150
|
+
timeoutMs: Math.max(1_000, timeoutMs),
|
|
151
|
+
});
|
|
115
152
|
try {
|
|
116
|
-
const response = await fetch(url, { signal: controller.signal });
|
|
117
153
|
if (!response.ok || !response.body) {
|
|
118
154
|
throw new Error(`Download failed (${response.status} ${response.statusText})`);
|
|
119
155
|
}
|
|
@@ -128,7 +164,7 @@ async function downloadFile(url, destPath, timeoutMs) {
|
|
|
128
164
|
return { bytes: stat.size };
|
|
129
165
|
}
|
|
130
166
|
finally {
|
|
131
|
-
|
|
167
|
+
await release();
|
|
132
168
|
}
|
|
133
169
|
}
|
|
134
170
|
async function extractArchive(params) {
|
|
@@ -261,39 +297,40 @@ export async function installSkill(params) {
|
|
|
261
297
|
code: null,
|
|
262
298
|
};
|
|
263
299
|
}
|
|
300
|
+
const warnings = await collectSkillInstallScanWarnings(entry);
|
|
264
301
|
const spec = findInstallSpec(entry, params.installId);
|
|
265
302
|
if (!spec) {
|
|
266
|
-
return {
|
|
303
|
+
return withWarnings({
|
|
267
304
|
ok: false,
|
|
268
305
|
message: `Installer not found: ${params.installId}`,
|
|
269
306
|
stdout: "",
|
|
270
307
|
stderr: "",
|
|
271
308
|
code: null,
|
|
272
|
-
};
|
|
309
|
+
}, warnings);
|
|
273
310
|
}
|
|
274
311
|
if (spec.kind === "download") {
|
|
275
|
-
return await installDownloadSpec({ entry, spec, timeoutMs });
|
|
312
|
+
return withWarnings(await installDownloadSpec({ entry, spec, timeoutMs }), warnings);
|
|
276
313
|
}
|
|
277
314
|
const prefs = resolveSkillsInstallPreferences(params.config);
|
|
278
315
|
const command = buildInstallCommand(spec, prefs);
|
|
279
316
|
if (command.error) {
|
|
280
|
-
return {
|
|
317
|
+
return withWarnings({
|
|
281
318
|
ok: false,
|
|
282
319
|
message: command.error,
|
|
283
320
|
stdout: "",
|
|
284
321
|
stderr: "",
|
|
285
322
|
code: null,
|
|
286
|
-
};
|
|
323
|
+
}, warnings);
|
|
287
324
|
}
|
|
288
325
|
const brewExe = hasBinary("brew") ? "brew" : resolveBrewExecutable();
|
|
289
326
|
if (spec.kind === "brew" && !brewExe) {
|
|
290
|
-
return {
|
|
327
|
+
return withWarnings({
|
|
291
328
|
ok: false,
|
|
292
329
|
message: "brew not installed",
|
|
293
330
|
stdout: "",
|
|
294
331
|
stderr: "",
|
|
295
332
|
code: null,
|
|
296
|
-
};
|
|
333
|
+
}, warnings);
|
|
297
334
|
}
|
|
298
335
|
if (spec.kind === "uv" && !hasBinary("uv")) {
|
|
299
336
|
if (brewExe) {
|
|
@@ -301,33 +338,33 @@ export async function installSkill(params) {
|
|
|
301
338
|
timeoutMs,
|
|
302
339
|
});
|
|
303
340
|
if (brewResult.code !== 0) {
|
|
304
|
-
return {
|
|
341
|
+
return withWarnings({
|
|
305
342
|
ok: false,
|
|
306
343
|
message: "Failed to install uv (brew)",
|
|
307
344
|
stdout: brewResult.stdout.trim(),
|
|
308
345
|
stderr: brewResult.stderr.trim(),
|
|
309
346
|
code: brewResult.code,
|
|
310
|
-
};
|
|
347
|
+
}, warnings);
|
|
311
348
|
}
|
|
312
349
|
}
|
|
313
350
|
else {
|
|
314
|
-
return {
|
|
351
|
+
return withWarnings({
|
|
315
352
|
ok: false,
|
|
316
353
|
message: "uv not installed (install via brew)",
|
|
317
354
|
stdout: "",
|
|
318
355
|
stderr: "",
|
|
319
356
|
code: null,
|
|
320
|
-
};
|
|
357
|
+
}, warnings);
|
|
321
358
|
}
|
|
322
359
|
}
|
|
323
360
|
if (!command.argv || command.argv.length === 0) {
|
|
324
|
-
return {
|
|
361
|
+
return withWarnings({
|
|
325
362
|
ok: false,
|
|
326
363
|
message: "invalid install command",
|
|
327
364
|
stdout: "",
|
|
328
365
|
stderr: "",
|
|
329
366
|
code: null,
|
|
330
|
-
};
|
|
367
|
+
}, warnings);
|
|
331
368
|
}
|
|
332
369
|
if (spec.kind === "brew" && brewExe && command.argv[0] === "brew") {
|
|
333
370
|
command.argv[0] = brewExe;
|
|
@@ -338,23 +375,23 @@ export async function installSkill(params) {
|
|
|
338
375
|
timeoutMs,
|
|
339
376
|
});
|
|
340
377
|
if (brewResult.code !== 0) {
|
|
341
|
-
return {
|
|
378
|
+
return withWarnings({
|
|
342
379
|
ok: false,
|
|
343
380
|
message: "Failed to install go (brew)",
|
|
344
381
|
stdout: brewResult.stdout.trim(),
|
|
345
382
|
stderr: brewResult.stderr.trim(),
|
|
346
383
|
code: brewResult.code,
|
|
347
|
-
};
|
|
384
|
+
}, warnings);
|
|
348
385
|
}
|
|
349
386
|
}
|
|
350
387
|
else {
|
|
351
|
-
return {
|
|
388
|
+
return withWarnings({
|
|
352
389
|
ok: false,
|
|
353
390
|
message: "go not installed (install via brew)",
|
|
354
391
|
stdout: "",
|
|
355
392
|
stderr: "",
|
|
356
393
|
code: null,
|
|
357
|
-
};
|
|
394
|
+
}, warnings);
|
|
358
395
|
}
|
|
359
396
|
}
|
|
360
397
|
let env;
|
|
@@ -380,11 +417,11 @@ export async function installSkill(params) {
|
|
|
380
417
|
}
|
|
381
418
|
})();
|
|
382
419
|
const success = result.code === 0;
|
|
383
|
-
return {
|
|
420
|
+
return withWarnings({
|
|
384
421
|
ok: success,
|
|
385
422
|
message: success ? "Installed" : formatInstallFailureMessage(result),
|
|
386
423
|
stdout: result.stdout.trim(),
|
|
387
424
|
stderr: result.stderr.trim(),
|
|
388
425
|
code: result.code,
|
|
389
|
-
};
|
|
426
|
+
}, warnings);
|
|
390
427
|
}
|
|
@@ -1,28 +1,16 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { resolveQueueSettings } from "../auto-reply/reply/queue.js";
|
|
3
4
|
import { loadConfig } from "../config/config.js";
|
|
4
5
|
import { loadSessionStore, resolveAgentIdFromSessionKey, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
|
|
5
|
-
import { normalizeMainKey } from "../routing/session-key.js";
|
|
6
|
-
import { resolveQueueSettings } from "../auto-reply/reply/queue.js";
|
|
7
6
|
import { callGateway } from "../gateway/call.js";
|
|
7
|
+
import { formatDurationCompact } from "../infra/format-time/format-duration.js";
|
|
8
|
+
import { normalizeMainKey } from "../routing/session-key.js";
|
|
8
9
|
import { defaultRuntime } from "../runtime.js";
|
|
9
10
|
import { deliveryContextFromSession, mergeDeliveryContext, normalizeDeliveryContext, } from "../utils/delivery-context.js";
|
|
10
|
-
import { isEmbeddedPiRunActive, queueEmbeddedPiMessage } from "./pi-embedded.js";
|
|
11
|
+
import { isEmbeddedPiRunActive, queueEmbeddedPiMessage, waitForEmbeddedPiRunEnd, } from "./pi-embedded.js";
|
|
11
12
|
import { enqueueAnnounce } from "./subagent-announce-queue.js";
|
|
12
13
|
import { readLatestAssistantReply } from "./tools/agent-step.js";
|
|
13
|
-
function formatDurationShort(valueMs) {
|
|
14
|
-
if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0)
|
|
15
|
-
return undefined;
|
|
16
|
-
const totalSeconds = Math.round(valueMs / 1000);
|
|
17
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
18
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
19
|
-
const seconds = totalSeconds % 60;
|
|
20
|
-
if (hours > 0)
|
|
21
|
-
return `${hours}h${minutes}m`;
|
|
22
|
-
if (minutes > 0)
|
|
23
|
-
return `${minutes}m${seconds}s`;
|
|
24
|
-
return `${seconds}s`;
|
|
25
|
-
}
|
|
26
14
|
function formatTokenCount(value) {
|
|
27
15
|
if (!value || !Number.isFinite(value))
|
|
28
16
|
return "0";
|
|
@@ -72,7 +60,10 @@ async function waitForSessionUsage(params) {
|
|
|
72
60
|
return { entry, storePath };
|
|
73
61
|
}
|
|
74
62
|
function resolveAnnounceOrigin(entry, requesterOrigin) {
|
|
75
|
-
|
|
63
|
+
// requesterOrigin (captured at spawn time) reflects the channel the user is
|
|
64
|
+
// actually on and must take priority over the session entry, which may carry
|
|
65
|
+
// stale lastChannel / lastTo values from a previous channel interaction.
|
|
66
|
+
return mergeDeliveryContext(requesterOrigin, deliveryContextFromSession(entry));
|
|
76
67
|
}
|
|
77
68
|
async function sendAnnounce(item) {
|
|
78
69
|
const origin = item.origin;
|
|
@@ -178,7 +169,7 @@ async function buildSubagentStatsLine(params) {
|
|
|
178
169
|
? (input * costConfig.input + output * costConfig.output) / 1_000_000
|
|
179
170
|
: undefined;
|
|
180
171
|
const parts = [];
|
|
181
|
-
const runtime =
|
|
172
|
+
const runtime = formatDurationCompact(runtimeMs);
|
|
182
173
|
parts.push(`runtime ${runtime ?? "n/a"}`);
|
|
183
174
|
if (typeof total === "number") {
|
|
184
175
|
const inputText = typeof input === "number" ? formatTokenCount(input) : "n/a";
|
|
@@ -199,6 +190,28 @@ async function buildSubagentStatsLine(params) {
|
|
|
199
190
|
parts.push(`transcript ${transcriptPath}`);
|
|
200
191
|
return `Stats: ${parts.join(" \u2022 ")}`;
|
|
201
192
|
}
|
|
193
|
+
function loadSessionEntryByKey(sessionKey) {
|
|
194
|
+
const cfg = loadConfig();
|
|
195
|
+
const agentId = resolveAgentIdFromSessionKey(sessionKey);
|
|
196
|
+
const storePath = resolveStorePath(cfg.session?.store, { agentId });
|
|
197
|
+
const store = loadSessionStore(storePath);
|
|
198
|
+
return store[sessionKey];
|
|
199
|
+
}
|
|
200
|
+
async function readLatestAssistantReplyWithRetry(params) {
|
|
201
|
+
let reply = params.initialReply?.trim() ? params.initialReply : undefined;
|
|
202
|
+
if (reply) {
|
|
203
|
+
return reply;
|
|
204
|
+
}
|
|
205
|
+
const deadline = Date.now() + Math.max(0, Math.min(params.maxWaitMs, 15_000));
|
|
206
|
+
while (Date.now() < deadline) {
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
208
|
+
const latest = await readLatestAssistantReply({ sessionKey: params.sessionKey });
|
|
209
|
+
if (latest?.trim()) {
|
|
210
|
+
return latest;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return reply;
|
|
214
|
+
}
|
|
202
215
|
export function buildSubagentSystemPrompt(params) {
|
|
203
216
|
const taskText = typeof params.task === "string" && params.task.trim()
|
|
204
217
|
? params.task.replace(/\s+/g, " ").trim()
|
|
@@ -227,10 +240,10 @@ export function buildSubagentSystemPrompt(params) {
|
|
|
227
240
|
"",
|
|
228
241
|
"## What You DON'T Do",
|
|
229
242
|
"- NO user conversations (that's main agent's job)",
|
|
230
|
-
"- NO external messages (email, tweets, etc.) unless explicitly tasked",
|
|
243
|
+
"- NO external messages (email, tweets, etc.) unless explicitly tasked with a specific recipient/channel",
|
|
231
244
|
"- NO cron jobs or persistent state",
|
|
232
245
|
"- NO pretending to be the main agent",
|
|
233
|
-
"-
|
|
246
|
+
"- Only use the `message` tool when explicitly instructed to contact a specific external recipient; otherwise return plain text and let the main agent deliver it",
|
|
234
247
|
"",
|
|
235
248
|
"## Session Context",
|
|
236
249
|
params.label ? `- Label: ${params.label}` : undefined,
|
|
@@ -245,25 +258,46 @@ export function buildSubagentSystemPrompt(params) {
|
|
|
245
258
|
}
|
|
246
259
|
export async function runSubagentAnnounceFlow(params) {
|
|
247
260
|
let didAnnounce = false;
|
|
261
|
+
let shouldDeleteChildSession = params.cleanup === "delete";
|
|
248
262
|
try {
|
|
249
263
|
const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin);
|
|
264
|
+
const childSessionId = (() => {
|
|
265
|
+
const entry = loadSessionEntryByKey(params.childSessionKey);
|
|
266
|
+
return typeof entry?.sessionId === "string" && entry.sessionId.trim()
|
|
267
|
+
? entry.sessionId.trim()
|
|
268
|
+
: undefined;
|
|
269
|
+
})();
|
|
270
|
+
const settleTimeoutMs = Math.min(Math.max(params.timeoutMs, 1), 120_000);
|
|
250
271
|
let reply = params.roundOneReply;
|
|
251
272
|
let outcome = params.outcome;
|
|
273
|
+
// Lifecycle "end" can arrive before auto-compaction retries finish. If the
|
|
274
|
+
// subagent is still active, wait for the embedded run to fully settle.
|
|
275
|
+
if (childSessionId && isEmbeddedPiRunActive(childSessionId)) {
|
|
276
|
+
const settled = await waitForEmbeddedPiRunEnd(childSessionId, settleTimeoutMs);
|
|
277
|
+
if (!settled && isEmbeddedPiRunActive(childSessionId)) {
|
|
278
|
+
// The child run is still active (e.g., compaction retry still in progress).
|
|
279
|
+
// Defer announcement so we don't report stale/partial output.
|
|
280
|
+
// Keep the child session so output is not lost while the run is still active.
|
|
281
|
+
shouldDeleteChildSession = false;
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
252
285
|
if (!reply && params.waitForCompletion !== false) {
|
|
253
|
-
const waitMs =
|
|
254
|
-
const wait =
|
|
286
|
+
const waitMs = settleTimeoutMs;
|
|
287
|
+
const wait = await callGateway({
|
|
255
288
|
method: "agent.wait",
|
|
256
289
|
params: {
|
|
257
290
|
runId: params.childRunId,
|
|
258
291
|
timeoutMs: waitMs,
|
|
259
292
|
},
|
|
260
293
|
timeoutMs: waitMs + 2000,
|
|
261
|
-
})
|
|
294
|
+
});
|
|
295
|
+
const waitError = typeof wait?.error === "string" ? wait.error : undefined;
|
|
262
296
|
if (wait?.status === "timeout") {
|
|
263
297
|
outcome = { status: "timeout" };
|
|
264
298
|
}
|
|
265
299
|
else if (wait?.status === "error") {
|
|
266
|
-
outcome = { status: "error", error:
|
|
300
|
+
outcome = { status: "error", error: waitError };
|
|
267
301
|
}
|
|
268
302
|
else if (wait?.status === "ok") {
|
|
269
303
|
outcome = { status: "ok" };
|
|
@@ -275,20 +309,30 @@ export async function runSubagentAnnounceFlow(params) {
|
|
|
275
309
|
params.endedAt = wait.endedAt;
|
|
276
310
|
}
|
|
277
311
|
if (wait?.status === "timeout") {
|
|
278
|
-
if (!outcome)
|
|
312
|
+
if (!outcome) {
|
|
279
313
|
outcome = { status: "timeout" };
|
|
314
|
+
}
|
|
280
315
|
}
|
|
281
|
-
reply = await readLatestAssistantReply({
|
|
282
|
-
sessionKey: params.childSessionKey,
|
|
283
|
-
});
|
|
316
|
+
reply = await readLatestAssistantReply({ sessionKey: params.childSessionKey });
|
|
284
317
|
}
|
|
285
318
|
if (!reply) {
|
|
286
|
-
reply = await readLatestAssistantReply({
|
|
319
|
+
reply = await readLatestAssistantReply({ sessionKey: params.childSessionKey });
|
|
320
|
+
}
|
|
321
|
+
if (!reply?.trim()) {
|
|
322
|
+
reply = await readLatestAssistantReplyWithRetry({
|
|
287
323
|
sessionKey: params.childSessionKey,
|
|
324
|
+
initialReply: reply,
|
|
325
|
+
maxWaitMs: params.timeoutMs,
|
|
288
326
|
});
|
|
289
327
|
}
|
|
290
|
-
if (!
|
|
328
|
+
if (!reply?.trim() && childSessionId && isEmbeddedPiRunActive(childSessionId)) {
|
|
329
|
+
// Avoid announcing "(no output)" while the child run is still producing output.
|
|
330
|
+
shouldDeleteChildSession = false;
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
if (!outcome) {
|
|
291
334
|
outcome = { status: "unknown" };
|
|
335
|
+
}
|
|
292
336
|
// Build stats
|
|
293
337
|
const statsLine = await buildSubagentStatsLine({
|
|
294
338
|
sessionKey: params.childSessionKey,
|
|
@@ -304,9 +348,10 @@ export async function runSubagentAnnounceFlow(params) {
|
|
|
304
348
|
? `failed: ${outcome.error || "unknown error"}`
|
|
305
349
|
: "finished with unknown status";
|
|
306
350
|
// Build instructional message for main agent
|
|
307
|
-
const
|
|
351
|
+
const announceType = params.announceType ?? "subagent task";
|
|
352
|
+
const taskLabel = params.label || params.task || "task";
|
|
308
353
|
const triggerMessage = [
|
|
309
|
-
`A
|
|
354
|
+
`A ${announceType} "${taskLabel}" just ${statusLabel}.`,
|
|
310
355
|
"",
|
|
311
356
|
"Findings:",
|
|
312
357
|
reply || "(no output)",
|
|
@@ -314,7 +359,7 @@ export async function runSubagentAnnounceFlow(params) {
|
|
|
314
359
|
statsLine,
|
|
315
360
|
"",
|
|
316
361
|
"Summarize this naturally for the user. Keep it brief (1-2 sentences). Flow it into the conversation naturally.",
|
|
317
|
-
|
|
362
|
+
`Do not mention technical details like tokens, stats, or that this was a ${announceType}.`,
|
|
318
363
|
"You can respond with NO_REPLY if no announcement is needed (e.g., internal task with no user-facing result).",
|
|
319
364
|
].join("\n");
|
|
320
365
|
const queued = await maybeQueueSubagentAnnounce({
|
|
@@ -374,7 +419,7 @@ export async function runSubagentAnnounceFlow(params) {
|
|
|
374
419
|
// Best-effort
|
|
375
420
|
}
|
|
376
421
|
}
|
|
377
|
-
if (
|
|
422
|
+
if (shouldDeleteChildSession) {
|
|
378
423
|
try {
|
|
379
424
|
await callGateway({
|
|
380
425
|
method: "sessions.delete",
|