@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,290 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { Readable } from "node:stream";
4
+ import { pipeline } from "node:stream/promises";
5
+ import { extractArchive as extractArchiveSafe } from "../infra/archive.js";
6
+ import { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
7
+ import { isWithinDir, resolveSafeBaseDir } from "../infra/path-safety.js";
8
+ import { runCommandWithTimeout } from "../process/exec.js";
9
+ import { ensureDir, resolveUserPath } from "../utils.js";
10
+ import { formatInstallFailureMessage } from "./skills-install-output.js";
11
+ import { hasBinary } from "./skills.js";
12
+ import { resolveSkillToolsRootDir } from "./skills/tools-dir.js";
13
+ function isNodeReadableStream(value) {
14
+ return Boolean(value && typeof value.pipe === "function");
15
+ }
16
+ function isWindowsDrivePath(p) {
17
+ return /^[a-zA-Z]:[\\/]/.test(p);
18
+ }
19
+ function resolveDownloadTargetDir(entry, spec) {
20
+ const safeRoot = resolveSkillToolsRootDir(entry);
21
+ const raw = spec.targetDir?.trim();
22
+ if (!raw) {
23
+ return safeRoot;
24
+ }
25
+ // Treat non-absolute paths as relative to the per-skill tools root.
26
+ const resolved = raw.startsWith("~") || path.isAbsolute(raw) || isWindowsDrivePath(raw)
27
+ ? resolveUserPath(raw)
28
+ : path.resolve(safeRoot, raw);
29
+ if (!isWithinDir(safeRoot, resolved)) {
30
+ throw new Error(`Refusing to install outside the skill tools directory. targetDir="${raw}" resolves to "${resolved}". Allowed root: "${safeRoot}".`);
31
+ }
32
+ return resolved;
33
+ }
34
+ function resolveArchiveType(spec, filename) {
35
+ const explicit = spec.archive?.trim().toLowerCase();
36
+ if (explicit) {
37
+ return explicit;
38
+ }
39
+ const lower = filename.toLowerCase();
40
+ if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz")) {
41
+ return "tar.gz";
42
+ }
43
+ if (lower.endsWith(".tar.bz2") || lower.endsWith(".tbz2")) {
44
+ return "tar.bz2";
45
+ }
46
+ if (lower.endsWith(".zip")) {
47
+ return "zip";
48
+ }
49
+ return undefined;
50
+ }
51
+ function normalizeArchiveEntryPath(raw) {
52
+ return raw.replaceAll("\\", "/");
53
+ }
54
+ function validateArchiveEntryPath(entryPath) {
55
+ if (!entryPath || entryPath === "." || entryPath === "./") {
56
+ return;
57
+ }
58
+ if (isWindowsDrivePath(entryPath)) {
59
+ throw new Error(`archive entry uses a drive path: ${entryPath}`);
60
+ }
61
+ const normalized = path.posix.normalize(normalizeArchiveEntryPath(entryPath));
62
+ if (normalized === ".." || normalized.startsWith("../")) {
63
+ throw new Error(`archive entry escapes targetDir: ${entryPath}`);
64
+ }
65
+ if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
66
+ throw new Error(`archive entry is absolute: ${entryPath}`);
67
+ }
68
+ }
69
+ function stripArchivePath(entryPath, stripComponents) {
70
+ const raw = normalizeArchiveEntryPath(entryPath);
71
+ if (!raw || raw === "." || raw === "./") {
72
+ return null;
73
+ }
74
+ // Important: tar's --strip-components semantics operate on raw path segments,
75
+ // before any normalization that would collapse "..". We mimic that so we
76
+ // can detect strip-induced escapes like "a/../b" with stripComponents=1.
77
+ const parts = raw.split("/").filter((part) => part.length > 0 && part !== ".");
78
+ const strip = Math.max(0, Math.floor(stripComponents));
79
+ const stripped = strip === 0 ? parts.join("/") : parts.slice(strip).join("/");
80
+ const result = path.posix.normalize(stripped);
81
+ if (!result || result === "." || result === "./") {
82
+ return null;
83
+ }
84
+ return result;
85
+ }
86
+ function validateExtractedPathWithinRoot(params) {
87
+ const safeBase = resolveSafeBaseDir(params.rootDir);
88
+ const outPath = path.resolve(params.rootDir, params.relPath);
89
+ if (!outPath.startsWith(safeBase)) {
90
+ throw new Error(`archive entry escapes targetDir: ${params.originalPath}`);
91
+ }
92
+ }
93
+ async function downloadFile(url, destPath, timeoutMs) {
94
+ const { response, release } = await fetchWithSsrFGuard({
95
+ url,
96
+ timeoutMs: Math.max(1_000, timeoutMs),
97
+ });
98
+ try {
99
+ if (!response.ok || !response.body) {
100
+ throw new Error(`Download failed (${response.status} ${response.statusText})`);
101
+ }
102
+ await ensureDir(path.dirname(destPath));
103
+ const file = fs.createWriteStream(destPath);
104
+ const body = response.body;
105
+ const readable = isNodeReadableStream(body)
106
+ ? body
107
+ : Readable.fromWeb(body);
108
+ await pipeline(readable, file);
109
+ const stat = await fs.promises.stat(destPath);
110
+ return { bytes: stat.size };
111
+ }
112
+ finally {
113
+ await release();
114
+ }
115
+ }
116
+ async function extractArchive(params) {
117
+ const { archivePath, archiveType, targetDir, stripComponents, timeoutMs } = params;
118
+ const strip = typeof stripComponents === "number" && Number.isFinite(stripComponents)
119
+ ? Math.max(0, Math.floor(stripComponents))
120
+ : 0;
121
+ try {
122
+ if (archiveType === "zip") {
123
+ await extractArchiveSafe({
124
+ archivePath,
125
+ destDir: targetDir,
126
+ timeoutMs,
127
+ kind: "zip",
128
+ stripComponents: strip,
129
+ });
130
+ return { stdout: "", stderr: "", code: 0 };
131
+ }
132
+ if (archiveType === "tar.gz") {
133
+ await extractArchiveSafe({
134
+ archivePath,
135
+ destDir: targetDir,
136
+ timeoutMs,
137
+ kind: "tar",
138
+ stripComponents: strip,
139
+ tarGzip: true,
140
+ });
141
+ return { stdout: "", stderr: "", code: 0 };
142
+ }
143
+ if (archiveType === "tar.bz2") {
144
+ if (!hasBinary("tar")) {
145
+ return { stdout: "", stderr: "tar not found on PATH", code: null };
146
+ }
147
+ // Preflight list to prevent zip-slip style traversal before extraction.
148
+ const listResult = await runCommandWithTimeout(["tar", "tf", archivePath], { timeoutMs });
149
+ if (listResult.code !== 0) {
150
+ return {
151
+ stdout: listResult.stdout,
152
+ stderr: listResult.stderr || "tar list failed",
153
+ code: listResult.code,
154
+ };
155
+ }
156
+ const entries = listResult.stdout
157
+ .split("\n")
158
+ .map((line) => line.trim())
159
+ .filter(Boolean);
160
+ const verboseResult = await runCommandWithTimeout(["tar", "tvf", archivePath], { timeoutMs });
161
+ if (verboseResult.code !== 0) {
162
+ return {
163
+ stdout: verboseResult.stdout,
164
+ stderr: verboseResult.stderr || "tar verbose list failed",
165
+ code: verboseResult.code,
166
+ };
167
+ }
168
+ for (const line of verboseResult.stdout.split("\n")) {
169
+ const trimmed = line.trim();
170
+ if (!trimmed) {
171
+ continue;
172
+ }
173
+ const typeChar = trimmed[0];
174
+ if (typeChar === "l" || typeChar === "h" || trimmed.includes(" -> ")) {
175
+ return {
176
+ stdout: verboseResult.stdout,
177
+ stderr: "tar archive contains link entries; refusing to extract for safety",
178
+ code: 1,
179
+ };
180
+ }
181
+ }
182
+ for (const entry of entries) {
183
+ validateArchiveEntryPath(entry);
184
+ const relPath = stripArchivePath(entry, strip);
185
+ if (!relPath) {
186
+ continue;
187
+ }
188
+ validateArchiveEntryPath(relPath);
189
+ validateExtractedPathWithinRoot({ rootDir: targetDir, relPath, originalPath: entry });
190
+ }
191
+ const argv = ["tar", "xf", archivePath, "-C", targetDir];
192
+ if (strip > 0) {
193
+ argv.push("--strip-components", String(strip));
194
+ }
195
+ return await runCommandWithTimeout(argv, { timeoutMs });
196
+ }
197
+ return { stdout: "", stderr: `unsupported archive type: ${archiveType}`, code: null };
198
+ }
199
+ catch (err) {
200
+ const message = err instanceof Error ? err.message : String(err);
201
+ return { stdout: "", stderr: message, code: 1 };
202
+ }
203
+ }
204
+ export async function installDownloadSpec(params) {
205
+ const { entry, spec, timeoutMs } = params;
206
+ const url = spec.url?.trim();
207
+ if (!url) {
208
+ return {
209
+ ok: false,
210
+ message: "missing download url",
211
+ stdout: "",
212
+ stderr: "",
213
+ code: null,
214
+ };
215
+ }
216
+ let filename = "";
217
+ try {
218
+ const parsed = new URL(url);
219
+ filename = path.basename(parsed.pathname);
220
+ }
221
+ catch {
222
+ filename = path.basename(url);
223
+ }
224
+ if (!filename) {
225
+ filename = "download";
226
+ }
227
+ let targetDir = "";
228
+ try {
229
+ targetDir = resolveDownloadTargetDir(entry, spec);
230
+ await ensureDir(targetDir);
231
+ const stat = await fs.promises.lstat(targetDir);
232
+ if (stat.isSymbolicLink()) {
233
+ throw new Error(`targetDir is a symlink: ${targetDir}`);
234
+ }
235
+ if (!stat.isDirectory()) {
236
+ throw new Error(`targetDir is not a directory: ${targetDir}`);
237
+ }
238
+ }
239
+ catch (err) {
240
+ const message = err instanceof Error ? err.message : String(err);
241
+ return { ok: false, message, stdout: "", stderr: message, code: null };
242
+ }
243
+ const archivePath = path.join(targetDir, filename);
244
+ let downloaded = 0;
245
+ try {
246
+ const result = await downloadFile(url, archivePath, timeoutMs);
247
+ downloaded = result.bytes;
248
+ }
249
+ catch (err) {
250
+ const message = err instanceof Error ? err.message : String(err);
251
+ return { ok: false, message, stdout: "", stderr: message, code: null };
252
+ }
253
+ const archiveType = resolveArchiveType(spec, filename);
254
+ const shouldExtract = spec.extract ?? Boolean(archiveType);
255
+ if (!shouldExtract) {
256
+ return {
257
+ ok: true,
258
+ message: `Downloaded to ${archivePath}`,
259
+ stdout: `downloaded=${downloaded}`,
260
+ stderr: "",
261
+ code: 0,
262
+ };
263
+ }
264
+ if (!archiveType) {
265
+ return {
266
+ ok: false,
267
+ message: "extract requested but archive type could not be detected",
268
+ stdout: "",
269
+ stderr: "",
270
+ code: null,
271
+ };
272
+ }
273
+ const extractResult = await extractArchive({
274
+ archivePath,
275
+ archiveType,
276
+ targetDir,
277
+ stripComponents: spec.stripComponents,
278
+ timeoutMs,
279
+ });
280
+ const success = extractResult.code === 0;
281
+ return {
282
+ ok: success,
283
+ message: success
284
+ ? `Downloaded and extracted to ${targetDir}`
285
+ : formatInstallFailureMessage(extractResult),
286
+ stdout: extractResult.stdout.trim(),
287
+ stderr: extractResult.stderr.trim(),
288
+ code: extractResult.code,
289
+ };
290
+ }
@@ -0,0 +1,30 @@
1
+ function summarizeInstallOutput(text) {
2
+ const raw = text.trim();
3
+ if (!raw) {
4
+ return undefined;
5
+ }
6
+ const lines = raw
7
+ .split("\n")
8
+ .map((line) => line.trim())
9
+ .filter(Boolean);
10
+ if (lines.length === 0) {
11
+ return undefined;
12
+ }
13
+ const preferred = lines.find((line) => /^error\b/i.test(line)) ??
14
+ lines.find((line) => /\b(err!|error:|failed)\b/i.test(line)) ??
15
+ lines.at(-1);
16
+ if (!preferred) {
17
+ return undefined;
18
+ }
19
+ const normalized = preferred.replace(/\s+/g, " ").trim();
20
+ const maxLen = 200;
21
+ return normalized.length > maxLen ? `${normalized.slice(0, maxLen - 1)}…` : normalized;
22
+ }
23
+ export function formatInstallFailureMessage(result) {
24
+ const code = typeof result.code === "number" ? `exit ${result.code}` : "unknown exit";
25
+ const summary = summarizeInstallOutput(result.stderr) ?? summarizeInstallOutput(result.stdout);
26
+ if (!summary) {
27
+ return `Install failed (${code})`;
28
+ }
29
+ return `Install failed (${code}): ${summary}`;
30
+ }
@@ -0,0 +1,36 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export function setTempStateDir(workspaceDir) {
4
+ const stateDir = path.join(workspaceDir, "state");
5
+ process.env.POOLBOT_STATE_DIR = stateDir;
6
+ return stateDir;
7
+ }
8
+ export async function writeDownloadSkill(params) {
9
+ const skillDir = path.join(params.workspaceDir, "skills", params.name);
10
+ await fs.mkdir(skillDir, { recursive: true });
11
+ const meta = {
12
+ openclaw: {
13
+ install: [
14
+ {
15
+ id: params.installId,
16
+ kind: "download",
17
+ url: params.url,
18
+ archive: params.archive,
19
+ extract: true,
20
+ stripComponents: params.stripComponents,
21
+ targetDir: params.targetDir,
22
+ },
23
+ ],
24
+ },
25
+ };
26
+ await fs.writeFile(path.join(skillDir, "SKILL.md"), `---
27
+ name: ${params.name}
28
+ description: test skill
29
+ metadata: ${JSON.stringify(meta)}
30
+ ---
31
+
32
+ # ${params.name}
33
+ `, "utf-8");
34
+ await fs.writeFile(path.join(skillDir, "runner.js"), "export {};\n", "utf-8");
35
+ return skillDir;
36
+ }
@@ -0,0 +1,13 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function writeSkill(params) {
4
+ const { dir, name, description, metadata, body } = params;
5
+ await fs.mkdir(dir, { recursive: true });
6
+ await fs.writeFile(path.join(dir, "SKILL.md"), `---
7
+ name: ${name}
8
+ description: ${description}${metadata ? `\nmetadata: ${metadata}` : ""}
9
+ ---
10
+
11
+ ${body ?? `# ${name}\n`}
12
+ `, "utf-8");
13
+ }
@@ -2,6 +2,31 @@ import { defaultRuntime } from "../runtime.js";
2
2
  import { deliveryContextKey, normalizeDeliveryContext, } from "../utils/delivery-context.js";
3
3
  import { applyQueueDropPolicy, buildCollectPrompt, buildQueueSummaryPrompt, hasCrossChannelItems, waitForQueueDebounce, } from "../utils/queue-helpers.js";
4
4
  const ANNOUNCE_QUEUES = new Map();
5
+ function previewQueueSummaryPrompt(queue) {
6
+ return buildQueueSummaryPrompt({
7
+ state: {
8
+ dropPolicy: queue.dropPolicy,
9
+ droppedCount: queue.droppedCount,
10
+ summaryLines: [...queue.summaryLines],
11
+ },
12
+ noun: "announce",
13
+ });
14
+ }
15
+ function clearQueueSummaryState(queue) {
16
+ queue.droppedCount = 0;
17
+ queue.summaryLines = [];
18
+ }
19
+ export function resetAnnounceQueuesForTests() {
20
+ // Test isolation: other suites may leave a draining queue behind in the worker.
21
+ // Clearing the map alone isn't enough because drain loops capture `queue` by reference.
22
+ for (const queue of ANNOUNCE_QUEUES.values()) {
23
+ queue.items.length = 0;
24
+ queue.summaryLines.length = 0;
25
+ queue.droppedCount = 0;
26
+ queue.lastEnqueuedAt = 0;
27
+ }
28
+ ANNOUNCE_QUEUES.clear();
29
+ }
5
30
  function getAnnounceQueue(key, settings, send) {
6
31
  const existing = ANNOUNCE_QUEUES.get(key);
7
32
  if (existing) {
@@ -35,8 +60,9 @@ function getAnnounceQueue(key, settings, send) {
35
60
  }
36
61
  function scheduleAnnounceDrain(key) {
37
62
  const queue = ANNOUNCE_QUEUES.get(key);
38
- if (!queue || queue.draining)
63
+ if (!queue || queue.draining) {
39
64
  return;
65
+ }
40
66
  queue.draining = true;
41
67
  void (async () => {
42
68
  try {
@@ -45,29 +71,35 @@ function scheduleAnnounceDrain(key) {
45
71
  await waitForQueueDebounce(queue);
46
72
  if (queue.mode === "collect") {
47
73
  if (forceIndividualCollect) {
48
- const next = queue.items.shift();
49
- if (!next)
74
+ const next = queue.items[0];
75
+ if (!next) {
50
76
  break;
77
+ }
51
78
  await queue.send(next);
79
+ queue.items.shift();
52
80
  continue;
53
81
  }
54
82
  const isCrossChannel = hasCrossChannelItems(queue.items, (item) => {
55
- if (!item.origin)
83
+ if (!item.origin) {
56
84
  return {};
57
- if (!item.originKey)
85
+ }
86
+ if (!item.originKey) {
58
87
  return { cross: true };
88
+ }
59
89
  return { key: item.originKey };
60
90
  });
61
91
  if (isCrossChannel) {
62
92
  forceIndividualCollect = true;
63
- const next = queue.items.shift();
64
- if (!next)
93
+ const next = queue.items[0];
94
+ if (!next) {
65
95
  break;
96
+ }
66
97
  await queue.send(next);
98
+ queue.items.shift();
67
99
  continue;
68
100
  }
69
- const items = queue.items.splice(0, queue.items.length);
70
- const summary = buildQueueSummaryPrompt({ state: queue, noun: "announce" });
101
+ const items = queue.items.slice();
102
+ const summary = previewQueueSummaryPrompt(queue);
71
103
  const prompt = buildCollectPrompt({
72
104
  title: "[Queued announce messages while agent was busy]",
73
105
  items,
@@ -75,26 +107,38 @@ function scheduleAnnounceDrain(key) {
75
107
  renderItem: (item, idx) => `---\nQueued #${idx + 1}\n${item.prompt}`.trim(),
76
108
  });
