@poolzin/pool-bot 2026.1.38 → 2026.2.0
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/cli-runner/helpers.js +1 -1
- 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/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 +10 -4
- package/dist/agents/models-config.js +3 -3
- package/dist/agents/models-config.providers.js +147 -39
- package/dist/agents/pi-embedded-helpers/openai.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +8 -8
- package/dist/agents/pi-embedded-runner/model.js +2 -2
- package/dist/agents/pi-embedded-runner/run/attempt.js +6 -6
- package/dist/agents/pi-embedded-runner/run.js +4 -4
- 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-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 +10 -5
- package/dist/agents/pi-tools.read.js +2 -2
- package/dist/agents/session-file-repair.js +83 -0
- package/dist/agents/session-transcript-repair.js +68 -0
- package/dist/agents/skills/frontmatter.js +1 -1
- package/dist/agents/skills/workspace.js +2 -2
- 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.js +1 -1
- package/dist/agents/tools/browser-tool.js +3 -3
- package/dist/agents/tools/image-tool.js +2 -2
- package/dist/agents/tools/memory-tool.js +94 -7
- package/dist/agents/tools/web-search.js +1 -1
- package/dist/agents/workspace.js +1 -5
- package/dist/auto-reply/commands-registry.data.js +1 -1
- package/dist/auto-reply/reply/commands-context-report.js +2 -2
- package/dist/auto-reply/reply/commands-session.js +2 -2
- package/dist/auto-reply/reply/get-reply-run.js +14 -4
- package/dist/auto-reply/reply/groups.js +1 -1
- package/dist/auto-reply/reply/inbound-context.js +4 -0
- package/dist/auto-reply/reply/inbound-meta.js +130 -0
- package/dist/auto-reply/reply/untrusted-context.js +15 -0
- package/dist/auto-reply/status.js +1 -1
- package/dist/browser/client-fetch.js +1 -1
- package/dist/browser/config.js +1 -1
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/server-context.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui.js +3 -3
- package/dist/channels/plugins/agent-tools/whatsapp-login.js +1 -17
- 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/cli/browser-cli-extension.js +2 -2
- package/dist/cli/docs-cli.js +1 -1
- package/dist/cli/gateway-cli/dev.js +1 -1
- package/dist/cli/memory-cli.js +25 -15
- package/dist/cli/nodes-cli/register.canvas.js +1 -1
- 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 +4 -4
- package/dist/cli/webhooks-cli.js +5 -5
- 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-gateway-services.js +3 -3
- package/dist/commands/doctor-state-integrity.js +2 -14
- package/dist/commands/doctor-update.js +3 -3
- package/dist/commands/doctor.js +1 -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 +2 -2
- 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-non-interactive/local/auth-choice.js +140 -6
- 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/io.js +3 -3
- package/dist/config/schema.js +1 -1
- package/dist/config/types.js +0 -1
- package/dist/config/types.memory.js +1 -0
- package/dist/config/version.js +4 -4
- package/dist/config/zod-schema.js +0 -6
- 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/message-handler.process.js +6 -4
- package/dist/gateway/client.js +0 -14
- package/dist/gateway/live-image-probe.js +1 -66
- package/dist/gateway/openai-http.js +2 -2
- package/dist/gateway/openresponses-http.js +4 -4
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +1 -1
- package/dist/gateway/server.impl.js +2 -6
- 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/index.js +2 -2
- package/dist/infra/bonjour.js +3 -3
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/provider-usage.fetch.minimax.js +1 -1
- package/dist/infra/restart.js +1 -1
- package/dist/infra/tailscale.js +1 -1
- package/dist/macos/relay.js +2 -2
- 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/providers/image.js +2 -2
- package/dist/memory/backend-config.js +207 -0
- package/dist/memory/embeddings.js +1 -1
- package/dist/memory/index.js +0 -5
- package/dist/memory/manager.js +3 -25
- package/dist/memory/types.js +1 -0
- package/dist/node-host/runner.js +2 -2
- package/dist/pairing/pairing-messages.js +1 -1
- package/dist/plugins/discovery.js +1 -1
- package/dist/plugins/install.js +2 -2
- package/dist/plugins/update.js +1 -1
- package/dist/security/audit.js +2 -2
- package/dist/shared/text/reasoning-tags.js +52 -7
- package/dist/slack/monitor/message-handler/prepare.js +10 -4
- package/dist/slack/monitor/slash.js +10 -4
- package/dist/tailscale/detect.js +146 -0
- package/dist/telegram/bot-message-context.js +1 -1
- 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/utils/shell-argv.js +61 -0
- package/dist/utils.js +10 -0
- 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 -4
- 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 -250
- package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
- package/skills/tmux/scripts/find-sessions.sh +1 -1
- package/CHANGELOG.md +0 -200
- 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
- package/skills/webgpu-threejs-tsl/REFERENCE.md +0 -283
- package/skills/webgpu-threejs-tsl/SKILL.md +0 -91
- package/skills/webgpu-threejs-tsl/docs/compute-shaders.md +0 -404
- package/skills/webgpu-threejs-tsl/docs/core-concepts.md +0 -453
- package/skills/webgpu-threejs-tsl/docs/materials.md +0 -353
- package/skills/webgpu-threejs-tsl/docs/post-processing.md +0 -434
- package/skills/webgpu-threejs-tsl/docs/wgsl-integration.md +0 -324
- package/skills/webgpu-threejs-tsl/examples/basic-setup.js +0 -87
- package/skills/webgpu-threejs-tsl/examples/custom-material.js +0 -170
- package/skills/webgpu-threejs-tsl/examples/earth-shader.js +0 -292
- package/skills/webgpu-threejs-tsl/examples/particle-system.js +0 -259
- package/skills/webgpu-threejs-tsl/examples/post-processing.js +0 -199
- package/skills/webgpu-threejs-tsl/templates/compute-shader.js +0 -305
- package/skills/webgpu-threejs-tsl/templates/webgpu-project.js +0 -276
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
|
3
|
+
import { parseDurationMs } from "../cli/parse-duration.js";
|
|
4
|
+
import { resolveUserPath } from "../utils.js";
|
|
5
|
+
import { splitShellArgs } from "../utils/shell-argv.js";
|
|
6
|
+
const DEFAULT_BACKEND = "builtin";
|
|
7
|
+
const DEFAULT_CITATIONS = "auto";
|
|
8
|
+
const DEFAULT_QMD_INTERVAL = "5m";
|
|
9
|
+
const DEFAULT_QMD_DEBOUNCE_MS = 15_000;
|
|
10
|
+
const DEFAULT_QMD_TIMEOUT_MS = 4_000;
|
|
11
|
+
const DEFAULT_QMD_EMBED_INTERVAL = "60m";
|
|
12
|
+
const DEFAULT_QMD_COMMAND_TIMEOUT_MS = 30_000;
|
|
13
|
+
const DEFAULT_QMD_UPDATE_TIMEOUT_MS = 120_000;
|
|
14
|
+
const DEFAULT_QMD_EMBED_TIMEOUT_MS = 120_000;
|
|
15
|
+
const DEFAULT_QMD_LIMITS = {
|
|
16
|
+
maxResults: 6,
|
|
17
|
+
maxSnippetChars: 700,
|
|
18
|
+
maxInjectedChars: 4_000,
|
|
19
|
+
timeoutMs: DEFAULT_QMD_TIMEOUT_MS,
|
|
20
|
+
};
|
|
21
|
+
const DEFAULT_QMD_SCOPE = {
|
|
22
|
+
default: "deny",
|
|
23
|
+
rules: [
|
|
24
|
+
{
|
|
25
|
+
action: "allow",
|
|
26
|
+
match: { chatType: "direct" },
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
function sanitizeName(input) {
|
|
31
|
+
const lower = input.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
32
|
+
const trimmed = lower.replace(/^-+|-+$/g, "");
|
|
33
|
+
return trimmed || "collection";
|
|
34
|
+
}
|
|
35
|
+
function ensureUniqueName(base, existing) {
|
|
36
|
+
let name = sanitizeName(base);
|
|
37
|
+
if (!existing.has(name)) {
|
|
38
|
+
existing.add(name);
|
|
39
|
+
return name;
|
|
40
|
+
}
|
|
41
|
+
let suffix = 2;
|
|
42
|
+
while (existing.has(`${name}-${suffix}`)) {
|
|
43
|
+
suffix += 1;
|
|
44
|
+
}
|
|
45
|
+
const unique = `${name}-${suffix}`;
|
|
46
|
+
existing.add(unique);
|
|
47
|
+
return unique;
|
|
48
|
+
}
|
|
49
|
+
function resolvePath(raw, workspaceDir) {
|
|
50
|
+
const trimmed = raw.trim();
|
|
51
|
+
if (!trimmed) {
|
|
52
|
+
throw new Error("path required");
|
|
53
|
+
}
|
|
54
|
+
if (trimmed.startsWith("~") || path.isAbsolute(trimmed)) {
|
|
55
|
+
return path.normalize(resolveUserPath(trimmed));
|
|
56
|
+
}
|
|
57
|
+
return path.normalize(path.resolve(workspaceDir, trimmed));
|
|
58
|
+
}
|
|
59
|
+
function resolveIntervalMs(raw) {
|
|
60
|
+
const value = raw?.trim();
|
|
61
|
+
if (!value) {
|
|
62
|
+
return parseDurationMs(DEFAULT_QMD_INTERVAL, { defaultUnit: "m" });
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return parseDurationMs(value, { defaultUnit: "m" });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return parseDurationMs(DEFAULT_QMD_INTERVAL, { defaultUnit: "m" });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function resolveEmbedIntervalMs(raw) {
|
|
72
|
+
const value = raw?.trim();
|
|
73
|
+
if (!value) {
|
|
74
|
+
return parseDurationMs(DEFAULT_QMD_EMBED_INTERVAL, { defaultUnit: "m" });
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return parseDurationMs(value, { defaultUnit: "m" });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return parseDurationMs(DEFAULT_QMD_EMBED_INTERVAL, { defaultUnit: "m" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function resolveDebounceMs(raw) {
|
|
84
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0) {
|
|
85
|
+
return Math.floor(raw);
|
|
86
|
+
}
|
|
87
|
+
return DEFAULT_QMD_DEBOUNCE_MS;
|
|
88
|
+
}
|
|
89
|
+
function resolveTimeoutMs(raw, fallback) {
|
|
90
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) {
|
|
91
|
+
return Math.floor(raw);
|
|
92
|
+
}
|
|
93
|
+
return fallback;
|
|
94
|
+
}
|
|
95
|
+
function resolveLimits(raw) {
|
|
96
|
+
const parsed = { ...DEFAULT_QMD_LIMITS };
|
|
97
|
+
if (raw?.maxResults && raw.maxResults > 0) {
|
|
98
|
+
parsed.maxResults = Math.floor(raw.maxResults);
|
|
99
|
+
}
|
|
100
|
+
if (raw?.maxSnippetChars && raw.maxSnippetChars > 0) {
|
|
101
|
+
parsed.maxSnippetChars = Math.floor(raw.maxSnippetChars);
|
|
102
|
+
}
|
|
103
|
+
if (raw?.maxInjectedChars && raw.maxInjectedChars > 0) {
|
|
104
|
+
parsed.maxInjectedChars = Math.floor(raw.maxInjectedChars);
|
|
105
|
+
}
|
|
106
|
+
if (raw?.timeoutMs && raw.timeoutMs > 0) {
|
|
107
|
+
parsed.timeoutMs = Math.floor(raw.timeoutMs);
|
|
108
|
+
}
|
|
109
|
+
return parsed;
|
|
110
|
+
}
|
|
111
|
+
function resolveSessionConfig(cfg, workspaceDir) {
|
|
112
|
+
const enabled = Boolean(cfg?.enabled);
|
|
113
|
+
const exportDirRaw = cfg?.exportDir?.trim();
|
|
114
|
+
const exportDir = exportDirRaw ? resolvePath(exportDirRaw, workspaceDir) : undefined;
|
|
115
|
+
const retentionDays = cfg?.retentionDays && cfg.retentionDays > 0 ? Math.floor(cfg.retentionDays) : undefined;
|
|
116
|
+
return {
|
|
117
|
+
enabled,
|
|
118
|
+
exportDir,
|
|
119
|
+
retentionDays,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function resolveCustomPaths(rawPaths, workspaceDir, existing) {
|
|
123
|
+
if (!rawPaths?.length) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const collections = [];
|
|
127
|
+
rawPaths.forEach((entry, index) => {
|
|
128
|
+
const trimmedPath = entry?.path?.trim();
|
|
129
|
+
if (!trimmedPath) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let resolved;
|
|
133
|
+
try {
|
|
134
|
+
resolved = resolvePath(trimmedPath, workspaceDir);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const pattern = entry.pattern?.trim() || "**/*.md";
|
|
140
|
+
const baseName = entry.name?.trim() || `custom-${index + 1}`;
|
|
141
|
+
const name = ensureUniqueName(baseName, existing);
|
|
142
|
+
collections.push({
|
|
143
|
+
name,
|
|
144
|
+
path: resolved,
|
|
145
|
+
pattern,
|
|
146
|
+
kind: "custom",
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return collections;
|
|
150
|
+
}
|
|
151
|
+
function resolveDefaultCollections(include, workspaceDir, existing) {
|
|
152
|
+
if (!include) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
const entries = [
|
|
156
|
+
{ path: workspaceDir, pattern: "MEMORY.md", base: "memory-root" },
|
|
157
|
+
{ path: workspaceDir, pattern: "memory.md", base: "memory-alt" },
|
|
158
|
+
{ path: path.join(workspaceDir, "memory"), pattern: "**/*.md", base: "memory-dir" },
|
|
159
|
+
];
|
|
160
|
+
return entries.map((entry) => ({
|
|
161
|
+
name: ensureUniqueName(entry.base, existing),
|
|
162
|
+
path: entry.path,
|
|
163
|
+
pattern: entry.pattern,
|
|
164
|
+
kind: "memory",
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
export function resolveMemoryBackendConfig(params) {
|
|
168
|
+
const backend = params.cfg.memory?.backend ?? DEFAULT_BACKEND;
|
|
169
|
+
const citations = params.cfg.memory?.citations ?? DEFAULT_CITATIONS;
|
|
170
|
+
if (backend !== "qmd") {
|
|
171
|
+
return { backend: "builtin", citations };
|
|
172
|
+
}
|
|
173
|
+
const workspaceDir = resolveAgentWorkspaceDir(params.cfg, params.agentId);
|
|
174
|
+
const qmdCfg = params.cfg.memory?.qmd;
|
|
175
|
+
const includeDefaultMemory = qmdCfg?.includeDefaultMemory !== false;
|
|
176
|
+
const nameSet = new Set();
|
|
177
|
+
const collections = [
|
|
178
|
+
...resolveDefaultCollections(includeDefaultMemory, workspaceDir, nameSet),
|
|
179
|
+
...resolveCustomPaths(qmdCfg?.paths, workspaceDir, nameSet),
|
|
180
|
+
];
|
|
181
|
+
const rawCommand = qmdCfg?.command?.trim() || "qmd";
|
|
182
|
+
const parsedCommand = splitShellArgs(rawCommand);
|
|
183
|
+
const command = parsedCommand?.[0] || rawCommand.split(/\s+/)[0] || "qmd";
|
|
184
|
+
const resolved = {
|
|
185
|
+
command,
|
|
186
|
+
collections,
|
|
187
|
+
includeDefaultMemory,
|
|
188
|
+
sessions: resolveSessionConfig(qmdCfg?.sessions, workspaceDir),
|
|
189
|
+
update: {
|
|
190
|
+
intervalMs: resolveIntervalMs(qmdCfg?.update?.interval),
|
|
191
|
+
debounceMs: resolveDebounceMs(qmdCfg?.update?.debounceMs),
|
|
192
|
+
onBoot: qmdCfg?.update?.onBoot !== false,
|
|
193
|
+
waitForBootSync: qmdCfg?.update?.waitForBootSync === true,
|
|
194
|
+
embedIntervalMs: resolveEmbedIntervalMs(qmdCfg?.update?.embedInterval),
|
|
195
|
+
commandTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.commandTimeoutMs, DEFAULT_QMD_COMMAND_TIMEOUT_MS),
|
|
196
|
+
updateTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.updateTimeoutMs, DEFAULT_QMD_UPDATE_TIMEOUT_MS),
|
|
197
|
+
embedTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.embedTimeoutMs, DEFAULT_QMD_EMBED_TIMEOUT_MS),
|
|
198
|
+
},
|
|
199
|
+
limits: resolveLimits(qmdCfg?.limits),
|
|
200
|
+
scope: qmdCfg?.scope ?? DEFAULT_QMD_SCOPE,
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
backend: "qmd",
|
|
204
|
+
citations,
|
|
205
|
+
qmd: resolved,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -160,7 +160,7 @@ function formatLocalSetupError(err) {
|
|
|
160
160
|
"To enable local embeddings:",
|
|
161
161
|
"1) Use Node 22 LTS (recommended for installs/updates)",
|
|
162
162
|
missing
|
|
163
|
-
? "2) Reinstall
|
|
163
|
+
? "2) Reinstall Poolbot (this should install node-llama-cpp): npm i -g poolbot@latest"
|
|
164
164
|
: null,
|
|
165
165
|
"3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp",
|
|
166
166
|
'Or set agents.defaults.memorySearch.provider = "openai" (remote).',
|
package/dist/memory/index.js
CHANGED
package/dist/memory/manager.js
CHANGED
|
@@ -157,7 +157,6 @@ export class MemoryIndexManager {
|
|
|
157
157
|
this.sessionWarm.add(key);
|
|
158
158
|
}
|
|
159
159
|
async search(query, opts) {
|
|
160
|
-
const searchStart = Date.now();
|
|
161
160
|
void this.warmSession(opts?.sessionKey);
|
|
162
161
|
if (this.settings.sync.onSearch && (this.dirty || this.sessionsDirty)) {
|
|
163
162
|
void this.sync({ reason: "search" }).catch((err) => {
|
|
@@ -180,17 +179,7 @@ export class MemoryIndexManager {
|
|
|
180
179
|
? await this.searchVector(queryVec, candidates).catch(() => [])
|
|
181
180
|
: [];
|
|
182
181
|
if (!hybrid.enabled) {
|
|
183
|
-
|
|
184
|
-
const searchDuration = Date.now() - searchStart;
|
|
185
|
-
log.debug("memory search performance", {
|
|
186
|
-
query: cleaned.substring(0, 50),
|
|
187
|
-
durationMs: searchDuration,
|
|
188
|
-
resultCount: results.length,
|
|
189
|
-
provider: this.provider.id,
|
|
190
|
-
model: this.provider.model,
|
|
191
|
-
hybrid: false,
|
|
192
|
-
});
|
|
193
|
-
return results;
|
|
182
|
+
return vectorResults.filter((entry) => entry.score >= minScore).slice(0, maxResults);
|
|
194
183
|
}
|
|
195
184
|
const merged = this.mergeHybridResults({
|
|
196
185
|
vector: vectorResults,
|
|
@@ -198,19 +187,7 @@ export class MemoryIndexManager {
|
|
|
198
187
|
vectorWeight: hybrid.vectorWeight,
|
|
199
188
|
textWeight: hybrid.textWeight,
|
|
200
189
|
});
|
|
201
|
-
|
|
202
|
-
const searchDuration = Date.now() - searchStart;
|
|
203
|
-
log.debug("memory search performance", {
|
|
204
|
-
query: cleaned.substring(0, 50),
|
|
205
|
-
durationMs: searchDuration,
|
|
206
|
-
resultCount: results.length,
|
|
207
|
-
provider: this.provider.id,
|
|
208
|
-
model: this.provider.model,
|
|
209
|
-
hybrid: true,
|
|
210
|
-
keywordResults: keywordResults.length,
|
|
211
|
-
vectorResults: vectorResults.length,
|
|
212
|
-
});
|
|
213
|
-
return results;
|
|
190
|
+
return merged.filter((entry) => entry.score >= minScore).slice(0, maxResults);
|
|
214
191
|
}
|
|
215
192
|
async searchVector(queryVec, limit) {
|
|
216
193
|
const results = await searchVector({
|
|
@@ -333,6 +310,7 @@ export class MemoryIndexManager {
|
|
|
333
310
|
return sources.map((source) => ({ source, ...bySource.get(source) }));
|
|
334
311
|
})();
|
|
335
312
|
return {
|
|
313
|
+
backend: "builtin",
|
|
336
314
|
files: files?.c ?? 0,
|
|
337
315
|
chunks: chunks?.c ?? 0,
|
|
338
316
|
dirty: this.dirty,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/node-host/runner.js
CHANGED
|
@@ -13,7 +13,7 @@ import { createBrowserControlContext, startBrowserControlServiceFromConfig, } fr
|
|
|
13
13
|
import { createBrowserRouteDispatcher } from "../browser/routes/dispatcher.js";
|
|
14
14
|
import { detectMime } from "../media/mime.js";
|
|
15
15
|
import { resolveAgentConfig } from "../agents/agent-scope.js";
|
|
16
|
-
import {
|
|
16
|
+
import { ensurePoolbotCliOnPath } from "../infra/path-env.js";
|
|
17
17
|
import { VERSION } from "../version.js";
|
|
18
18
|
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
|
19
19
|
import { ensureNodeHostConfig, saveNodeHostConfig } from "./config.js";
|
|
@@ -296,7 +296,7 @@ function resolveEnvPath(env) {
|
|
|
296
296
|
return raw.split(path.delimiter).filter(Boolean);
|
|
297
297
|
}
|
|
298
298
|
function ensureNodePathEnv() {
|
|
299
|
-
|
|
299
|
+
ensurePoolbotCliOnPath({ pathEnv: process.env.PATH ?? "" });
|
|
300
300
|
const current = process.env.PATH ?? "";
|
|
301
301
|
if (current.trim())
|
|
302
302
|
return current;
|
|
@@ -58,7 +58,7 @@ function addCandidate(params) {
|
|
|
58
58
|
packageVersion: manifest?.version?.trim() || undefined,
|
|
59
59
|
packageDescription: manifest?.description?.trim() || undefined,
|
|
60
60
|
packageDir: params.packageDir,
|
|
61
|
-
|
|
61
|
+
packagePoolbot: getPackageManifestMetadata(manifest ?? undefined),
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
function discoverInDirectory(params) {
|
package/dist/plugins/install.js
CHANGED
|
@@ -21,7 +21,7 @@ function safeDirName(input) {
|
|
|
21
21
|
function safeFileName(input) {
|
|
22
22
|
return safeDirName(input);
|
|
23
23
|
}
|
|
24
|
-
async function
|
|
24
|
+
async function ensurePoolbotExtensions(manifest) {
|
|
25
25
|
const extensions = manifest.poolbot?.extensions ?? manifest[LEGACY_MANIFEST_KEY]?.extensions;
|
|
26
26
|
if (!Array.isArray(extensions)) {
|
|
27
27
|
throw new Error("package.json missing poolbot.extensions");
|
|
@@ -56,7 +56,7 @@ async function installPluginFromPackageDir(params) {
|
|
|
56
56
|
}
|
|
57
57
|
let extensions;
|
|
58
58
|
try {
|
|
59
|
-
extensions = await
|
|
59
|
+
extensions = await ensurePoolbotExtensions(manifest);
|
|
60
60
|
}
|
|
61
61
|
catch (err) {
|
|
62
62
|
return { ok: false, error: String(err) };
|
package/dist/plugins/update.js
CHANGED
|
@@ -26,7 +26,7 @@ function resolveBundledPluginSources(params) {
|
|
|
26
26
|
const pluginId = manifest.manifest.id;
|
|
27
27
|
if (bundled.has(pluginId))
|
|
28
28
|
continue;
|
|
29
|
-
const npmSpec = candidate.
|
|
29
|
+
const npmSpec = candidate.packagePoolbot?.install?.npmSpec?.trim() ||
|
|
30
30
|
candidate.packageName?.trim() ||
|
|
31
31
|
undefined;
|
|
32
32
|
bundled.set(pluginId, {
|
package/dist/security/audit.js
CHANGED
|
@@ -65,7 +65,7 @@ async function collectFilesystemFindings(params) {
|
|
|
65
65
|
checkId: "fs.state_dir.perms_world_writable",
|
|
66
66
|
severity: "critical",
|
|
67
67
|
title: "State dir is world-writable",
|
|
68
|
-
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your
|
|
68
|
+
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your Poolbot state.`,
|
|
69
69
|
remediation: formatPermissionRemediation({
|
|
70
70
|
targetPath: params.stateDir,
|
|
71
71
|
perms: stateDirPerms,
|
|
@@ -80,7 +80,7 @@ async function collectFilesystemFindings(params) {
|
|
|
80
80
|
checkId: "fs.state_dir.perms_group_writable",
|
|
81
81
|
severity: "warn",
|
|
82
82
|
title: "State dir is group-writable",
|
|
83
|
-
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your
|
|
83
|
+
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your Poolbot state.`,
|
|
84
84
|
remediation: formatPermissionRemediation({
|
|
85
85
|
targetPath: params.stateDir,
|
|
86
86
|
perms: stateDirPerms,
|
|
@@ -1,28 +1,70 @@
|
|
|
1
1
|
const QUICK_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking|final)\b/i;
|
|
2
|
-
const FINAL_TAG_RE = /<\s*\/?\s*final\b[
|
|
3
|
-
const THINKING_TAG_RE = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\b[
|
|
2
|
+
const FINAL_TAG_RE = /<\s*\/?\s*final\b[^<>]*>/gi;
|
|
3
|
+
const THINKING_TAG_RE = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>/gi;
|
|
4
|
+
function findCodeRegions(text) {
|
|
5
|
+
const regions = [];
|
|
6
|
+
const fencedRe = /(^|\n)(```|~~~)[^\n]*\n[\s\S]*?(?:\n\2(?:\n|$)|$)/g;
|
|
7
|
+
for (const match of text.matchAll(fencedRe)) {
|
|
8
|
+
const start = (match.index ?? 0) + match[1].length;
|
|
9
|
+
regions.push({ start, end: start + match[0].length - match[1].length });
|
|
10
|
+
}
|
|
11
|
+
const inlineRe = /`+[^`]+`+/g;
|
|
12
|
+
for (const match of text.matchAll(inlineRe)) {
|
|
13
|
+
const start = match.index ?? 0;
|
|
14
|
+
const end = start + match[0].length;
|
|
15
|
+
const insideFenced = regions.some((r) => start >= r.start && end <= r.end);
|
|
16
|
+
if (!insideFenced) {
|
|
17
|
+
regions.push({ start, end });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
regions.sort((a, b) => a.start - b.start);
|
|
21
|
+
return regions;
|
|
22
|
+
}
|
|
23
|
+
function isInsideCode(pos, regions) {
|
|
24
|
+
return regions.some((r) => pos >= r.start && pos < r.end);
|
|
25
|
+
}
|
|
4
26
|
function applyTrim(value, mode) {
|
|
5
|
-
if (mode === "none")
|
|
27
|
+
if (mode === "none") {
|
|
6
28
|
return value;
|
|
7
|
-
|
|
29
|
+
}
|
|
30
|
+
if (mode === "start") {
|
|
8
31
|
return value.trimStart();
|
|
32
|
+
}
|
|
9
33
|
return value.trim();
|
|
10
34
|
}
|
|
11
35
|
export function stripReasoningTagsFromText(text, options) {
|
|
12
|
-
if (!text)
|
|
36
|
+
if (!text) {
|
|
13
37
|
return text;
|
|
14
|
-
|
|
38
|
+
}
|
|
39
|
+
if (!QUICK_TAG_RE.test(text)) {
|
|
15
40
|
return text;
|
|
41
|
+
}
|
|
16
42
|
const mode = options?.mode ?? "strict";
|
|
17
43
|
const trimMode = options?.trim ?? "both";
|
|
18
44
|
let cleaned = text;
|
|
19
45
|
if (FINAL_TAG_RE.test(cleaned)) {
|
|
20
46
|
FINAL_TAG_RE.lastIndex = 0;
|
|
21
|
-
|
|
47
|
+
const finalMatches = [];
|
|
48
|
+
const preCodeRegions = findCodeRegions(cleaned);
|
|
49
|
+
for (const match of cleaned.matchAll(FINAL_TAG_RE)) {
|
|
50
|
+
const start = match.index ?? 0;
|
|
51
|
+
finalMatches.push({
|
|
52
|
+
start,
|
|
53
|
+
length: match[0].length,
|
|
54
|
+
inCode: isInsideCode(start, preCodeRegions),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
for (let i = finalMatches.length - 1; i >= 0; i--) {
|
|
58
|
+
const m = finalMatches[i];
|
|
59
|
+
if (!m.inCode) {
|
|
60
|
+
cleaned = cleaned.slice(0, m.start) + cleaned.slice(m.start + m.length);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
22
63
|
}
|
|
23
64
|
else {
|
|
24
65
|
FINAL_TAG_RE.lastIndex = 0;
|
|
25
66
|
}
|
|
67
|
+
const codeRegions = findCodeRegions(cleaned);
|
|
26
68
|
THINKING_TAG_RE.lastIndex = 0;
|
|
27
69
|
let result = "";
|
|
28
70
|
let lastIndex = 0;
|
|
@@ -30,6 +72,9 @@ export function stripReasoningTagsFromText(text, options) {
|
|
|
30
72
|
for (const match of cleaned.matchAll(THINKING_TAG_RE)) {
|
|
31
73
|
const idx = match.index ?? 0;
|
|
32
74
|
const isClose = match[1] === "/";
|
|
75
|
+
if (isInsideCode(idx, codeRegions)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
33
78
|
if (!inThinking) {
|
|
34
79
|
result += cleaned.slice(lastIndex, idx);
|
|
35
80
|
if (!isClose) {
|
|
@@ -350,10 +350,16 @@ export async function prepareSlackMessage(params) {
|
|
|
350
350
|
});
|
|
351
351
|
}
|
|
352
352
|
const slackTo = isDirectMessage ? `user:${message.user}` : `channel:${message.channel}`;
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
353
|
+
const channelDescription = [channelInfo?.topic, channelInfo?.purpose]
|
|
354
|
+
.map((entry) => entry?.trim())
|
|
355
|
+
.filter((entry) => Boolean(entry))
|
|
356
|
+
.filter((entry, index, list) => list.indexOf(entry) === index)
|
|
357
|
+
.join("\n");
|
|
358
|
+
const systemPromptParts = [
|
|
359
|
+
channelDescription ? `Channel description: ${channelDescription}` : null,
|
|
360
|
+
channelConfig?.systemPrompt?.trim() || null,
|
|
361
|
+
].filter((entry) => Boolean(entry));
|
|
362
|
+
const groupSystemPrompt = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
|
357
363
|
let threadStarterBody;
|
|
358
364
|
let threadLabel;
|
|
359
365
|
let threadStarterMedia = null;
|
|
@@ -288,10 +288,16 @@ export function registerSlackMonitorSlashCommands(params) {
|
|
|
288
288
|
id: isDirectMessage ? command.user_id : command.channel_id,
|
|
289
289
|
},
|
|
290
290
|
});
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
291
|
+
const channelDescription = [channelInfo?.topic, channelInfo?.purpose]
|
|
292
|
+
.map((entry) => entry?.trim())
|
|
293
|
+
.filter((entry) => Boolean(entry))
|
|
294
|
+
.filter((entry, index, list) => list.indexOf(entry) === index)
|
|
295
|
+
.join("\n");
|
|
296
|
+
const systemPromptParts = [
|
|
297
|
+
channelDescription ? `Channel description: ${channelDescription}` : null,
|
|
298
|
+
channelConfig?.systemPrompt?.trim() || null,
|
|
299
|
+
].filter((entry) => Boolean(entry));
|
|
300
|
+
const groupSystemPrompt = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
|
295
301
|
const ctxPayload = finalizeInboundContext({
|
|
296
302
|
Body: prompt,
|
|
297
303
|
RawBody: prompt,
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
/**
|
|
5
|
+
* Check if Tailscale is installed by looking for the binary.
|
|
6
|
+
*/
|
|
7
|
+
async function isTailscaleInstalled() {
|
|
8
|
+
try {
|
|
9
|
+
const platform = os.platform();
|
|
10
|
+
const possiblePaths = [];
|
|
11
|
+
if (platform === "linux") {
|
|
12
|
+
possiblePaths.push("/usr/bin/tailscale", "/usr/local/bin/tailscale");
|
|
13
|
+
}
|
|
14
|
+
else if (platform === "darwin") {
|
|
15
|
+
possiblePaths.push("/Applications/Tailscale.app/Contents/MacOS/Tailscale", "/usr/local/bin/tailscale");
|
|
16
|
+
}
|
|
17
|
+
else if (platform === "win32") {
|
|
18
|
+
possiblePaths.push("C:\\Program Files\\Tailscale\\tailscale.exe", "C:\\ProgramData\\chocolatey\\lib\\tailscale\\tools\\tailscale.exe");
|
|
19
|
+
}
|
|
20
|
+
for (const binPath of possiblePaths) {
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(binPath);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Run tailscale status command and parse output.
|
|
37
|
+
*/
|
|
38
|
+
async function getTailscaleStatus() {
|
|
39
|
+
try {
|
|
40
|
+
const platform = os.platform();
|
|
41
|
+
const binPath = platform === "win32"
|
|
42
|
+
? "tailscale.exe"
|
|
43
|
+
: platform === "darwin"
|
|
44
|
+
? "/Applications/Tailscale.app/Contents/MacOS/Tailscale"
|
|
45
|
+
: "tailscale";
|
|
46
|
+
const timeout = 5000;
|
|
47
|
+
const result = execSync(`"${binPath}" status --json`, {
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
50
|
+
timeout,
|
|
51
|
+
});
|
|
52
|
+
const status = JSON.parse(result.trim());
|
|
53
|
+
// Extract useful info from Tailscale status JSON
|
|
54
|
+
const self = status.Self || {};
|
|
55
|
+
const backendState = status.BackendState || "";
|
|
56
|
+
return {
|
|
57
|
+
installed: true,
|
|
58
|
+
running: backendState === "Running",
|
|
59
|
+
ip: self.TailscaleIPs?.[0],
|
|
60
|
+
dnsName: self.DNSName,
|
|
61
|
+
hostname: self.HostName,
|
|
62
|
+
tailnet: status.MagicsockName || status.TailnetName,
|
|
63
|
+
online: self.Online ?? false,
|
|
64
|
+
canServe: true, // If running, can serve
|
|
65
|
+
canFunnel: self.Capabilities?.map.includes("funnel") ?? false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
// If command fails, return minimal info
|
|
70
|
+
return {
|
|
71
|
+
installed: await isTailscaleInstalled(),
|
|
72
|
+
running: false,
|
|
73
|
+
canServe: false,
|
|
74
|
+
canFunnel: false,
|
|
75
|
+
online: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Auto-detect Tailscale configuration and recommend settings.
|
|
81
|
+
*
|
|
82
|
+
* This is a SAFE detection function - it only reads status and never
|
|
83
|
+
* modifies configuration. Recommendations are purely advisory.
|
|
84
|
+
*
|
|
85
|
+
* @returns Tailscale auto-detection result
|
|
86
|
+
*/
|
|
87
|
+
export async function detectTailscaleConfig() {
|
|
88
|
+
const info = {
|
|
89
|
+
installed: await isTailscaleInstalled(),
|
|
90
|
+
running: false,
|
|
91
|
+
canServe: false,
|
|
92
|
+
canFunnel: false,
|
|
93
|
+
online: false,
|
|
94
|
+
};
|
|
95
|
+
if (!info.installed) {
|
|
96
|
+
return { detected: false };
|
|
97
|
+
}
|
|
98
|
+
// Get detailed status if installed
|
|
99
|
+
const status = await getTailscaleStatus();
|
|
100
|
+
Object.assign(info, status);
|
|
101
|
+
// Generate recommendations based on detected state
|
|
102
|
+
const recommended = info.online
|
|
103
|
+
? {
|
|
104
|
+
mode: info.canFunnel ? "funnel" : "serve",
|
|
105
|
+
bind: "tailnet",
|
|
106
|
+
port: 18789,
|
|
107
|
+
reason: info.canFunnel
|
|
108
|
+
? "Tailscale is online and supports funnel (public access)"
|
|
109
|
+
: "Tailscale is online - use serve for private tailnet access",
|
|
110
|
+
}
|
|
111
|
+
: info.running
|
|
112
|
+
? {
|
|
113
|
+
mode: "off",
|
|
114
|
+
bind: "loopback",
|
|
115
|
+
port: 18789,
|
|
116
|
+
reason: "Tailscale is installed but offline - use loopback bind",
|
|
117
|
+
}
|
|
118
|
+
: undefined;
|
|
119
|
+
return {
|
|
120
|
+
detected: true,
|
|
121
|
+
info,
|
|
122
|
+
recommended,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get a human-readable summary of Tailscale detection.
|
|
127
|
+
*/
|
|
128
|
+
export function formatTailscaleDetection(result) {
|
|
129
|
+
if (!result.detected || !result.info) {
|
|
130
|
+
return "Tailscale: Not installed";
|
|
131
|
+
}
|
|
132
|
+
const { info, recommended } = result;
|
|
133
|
+
const parts = [];
|
|
134
|
+
parts.push(`Tailscale: ${info.installed ? "Installed" : "Not installed"}`);
|
|
135
|
+
parts.push(`Status: ${info.running ? (info.online ? "Online" : "Offline") : "Not running"}`);
|
|
136
|
+
if (info.online && info.ip) {
|
|
137
|
+
parts.push(`IP: ${info.ip}`);
|
|
138
|
+
}
|
|
139
|
+
if (info.dnsName) {
|
|
140
|
+
parts.push(`DNS: ${info.dnsName}`);
|
|
141
|
+
}
|
|
142
|
+
if (recommended) {
|
|
143
|
+
parts.push(`\nRecommendation: ${recommended.mode} (${recommended.reason})`);
|
|
144
|
+
}
|
|
145
|
+
return parts.join(" | ");
|
|
146
|
+
}
|
|
@@ -141,7 +141,7 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
141
141
|
await withTelegramApiErrorLogging({
|
|
142
142
|
operation: "sendMessage",
|
|
143
143
|
fn: () => bot.api.sendMessage(chatId, [
|
|
144
|
-
"
|
|
144
|
+
"Poolbot: access not configured.",
|
|
145
145
|
"",
|
|
146
146
|
`Your Telegram user id: ${telegramUserId}`,
|
|
147
147
|
"",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export async function makeTempWorkspace(prefix = "poolbot-workspace-") {
|
|
5
|
+
return fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
|
6
|
+
}
|
|
7
|
+
export async function writeWorkspaceFile(params) {
|
|
8
|
+
const filePath = path.join(params.dir, params.name);
|
|
9
|
+
await fs.writeFile(filePath, params.content, "utf-8");
|
|
10
|
+
return filePath;
|
|
11
|
+
}
|