@poolzin/pool-bot 2026.3.25 → 2026.3.27

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.
Files changed (271) hide show
  1. package/dist/agents/model-fallback.js +5 -4
  2. package/dist/agents/tools/common.js +16 -201
  3. package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
  4. package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
  5. package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
  6. package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
  7. package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
  8. package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
  9. package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
  10. package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
  11. package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
  12. package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
  13. package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
  14. package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
  15. package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
  16. package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
  17. package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
  18. package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
  19. package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
  20. package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
  21. package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
  22. package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
  23. package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
  24. package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
  25. package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
  26. package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
  27. package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
  28. package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
  29. package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
  30. package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
  31. package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
  32. package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
  33. package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
  34. package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
  35. package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
  36. package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
  37. package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
  38. package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
  39. package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
  40. package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
  41. package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
  42. package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
  43. package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
  44. package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
  45. package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
  46. package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
  47. package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
  48. package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
  49. package/dist/build-info.json +3 -3
  50. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  51. package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
  52. package/dist/canvas-host/a2ui/index.html +1 -307
  53. package/dist/channels/channels/directory-config.js +185 -0
  54. package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
  55. package/dist/channels/channels/discord/handle-action.js +165 -0
  56. package/dist/channels/channels/discord.js +413 -0
  57. package/dist/channels/channels/dock.js +436 -0
  58. package/dist/channels/channels/index.js +51 -0
  59. package/dist/channels/channels/plugins/outbound/discord.js +101 -0
  60. package/dist/channels/channels/whatsapp.js +17 -0
  61. package/dist/channels/plugins/types.js +1 -1
  62. package/dist/channels/run-state-machine.js +7 -0
  63. package/dist/commands/models/auth.js +47 -1
  64. package/dist/commands-subagents/action-agents.js +44 -0
  65. package/dist/commands-subagents/action-focus.js +64 -0
  66. package/dist/commands-subagents/action-help.js +4 -0
  67. package/dist/commands-subagents/action-info.js +45 -0
  68. package/dist/commands-subagents/action-kill.js +60 -0
  69. package/dist/commands-subagents/action-list.js +44 -0
  70. package/dist/commands-subagents/action-log.js +29 -0
  71. package/dist/commands-subagents/action-send.js +119 -0
  72. package/dist/commands-subagents/action-spawn.js +52 -0
  73. package/dist/commands-subagents/action-unfocus.js +30 -0
  74. package/dist/commands-subagents/shared.js +303 -0
  75. package/dist/config/config.js +1 -8
  76. package/dist/config/types.secrets.js +61 -0
  77. package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
  78. package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
  79. package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
  80. package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
  81. package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
  82. package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
  83. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
  84. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/gateway/method-scopes.js +9 -1
  87. package/dist/gateway/node-pending-work.js +142 -0
  88. package/dist/gateway/protocol/index.js +5 -1
  89. package/dist/gateway/protocol/schema/nodes.js +18 -0
  90. package/dist/gateway/server-methods/nodes-pending.js +96 -0
  91. package/dist/gateway/server-methods-list.js +4 -0
  92. package/dist/gateway/server-methods.js +2 -0
  93. package/dist/imessage/channel.js +253 -0
  94. package/dist/imessage/monitor/echo-cache.js +70 -0
  95. package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
  96. package/dist/imessage/monitor/reflection-guard.js +50 -0
  97. package/dist/imessage/monitor/sanitize-outbound.js +25 -0
  98. package/dist/imessage/monitor/self-chat-cache.js +75 -0
  99. package/dist/imessage/runtime.js +3 -0
  100. package/dist/infra/exec-approval-reply.js +7 -0
  101. package/dist/infra/tmp-openclaw-dir.js +84 -0
  102. package/dist/pairing/pairing-challenge.js +15 -0
  103. package/dist/plugin-sdk/account-id.d.ts +1 -0
  104. package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
  105. package/dist/plugin-sdk/allow-from.d.ts +27 -0
  106. package/dist/plugin-sdk/command-auth.d.ts +25 -0
  107. package/dist/plugin-sdk/command-auth.js +3 -1
  108. package/dist/plugin-sdk/config-paths.d.ts +6 -0
  109. package/dist/plugin-sdk/file-lock.d.ts +16 -0
  110. package/dist/plugin-sdk/index.d.ts +428 -0
  111. package/dist/plugin-sdk/index.js +237 -103
  112. package/dist/plugin-sdk/json-store.d.ts +5 -0
  113. package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
  114. package/dist/plugin-sdk/onboarding.d.ts +11 -0
  115. package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
  116. package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
  117. package/dist/plugin-sdk/status-helpers.d.ts +25 -0
  118. package/dist/plugin-sdk/temp-path.d.ts +12 -0
  119. package/dist/plugin-sdk/text-chunking.d.ts +1 -0
  120. package/dist/plugin-sdk/tool-send.d.ts +4 -0
  121. package/dist/plugin-sdk/webhook-path.d.ts +6 -0
  122. package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
  123. package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
  124. package/dist/plugin-sdk-internal/accounts.js +6 -0
  125. package/dist/plugin-sdk-internal/discord.js +23 -0
  126. package/dist/plugin-sdk-internal/imessage.js +13 -0
  127. package/dist/plugin-sdk-internal/setup.js +9 -0
  128. package/dist/plugin-sdk-internal/signal.js +13 -0
  129. package/dist/plugin-sdk-internal/slack.js +22 -0
  130. package/dist/plugin-sdk-internal/telegram.js +32 -0
  131. package/dist/plugin-sdk-internal/whatsapp.js +29 -0
  132. package/dist/routing/session-key.js +4 -185
  133. package/dist/shared/pid-alive.js +2 -61
  134. package/dist/shared/process-scoped-map.js +5 -7
  135. package/dist/signal/channel.js +264 -0
  136. package/dist/signal/monitor/access-policy.js +60 -0
  137. package/dist/signal/runtime.js +3 -0
  138. package/dist/slack/account-inspect.js +135 -0
  139. package/dist/slack/blocks-input.js +7 -38
  140. package/dist/slack/channel.js +394 -0
  141. package/dist/slack/interactive-replies.js +28 -0
  142. package/dist/slack/monitor/channel-type.js +31 -0
  143. package/dist/slack/monitor/dm-auth.js +49 -0
  144. package/dist/slack/monitor/events/interactions.modal.js +137 -0
  145. package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
  146. package/dist/slack/monitor/events/system-event-context.js +29 -0
  147. package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
  148. package/dist/slack/monitor/external-arg-menu-store.js +46 -0
  149. package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
  150. package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
  151. package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
  152. package/dist/slack/monitor/reconnect-policy.js +78 -0
  153. package/dist/slack/monitor/slash-commands.runtime.js +1 -0
  154. package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
  155. package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
  156. package/dist/slack/resolve-allowlist-common.js +36 -0
  157. package/dist/slack/runtime.js +3 -0
  158. package/dist/slack/sent-thread-cache.js +61 -0
  159. package/dist/slack/truncate.js +10 -0
  160. package/dist/telegram/account-inspect.js +175 -0
  161. package/dist/telegram/allow-from.js +10 -0
  162. package/dist/telegram/api-fetch.js +18 -0
  163. package/dist/telegram/approval-buttons.js +30 -0
  164. package/dist/telegram/audit-membership-runtime.js +61 -0
  165. package/dist/telegram/bot/delivery.replies.js +508 -0
  166. package/dist/telegram/bot/delivery.resolve-media.js +227 -0
  167. package/dist/telegram/bot/delivery.send.js +132 -0
  168. package/dist/telegram/bot/reply-threading.js +46 -0
  169. package/dist/telegram/bot-message-context.body.js +186 -0
  170. package/dist/telegram/bot-message-context.session.js +207 -0
  171. package/dist/telegram/bot-message-context.types.js +1 -0
  172. package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
  173. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  174. package/dist/telegram/bot.media.test-utils.js +81 -0
  175. package/dist/telegram/channel-actions.js +225 -0
  176. package/dist/telegram/channel.js +515 -0
  177. package/dist/telegram/conversation-route.js +107 -0
  178. package/dist/telegram/delivery.js +2 -0
  179. package/dist/telegram/delivery.replies.js +508 -0
  180. package/dist/telegram/dm-access.js +86 -0
  181. package/dist/telegram/draft-stream.test-helpers.js +62 -0
  182. package/dist/telegram/exec-approvals-handler.js +281 -0
  183. package/dist/telegram/exec-approvals.js +62 -0
  184. package/dist/telegram/forum-service-message.js +22 -0
  185. package/dist/telegram/group-config-helpers.js +10 -0
  186. package/dist/telegram/lane-delivery-state.js +19 -0
  187. package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
  188. package/dist/telegram/lane-delivery.js +2 -0
  189. package/dist/telegram/normalize.js +37 -0
  190. package/dist/telegram/onboarding.js +192 -0
  191. package/dist/telegram/outbound-adapter.js +100 -0
  192. package/dist/telegram/polling-session.js +275 -0
  193. package/dist/telegram/runtime.js +3 -0
  194. package/dist/telegram/sendchataction-401-backoff.js +71 -0
  195. package/dist/telegram/sequential-key.js +46 -0
  196. package/dist/telegram/status-issues.js +105 -0
  197. package/dist/telegram/target-writeback.js +165 -0
  198. package/dist/telegram/thread-bindings.js +560 -0
  199. package/dist/utils.js +32 -257
  200. package/dist/wizard/prompts.js +5 -5
  201. package/extensions/feishu/src/policy.ts +1 -1
  202. package/extensions/firecrawl/index.test.ts +82 -0
  203. package/extensions/firecrawl/index.ts +20 -0
  204. package/extensions/firecrawl/openclaw.plugin.json +8 -0
  205. package/extensions/firecrawl/package.json +12 -0
  206. package/extensions/firecrawl/src/config.ts +159 -0
  207. package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
  208. package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
  209. package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
  210. package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
  211. package/package.json +1 -1
  212. package/dist/.buildstamp +0 -1
  213. package/dist/acp/bindings-store.js +0 -209
  214. package/dist/acp/control-plane/runtime-cache.js +0 -54
  215. package/dist/acp/control-plane/runtime-options.js +0 -215
  216. package/dist/acp/control-plane/session-actor-queue.js +0 -36
  217. package/dist/acp/index.js +0 -2
  218. package/dist/acp/runtime/errors.js +0 -47
  219. package/dist/acp/runtime/registry.js +0 -86
  220. package/dist/acp/secret-file.js +0 -22
  221. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
  222. package/dist/agents/bash-process-registry.test-helpers.js +0 -29
  223. package/dist/agents/bash-tools.exec-approval-request.js +0 -20
  224. package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
  225. package/dist/agents/bash-tools.exec-host-node.js +0 -235
  226. package/dist/agents/checkpoint-manager.js +0 -290
  227. package/dist/agents/claude-cli-runner.js +0 -3
  228. package/dist/agents/error-classifier.js +0 -251
  229. package/dist/agents/live-model-filter.js +0 -84
  230. package/dist/agents/nvidia-models.js +0 -228
  231. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
  232. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
  233. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
  234. package/dist/agents/provider/config-loader.js +0 -76
  235. package/dist/agents/provider/index.js +0 -15
  236. package/dist/agents/provider/models-dev.js +0 -129
  237. package/dist/agents/provider/session-binding.js +0 -376
  238. package/dist/agents/queued-file-writer.js +0 -22
  239. package/dist/agents/skills/bundled-context.js +0 -23
  240. package/dist/agents/skills/security.js +0 -211
  241. package/dist/agents/skills/tools-dir.js +0 -9
  242. package/dist/agents/skills-install-download.js +0 -290
  243. package/dist/agents/skills-install-output.js +0 -30
  244. package/dist/agents/skills-install.download-test-utils.js +0 -36
  245. package/dist/agents/skills.test-helpers.js +0 -13
  246. package/dist/agents/subagent-announce-reliability.js +0 -160
  247. package/dist/agents/subagent-registry.mocks.shared.js +0 -12
  248. package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
  249. package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
  250. package/dist/agents/test-helpers/fast-core-tools.js +0 -8
  251. package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
  252. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
  253. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
  254. package/dist/agents/tool-display-common.js +0 -915
  255. package/dist/agents/tool-policy-shared.js +0 -108
  256. package/dist/agents/tool-policy.conformance.js +0 -14
  257. package/dist/agents/tool-result-truncation.js +0 -299
  258. package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
  259. package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
  260. package/dist/agents/tools/discord-actions-presence.js +0 -78
  261. package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
  262. package/dist/discord/discord-improvements.js +0 -167
  263. package/dist/discord/index.js +0 -2
  264. package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
  265. package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
  266. package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
  267. package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
  268. package/dist/whatsapp/normalize.js +0 -66
  269. package/dist/whatsapp/resolve-outbound-target.js +0 -42
  270. /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
  271. /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
