@poolzin/pool-bot 2026.2.11 → 2026.2.18

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 (535) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/agents/agent-scope.js +4 -0
  3. package/dist/agents/announce-idempotency.js +14 -0
  4. package/dist/agents/auth-profiles/usage.js +22 -0
  5. package/dist/agents/auth-profiles.js +1 -1
  6. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
  7. package/dist/agents/bash-tools.exec-runtime.js +438 -0
  8. package/dist/agents/bash-tools.shared.js +6 -0
  9. package/dist/agents/cli-runner/reliability.js +61 -0
  10. package/dist/agents/cli-watchdog-defaults.js +11 -0
  11. package/dist/agents/command-poll-backoff.js +63 -0
  12. package/dist/agents/current-time.js +16 -0
  13. package/dist/agents/glob-pattern.js +42 -0
  14. package/dist/agents/memory-search.js +33 -0
  15. package/dist/agents/model-alias-lines.js +18 -0
  16. package/dist/agents/model-auth-label.js +61 -0
  17. package/dist/agents/model-fallback.js +59 -8
  18. package/dist/agents/models-config.e2e-harness.js +115 -0
  19. package/dist/agents/ollama-stream.js +11 -3
  20. package/dist/agents/openclaw-tools.js +135 -0
  21. package/dist/agents/pi-auth-json.js +118 -0
  22. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
  23. package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
  24. package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
  25. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
  26. package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
  27. package/dist/agents/pi-tools.before-tool-call.js +145 -4
  28. package/dist/agents/pi-tools.js +29 -9
  29. package/dist/agents/pi-tools.policy.js +85 -92
  30. package/dist/agents/pi-tools.schema.js +54 -27
  31. package/dist/agents/queued-file-writer.js +22 -0
  32. package/dist/agents/sandbox/docker.js +133 -40
  33. package/dist/agents/sandbox/fs-bridge.js +146 -0
  34. package/dist/agents/sandbox/fs-paths.js +205 -0
  35. package/dist/agents/sandbox/hash.js +4 -0
  36. package/dist/agents/sandbox/validate-sandbox-security.js +157 -0
  37. package/dist/agents/sandbox-paths.js +3 -0
  38. package/dist/agents/sandbox-tool-policy.js +26 -0
  39. package/dist/agents/sanitize-for-prompt.js +18 -0
  40. package/dist/agents/session-dirs.js +20 -0
  41. package/dist/agents/session-write-lock.js +203 -39
  42. package/dist/agents/skills/filter.js +24 -0
  43. package/dist/agents/skills/tools-dir.js +9 -0
  44. package/dist/agents/skills-install-download.js +290 -0
  45. package/dist/agents/skills-install-output.js +30 -0
  46. package/dist/agents/skills-install.download-test-utils.js +36 -0
  47. package/dist/agents/skills.e2e-test-helpers.js +13 -0
  48. package/dist/agents/subagent-announce-queue.js +59 -15
  49. package/dist/agents/subagent-depth.js +137 -0
  50. package/dist/agents/subagent-registry.js +448 -96
  51. package/dist/agents/subagent-spawn.js +262 -0
  52. package/dist/agents/system-prompt.js +52 -10
  53. package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
  54. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
  55. package/dist/agents/tool-display-common.js +782 -0
  56. package/dist/agents/tool-loop-detection.js +466 -0
  57. package/dist/agents/tool-policy.js +6 -0
  58. package/dist/agents/tools/image-tool.js +1 -1
  59. package/dist/agents/tools/sessions-access.js +178 -0
  60. package/dist/agents/tools/sessions-resolution.js +206 -0
  61. package/dist/agents/tools/subagents-tool.js +616 -0
  62. package/dist/agents/workspace-dir.js +18 -0
  63. package/dist/agents/workspace-dirs.js +14 -0
  64. package/dist/agents/workspace.js +70 -0
  65. package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
  66. package/dist/auto-reply/reply/commands-export-session.js +163 -0
  67. package/dist/auto-reply/reply/commands-mesh.js +245 -0
  68. package/dist/auto-reply/reply/commands-setunset.js +28 -0
  69. package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
  70. package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
  71. package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
  72. package/dist/auto-reply/reply/directive-handling.params.js +1 -0
  73. package/dist/auto-reply/reply/directive-parsing.js +36 -0
  74. package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
  75. package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
  76. package/dist/auto-reply/reply/post-compaction-audit.js +96 -0
  77. package/dist/auto-reply/reply/post-compaction-context.js +98 -0
  78. package/dist/auto-reply/reply/reply-delivery.js +92 -0
  79. package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
  80. package/dist/auto-reply/reply/session-run-accounting.js +33 -0
  81. package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
  82. package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
  83. package/dist/browser/bridge-auth-registry.js +26 -0
  84. package/dist/browser/client-actions-url.js +10 -0
  85. package/dist/browser/control-auth.js +73 -0
  86. package/dist/browser/csrf.js +64 -0
  87. package/dist/browser/http-auth.js +52 -0
  88. package/dist/browser/paths.js +37 -0
  89. package/dist/browser/proxy-files.js +32 -0
  90. package/dist/browser/pw-ai-state.js +7 -0
  91. package/dist/browser/resolved-config-refresh.js +42 -0
  92. package/dist/browser/routes/path-output.js +1 -0
  93. package/dist/browser/server-context.chrome-test-harness.js +20 -0
  94. package/dist/browser/server-middleware.js +31 -0
  95. package/dist/browser/test-port.js +16 -0
  96. package/dist/build-info.json +3 -3
  97. package/dist/canvas-host/file-resolver.js +43 -0
  98. package/dist/channels/account-summary.js +19 -0
  99. package/dist/channels/draft-stream-loop.js +77 -0
  100. package/dist/channels/plugins/account-helpers.js +26 -0
  101. package/dist/channels/telegram/allow-from.js +10 -0
  102. package/dist/cli/browser-cli-resize.js +22 -0
  103. package/dist/cli/browser-cli-shared.js +8 -0
  104. package/dist/cli/clawbot-cli.js +5 -0
  105. package/dist/cli/completion-cli.js +566 -0
  106. package/dist/cli/config-cli.js +63 -5
  107. package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
  108. package/dist/cli/daemon-cli/register-service-commands.js +60 -0
  109. package/dist/cli/daemon-cli-compat.js +80 -0
  110. package/dist/cli/nodes-cli/pairing-render.js +26 -0
  111. package/dist/cli/program/action-reparse.js +17 -0
  112. package/dist/cli/program/command-registry.js +17 -0
  113. package/dist/cli/program/program-context.js +8 -0
  114. package/dist/cli/program/register.subclis.js +7 -0
  115. package/dist/cli/program/routes.js +233 -0
  116. package/dist/cli/qr-cli.js +132 -0
  117. package/dist/cli/requirements-test-fixtures.js +17 -0
  118. package/dist/cli/respawn-policy.js +4 -0
  119. package/dist/cli/shared/parse-port.js +18 -0
  120. package/dist/cli/skills-cli.format.js +241 -0
  121. package/dist/cli/update-cli/progress.js +121 -0
  122. package/dist/cli/update-cli/restart-helper.js +108 -0
  123. package/dist/cli/update-cli/shared.js +196 -0
  124. package/dist/cli/update-cli/status.js +97 -0
  125. package/dist/cli/update-cli/suppress-deprecations.js +17 -0
  126. package/dist/cli/update-cli/update-command.js +506 -0
  127. package/dist/cli/update-cli/wizard.js +130 -0
  128. package/dist/cli/update-cli.js +3 -9
  129. package/dist/cli/windows-argv.js +69 -0
  130. package/dist/commands/auth-choice-legacy.js +20 -0
  131. package/dist/commands/auth-choice.apply-helpers.js +8 -0
  132. package/dist/commands/channel-test-helpers.js +19 -0
  133. package/dist/commands/cleanup-plan.js +10 -0
  134. package/dist/commands/cleanup-utils.js +7 -0
  135. package/dist/commands/config-validation.js +15 -0
  136. package/dist/commands/doctor-completion.js +112 -0
  137. package/dist/commands/doctor-memory-search.js +119 -0
  138. package/dist/commands/doctor-session-locks.js +73 -0
  139. package/dist/commands/doctor.e2e-harness.js +364 -0
  140. package/dist/commands/gateway-presence.js +19 -0
  141. package/dist/commands/model-default.js +35 -0
  142. package/dist/commands/models/fallbacks-shared.js +102 -0
  143. package/dist/commands/models/shared.js +24 -0
  144. package/dist/commands/onboard-auth.config-gateways.js +64 -0
  145. package/dist/commands/onboard-auth.config-litellm.js +45 -0
  146. package/dist/commands/onboard-auth.config-shared.js +116 -0
  147. package/dist/commands/onboard-config.js +16 -0
  148. package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
  149. package/dist/commands/onboard-provider-auth-flags.js +136 -0
  150. package/dist/commands/openai-codex-oauth.js +40 -0
  151. package/dist/commands/test-runtime-config-helpers.js +21 -0
  152. package/dist/commands/test-wizard-helpers.js +68 -0
  153. package/dist/commands/vllm-setup.js +66 -0
  154. package/dist/compat/legacy-names.js +2 -0
  155. package/dist/config/backup-rotation.js +19 -0
  156. package/dist/config/env-preserve.js +122 -0
  157. package/dist/config/includes-scan.js +78 -0
  158. package/dist/config/plugins-allowlist.js +13 -0
  159. package/dist/config/schema.help.js +256 -0
  160. package/dist/config/schema.hints.js +189 -0
  161. package/dist/config/schema.irc.js +20 -0
  162. package/dist/config/schema.labels.js +317 -0
  163. package/dist/config/sessions/delivery-info.js +40 -0
  164. package/dist/config/types.irc.js +1 -0
  165. package/dist/config/zod-schema.agent-defaults.js +14 -0
  166. package/dist/config/zod-schema.agent-model.js +10 -0
  167. package/dist/config/zod-schema.agent-runtime.js +14 -0
  168. package/dist/config/zod-schema.allowdeny.js +35 -0
  169. package/dist/config/zod-schema.sensitive.js +4 -0
  170. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  171. package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
  172. package/dist/cron/isolated-agent/subagent-followup.js +127 -0
  173. package/dist/cron/isolated-agent.mocks.js +12 -0
  174. package/dist/cron/isolated-agent.test-setup.js +22 -0
  175. package/dist/cron/legacy-delivery.js +43 -0
  176. package/dist/cron/webhook-url.js +22 -0
  177. package/dist/daemon/arg-split.js +40 -0
  178. package/dist/daemon/exec-file.js +23 -0
  179. package/dist/daemon/output.js +6 -0
  180. package/dist/daemon/runtime-format.js +31 -0
  181. package/dist/daemon/schtasks-exec.js +4 -0
  182. package/dist/daemon/service-audit.js +22 -0
  183. package/dist/discord/client.js +41 -0
  184. package/dist/discord/components-registry.js +57 -0
  185. package/dist/discord/components.js +816 -0
  186. package/dist/discord/guilds.js +12 -0
  187. package/dist/discord/monitor/gateway-plugin.js +48 -0
  188. package/dist/discord/monitor/presence.js +30 -0
  189. package/dist/discord/send.components.js +115 -0
  190. package/dist/discord/send.shared.js +4 -0
  191. package/dist/discord/ui.js +26 -0
  192. package/dist/discord/voice-message.js +254 -0
  193. package/dist/gateway/agent-event-assistant-text.js +5 -0
  194. package/dist/gateway/agent-prompt.js +33 -0
  195. package/dist/gateway/auth-rate-limit.js +136 -0
  196. package/dist/gateway/channel-health-monitor.js +114 -0
  197. package/dist/gateway/control-ui-contract.js +1 -0
  198. package/dist/gateway/control-ui-csp.js +15 -0
  199. package/dist/gateway/gateway-config-prompts.shared.js +25 -0
  200. package/dist/gateway/http-auth-helpers.js +18 -0
  201. package/dist/gateway/http-common.js +18 -0
  202. package/dist/gateway/http-endpoint-helpers.js +27 -0
  203. package/dist/gateway/node-invoke-sanitize.js +11 -0
  204. package/dist/gateway/node-invoke-system-run-approval.js +205 -0
  205. package/dist/gateway/probe-auth.js +21 -0
  206. package/dist/gateway/protocol/index.js +7 -2
  207. package/dist/gateway/protocol/schema/mesh.js +54 -0
  208. package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
  209. package/dist/gateway/protocol/schema.js +1 -0
  210. package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
  211. package/dist/gateway/server-channels.js +11 -0
  212. package/dist/gateway/server-methods/attachment-normalize.js +16 -0
  213. package/dist/gateway/server-methods/base-hash.js +8 -0
  214. package/dist/gateway/server-methods/mesh.js +700 -0
  215. package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
  216. package/dist/gateway/server-methods/restart-request.js +13 -0
  217. package/dist/gateway/server-methods/validation.js +8 -0
  218. package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
  219. package/dist/gateway/server.e2e-registry-helpers.js +1 -0
  220. package/dist/gateway/server.e2e-ws-harness.js +20 -0
  221. package/dist/gateway/test-helpers.js +2 -0
  222. package/dist/gateway/test-helpers.server.js +3 -1
  223. package/dist/gateway/test-http-response.js +12 -0
  224. package/dist/gateway/test-openai-responses-model.js +20 -0
  225. package/dist/gateway/test-temp-config.js +30 -0
  226. package/dist/gateway/test-with-server.js +32 -0
  227. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
  228. package/dist/imessage/monitor/abort-handler.js +23 -0
  229. package/dist/imessage/monitor/inbound-processing.js +346 -0
  230. package/dist/imessage/monitor/parse-notification.js +64 -0
  231. package/dist/imessage/target-parsing-helpers.js +92 -0
  232. package/dist/infra/archive.js +244 -20
  233. package/dist/infra/detect-package-manager.js +26 -0
  234. package/dist/infra/exec-approvals-allowlist.js +257 -0
  235. package/dist/infra/exec-approvals-analysis.js +770 -0
  236. package/dist/infra/exec-approvals.js +13 -0
  237. package/dist/infra/file-lock.js +1 -0
  238. package/dist/infra/gemini-auth.js +39 -0
  239. package/dist/infra/heartbeat-active-hours.js +85 -0
  240. package/dist/infra/heartbeat-events-filter.js +50 -0
  241. package/dist/infra/heartbeat-runner.test-utils.js +39 -0
  242. package/dist/infra/http-body.js +265 -0
  243. package/dist/infra/install-package-dir.js +50 -0
  244. package/dist/infra/install-safe-path.js +49 -0
  245. package/dist/infra/json-files.js +49 -0
  246. package/dist/infra/jsonl-socket.js +52 -0
  247. package/dist/infra/map-size.js +14 -0
  248. package/dist/infra/net/hostname.js +7 -0
  249. package/dist/infra/npm-registry-spec.js +39 -0
  250. package/dist/infra/openclaw-root.js +109 -0
  251. package/dist/infra/outbound/delivery-queue.js +214 -0
  252. package/dist/infra/outbound/identity.js +23 -0
  253. package/dist/infra/outbound/message-action-params.js +307 -0
  254. package/dist/infra/outbound/tool-payload.js +21 -0
  255. package/dist/infra/package-json.js +23 -0
  256. package/dist/infra/pairing-files.js +19 -0
  257. package/dist/infra/pairing-token.js +9 -0
  258. package/dist/infra/path-prepend.js +51 -0
  259. package/dist/infra/path-safety.js +16 -0
  260. package/dist/infra/process-respawn.js +49 -0
  261. package/dist/infra/runtime-status.js +16 -0
  262. package/dist/infra/session-cost-usage.types.js +1 -0
  263. package/dist/infra/session-maintenance-warning.js +89 -0
  264. package/dist/infra/system-run-command.js +78 -0
  265. package/dist/infra/tmp-openclaw-dir.js +81 -0
  266. package/dist/infra/tmp-poolbot-dir.js +2 -0
  267. package/dist/infra/update-channels.js +19 -0
  268. package/dist/line/actions.js +45 -0
  269. package/dist/line/channel-access-token.js +9 -0
  270. package/dist/line/flex-templates/basic-cards.js +332 -0
  271. package/dist/line/flex-templates/common.js +18 -0
  272. package/dist/line/flex-templates/media-control-cards.js +453 -0
  273. package/dist/line/flex-templates/message.js +10 -0
  274. package/dist/line/flex-templates/schedule-cards.js +399 -0
  275. package/dist/line/flex-templates/types.js +1 -0
  276. package/dist/line/webhook-node.js +100 -0
  277. package/dist/line/webhook-utils.js +11 -0
  278. package/dist/logging/diagnostic-session-state.js +73 -0
  279. package/dist/logging/diagnostic.js +22 -0
  280. package/dist/logging/timestamps.js +14 -0
  281. package/dist/markdown/whatsapp.js +62 -0
  282. package/dist/media/base64.js +34 -0
  283. package/dist/media/local-roots.js +32 -0
  284. package/dist/media/outbound-attachment.js +10 -0
  285. package/dist/media/read-response-with-limit.js +41 -0
  286. package/dist/media/sniff-mime-from-base64.js +19 -0
  287. package/dist/media-understanding/audio-preflight.js +67 -0
  288. package/dist/media-understanding/fs.js +13 -0
  289. package/dist/media-understanding/output-extract.js +26 -0
  290. package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
  291. package/dist/media-understanding/providers/google/inline-data.js +64 -0
  292. package/dist/media-understanding/providers/shared.js +7 -0
  293. package/dist/media-understanding/runner.entries.js +459 -0
  294. package/dist/memory/batch-error-utils.js +11 -0
  295. package/dist/memory/batch-http.js +27 -0
  296. package/dist/memory/batch-output.js +29 -0
  297. package/dist/memory/batch-runner.js +22 -0
  298. package/dist/memory/batch-upload.js +23 -0
  299. package/dist/memory/batch-utils.js +26 -0
  300. package/dist/memory/embeddings-debug.js +11 -0
  301. package/dist/memory/embeddings-remote-client.js +22 -0
  302. package/dist/memory/embeddings-remote-fetch.js +14 -0
  303. package/dist/memory/embeddings.js +36 -9
  304. package/dist/memory/hybrid.js +24 -5
  305. package/dist/memory/manager-embedding-ops.js +616 -0
  306. package/dist/memory/manager-sync-ops.js +953 -0
  307. package/dist/memory/manager.js +76 -28
  308. package/dist/memory/mmr.js +164 -0
  309. package/dist/memory/qmd-manager.js +1061 -0
  310. package/dist/memory/qmd-query-parser.js +107 -0
  311. package/dist/memory/qmd-scope.js +93 -0
  312. package/dist/memory/query-expansion.js +331 -0
  313. package/dist/memory/search-manager.js +0 -1
  314. package/dist/memory/sync-index.js +21 -0
  315. package/dist/memory/sync-progress.js +22 -0
  316. package/dist/memory/sync-stale.js +30 -0
  317. package/dist/memory/temporal-decay.js +119 -0
  318. package/dist/memory/test-embeddings-mock.js +16 -0
  319. package/dist/memory/test-manager-helpers.js +14 -0
  320. package/dist/memory/test-runtime-mocks.js +11 -0
  321. package/dist/node-host/invoke-browser.js +177 -0
  322. package/dist/node-host/invoke.js +685 -0
  323. package/dist/pairing/setup-code.js +285 -0
  324. package/dist/plugin-sdk/account-id.js +1 -0
  325. package/dist/plugin-sdk/agent-media-payload.js +13 -0
  326. package/dist/plugin-sdk/allow-from.js +47 -0
  327. package/dist/plugin-sdk/command-auth.js +23 -0
  328. package/dist/plugin-sdk/config-paths.js +9 -0
  329. package/dist/plugin-sdk/file-lock.js +116 -0
  330. package/dist/plugin-sdk/json-store.js +31 -0
  331. package/dist/plugin-sdk/onboarding.js +28 -0
  332. package/dist/plugin-sdk/provider-auth-result.js +29 -0
  333. package/dist/plugin-sdk/slack-message-actions.js +133 -0
  334. package/dist/plugin-sdk/status-helpers.js +35 -0
  335. package/dist/plugin-sdk/text-chunking.js +31 -0
  336. package/dist/plugin-sdk/tool-send.js +12 -0
  337. package/dist/plugin-sdk/webhook-path.js +27 -0
  338. package/dist/plugin-sdk/webhook-targets.js +34 -0
  339. package/dist/plugins/hooks.test-helpers.js +21 -0
  340. package/dist/plugins/uninstall.js +171 -0
  341. package/dist/process/kill-tree.js +98 -0
  342. package/dist/process/supervisor/adapters/child.js +143 -0
  343. package/dist/process/supervisor/adapters/env.js +13 -0
  344. package/dist/process/supervisor/adapters/pty.js +148 -0
  345. package/dist/process/supervisor/index.js +10 -0
  346. package/dist/process/supervisor/registry.js +117 -0
  347. package/dist/process/supervisor/supervisor.js +244 -0
  348. package/dist/process/supervisor/types.js +1 -0
  349. package/dist/providers/google-shared.test-helpers.js +75 -0
  350. package/dist/security/audit-channel.js +419 -0
  351. package/dist/security/audit-tool-policy.js +1 -0
  352. package/dist/security/scan-paths.js +12 -0
  353. package/dist/sessions/input-provenance.js +55 -0
  354. package/dist/sessions/session-key-utils.js +7 -0
  355. package/dist/shared/chat-content.js +31 -0
  356. package/dist/shared/chat-envelope.js +45 -0
  357. package/dist/shared/config-eval.js +117 -0
  358. package/dist/shared/device-auth.js +16 -0
  359. package/dist/shared/entry-metadata.js +9 -0
  360. package/dist/shared/entry-status.js +25 -0
  361. package/dist/shared/frontmatter.js +98 -0
  362. package/dist/shared/model-param-b.js +19 -0
  363. package/dist/shared/net/ipv4.js +17 -0
  364. package/dist/shared/node-match.js +53 -0
  365. package/dist/shared/pid-alive.js +12 -0
  366. package/dist/shared/process-scoped-map.js +10 -0
  367. package/dist/shared/requirements.js +128 -0
  368. package/dist/shared/subagents-format.js +84 -0
  369. package/dist/shared/usage-aggregates.js +28 -0
  370. package/dist/signal/monitor/mentions.js +45 -0
  371. package/dist/signal/rpc-context.js +19 -0
  372. package/dist/slack/blocks-fallback.js +76 -0
  373. package/dist/slack/blocks-input.js +40 -0
  374. package/dist/slack/draft-stream.js +106 -0
  375. package/dist/slack/message-actions.js +51 -0
  376. package/dist/slack/modal-metadata.js +32 -0
  377. package/dist/slack/monitor/events/interactions.js +462 -0
  378. package/dist/slack/monitor/room-context.js +17 -0
  379. package/dist/slack/stream-mode.js +41 -0
  380. package/dist/telegram/bot-native-command-menu.js +64 -0
  381. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  382. package/dist/telegram/button-types.js +1 -0
  383. package/dist/telegram/group-access.js +65 -0
  384. package/dist/telegram/outbound-params.js +21 -0
  385. package/dist/telegram/poll-vote-cache.js +21 -0
  386. package/dist/terminal/health-style.js +36 -0
  387. package/dist/test-utils/chunk-test-helpers.js +21 -0
  388. package/dist/test-utils/env.js +72 -0
  389. package/dist/test-utils/exec-assertions.js +12 -0
  390. package/dist/test-utils/imessage-test-plugin.js +54 -0
  391. package/dist/test-utils/mock-http-response.js +17 -0
  392. package/dist/test-utils/vitest-mock-fn.js +1 -0
  393. package/dist/tts/tts-core.js +550 -0
  394. package/dist/utils/chunk-items.js +10 -0
  395. package/dist/utils/reaction-level.js +52 -0
  396. package/dist/utils/safe-json.js +22 -0
  397. package/dist/utils/with-timeout.js +14 -0
  398. package/dist/web/media.js +17 -5
  399. package/dist/whatsapp/resolve-outbound-target.js +42 -0
  400. package/dist/wizard/onboarding.completion.js +74 -0
  401. package/extensions/bluebubbles/package.json +1 -1
  402. package/extensions/bluebubbles/src/account-resolve.ts +29 -0
  403. package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
  404. package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
  405. package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
  406. package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
  407. package/extensions/bluebubbles/src/multipart.ts +32 -0
  408. package/extensions/bluebubbles/src/send-helpers.ts +53 -0
  409. package/extensions/bluebubbles/src/test-harness.ts +50 -0
  410. package/extensions/bluebubbles/src/test-mocks.ts +11 -0
  411. package/extensions/copilot-proxy/package.json +1 -1
  412. package/extensions/device-pair/index.ts +554 -0
  413. package/extensions/diagnostics-otel/package.json +1 -1
  414. package/extensions/discord/package.json +1 -1
  415. package/extensions/discord/src/channel.js +366 -0
  416. package/extensions/discord/src/runtime.js +10 -0
  417. package/extensions/feishu/index.ts +63 -0
  418. package/extensions/feishu/src/accounts.ts +114 -0
  419. package/extensions/feishu/src/bitable.ts +739 -0
  420. package/extensions/feishu/src/bot.ts +965 -0
  421. package/extensions/feishu/src/channel.ts +351 -0
  422. package/extensions/feishu/src/client.ts +118 -0
  423. package/extensions/feishu/src/config-schema.ts +206 -0
  424. package/extensions/feishu/src/dedup.ts +33 -0
  425. package/extensions/feishu/src/directory.ts +177 -0
  426. package/extensions/feishu/src/doc-schema.ts +47 -0
  427. package/extensions/feishu/src/docx.ts +536 -0
  428. package/extensions/feishu/src/drive-schema.ts +46 -0
  429. package/extensions/feishu/src/drive.ts +227 -0
  430. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  431. package/extensions/feishu/src/media.ts +449 -0
  432. package/extensions/feishu/src/mention.ts +126 -0
  433. package/extensions/feishu/src/monitor.ts +330 -0
  434. package/extensions/feishu/src/onboarding.ts +359 -0
  435. package/extensions/feishu/src/outbound.ts +55 -0
  436. package/extensions/feishu/src/perm-schema.ts +52 -0
  437. package/extensions/feishu/src/perm.ts +173 -0
  438. package/extensions/feishu/src/policy.ts +84 -0
  439. package/extensions/feishu/src/probe.ts +44 -0
  440. package/extensions/feishu/src/reactions.ts +160 -0
  441. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  442. package/extensions/feishu/src/runtime.ts +14 -0
  443. package/extensions/feishu/src/send-result.ts +29 -0
  444. package/extensions/feishu/src/send.ts +335 -0
  445. package/extensions/feishu/src/streaming-card.ts +223 -0
  446. package/extensions/feishu/src/targets.ts +78 -0
  447. package/extensions/feishu/src/tools-config.ts +21 -0
  448. package/extensions/feishu/src/types.ts +81 -0
  449. package/extensions/feishu/src/typing.ts +80 -0
  450. package/extensions/feishu/src/wiki-schema.ts +55 -0
  451. package/extensions/feishu/src/wiki.ts +232 -0
  452. package/extensions/google-antigravity-auth/package.json +1 -1
  453. package/extensions/google-gemini-cli-auth/package.json +1 -1
  454. package/extensions/googlechat/package.json +1 -1
  455. package/extensions/imessage/package.json +1 -1
  456. package/extensions/imessage/src/channel.js +253 -0
  457. package/extensions/imessage/src/runtime.js +10 -0
  458. package/extensions/irc/index.ts +17 -0
  459. package/extensions/irc/src/accounts.ts +268 -0
  460. package/extensions/irc/src/channel.ts +367 -0
  461. package/extensions/irc/src/client.ts +439 -0
  462. package/extensions/irc/src/config-schema.ts +97 -0
  463. package/extensions/irc/src/connect-options.ts +30 -0
  464. package/extensions/irc/src/control-chars.ts +22 -0
  465. package/extensions/irc/src/inbound.ts +334 -0
  466. package/extensions/irc/src/monitor.ts +147 -0
  467. package/extensions/irc/src/normalize.ts +117 -0
  468. package/extensions/irc/src/onboarding.ts +479 -0
  469. package/extensions/irc/src/policy.ts +157 -0
  470. package/extensions/irc/src/probe.ts +53 -0
  471. package/extensions/irc/src/protocol.ts +169 -0
  472. package/extensions/irc/src/runtime.ts +14 -0
  473. package/extensions/irc/src/send.ts +88 -0
  474. package/extensions/irc/src/types.ts +93 -0
  475. package/extensions/line/package.json +1 -1
  476. package/extensions/llm-task/package.json +1 -1
  477. package/extensions/lobster/package.json +1 -1
  478. package/extensions/matrix/CHANGELOG.md +5 -0
  479. package/extensions/matrix/package.json +1 -1
  480. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  481. package/extensions/mattermost/package.json +1 -1
  482. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  483. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  484. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  485. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  486. package/extensions/memory-core/package.json +1 -1
  487. package/extensions/memory-lancedb/package.json +1 -1
  488. package/extensions/minimax-portal-auth/index.ts +161 -0
  489. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  490. package/extensions/msteams/CHANGELOG.md +5 -0
  491. package/extensions/msteams/package.json +1 -1
  492. package/extensions/msteams/src/file-lock.ts +1 -0
  493. package/extensions/msteams/src/graph.ts +92 -0
  494. package/extensions/msteams/src/mentions.ts +114 -0
  495. package/extensions/msteams/src/test-runtime.ts +16 -0
  496. package/extensions/nextcloud-talk/package.json +1 -1
  497. package/extensions/nostr/CHANGELOG.md +5 -0
  498. package/extensions/nostr/package.json +1 -1
  499. package/extensions/open-prose/package.json +1 -1
  500. package/extensions/openai-codex-auth/index.ts +177 -0
  501. package/extensions/phone-control/index.ts +421 -0
  502. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  503. package/extensions/signal/package.json +1 -1
  504. package/extensions/signal/src/channel.js +273 -0
  505. package/extensions/signal/src/runtime.js +10 -0
  506. package/extensions/slack/package.json +1 -1
  507. package/extensions/slack/src/channel.js +489 -0
  508. package/extensions/slack/src/runtime.js +10 -0
  509. package/extensions/talk-voice/index.ts +150 -0
  510. package/extensions/telegram/package.json +1 -1
  511. package/extensions/telegram/src/channel.js +424 -0
  512. package/extensions/telegram/src/runtime.js +10 -0
  513. package/extensions/thread-ownership/index.ts +133 -0
  514. package/extensions/tlon/package.json +1 -1
  515. package/extensions/tlon/src/account-fields.ts +25 -0
  516. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  517. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  518. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  519. package/extensions/tlon/src/urbit/context.ts +47 -0
  520. package/extensions/tlon/src/urbit/errors.ts +51 -0
  521. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  522. package/extensions/twitch/CHANGELOG.md +5 -0
  523. package/extensions/twitch/package.json +1 -1
  524. package/extensions/twitch/src/test-fixtures.ts +30 -0
  525. package/extensions/voice-call/CHANGELOG.md +5 -0
  526. package/extensions/voice-call/package.json +1 -1
  527. package/extensions/voice-call/src/allowlist.ts +19 -0
  528. package/extensions/whatsapp/package.json +1 -1
  529. package/extensions/whatsapp/src/channel.js +429 -0
  530. package/extensions/whatsapp/src/runtime.js +10 -0
  531. package/extensions/zalo/CHANGELOG.md +5 -0
  532. package/extensions/zalo/package.json +1 -1
  533. package/extensions/zalouser/CHANGELOG.md +5 -0
  534. package/extensions/zalouser/package.json +1 -1
  535. package/package.json +1 -1