77
109
  const last = items.at(-1);
78
- if (!last)
110
+ if (!last) {
79
111
  break;
112
+ }
80
113
  await queue.send({ ...last, prompt });
114
+ queue.items.splice(0, items.length);
115
+ if (summary) {
116
+ clearQueueSummaryState(queue);
117
+ }
81
118
  continue;
82
119
  }
83
- const summaryPrompt = buildQueueSummaryPrompt({ state: queue, noun: "announce" });
120
+ const summaryPrompt = previewQueueSummaryPrompt(queue);
84
121
  if (summaryPrompt) {
85
- const next = queue.items.shift();
86
- if (!next)
122
+ const next = queue.items[0];
123
+ if (!next) {
87
124
  break;
125
+ }
88
126
  await queue.send({ ...next, prompt: summaryPrompt });
127
+ queue.items.shift();
128
+ clearQueueSummaryState(queue);
89
129
  continue;
90
130
  }
91
- const next = queue.items.shift();
92
- if (!next)
131
+ const next = queue.items[0];
132
+ if (!next) {
93
133
  break;
134
+ }
94
135
  await queue.send(next);
136
+ queue.items.shift();
95
137
  }
96
138
  }
97
139
  catch (err) {
140
+ // Keep items in queue and retry after debounce; avoid hot-loop retries.
141
+ queue.lastEnqueuedAt = Date.now();
98
142
  defaultRuntime.error?.(`announce queue drain failed for ${key}: ${String(err)}`);
99
143
  }