@@ -1,29 +0,0 @@
1
- export function createProcessSessionFixture(params) {
2
- const session = {
3
- id: params.id,
4
- command: params.command ?? "test",
5
- startedAt: params.startedAt ?? Date.now(),
6
- cwd: params.cwd ?? "/tmp",
7
- maxOutputChars: params.maxOutputChars ?? 10_000,
8
- pendingMaxOutputChars: params.pendingMaxOutputChars ?? 30_000,
9
- totalOutputChars: 0,
10
- pendingStdout: [],
11
- pendingStderr: [],
12
- pendingStdoutChars: 0,
13
- pendingStderrChars: 0,
14
- aggregated: "",
15
- tail: "",
16
- exited: false,
17
- exitCode: undefined,
18
- exitSignal: undefined,
19
- truncated: false,
20
- backgrounded: params.backgrounded ?? false,
21
- };
22
- if (params.pid !== undefined) {
23
- session.pid = params.pid;
24
- }
25
- if (params.child) {
26
- session.child = params.child;
27
- }
28
- return session;
29
- }
@@ -1,20 +0,0 @@
1
- import { DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS, DEFAULT_APPROVAL_TIMEOUT_MS, } from "./bash-tools.exec-runtime.js";
2
- import { callGatewayTool } from "./tools/gateway.js";
3
- export async function requestExecApprovalDecision(params) {
4
- const decisionResult = await callGatewayTool("exec.approval.request", { timeoutMs: DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS }, {
5
- id: params.id,
6
- command: params.command,
7
- cwd: params.cwd,
8
- host: params.host,
9
- security: params.security,
10
- ask: params.ask,
11
- agentId: params.agentId,
12
- resolvedPath: params.resolvedPath,
13
- sessionKey: params.sessionKey,
14
- timeoutMs: DEFAULT_APPROVAL_TIMEOUT_MS,
15
- });
16
- const decisionValue = decisionResult && typeof decisionResult === "object"
17
- ? decisionResult.decision
18
- : undefined;
19
- return typeof decisionValue === "string" ? decisionValue : null;
20
- }
@@ -1,240 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { addAllowlistEntry, buildSafeBinsShellCommand, buildSafeShellCommand, evaluateShellAllowlist, maxAsk, minSecurity, recordAllowlistUse, requiresExecApproval, resolveAllowAlwaysPatterns, resolveExecApprovals, } from "../infra/exec-approvals.js";
3
- import { markBackgrounded, tail } from "./bash-process-registry.js";
4
- import { requestExecApprovalDecision } from "./bash-tools.exec-approval-request.js";
5
- import { DEFAULT_APPROVAL_TIMEOUT_MS, DEFAULT_NOTIFY_TAIL_CHARS, createApprovalSlug, emitExecSystemEvent, normalizeNotifyOutput, runExecProcess, } from "./bash-tools.exec-runtime.js";
6
- export async function processGatewayAllowlist(params) {
7
- const approvals = resolveExecApprovals(params.agentId, {
8
- security: params.security,
9
- ask: params.ask,
10
- });
11
- const hostSecurity = minSecurity(params.security, approvals.agent.security);
12
- const hostAsk = maxAsk(params.ask, approvals.agent.ask);
13
- const askFallback = approvals.agent.askFallback;
14
- if (hostSecurity === "deny") {
15
- throw new Error("exec denied: host=gateway security=deny");
16
- }
17
- const allowlistEval = evaluateShellAllowlist({
18
- command: params.command,
19
- allowlist: approvals.allowlist,
20
- safeBins: params.safeBins,
21
- cwd: params.workdir,
22
- env: params.env,
23
- platform: process.platform,
24
- trustedSafeBinDirs: params.trustedSafeBinDirs,
25
- });
26
- const allowlistMatches = allowlistEval.allowlistMatches;
27
- const analysisOk = allowlistEval.analysisOk;
28
- const allowlistSatisfied = hostSecurity === "allowlist" && analysisOk ? allowlistEval.allowlistSatisfied : false;
29
- const hasHeredocSegment = allowlistEval.segments.some((segment) => segment.argv.some((token) => token.startsWith("<<")));
30
- const requiresHeredocApproval = hostSecurity === "allowlist" && analysisOk && allowlistSatisfied && hasHeredocSegment;
31
- const requiresAsk = requiresExecApproval({
32
- ask: hostAsk,
33
- security: hostSecurity,
34
- analysisOk,
35
- allowlistSatisfied,
36
- }) || requiresHeredocApproval;
37
- if (requiresHeredocApproval) {
38
- params.warnings.push("Warning: heredoc execution requires explicit approval in allowlist mode.");
39
- }
40
- if (requiresAsk) {
41
- const approvalId = crypto.randomUUID();
42
- const approvalSlug = createApprovalSlug(approvalId);
43
- const expiresAtMs = Date.now() + DEFAULT_APPROVAL_TIMEOUT_MS;
44
- const contextKey = `exec:${approvalId}`;
45
- const resolvedPath = allowlistEval.segments[0]?.resolution?.resolvedPath;
46
- const noticeSeconds = Math.max(1, Math.round(params.approvalRunningNoticeMs / 1000));
47
- const effectiveTimeout = typeof params.timeoutSec === "number" ? params.timeoutSec : params.defaultTimeoutSec;
48
- const warningText = params.warnings.length ? `${params.warnings.join("\n")}\n\n` : "";
49
- void (async () => {
50
- let decision = null;
51
- try {
52
- decision = await requestExecApprovalDecision({
53
- id: approvalId,
54
- command: params.command,
55
- cwd: params.workdir,
56
- host: "gateway",
57
- security: hostSecurity,
58
- ask: hostAsk,
59
- agentId: params.agentId,
60
- resolvedPath,
61
- sessionKey: params.sessionKey,
62
- });
63
- }
64
- catch {
65
- emitExecSystemEvent(`Exec denied (gateway id=${approvalId}, approval-request-failed): ${params.command}`, {
66
- sessionKey: params.notifySessionKey,
67
- contextKey,
68
- });
69
- return;
70
- }
71
- let approvedByAsk = false;
72
- let deniedReason = null;
73
- if (decision === "deny") {
74
- deniedReason = "user-denied";
75
- }
76
- else if (!decision) {
77
- if (askFallback === "full") {
78
- approvedByAsk = true;
79
- }
80
- else if (askFallback === "allowlist") {
81
- if (!analysisOk || !allowlistSatisfied) {
82
- deniedReason = "approval-timeout (allowlist-miss)";
83
- }
84
- else {
85
- approvedByAsk = true;
86
- }
87
- }
88
- else {
89
- deniedReason = "approval-timeout";
90
- }
91
- }
92
- else if (decision === "allow-once") {
93
- approvedByAsk = true;
94
- }
95
- else if (decision === "allow-always") {
96
- approvedByAsk = true;
97
- if (hostSecurity === "allowlist") {
98
- const patterns = resolveAllowAlwaysPatterns({
99
- segments: allowlistEval.segments,
100
- cwd: params.workdir,
101
- env: params.env,
102
- platform: process.platform,
103
- });
104
- for (const pattern of patterns) {
105
- if (pattern) {
106
- addAllowlistEntry(approvals.file, params.agentId, pattern);
107
- }
108
- }
109
- }
110
- }
111
- if (hostSecurity === "allowlist" && (!analysisOk || !allowlistSatisfied) && !approvedByAsk) {
112
- deniedReason = deniedReason ?? "allowlist-miss";
113
- }
114
- if (deniedReason) {
115
- emitExecSystemEvent(`Exec denied (gateway id=${approvalId}, ${deniedReason}): ${params.command}`, {
116
- sessionKey: params.notifySessionKey,
117
- contextKey,
118
- });
119
- return;
120
- }
121
- if (allowlistMatches.length > 0) {
122
- const seen = new Set();
123
- for (const match of allowlistMatches) {
124
- if (seen.has(match.pattern)) {
125
- continue;
126
- }
127
- seen.add(match.pattern);
128
- recordAllowlistUse(approvals.file, params.agentId, match, params.command, resolvedPath ?? undefined);
129
- }
130
- }
131
- let run = null;
132
- try {
133
- run = await runExecProcess({
134
- command: params.command,
135
- workdir: params.workdir,
136
- env: params.env,
137
- sandbox: undefined,
138
- containerWorkdir: null,
139
- usePty: params.pty,
140
- warnings: params.warnings,
141
- maxOutput: params.maxOutput,
142
- pendingMaxOutput: params.pendingMaxOutput,
143
- notifyOnExit: false,
144
- notifyOnExitEmptySuccess: false,
145
- scopeKey: params.scopeKey,
146
- sessionKey: params.notifySessionKey,
147
- timeoutSec: effectiveTimeout,
148
- });
149
- }
150
- catch {
151
- emitExecSystemEvent(`Exec denied (gateway id=${approvalId}, spawn-failed): ${params.command}`, {
152
- sessionKey: params.notifySessionKey,
153
- contextKey,
154
- });
155
- return;
156
- }
157
- markBackgrounded(run.session);
158
- let runningTimer = null;
159
- if (params.approvalRunningNoticeMs > 0) {
160
- runningTimer = setTimeout(() => {
161
- emitExecSystemEvent(`Exec running (gateway id=${approvalId}, session=${run?.session.id}, >${noticeSeconds}s): ${params.command}`, { sessionKey: params.notifySessionKey, contextKey });
162
- }, params.approvalRunningNoticeMs);
163
- }
164
- const outcome = await run.promise;
165
- if (runningTimer) {
166
- clearTimeout(runningTimer);
167
- }
168
- const output = normalizeNotifyOutput(tail(outcome.aggregated || "", DEFAULT_NOTIFY_TAIL_CHARS));
169
- const exitLabel = outcome.timedOut ? "timeout" : `code ${outcome.exitCode ?? "?"}`;
170
- const summary = output
171
- ? `Exec finished (gateway id=${approvalId}, session=${run.session.id}, ${exitLabel})\n${output}`
172
- : `Exec finished (gateway id=${approvalId}, session=${run.session.id}, ${exitLabel})`;
173
- emitExecSystemEvent(summary, { sessionKey: params.notifySessionKey, contextKey });
174
- })();
175
- return {
176
- pendingResult: {
177
- content: [
178
- {
179
- type: "text",
180
- text: `${warningText}Approval required (id ${approvalSlug}). ` +
181
- "Approve to run; updates will arrive after completion.",
182
- },
183
- ],
184
- details: {
185
- status: "approval-pending",
186
- approvalId,
187
- approvalSlug,
188
- expiresAtMs,
189
- host: "gateway",
190
- command: params.command,
191
- cwd: params.workdir,
192
- },
193
- },
194
- };
195
- }
196
- if (hostSecurity === "allowlist" && (!analysisOk || !allowlistSatisfied)) {
197
- throw new Error("exec denied: allowlist miss");
198
- }
199
- let execCommandOverride;
200
- // If allowlist uses safeBins, sanitize only those stdin-only segments:
201
- // disable glob/var expansion by forcing argv tokens to be literal via single-quoting.
202
- if (hostSecurity === "allowlist" &&
203
- analysisOk &&
204
- allowlistSatisfied &&
205
- allowlistEval.segmentSatisfiedBy.some((by) => by === "safeBins")) {
206
- const safe = buildSafeBinsShellCommand({
207
- command: params.command,
208
- segments: allowlistEval.segments,
209
- segmentSatisfiedBy: allowlistEval.segmentSatisfiedBy,
210
- platform: process.platform,
211
- });
212
- if (!safe.ok || !safe.command) {
213
- // Fallback: quote everything (safe, but may change glob behavior).
214
- const fallback = buildSafeShellCommand({
215
- command: params.command,
216
- platform: process.platform,
217
- });
218
- if (!fallback.ok || !fallback.command) {
219
- throw new Error(`exec denied: safeBins sanitize failed (${safe.reason ?? "unknown"})`);
220
- }
221
- params.warnings.push("Warning: safeBins hardening used fallback quoting due to parser mismatch.");
222
- execCommandOverride = fallback.command;
223
- }
224
- else {
225
- params.warnings.push("Warning: safeBins hardening disabled glob/variable expansion for stdin-only segments.");
226
- execCommandOverride = safe.command;
227
- }
228
- }
229
- if (allowlistMatches.length > 0) {
230
- const seen = new Set();
231
- for (const match of allowlistMatches) {
232
- if (seen.has(match.pattern)) {
233
- continue;
234
- }
235
- seen.add(match.pattern);
236
- recordAllowlistUse(approvals.file, params.agentId, match, params.command, allowlistEval.segments[0]?.resolution?.resolvedPath);
237
- }
238
- }
239
- return { execCommandOverride };
240
- }
@@ -1,235 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { evaluateShellAllowlist, maxAsk, minSecurity, requiresExecApproval, resolveExecApprovals, resolveExecApprovalsFromFile, } from "../infra/exec-approvals.js";
3
- import { buildNodeShellCommand } from "../infra/node-shell.js";
4
- import { requestExecApprovalDecision } from "./bash-tools.exec-approval-request.js";
5
- import { DEFAULT_APPROVAL_TIMEOUT_MS, createApprovalSlug, emitExecSystemEvent, } from "./bash-tools.exec-runtime.js";
6
- import { callGatewayTool } from "./tools/gateway.js";
7
- import { listNodes, resolveNodeIdFromList } from "./tools/nodes-utils.js";
8
- export async function executeNodeHostCommand(params) {
9
- const approvals = resolveExecApprovals(params.agentId, {
10
- security: params.security,
11
- ask: params.ask,
12
- });
13
- const hostSecurity = minSecurity(params.security, approvals.agent.security);
14
- const hostAsk = maxAsk(params.ask, approvals.agent.ask);
15
- const askFallback = approvals.agent.askFallback;
16
- if (hostSecurity === "deny") {
17
- throw new Error("exec denied: host=node security=deny");
18
- }
19
- if (params.boundNode && params.requestedNode && params.boundNode !== params.requestedNode) {
20
- throw new Error(`exec node not allowed (bound to ${params.boundNode})`);
21
- }
22
- const nodeQuery = params.boundNode || params.requestedNode;
23
- const nodes = await listNodes({});
24
- if (nodes.length === 0) {
25
- throw new Error("exec host=node requires a paired node (none available). This requires a companion app or node host.");
26
- }
27
- let nodeId;
28
- try {
29
- nodeId = resolveNodeIdFromList(nodes, nodeQuery, !nodeQuery);
30
- }
31
- catch (err) {
32
- if (!nodeQuery && String(err).includes("node required")) {
33
- throw new Error("exec host=node requires a node id when multiple nodes are available (set tools.exec.node or exec.node).", { cause: err });
34
- }
35
- throw err;
36
- }
37
- const nodeInfo = nodes.find((entry) => entry.nodeId === nodeId);
38
- const supportsSystemRun = Array.isArray(nodeInfo?.commands)
39
- ? nodeInfo?.commands?.includes("system.run")
40
- : false;
41
- if (!supportsSystemRun) {
42
- throw new Error("exec host=node requires a node that supports system.run (companion app or node host).");
43
- }
44
- const argv = buildNodeShellCommand(params.command, nodeInfo?.platform);
45
- const nodeEnv = params.requestedEnv ? { ...params.requestedEnv } : undefined;
46
- const baseAllowlistEval = evaluateShellAllowlist({
47
- command: params.command,
48
- allowlist: [],
49
- safeBins: new Set(),
50
- cwd: params.workdir,
51
- env: params.env,
52
- platform: nodeInfo?.platform,
53
- trustedSafeBinDirs: params.trustedSafeBinDirs,
54
- });
55
- let analysisOk = baseAllowlistEval.analysisOk;
56
- let allowlistSatisfied = false;
57
- if (hostAsk === "on-miss" && hostSecurity === "allowlist" && analysisOk) {
58
- try {
59
- const approvalsSnapshot = await callGatewayTool("exec.approvals.node.get", { timeoutMs: 10_000 }, { nodeId });
60
- const approvalsFile = approvalsSnapshot && typeof approvalsSnapshot === "object"
61
- ? approvalsSnapshot.file
62
- : undefined;
63
- if (approvalsFile && typeof approvalsFile === "object") {
64
- const resolved = resolveExecApprovalsFromFile({
65
- file: approvalsFile,
66
- agentId: params.agentId,
67
- overrides: { security: "allowlist" },
68
- });
69
- // Allowlist-only precheck; safe bins are node-local and may diverge.
70
- const allowlistEval = evaluateShellAllowlist({
71
- command: params.command,
72
- allowlist: resolved.allowlist,
73
- safeBins: new Set(),
74
- cwd: params.workdir,
75
- env: params.env,
76
- platform: nodeInfo?.platform,
77
- trustedSafeBinDirs: params.trustedSafeBinDirs,
78
- });
79
- allowlistSatisfied = allowlistEval.allowlistSatisfied;
80
- analysisOk = allowlistEval.analysisOk;
81
- }
82
- }
83
- catch {
84
- // Fall back to requiring approval if node approvals cannot be fetched.
85
- }
86
- }
87
- const requiresAsk = requiresExecApproval({
88
- ask: hostAsk,
89
- security: hostSecurity,
90
- analysisOk,
91
- allowlistSatisfied,
92
- });
93
- const invokeTimeoutMs = Math.max(10_000, (typeof params.timeoutSec === "number" ? params.timeoutSec : params.defaultTimeoutSec) * 1000 +
94
- 5_000);
95
- const buildInvokeParams = (approvedByAsk, approvalDecision, runId) => ({
96
- nodeId,
97
- command: "system.run",
98
- params: {
99
- command: argv,
100
- rawCommand: params.command,
101
- cwd: params.workdir,
102
- env: nodeEnv,
103
- timeoutMs: typeof params.timeoutSec === "number" ? params.timeoutSec * 1000 : undefined,
104
- agentId: params.agentId,
105
- sessionKey: params.sessionKey,
106
- approved: approvedByAsk,
107
- approvalDecision: approvalDecision ?? undefined,
108
- runId: runId ?? undefined,
109
- },
110
- idempotencyKey: crypto.randomUUID(),
111
- });
112
- if (requiresAsk) {
113
- const approvalId = crypto.randomUUID();
114
- const approvalSlug = createApprovalSlug(approvalId);
115
- const expiresAtMs = Date.now() + DEFAULT_APPROVAL_TIMEOUT_MS;
116
- const contextKey = `exec:${approvalId}`;
117
- const noticeSeconds = Math.max(1, Math.round(params.approvalRunningNoticeMs / 1000));
118
- const warningText = params.warnings.length ? `${params.warnings.join("\n")}\n\n` : "";
119
- void (async () => {
120
- let decision = null;
121
- try {
122
- decision = await requestExecApprovalDecision({
123
- id: approvalId,
124
- command: params.command,
125
- cwd: params.workdir,
126
- host: "node",
127
- security: hostSecurity,
128
- ask: hostAsk,
129
- agentId: params.agentId,
130
- sessionKey: params.sessionKey,
131
- });
132
- }
133
- catch {
134
- emitExecSystemEvent(`Exec denied (node=${nodeId} id=${approvalId}, approval-request-failed): ${params.command}`, { sessionKey: params.notifySessionKey, contextKey });
135
- return;
136
- }
137
- let approvedByAsk = false;
138
- let approvalDecision = null;
139
- let deniedReason = null;
140
- if (decision === "deny") {
141
- deniedReason = "user-denied";
142
- }
143
- else if (!decision) {
144
- if (askFallback === "full") {
145
- approvedByAsk = true;
146
- approvalDecision = "allow-once";
147
- }
148
- else if (askFallback === "allowlist") {
149
- // Defer allowlist enforcement to the node host.
150
- }
151
- else {
152
- deniedReason = "approval-timeout";
153
- }
154
- }
155
- else if (decision === "allow-once") {
156
- approvedByAsk = true;
157
- approvalDecision = "allow-once";
158
- }
159
- else if (decision === "allow-always") {
160
- approvedByAsk = true;
161
- approvalDecision = "allow-always";
162
- }
163
- if (deniedReason) {
164
- emitExecSystemEvent(`Exec denied (node=${nodeId} id=${approvalId}, ${deniedReason}): ${params.command}`, {
165
- sessionKey: params.notifySessionKey,
166
- contextKey,
167
- });
168
- return;
169
- }
170
- let runningTimer = null;
171
- if (params.approvalRunningNoticeMs > 0) {
172
- runningTimer = setTimeout(() => {
173
- emitExecSystemEvent(`Exec running (node=${nodeId} id=${approvalId}, >${noticeSeconds}s): ${params.command}`, { sessionKey: params.notifySessionKey, contextKey });
174
- }, params.approvalRunningNoticeMs);
175
- }
176
- try {
177
- await callGatewayTool("node.invoke", { timeoutMs: invokeTimeoutMs }, buildInvokeParams(approvedByAsk, approvalDecision, approvalId));
178
- }
179
- catch {
180
- emitExecSystemEvent(`Exec denied (node=${nodeId} id=${approvalId}, invoke-failed): ${params.command}`, {
181
- sessionKey: params.notifySessionKey,
182
- contextKey,
183
- });
184
- }
185
- finally {
186
- if (runningTimer) {
187
- clearTimeout(runningTimer);
188
- }
189
- }
190
- })();
191
- return {
192
- content: [
193
- {
194
- type: "text",
195
- text: `${warningText}Approval required (id ${approvalSlug}). ` +
196
- "Approve to run; updates will arrive after completion.",
197
- },
198
- ],
199
- details: {
200
- status: "approval-pending",
201
- approvalId,
202
- approvalSlug,
203
- expiresAtMs,
204
- host: "node",
205
- command: params.command,
206
- cwd: params.workdir,
207
- nodeId,
208
- },
209
- };
210
- }
211
- const startedAt = Date.now();
212
- const raw = await callGatewayTool("node.invoke", { timeoutMs: invokeTimeoutMs }, buildInvokeParams(false, null));
213
- const payload = raw && typeof raw === "object" ? raw.payload : undefined;
214
- const payloadObj = payload && typeof payload === "object" ? payload : {};
215
- const stdout = typeof payloadObj.stdout === "string" ? payloadObj.stdout : "";
216
- const stderr = typeof payloadObj.stderr === "string" ? payloadObj.stderr : "";
217
- const errorText = typeof payloadObj.error === "string" ? payloadObj.error : "";
218
- const success = typeof payloadObj.success === "boolean" ? payloadObj.success : false;
219
- const exitCode = typeof payloadObj.exitCode === "number" ? payloadObj.exitCode : null;
220
- return {
221
- content: [
222
- {
223
- type: "text",
224
- text: stdout || stderr || errorText || "",
225
- },
226
- ],
227
- details: {
228
- status: success ? "completed" : "failed",
229
- exitCode,
230
- durationMs: Date.now() - startedAt,
231
- aggregated: [stdout, stderr, errorText].filter(Boolean).join("\n"),
232
- cwd: params.workdir,
233
- },
234
- };
235
- }