@@ -0,0 +1,133 @@
1
+ import { readNumberParam, readStringParam } from "../agents/tools/common.js";
2
+ import { parseSlackBlocksInput } from "../slack/blocks-input.js";
3
+ function readSlackBlocksParam(actionParams) {
4
+ return parseSlackBlocksInput(actionParams.blocks);
5
+ }
6
+ export async function handleSlackMessageAction(params) {
7
+ const { providerId, ctx, invoke, normalizeChannelId, includeReadThreadId = false } = params;
8
+ const { action, cfg, params: actionParams } = ctx;
9
+ const accountId = ctx.accountId ?? undefined;
10
+ const resolveChannelId = () => {
11
+ const channelId = readStringParam(actionParams, "channelId") ??
12
+ readStringParam(actionParams, "to", { required: true });
13
+ return normalizeChannelId ? normalizeChannelId(channelId) : channelId;
14
+ };
15
+ if (action === "send") {
16
+ const to = readStringParam(actionParams, "to", { required: true });
17
+ const content = readStringParam(actionParams, "message", {
18
+ required: false,
19
+ allowEmpty: true,
20
+ });
21
+ const mediaUrl = readStringParam(actionParams, "media", { trim: false });
22
+ const blocks = readSlackBlocksParam(actionParams);
23
+ if (!content && !mediaUrl && !blocks) {
24
+ throw new Error("Slack send requires message, blocks, or media.");
25
+ }
26
+ if (mediaUrl && blocks) {
27
+ throw new Error("Slack send does not support blocks with media.");
28
+ }
29
+ const threadId = readStringParam(actionParams, "threadId");
30
+ const replyTo = readStringParam(actionParams, "replyTo");
31
+ return await invoke({
32
+ action: "sendMessage",
33
+ to,
34
+ content: content ?? "",
35
+ mediaUrl: mediaUrl ?? undefined,
36
+ blocks,
37
+ accountId,
38
+ threadTs: threadId ?? replyTo ?? undefined,
39
+ }, cfg, ctx.toolContext);
40
+ }
41
+ if (action === "react") {
42
+ const messageId = readStringParam(actionParams, "messageId", {
43
+ required: true,
44
+ });
45
+ const emoji = readStringParam(actionParams, "emoji", { allowEmpty: true });
46
+ const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : undefined;
47
+ return await invoke({
48
+ action: "react",
49
+ channelId: resolveChannelId(),
50
+ messageId,
51
+ emoji,
52
+ remove,
53
+ accountId,
54
+ }, cfg);
55
+ }
56
+ if (action === "reactions") {
57
+ const messageId = readStringParam(actionParams, "messageId", {
58
+ required: true,
59
+ });
60
+ const limit = readNumberParam(actionParams, "limit", { integer: true });
61
+ return await invoke({
62
+ action: "reactions",
63
+ channelId: resolveChannelId(),
64
+ messageId,
65
+ limit,
66
+ accountId,
67
+ }, cfg);
68
+ }
69
+ if (action === "read") {
70
+ const limit = readNumberParam(actionParams, "limit", { integer: true });
71
+ const readAction = {
72
+ action: "readMessages",
73
+ channelId: resolveChannelId(),
74
+ limit,
75
+ before: readStringParam(actionParams, "before"),
76
+ after: readStringParam(actionParams, "after"),
77
+ accountId,
78
+ };
79
+ if (includeReadThreadId) {
80
+ readAction.threadId = readStringParam(actionParams, "threadId");
81
+ }
82
+ return await invoke(readAction, cfg);
83
+ }
84
+ if (action === "edit") {
85
+ const messageId = readStringParam(actionParams, "messageId", {
86
+ required: true,
87
+ });
88
+ const content = readStringParam(actionParams, "message", { allowEmpty: true });
89
+ const blocks = readSlackBlocksParam(actionParams);
90
+ if (!content && !blocks) {
91
+ throw new Error("Slack edit requires message or blocks.");
92
+ }
93
+ return await invoke({
94
+ action: "editMessage",
95
+ channelId: resolveChannelId(),
96
+ messageId,
97
+ content: content ?? "",
98
+ blocks,
99
+ accountId,
100
+ }, cfg);
101
+ }
102
+ if (action === "delete") {
103
+ const messageId = readStringParam(actionParams, "messageId", {
104
+ required: true,
105
+ });
106
+ return await invoke({
107
+ action: "deleteMessage",
108
+ channelId: resolveChannelId(),
109
+ messageId,
110
+ accountId,
111
+ }, cfg);
112
+ }
113
+ if (action === "pin" || action === "unpin" || action === "list-pins") {
114
+ const messageId = action === "list-pins"
115
+ ? undefined
116
+ : readStringParam(actionParams, "messageId", { required: true });
117
+ return await invoke({
118
+ action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins",
119
+ channelId: resolveChannelId(),
120
+ messageId,
121
+ accountId,
122
+ }, cfg);
123
+ }
124
+ if (action === "member-info") {
125
+ const userId = readStringParam(actionParams, "userId", { required: true });
126
+ return await invoke({ action: "memberInfo", userId, accountId }, cfg);
127
+ }
128
+ if (action === "emoji-list") {
129
+ const limit = readNumberParam(actionParams, "limit", { integer: true });
130
+ return await invoke({ action: "emojiList", limit, accountId }, cfg);
131
+ }
132
+ throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
133
+ }
@@ -0,0 +1,35 @@
1
+ export function createDefaultChannelRuntimeState(accountId, extra) {
2
+ return {
3
+ accountId,
4
+ running: false,
5
+ lastStartAt: null,
6
+ lastStopAt: null,
7
+ lastError: null,
8
+ ...(extra ?? {}),
9
+ };
10
+ }
11
+ export function buildBaseChannelStatusSummary(snapshot) {
12
+ return {
13
+ configured: snapshot.configured ?? false,
14
+ running: snapshot.running ?? false,
15
+ lastStartAt: snapshot.lastStartAt ?? null,
16
+ lastStopAt: snapshot.lastStopAt ?? null,
17
+ lastError: snapshot.lastError ?? null,
18
+ };
19
+ }
20
+ export function collectStatusIssuesFromLastError(channel, accounts) {
21
+ return accounts.flatMap((account) => {
22
+ const lastError = typeof account.lastError === "string" ? account.lastError.trim() : "";
23
+ if (!lastError) {
24
+ return [];
25
+ }
26
+ return [
27
+ {
28
+ channel,
29
+ accountId: account.accountId,
30
+ kind: "runtime",
31
+ message: `Channel error: ${lastError}`,
32
+ },
33
+ ];
34
+ });
35
+ }
@@ -0,0 +1,31 @@
1
+ export function chunkTextForOutbound(text, limit) {
2
+ if (!text) {
3
+ return [];
4
+ }
5
+ if (limit <= 0 || text.length <= limit) {
6
+ return [text];
7
+ }
8
+ const chunks = [];
9
+ let remaining = text;
10
+ while (remaining.length > limit) {
11
+ const window = remaining.slice(0, limit);
12
+ const lastNewline = window.lastIndexOf("\n");
13
+ const lastSpace = window.lastIndexOf(" ");
14
+ let breakIdx = lastNewline > 0 ? lastNewline : lastSpace;
15
+ if (breakIdx <= 0) {
16
+ breakIdx = limit;
17
+ }
18
+ const rawChunk = remaining.slice(0, breakIdx);
19
+ const chunk = rawChunk.trimEnd();
20
+ if (chunk.length > 0) {
21
+ chunks.push(chunk);
22
+ }
23
+ const brokeOnSeparator = breakIdx < remaining.length && /\s/.test(remaining[breakIdx]);
24
+ const nextStart = Math.min(remaining.length, breakIdx + (brokeOnSeparator ? 1 : 0));
25
+ remaining = remaining.slice(nextStart).trimStart();
26
+ }
27
+ if (remaining.length) {
28
+ chunks.push(remaining);
29
+ }
30
+ return chunks;
31
+ }
@@ -0,0 +1,12 @@
1
+ export function extractToolSend(args, expectedAction = "sendMessage") {
2
+ const action = typeof args.action === "string" ? args.action.trim() : "";
3
+ if (action !== expectedAction) {
4
+ return null;
5
+ }
6
+ const to = typeof args.to === "string" ? args.to : undefined;
7
+ if (!to) {
8
+ return null;
9
+ }
10
+ const accountId = typeof args.accountId === "string" ? args.accountId.trim() : undefined;
11
+ return { to, accountId };
12
+ }
@@ -0,0 +1,27 @@
1
+ export function normalizeWebhookPath(raw) {
2
+ const trimmed = raw.trim();
3
+ if (!trimmed) {
4
+ return "/";
5
+ }
6
+ const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
7
+ if (withSlash.length > 1 && withSlash.endsWith("/")) {
8
+ return withSlash.slice(0, -1);
9
+ }
10
+ return withSlash;
11
+ }
12
+ export function resolveWebhookPath(params) {
13
+ const trimmedPath = params.webhookPath?.trim();
14
+ if (trimmedPath) {
15
+ return normalizeWebhookPath(trimmedPath);
16
+ }
17
+ if (params.webhookUrl?.trim()) {
18
+ try {
19
+ const parsed = new URL(params.webhookUrl);
20
+ return normalizeWebhookPath(parsed.pathname || "/");
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ return params.defaultPath ?? null;
27
+ }
@@ -0,0 +1,34 @@
1
+ import { normalizeWebhookPath } from "./webhook-path.js";
2
+ export function registerWebhookTarget(targetsByPath, target) {
3
+ const key = normalizeWebhookPath(target.path);
4
+ const normalizedTarget = { ...target, path: key };
5
+ const existing = targetsByPath.get(key) ?? [];
6
+ targetsByPath.set(key, [...existing, normalizedTarget]);
7
+ const unregister = () => {
8
+ const updated = (targetsByPath.get(key) ?? []).filter((entry) => entry !== normalizedTarget);
9
+ if (updated.length > 0) {
10
+ targetsByPath.set(key, updated);
11
+ return;
12
+ }
13
+ targetsByPath.delete(key);
14
+ };
15
+ return { target: normalizedTarget, unregister };
16
+ }
17
+ export function resolveWebhookTargets(req, targetsByPath) {
18
+ const url = new URL(req.url ?? "/", "http://localhost");
19
+ const path = normalizeWebhookPath(url.pathname);
20
+ const targets = targetsByPath.get(path);
21
+ if (!targets || targets.length === 0) {
22
+ return null;
23
+ }
24
+ return { path, targets };
25
+ }
26
+ export function rejectNonPostWebhookRequest(req, res) {
27
+ if (req.method === "POST") {
28
+ return false;
29
+ }
30
+ res.statusCode = 405;
31
+ res.setHeader("Allow", "POST");
32
+ res.end("Method Not Allowed");
33
+ return true;
34
+ }
@@ -0,0 +1,21 @@
1
+ export function createMockPluginRegistry(hooks) {
2
+ return {
3
+ hooks: hooks,
4
+ typedHooks: hooks.map((h) => ({
5
+ pluginId: "test-plugin",
6
+ hookName: h.hookName,
7
+ handler: h.handler,
8
+ priority: 0,
9
+ source: "test",
10
+ })),
11
+ tools: [],
12
+ httpHandlers: [],
13
+ httpRoutes: [],
14
+ channelRegistrations: [],
15
+ gatewayHandlers: {},
16
+ cliRegistrars: [],
17
+ services: [],
18
+ providers: [],
19
+ commands: [],
20
+ };
21
+ }
@@ -0,0 +1,171 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { resolvePluginInstallDir } from "./install.js";
4
+ import { defaultSlotIdForKey } from "./slots.js";
5
+ export function resolveUninstallDirectoryTarget(params) {
6
+ if (!params.hasInstall) {
7
+ return null;
8
+ }
9
+ if (params.installRecord?.source === "path") {
10
+ return null;
11
+ }
12
+ let defaultPath;
13
+ try {
14
+ defaultPath = resolvePluginInstallDir(params.pluginId, params.extensionsDir);
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ const configuredPath = params.installRecord?.installPath;
20
+ if (!configuredPath) {
21
+ return defaultPath;
22
+ }
23
+ if (path.resolve(configuredPath) === path.resolve(defaultPath)) {
24
+ return configuredPath;
25
+ }
26
+ // Never trust configured installPath blindly for recursive deletes.
27
+ return defaultPath;
28
+ }
29
+ /**
30
+ * Remove plugin references from config (pure config mutation).
31
+ * Returns a new config with the plugin removed from entries, installs, allow, load.paths, and slots.
32
+ */
33
+ export function removePluginFromConfig(cfg, pluginId) {
34
+ const actions = {
35
+ entry: false,
36
+ install: false,
37
+ allowlist: false,
38
+ loadPath: false,
39
+ memorySlot: false,
40
+ };
41
+ const pluginsConfig = cfg.plugins ?? {};
42
+ // Remove from entries
43
+ let entries = pluginsConfig.entries;
44
+ if (entries && pluginId in entries) {
45
+ const { [pluginId]: _, ...rest } = entries;
46
+ entries = Object.keys(rest).length > 0 ? rest : undefined;
47
+ actions.entry = true;
48
+ }
49
+ // Remove from installs
50
+ let installs = pluginsConfig.installs;
51
+ const installRecord = installs?.[pluginId];
52
+ if (installs && pluginId in installs) {
53
+ const { [pluginId]: _, ...rest } = installs;
54
+ installs = Object.keys(rest).length > 0 ? rest : undefined;
55
+ actions.install = true;
56
+ }
57
+ // Remove from allowlist
58
+ let allow = pluginsConfig.allow;
59
+ if (Array.isArray(allow) && allow.includes(pluginId)) {
60
+ allow = allow.filter((id) => id !== pluginId);
61
+ if (allow.length === 0) {
62
+ allow = undefined;
63
+ }
64
+ actions.allowlist = true;
65
+ }
66
+ // Remove linked path from load.paths (for source === "path" plugins)
67
+ let load = pluginsConfig.load;
68
+ if (installRecord?.source === "path" && installRecord.sourcePath) {
69
+ const sourcePath = installRecord.sourcePath;
70
+ const loadPaths = load?.paths;
71
+ if (Array.isArray(loadPaths) && loadPaths.includes(sourcePath)) {
72
+ const nextLoadPaths = loadPaths.filter((p) => p !== sourcePath);
73
+ load = nextLoadPaths.length > 0 ? { ...load, paths: nextLoadPaths } : undefined;
74
+ actions.loadPath = true;
75
+ }
76
+ }
77
+ // Reset memory slot if this plugin was selected
78
+ let slots = pluginsConfig.slots;
79
+ if (slots?.memory === pluginId) {
80
+ slots = {
81
+ ...slots,
82
+ memory: defaultSlotIdForKey("memory"),
83
+ };
84
+ actions.memorySlot = true;
85
+ }
86
+ if (slots && Object.keys(slots).length === 0) {
87
+ slots = undefined;
88
+ }
89
+ const newPlugins = {
90
+ ...pluginsConfig,
91
+ entries,
92
+ installs,
93
+ allow,
94
+ load,
95
+ slots,
96
+ };
97
+ // Clean up undefined properties from newPlugins
98
+ const cleanedPlugins = { ...newPlugins };
99
+ if (cleanedPlugins.entries === undefined) {
100
+ delete cleanedPlugins.entries;
101
+ }
102
+ if (cleanedPlugins.installs === undefined) {
103
+ delete cleanedPlugins.installs;
104
+ }
105
+ if (cleanedPlugins.allow === undefined) {
106
+ delete cleanedPlugins.allow;
107
+ }
108
+ if (cleanedPlugins.load === undefined) {
109
+ delete cleanedPlugins.load;
110
+ }
111
+ if (cleanedPlugins.slots === undefined) {
112
+ delete cleanedPlugins.slots;
113
+ }
114
+ const config = {
115
+ ...cfg,
116
+ plugins: Object.keys(cleanedPlugins).length > 0 ? cleanedPlugins : undefined,
117
+ };
118
+ return { config, actions };
119
+ }
120
+ /**
121
+ * Uninstall a plugin by removing it from config and optionally deleting installed files.
122
+ * Linked plugins (source === "path") never have their source directory deleted.
123
+ */
124
+ export async function uninstallPlugin(params) {
125
+ const { config, pluginId, deleteFiles = true, extensionsDir } = params;
126
+ // Validate plugin exists
127
+ const hasEntry = pluginId in (config.plugins?.entries ?? {});
128
+ const hasInstall = pluginId in (config.plugins?.installs ?? {});
129
+ if (!hasEntry && !hasInstall) {
130
+ return { ok: false, error: `Plugin not found: ${pluginId}` };
131
+ }
132
+ const installRecord = config.plugins?.installs?.[pluginId];
133
+ const isLinked = installRecord?.source === "path";
134
+ // Remove from config
135
+ const { config: newConfig, actions: configActions } = removePluginFromConfig(config, pluginId);
136
+ const actions = {
137
+ ...configActions,
138
+ directory: false,
139
+ };
140
+ const warnings = [];
141
+ const deleteTarget = deleteFiles && !isLinked
142
+ ? resolveUninstallDirectoryTarget({
143
+ pluginId,
144
+ hasInstall,
145
+ installRecord,
146
+ extensionsDir,
147
+ })
148
+ : null;
149
+ // Delete installed directory if requested and safe.
150
+ if (deleteTarget) {
151
+ const existed = (await fs
152
+ .access(deleteTarget)
153
+ .then(() => true)
154
+ .catch(() => false)) ?? false;
155
+ try {
156
+ await fs.rm(deleteTarget, { recursive: true, force: true });
157
+ actions.directory = existed;
158
+ }
159
+ catch (error) {
160
+ warnings.push(`Failed to remove plugin directory ${deleteTarget}: ${error instanceof Error ? error.message : String(error)}`);
161
+ // Directory deletion failure is not fatal; config is the source of truth.
162
+ }
163
+ }
164
+ return {
165
+ ok: true,
166
+ config: newConfig,
167
+ pluginId,
168
+ actions,
169
+ warnings,
170
+ };
171
+ }
@@ -0,0 +1,98 @@
1
+ import { spawn } from "node:child_process";
2
+ const DEFAULT_GRACE_MS = 3000;
3
+ const MAX_GRACE_MS = 60_000;
4
+ /**
5
+ * Best-effort process-tree termination with graceful shutdown.
6
+ * - Windows: use taskkill /T to include descendants. Sends SIGTERM-equivalent
7
+ * first (without /F), then force-kills if process survives.
8
+ * - Unix: send SIGTERM to process group first, wait grace period, then SIGKILL.
9
+ *
10
+ * This gives child processes a chance to clean up (close connections, remove
11
+ * temp files, terminate their own children) before being hard-killed.
12
+ */
13
+ export function killProcessTree(pid, opts) {
14
+ if (!Number.isFinite(pid) || pid <= 0) {
15
+ return;
16
+ }
17
+ const graceMs = normalizeGraceMs(opts?.graceMs);
18
+ if (process.platform === "win32") {
19
+ killProcessTreeWindows(pid, graceMs);
20
+ return;
21
+ }
22
+ killProcessTreeUnix(pid, graceMs);
23
+ }
24
+ function normalizeGraceMs(value) {
25
+ if (typeof value !== "number" || !Number.isFinite(value)) {
26
+ return DEFAULT_GRACE_MS;
27
+ }
28
+ return Math.max(0, Math.min(MAX_GRACE_MS, Math.floor(value)));
29
+ }
30
+ function isProcessAlive(pid) {
31
+ try {
32
+ process.kill(pid, 0);
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ function killProcessTreeUnix(pid, graceMs) {
40
+ // Step 1: Try graceful SIGTERM to process group
41
+ try {
42
+ process.kill(-pid, "SIGTERM");
43
+ }
44
+ catch {
45
+ // Process group doesn't exist or we lack permission - try direct
46
+ try {
47
+ process.kill(pid, "SIGTERM");
48
+ }
49
+ catch {
50
+ // Already gone
51
+ return;
52
+ }
53
+ }
54
+ // Step 2: Wait grace period, then SIGKILL if still alive
55
+ setTimeout(() => {
56
+ if (isProcessAlive(-pid)) {
57
+ try {
58
+ process.kill(-pid, "SIGKILL");
59
+ return;
60
+ }
61
+ catch {
62
+ // Fall through to direct pid kill
63
+ }
64
+ }
65
+ if (!isProcessAlive(pid)) {
66
+ return;
67
+ }
68
+ try {
69
+ process.kill(pid, "SIGKILL");
70
+ }
71
+ catch {
72
+ // Process exited between liveness check and kill
73
+ }
74
+ }, graceMs).unref(); // Don't block event loop exit
75
+ }
76
+ function runTaskkill(args) {
77
+ try {
78
+ spawn("taskkill", args, {
79
+ stdio: "ignore",
80
+ detached: true,
81
+ });
82
+ }
83
+ catch {
84
+ // Ignore taskkill spawn failures
85
+ }
86
+ }
87
+ function killProcessTreeWindows(pid, graceMs) {
88
+ // Step 1: Try graceful termination (taskkill without /F)
89
+ runTaskkill(["/T", "/PID", String(pid)]);
90
+ // Step 2: Wait grace period, then force kill only if pid still exists.
91
+ // This avoids unconditional delayed /F kills after graceful shutdown.
92
+ setTimeout(() => {
93
+ if (!isProcessAlive(pid)) {
94
+ return;
95
+ }
96
+ runTaskkill(["/F", "/T", "/PID", String(pid)]);
97
+ }, graceMs).unref(); // Don't block event loop exit
98
+ }