100
144
  finally {
@@ -0,0 +1,137 @@
1
+ import fs from "node:fs";
2
+ import JSON5 from "json5";
3
+ import { resolveStorePath } from "../config/sessions/paths.js";
4
+ import { getSubagentDepth, parseAgentSessionKey } from "../sessions/session-key-utils.js";
5
+ import { resolveDefaultAgentId } from "./agent-scope.js";
6
+ function normalizeSpawnDepth(value) {
7
+ if (typeof value === "number") {
8
+ return Number.isInteger(value) && value >= 0 ? value : undefined;
9
+ }
10
+ if (typeof value === "string") {
11
+ const trimmed = value.trim();
12
+ if (!trimmed) {
13
+ return undefined;
14
+ }
15
+ const numeric = Number(trimmed);
16
+ return Number.isInteger(numeric) && numeric >= 0 ? numeric : undefined;
17
+ }
18
+ return undefined;
19
+ }
20
+ function normalizeSessionKey(value) {
21
+ if (typeof value !== "string") {
22
+ return undefined;
23
+ }
24
+ const trimmed = value.trim();
25
+ return trimmed || undefined;
26
+ }
27
+ function readSessionStore(storePath) {
28
+ try {
29
+ const raw = fs.readFileSync(storePath, "utf-8");
30
+ const parsed = JSON5.parse(raw);
31
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
32
+ return parsed;
33
+ }
34
+ }
35
+ catch {
36
+ // ignore missing/invalid stores
37
+ }
38
+ return {};
39
+ }
40
+ function buildKeyCandidates(rawKey, cfg) {
41
+ if (!cfg) {
42
+ return [rawKey];
43
+ }
44
+ if (rawKey === "global" || rawKey === "unknown") {
45
+ return [rawKey];
46
+ }
47
+ if (parseAgentSessionKey(rawKey)) {
48
+ return [rawKey];
49
+ }
50
+ const defaultAgentId = resolveDefaultAgentId(cfg);
51
+ const prefixed = `agent:${defaultAgentId}:${rawKey}`;
52
+ return prefixed === rawKey ? [rawKey] : [rawKey, prefixed];
53
+ }
54
+ function findEntryBySessionId(store, sessionId) {
55
+ const normalizedSessionId = normalizeSessionKey(sessionId);
56
+ if (!normalizedSessionId) {
57
+ return undefined;
58
+ }
59
+ for (const entry of Object.values(store)) {
60
+ const candidateSessionId = normalizeSessionKey(entry?.sessionId);
61
+ if (candidateSessionId && candidateSessionId === normalizedSessionId) {
62
+ return entry;
63
+ }
64
+ }
65
+ return undefined;
66
+ }
67
+ function resolveEntryForSessionKey(params) {
68
+ const candidates = buildKeyCandidates(params.sessionKey, params.cfg);
69
+ if (params.store) {
70
+ for (const key of candidates) {
71
+ const entry = params.store[key];
72
+ if (entry) {
73
+ return entry;
74
+ }
75
+ }
76
+ return findEntryBySessionId(params.store, params.sessionKey);
77
+ }
78
+ if (!params.cfg) {
79
+ return undefined;
80
+ }
81
+ for (const key of candidates) {
82
+ const parsed = parseAgentSessionKey(key);
83
+ if (!parsed?.agentId) {
84
+ continue;
85
+ }
86
+ const storePath = resolveStorePath(params.cfg.session?.store, { agentId: parsed.agentId });
87
+ let store = params.cache.get(storePath);
88
+ if (!store) {
89
+ store = readSessionStore(storePath);
90
+ params.cache.set(storePath, store);
91
+ }
92
+ const entry = store[key] ?? findEntryBySessionId(store, params.sessionKey);
93
+ if (entry) {
94
+ return entry;
95
+ }
96
+ }
97
+ return undefined;
98
+ }
99
+ export function getSubagentDepthFromSessionStore(sessionKey, opts) {
100
+ const raw = (sessionKey ?? "").trim();
101
+ const fallbackDepth = getSubagentDepth(raw);
102
+ if (!raw) {
103
+ return fallbackDepth;
104
+ }
105
+ const cache = new Map();
106
+ const visited = new Set();
107
+ const depthFromStore = (key) => {
108
+ const normalizedKey = normalizeSessionKey(key);
109
+ if (!normalizedKey) {
110
+ return undefined;
111
+ }
112
+ if (visited.has(normalizedKey)) {
113
+ return undefined;
114
+ }
115
+ visited.add(normalizedKey);
116
+ const entry = resolveEntryForSessionKey({
117
+ sessionKey: normalizedKey,
118
+ cfg: opts?.cfg,
119
+ store: opts?.store,
120
+ cache,
121
+ });
122
+ const storedDepth = normalizeSpawnDepth(entry?.spawnDepth);
123
+ if (storedDepth !== undefined) {
124
+ return storedDepth;
125
+ }
126
+ const spawnedBy = normalizeSessionKey(entry?.spawnedBy);
127
+ if (!spawnedBy) {
128
+ return undefined;
129
+ }
130
+ const parentDepth = depthFromStore(spawnedBy);
131
+ if (parentDepth !== undefined) {
132
+ return parentDepth + 1;
133
+ }
134
+ return getSubagentDepth(spawnedBy) + 1;
135
+ };
136
+ return depthFromStore(raw) ?? fallbackDepth;
137
+ }