@poolzin/pool-bot 2026.2.21 → 2026.2.22

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 (369) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/agents/api-key-rotation.js +47 -0
  3. package/dist/agents/apply-patch-update.js +19 -9
  4. package/dist/agents/apply-patch.js +72 -47
  5. package/dist/agents/bash-tools.exec.js +141 -559
  6. package/dist/agents/cli-backends.js +49 -6
  7. package/dist/agents/cli-runner/helpers.js +69 -152
  8. package/dist/agents/cli-runner.js +70 -19
  9. package/dist/agents/identity.js +20 -1
  10. package/dist/agents/image-sanitization.js +9 -0
  11. package/dist/agents/live-auth-keys.js +123 -26
  12. package/dist/agents/live-model-filter.js +13 -4
  13. package/dist/agents/model-catalog.js +40 -9
  14. package/dist/agents/model-forward-compat.js +60 -23
  15. package/dist/agents/model-selection.js +134 -41
  16. package/dist/agents/pi-auth-json.js +2 -2
  17. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  18. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  19. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  20. package/dist/agents/pi-embedded-helpers.js +2 -2
  21. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  22. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  23. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  24. package/dist/agents/pi-embedded-runner/google.js +109 -19
  25. package/dist/agents/pi-embedded-runner/history.js +35 -17
  26. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
  27. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  28. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  29. package/dist/agents/pi-embedded-runner/run.js +193 -25
  30. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  31. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  32. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  33. package/dist/agents/pi-embedded-runner.js +1 -1
  34. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  35. package/dist/agents/pi-embedded-subscribe.js +37 -0
  36. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  37. package/dist/agents/pi-model-discovery.js +9 -2
  38. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  39. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  40. package/dist/agents/pi-tools.js +113 -94
  41. package/dist/agents/pi-tools.read.js +337 -38
  42. package/dist/agents/poolbot-tools.js +14 -5
  43. package/dist/agents/sandbox/docker.js +10 -5
  44. package/dist/agents/sandbox/registry.js +96 -46
  45. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  46. package/dist/agents/sandbox-paths.js +43 -10
  47. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  48. package/dist/agents/session-tool-result-guard.js +39 -39
  49. package/dist/agents/session-transcript-repair.js +36 -33
  50. package/dist/agents/session-write-lock.js +62 -44
  51. package/dist/agents/skills/frontmatter.js +49 -88
  52. package/dist/agents/skills/workspace.js +335 -28
  53. package/dist/agents/subagent-announce.js +508 -174
  54. package/dist/agents/subagent-registry.js +45 -4
  55. package/dist/agents/subagent-spawn.js +16 -33
  56. package/dist/agents/system-prompt-report.js +27 -10
  57. package/dist/agents/system-prompt.js +26 -32
  58. package/dist/agents/tool-call-id.js +69 -17
  59. package/dist/agents/tool-display-common.js +1 -1
  60. package/dist/agents/tool-images.js +64 -31
  61. package/dist/agents/tools/canvas-tool.js +17 -11
  62. package/dist/agents/tools/common.js +37 -19
  63. package/dist/agents/tools/cron-tool.js +40 -38
  64. package/dist/agents/tools/gateway.js +70 -2
  65. package/dist/agents/tools/message-tool.js +181 -40
  66. package/dist/agents/tools/nodes-tool.js +128 -36
  67. package/dist/agents/tools/nodes-utils.js +12 -38
  68. package/dist/agents/tools/session-status-tool.js +24 -71
  69. package/dist/agents/tools/sessions-helpers.js +38 -210
  70. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  71. package/dist/agents/tools/telegram-actions.js +58 -7
  72. package/dist/agents/tools/web-fetch-utils.js +112 -7
  73. package/dist/agents/tools/web-fetch.js +279 -175
  74. package/dist/agents/tools/web-shared.js +71 -8
  75. package/dist/agents/usage.js +25 -16
  76. package/dist/auto-reply/commands-registry.data.js +85 -11
  77. package/dist/auto-reply/dispatch.js +40 -21
  78. package/dist/auto-reply/reply/abort.js +102 -33
  79. package/dist/auto-reply/reply/commands-core.js +82 -33
  80. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  81. package/dist/auto-reply/reply/commands-info.js +41 -12
  82. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  83. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  84. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  85. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  86. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  87. package/dist/auto-reply/reply/mentions.js +18 -11
  88. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  89. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  90. package/dist/auto-reply/reply/session.js +102 -21
  91. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  92. package/dist/auto-reply/status.js +73 -50
  93. package/dist/browser/extension-relay.js +3 -3
  94. package/dist/browser/http-auth.js +1 -1
  95. package/dist/browser/paths.js +2 -2
  96. package/dist/build-info.json +3 -3
  97. package/dist/channels/allowlist-match.js +20 -0
  98. package/dist/channels/allowlists/resolve-utils.js +65 -2
  99. package/dist/channels/chat-type.js +8 -4
  100. package/dist/channels/dock.js +127 -35
  101. package/dist/channels/draft-stream-loop.js +6 -2
  102. package/dist/channels/plugins/actions/telegram.js +42 -18
  103. package/dist/channels/plugins/allowlist-match.js +1 -1
  104. package/dist/channels/plugins/group-mentions.js +51 -41
  105. package/dist/channels/plugins/message-action-names.js +2 -0
  106. package/dist/channels/plugins/message-actions.js +24 -5
  107. package/dist/channels/plugins/normalize/discord.js +26 -4
  108. package/dist/channels/plugins/normalize/signal.js +35 -22
  109. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  110. package/dist/channels/plugins/outbound/imessage.js +15 -14
  111. package/dist/channels/registry.js +20 -7
  112. package/dist/cli/acp-cli.js +7 -5
  113. package/dist/cli/browser-cli-extension.js +25 -12
  114. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  115. package/dist/cli/browser-cli-state.js +101 -145
  116. package/dist/cli/command-options.js +28 -0
  117. package/dist/cli/completion-cli.js +6 -6
  118. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  119. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  120. package/dist/cli/cron-cli/shared.js +7 -1
  121. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  122. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  123. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  124. package/dist/cli/daemon-cli.js +1 -0
  125. package/dist/cli/devices-cli.js +33 -20
  126. package/dist/cli/gateway-cli/register.js +37 -105
  127. package/dist/cli/gateway-cli/run.js +49 -11
  128. package/dist/cli/nodes-camera.js +59 -4
  129. package/dist/cli/nodes-cli/register.camera.js +27 -24
  130. package/dist/cli/nodes-cli/rpc.js +21 -38
  131. package/dist/cli/qr-cli.js +2 -2
  132. package/dist/cli/skills-cli.format.js +2 -2
  133. package/dist/cli/update-cli/progress.js +2 -2
  134. package/dist/cli/update-cli/restart-helper.js +28 -7
  135. package/dist/cli/update-cli/shared.js +7 -7
  136. package/dist/cli/update-cli/status.js +1 -1
  137. package/dist/cli/update-cli/update-command.js +14 -8
  138. package/dist/cli/update-cli/wizard.js +2 -2
  139. package/dist/cli/update-cli.js +21 -1027
  140. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  141. package/dist/commands/channels/add-mutators.js +3 -35
  142. package/dist/commands/channels/add.js +39 -51
  143. package/dist/commands/config-validation.js +1 -1
  144. package/dist/commands/configure.gateway-auth.js +52 -15
  145. package/dist/commands/configure.gateway.js +84 -40
  146. package/dist/commands/doctor-completion.js +3 -3
  147. package/dist/commands/doctor-config-flow.js +536 -16
  148. package/dist/commands/doctor-gateway-services.js +103 -79
  149. package/dist/commands/doctor-memory-search.js +9 -9
  150. package/dist/commands/doctor-platform-notes.js +57 -30
  151. package/dist/commands/doctor-prompter.js +26 -15
  152. package/dist/commands/doctor-session-locks.js +1 -1
  153. package/dist/commands/doctor.js +21 -9
  154. package/dist/commands/model-picker.js +120 -95
  155. package/dist/commands/models/set.js +2 -21
  156. package/dist/commands/models/shared.js +65 -37
  157. package/dist/commands/onboard-helpers.js +81 -39
  158. package/dist/commands/openai-codex-oauth.js +1 -1
  159. package/dist/commands/sessions.js +52 -53
  160. package/dist/commands/status.summary.js +52 -34
  161. package/dist/commands/test-wizard-helpers.js +2 -2
  162. package/dist/config/defaults.js +79 -42
  163. package/dist/config/group-policy.js +50 -18
  164. package/dist/config/includes.js +37 -10
  165. package/dist/config/schema.help.js +5 -4
  166. package/dist/config/schema.hints.js +2 -2
  167. package/dist/config/schema.labels.js +1 -0
  168. package/dist/config/sessions/group.js +12 -11
  169. package/dist/config/sessions/paths.js +137 -11
  170. package/dist/config/sessions/store.js +185 -65
  171. package/dist/config/sessions/types.js +15 -1
  172. package/dist/config/sessions.js +1 -0
  173. package/dist/config/telegram-custom-commands.js +3 -2
  174. package/dist/config/types.js +2 -0
  175. package/dist/config/zod-schema.agent-defaults.js +6 -27
  176. package/dist/config/zod-schema.agent-runtime.js +171 -79
  177. package/dist/config/zod-schema.providers-core.js +138 -65
  178. package/dist/config/zod-schema.session.js +49 -22
  179. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  180. package/dist/cron/isolated-agent/run.js +224 -57
  181. package/dist/cron/normalize.js +48 -45
  182. package/dist/cron/run-log.js +14 -0
  183. package/dist/cron/service/jobs.js +190 -28
  184. package/dist/cron/service/normalize.js +29 -11
  185. package/dist/cron/service/store.js +30 -44
  186. package/dist/cron/service/timer.js +182 -96
  187. package/dist/cron/service.js +3 -0
  188. package/dist/cron/stagger.js +37 -0
  189. package/dist/daemon/inspect.js +132 -92
  190. package/dist/daemon/runtime-paths.js +25 -4
  191. package/dist/daemon/service-audit.js +47 -16
  192. package/dist/discord/accounts.js +23 -20
  193. package/dist/discord/monitor/agent-components.js +1115 -219
  194. package/dist/discord/monitor/allow-list.js +114 -34
  195. package/dist/discord/monitor/listeners.js +204 -97
  196. package/dist/discord/monitor/message-handler.js +21 -10
  197. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  198. package/dist/discord/monitor/message-handler.process.js +384 -123
  199. package/dist/discord/monitor/message-utils.js +86 -23
  200. package/dist/discord/monitor/native-command.js +77 -57
  201. package/dist/discord/monitor/provider.js +122 -117
  202. package/dist/discord/monitor/reply-context.js +20 -16
  203. package/dist/discord/monitor/reply-delivery.js +40 -8
  204. package/dist/discord/monitor/rest-fetch.js +22 -0
  205. package/dist/discord/monitor/threading.js +117 -24
  206. package/dist/discord/send.js +2 -1
  207. package/dist/discord/send.outbound.js +124 -11
  208. package/dist/discord/send.shared.js +112 -72
  209. package/dist/discord/voice-message.js +3 -3
  210. package/dist/gateway/auth.js +119 -44
  211. package/dist/gateway/call.js +76 -34
  212. package/dist/gateway/channel-health-monitor.js +57 -50
  213. package/dist/gateway/client.js +63 -29
  214. package/dist/gateway/control-ui-contract.js +1 -1
  215. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  216. package/dist/gateway/net.js +109 -1
  217. package/dist/gateway/protocol/index.js +5 -8
  218. package/dist/gateway/protocol/schema/agent.js +19 -1
  219. package/dist/gateway/protocol/schema/channels.js +21 -0
  220. package/dist/gateway/protocol/schema/cron.js +43 -30
  221. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  222. package/dist/gateway/protocol/schema/sessions.js +5 -1
  223. package/dist/gateway/protocol/schema.js +0 -1
  224. package/dist/gateway/server/presence-events.js +12 -0
  225. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  226. package/dist/gateway/server/ws-connection.js +58 -21
  227. package/dist/gateway/server-broadcast.js +18 -13
  228. package/dist/gateway/server-cron.js +177 -10
  229. package/dist/gateway/server-methods/agent-job.js +131 -38
  230. package/dist/gateway/server-methods/send.js +60 -14
  231. package/dist/gateway/server-methods/sessions.js +160 -96
  232. package/dist/gateway/server-methods/system.js +5 -7
  233. package/dist/gateway/server-methods-list.js +8 -0
  234. package/dist/gateway/server-methods.js +24 -8
  235. package/dist/gateway/server-node-events.js +278 -68
  236. package/dist/gateway/session-utils.fs.js +316 -75
  237. package/dist/gateway/session-utils.js +224 -70
  238. package/dist/gateway/sessions-patch.js +63 -20
  239. package/dist/gateway/test-temp-config.js +1 -1
  240. package/dist/gateway/tools-invoke-http.js +118 -70
  241. package/dist/gateway/ws-log.js +135 -107
  242. package/dist/hooks/frontmatter.js +36 -82
  243. package/dist/hooks/install.js +149 -139
  244. package/dist/hooks/internal-hooks.js +29 -4
  245. package/dist/hooks/plugin-hooks.js +2 -1
  246. package/dist/imessage/monitor/deliver.js +10 -4
  247. package/dist/imessage/monitor/monitor-provider.js +138 -375
  248. package/dist/imessage/monitor/runtime.js +4 -8
  249. package/dist/imessage/send.js +65 -19
  250. package/dist/infra/exec-approvals-allowlist.js +7 -0
  251. package/dist/infra/exec-approvals.js +35 -920
  252. package/dist/infra/exec-safe-bin-trust.js +64 -0
  253. package/dist/infra/heartbeat-runner.js +207 -134
  254. package/dist/infra/heartbeat-wake.js +183 -22
  255. package/dist/infra/install-source-utils.js +47 -0
  256. package/dist/infra/net/ssrf.js +170 -36
  257. package/dist/infra/outbound/deliver.js +224 -58
  258. package/dist/infra/outbound/message-action-spec.js +12 -5
  259. package/dist/infra/outbound/outbound-session.js +27 -25
  260. package/dist/infra/poolbot-root.js +32 -22
  261. package/dist/infra/ports.js +14 -11
  262. package/dist/infra/skills-remote.js +48 -37
  263. package/dist/infra/system-events.js +25 -11
  264. package/dist/infra/system-presence.js +26 -33
  265. package/dist/infra/tmp-poolbot-dir.js +81 -2
  266. package/dist/infra/wsl.js +37 -1
  267. package/dist/line/bot-message-context.js +163 -191
  268. package/dist/logging/subsystem.js +59 -22
  269. package/dist/markdown/ir.js +124 -50
  270. package/dist/media/store.js +1 -1
  271. package/dist/media-understanding/runner.entries.js +42 -25
  272. package/dist/media-understanding/runner.js +53 -488
  273. package/dist/memory/embeddings-gemini.js +53 -38
  274. package/dist/memory/manager-embedding-ops.js +48 -69
  275. package/dist/pairing/pairing-store.js +178 -119
  276. package/dist/plugin-sdk/index.js +34 -6
  277. package/dist/plugins/hooks.js +135 -14
  278. package/dist/plugins/install.js +190 -152
  279. package/dist/polls.js +11 -0
  280. package/dist/routing/resolve-route.js +190 -56
  281. package/dist/routing/session-key.js +38 -22
  282. package/dist/runtime.js +35 -9
  283. package/dist/security/audit-channel.js +1 -1
  284. package/dist/sessions/session-key-utils.js +29 -11
  285. package/dist/shared/frontmatter.js +5 -5
  286. package/dist/shared/node-list-types.js +1 -0
  287. package/dist/shared/string-normalization.js +15 -0
  288. package/dist/signal/monitor/event-handler.js +68 -36
  289. package/dist/signal/send.js +29 -37
  290. package/dist/slack/monitor/allow-list.js +10 -11
  291. package/dist/slack/monitor/commands.js +14 -3
  292. package/dist/slack/monitor/events/interactions.js +4 -4
  293. package/dist/slack/monitor/media.js +224 -16
  294. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  295. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  296. package/dist/slack/monitor/slash.js +357 -144
  297. package/dist/slack/streaming.js +77 -0
  298. package/dist/telegram/accounts.js +40 -13
  299. package/dist/telegram/allowed-updates.js +3 -0
  300. package/dist/telegram/bot/delivery.js +129 -66
  301. package/dist/telegram/bot/helpers.js +136 -122
  302. package/dist/telegram/bot-handlers.js +600 -339
  303. package/dist/telegram/bot-message-context.js +115 -73
  304. package/dist/telegram/bot-message-dispatch.js +235 -104
  305. package/dist/telegram/bot-native-command-menu.js +3 -1
  306. package/dist/telegram/bot-native-commands.js +213 -193
  307. package/dist/telegram/bot.js +24 -132
  308. package/dist/telegram/draft-stream.js +84 -75
  309. package/dist/telegram/format.js +150 -6
  310. package/dist/telegram/send.js +415 -255
  311. package/dist/telegram/targets.js +21 -2
  312. package/dist/telegram/update-offset-store.js +19 -3
  313. package/dist/terminal/restore.js +5 -2
  314. package/dist/test-utils/fetch-mock.js +5 -0
  315. package/dist/version.js +18 -5
  316. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  317. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  318. package/dist/web/inbound/media.js +34 -8
  319. package/dist/web/inbound/monitor.js +34 -17
  320. package/dist/web/inbound/send-api.js +18 -17
  321. package/dist/web/outbound.js +12 -5
  322. package/dist/wizard/clack-prompter.js +40 -7
  323. package/extensions/bluebubbles/package.json +1 -1
  324. package/extensions/copilot-proxy/package.json +1 -1
  325. package/extensions/diagnostics-otel/package.json +1 -1
  326. package/extensions/discord/package.json +1 -1
  327. package/extensions/feishu/package.json +1 -1
  328. package/extensions/google-antigravity-auth/package.json +1 -1
  329. package/extensions/google-gemini-cli-auth/package.json +1 -1
  330. package/extensions/googlechat/package.json +1 -1
  331. package/extensions/imessage/package.json +1 -1
  332. package/extensions/irc/package.json +1 -1
  333. package/extensions/line/package.json +1 -1
  334. package/extensions/llm-task/package.json +1 -1
  335. package/extensions/lobster/package.json +1 -1
  336. package/extensions/matrix/CHANGELOG.md +5 -0
  337. package/extensions/matrix/package.json +1 -1
  338. package/extensions/mattermost/package.json +1 -1
  339. package/extensions/memory-core/package.json +1 -1
  340. package/extensions/memory-lancedb/package.json +1 -1
  341. package/extensions/minimax-portal-auth/package.json +1 -1
  342. package/extensions/msteams/CHANGELOG.md +5 -0
  343. package/extensions/msteams/package.json +1 -1
  344. package/extensions/nextcloud-talk/package.json +1 -1
  345. package/extensions/nostr/CHANGELOG.md +5 -0
  346. package/extensions/nostr/package.json +1 -1
  347. package/extensions/open-prose/package.json +1 -1
  348. package/extensions/openai-codex-auth/package.json +1 -1
  349. package/extensions/signal/package.json +1 -1
  350. package/extensions/slack/package.json +1 -1
  351. package/extensions/telegram/package.json +1 -1
  352. package/extensions/tlon/package.json +1 -1
  353. package/extensions/twitch/CHANGELOG.md +5 -0
  354. package/extensions/twitch/package.json +1 -1
  355. package/extensions/voice-call/CHANGELOG.md +5 -0
  356. package/extensions/voice-call/package.json +1 -1
  357. package/extensions/whatsapp/package.json +1 -1
  358. package/extensions/zalo/CHANGELOG.md +5 -0
  359. package/extensions/zalo/package.json +1 -1
  360. package/extensions/zalouser/CHANGELOG.md +5 -0
  361. package/extensions/zalouser/package.json +1 -1
  362. package/package.json +1 -1
  363. package/skills/apple-reminders/SKILL.md +100 -49
  364. package/skills/coding-agent/SKILL.md +34 -28
  365. package/skills/github/SKILL.md +131 -16
  366. package/skills/imsg/SKILL.md +112 -15
  367. package/skills/openhue/SKILL.md +101 -19
  368. package/skills/tmux/SKILL.md +111 -79
  369. package/skills/weather/SKILL.md +88 -25
@@ -14,8 +14,9 @@ export function normalizeCacheKey(value) {
14
14
  }
15
15
  export function readCache(cache, key) {
16
16
  const entry = cache.get(key);
17
- if (!entry)
17
+ if (!entry) {
18
18
  return null;
19
+ }
19
20
  if (Date.now() > entry.expiresAt) {
20
21
  cache.delete(key);
21
22
  return null;
@@ -23,12 +24,14 @@ export function readCache(cache, key) {
23
24
  return { value: entry.value, cached: true };
24
25
  }
25
26
  export function writeCache(cache, key, value, ttlMs) {
26
- if (ttlMs <= 0)
27
+ if (ttlMs <= 0) {
27
28
  return;
29
+ }
28
30
  if (cache.size >= DEFAULT_CACHE_MAX_ENTRIES) {
29
31
  const oldest = cache.keys().next();
30
- if (!oldest.done)
32
+ if (!oldest.done) {
31
33
  cache.delete(oldest.value);
34
+ }
32
35
  }
33
36
  cache.set(key, {
34
37
  value,
@@ -37,10 +40,11 @@ export function writeCache(cache, key, value, ttlMs) {
37
40
  });
38
41
  }
39
42
  export function withTimeout(signal, timeoutMs) {
40
- if (timeoutMs <= 0)
43
+ if (timeoutMs <= 0) {
41
44
  return signal ?? new AbortController().signal;
45
+ }
42
46
  const controller = new AbortController();
43
- const timer = setTimeout(() => controller.abort(), timeoutMs);
47
+ const timer = setTimeout(controller.abort.bind(controller), timeoutMs);
44
48
  if (signal) {
45
49
  signal.addEventListener("abort", () => {
46
50
  clearTimeout(timer);
@@ -52,11 +56,70 @@ export function withTimeout(signal, timeoutMs) {
52
56
  }, { once: true });
53
57
  return controller.signal;
54
58
  }
55
- export async function readResponseText(res) {
59
+ export async function readResponseText(res, options) {
60
+ const maxBytesRaw = options?.maxBytes;
61
+ const maxBytes = typeof maxBytesRaw === "number" && Number.isFinite(maxBytesRaw) && maxBytesRaw > 0
62
+ ? Math.floor(maxBytesRaw)
63
+ : undefined;
64
+ const body = res.body;
65
+ if (maxBytes &&
66
+ body &&
67
+ typeof body === "object" &&
68
+ "getReader" in body &&
69
+ typeof body.getReader === "function") {
70
+ const reader = body.getReader();
71
+ const decoder = new TextDecoder();
72
+ let bytesRead = 0;
73
+ let truncated = false;
74
+ const parts = [];
75
+ try {
76
+ while (true) {
77
+ const { value, done } = await reader.read();
78
+ if (done) {
79
+ break;
80
+ }
81
+ if (!value || value.byteLength === 0) {
82
+ continue;
83
+ }
84
+ let chunk = value;
85
+ if (bytesRead + chunk.byteLength > maxBytes) {
86
+ const remaining = Math.max(0, maxBytes - bytesRead);
87
+ if (remaining <= 0) {
88
+ truncated = true;
89
+ break;
90
+ }
91
+ chunk = chunk.subarray(0, remaining);
92
+ truncated = true;
93
+ }
94
+ bytesRead += chunk.byteLength;
95
+ parts.push(decoder.decode(chunk, { stream: true }));
96
+ if (truncated || bytesRead >= maxBytes) {
97
+ truncated = true;
98
+ break;
99
+ }
100
+ }
101
+ }
102
+ catch {
103
+ // Best-effort: return whatever we decoded so far.
104
+ }
105
+ finally {
106
+ if (truncated) {
107
+ try {
108
+ await reader.cancel();
109
+ }
110
+ catch {
111
+ // ignore
112
+ }
113
+ }
114
+ }
115
+ parts.push(decoder.decode());
116
+ return { text: parts.join(""), truncated, bytesRead };
117
+ }
56
118
  try {
57
- return await res.text();
119
+ const text = await res.text();
120
+ return { text, truncated: false, bytesRead: text.length };
58
121
  }
59
122
  catch {
60
- return "";
123
+ return { text: "", truncated: false, bytesRead: 0 };
61
124
  }
62
125
  }
@@ -1,18 +1,22 @@
1
1
  const asFiniteNumber = (value) => {
2
- if (typeof value !== "number")
2
+ if (typeof value !== "number") {
3
3
  return undefined;
4
- if (!Number.isFinite(value))
4
+ }
5
+ if (!Number.isFinite(value)) {
5
6
  return undefined;
7
+ }
6
8
  return value;
7
9
  };
8
10
  export function hasNonzeroUsage(usage) {
9
- if (!usage)
11
+ if (!usage) {
10
12
  return false;
13
+ }
11
14
  return [usage.input, usage.output, usage.cacheRead, usage.cacheWrite, usage.total].some((v) => typeof v === "number" && Number.isFinite(v) && v > 0);
12
15
  }
13
16
  export function normalizeUsage(raw) {
14
- if (!raw)
17
+ if (!raw) {
15
18
  return undefined;
19
+ }
16
20
  const input = asFiniteNumber(raw.input ?? raw.inputTokens ?? raw.input_tokens ?? raw.promptTokens ?? raw.prompt_tokens);
17
21
  const output = asFiniteNumber(raw.output ??
18
22
  raw.outputTokens ??
@@ -48,23 +52,28 @@ export function derivePromptTokens(usage) {
48
52
  return sum > 0 ? sum : undefined;
49
53
  }
50
54
  export function deriveSessionTotalTokens(params) {
55
+ const promptOverride = params.promptTokens;
56
+ const hasPromptOverride = typeof promptOverride === "number" && Number.isFinite(promptOverride) && promptOverride > 0;
51
57
  const usage = params.usage;
52
- if (!usage) {
58
+ if (!usage && !hasPromptOverride) {
53
59
  return undefined;
54
60
  }
55
- const input = usage.input ?? 0;
56
- const promptTokens = derivePromptTokens({
57
- input: usage.input,
58
- cacheRead: usage.cacheRead,
59
- cacheWrite: usage.cacheWrite,
60
- });
61
- let total = promptTokens ?? usage.total ?? input;
61
+ const input = usage?.input ?? 0;
62
+ const promptTokens = hasPromptOverride
63
+ ? promptOverride
64
+ : derivePromptTokens({
65
+ input: usage?.input,
66
+ cacheRead: usage?.cacheRead,
67
+ cacheWrite: usage?.cacheWrite,
68
+ });
69
+ let total = promptTokens ?? usage?.total ?? input;
62
70
  if (!(total > 0)) {
63
71
  return undefined;
64
72
  }
65
- const contextTokens = params.contextTokens;
66
- if (typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens > 0) {
67
- total = Math.min(total, contextTokens);
68
- }
73
+ // NOTE: Do NOT clamp total to contextTokens here. The stored totalTokens
74
+ // should reflect the actual token count (or best estimate). Clamping causes
75
+ // /status to display contextTokens/contextTokens (100%) when the accumulated
76
+ // input exceeds the context window, hiding the real usage. The display layer
77
+ // (formatTokens in status.ts) already caps the percentage at 999%.
69
78
  return total;
70
79
  }
@@ -1,7 +1,7 @@
1
1
  import { listChannelDocks } from "../channels/dock.js";
2
2
  import { getActivePluginRegistry } from "../plugins/runtime.js";
3
- import { listThinkingLevels } from "./thinking.js";
4
3
  import { COMMAND_ARG_FORMATTERS } from "./commands-args.js";
4
+ import { listThinkingLevels } from "./thinking.js";
5
5
  function defineChatCommand(command) {
6
6
  const aliases = (command.textAliases ?? (command.textAlias ? [command.textAlias] : []))
7
7
  .map((alias) => alias.trim())
@@ -40,11 +40,13 @@ function registerAlias(commands, key, ...aliases) {
40
40
  const existing = new Set(command.textAliases.map((alias) => alias.trim().toLowerCase()));
41
41
  for (const alias of aliases) {
42
42
  const trimmed = alias.trim();
43
- if (!trimmed)
43
+ if (!trimmed) {
44
44
  continue;
45
+ }
45
46
  const lowered = trimmed.toLowerCase();
46
- if (existing.has(lowered))
47
+ if (existing.has(lowered)) {
47
48
  continue;
49
+ }
48
50
  existing.add(lowered);
49
51
  command.textAliases.push(trimmed);
50
52
  }
@@ -164,6 +166,22 @@ function buildChatCommands() {
164
166
  acceptsArgs: true,
165
167
  category: "status",
166
168
  }),
169
+ defineChatCommand({
170
+ key: "export-session",
171
+ nativeName: "export-session",
172
+ description: "Export current session to HTML file with full system prompt.",
173
+ textAliases: ["/export-session", "/export"],
174
+ acceptsArgs: true,
175
+ category: "status",
176
+ args: [
177
+ {
178
+ name: "path",
179
+ description: "Output path (default: workspace)",
180
+ type: "string",
181
+ required: false,
182
+ },
183
+ ],
184
+ }),
167
185
  defineChatCommand({
168
186
  key: "tts",
169
187
  nativeName: "tts",
@@ -216,15 +234,15 @@ function buildChatCommands() {
216
234
  defineChatCommand({
217
235
  key: "subagents",
218
236
  nativeName: "subagents",
219
- description: "List/stop/log/info subagent runs for this session.",
237
+ description: "List, kill, log, spawn, or steer subagent runs for this session.",
220
238
  textAlias: "/subagents",
221
239
  category: "management",
222
240
  args: [
223
241
  {
224
242
  name: "action",
225
- description: "list | stop | log | info | send",
243
+ description: "list | kill | log | info | send | steer | spawn",
226
244
  type: "string",
227
- choices: ["list", "stop", "log", "info", "send"],
245
+ choices: ["list", "kill", "log", "info", "send", "steer", "spawn"],
228
246
  },
229
247
  {
230
248
  name: "target",
@@ -240,6 +258,41 @@ function buildChatCommands() {
240
258
  ],
241
259
  argsMenu: "auto",
242
260
  }),
261
+ defineChatCommand({
262
+ key: "kill",
263
+ nativeName: "kill",
264
+ description: "Kill a running subagent (or all).",
265
+ textAlias: "/kill",
266
+ category: "management",
267
+ args: [
268
+ {
269
+ name: "target",
270
+ description: "Label, run id, index, or all",
271
+ type: "string",
272
+ },
273
+ ],
274
+ argsMenu: "auto",
275
+ }),
276
+ defineChatCommand({
277
+ key: "steer",
278
+ nativeName: "steer",
279
+ description: "Send guidance to a running subagent.",
280
+ textAlias: "/steer",
281
+ category: "management",
282
+ args: [
283
+ {
284
+ name: "target",
285
+ description: "Label, run id, or index",
286
+ type: "string",
287
+ },
288
+ {
289
+ name: "message",
290
+ description: "Steering message",
291
+ type: "string",
292
+ captureRemaining: true,
293
+ },
294
+ ],
295
+ }),
243
296
  defineChatCommand({
244
297
  key: "config",
245
298
  nativeName: "config",
@@ -322,7 +375,7 @@ function buildChatCommands() {
322
375
  defineChatCommand({
323
376
  key: "restart",
324
377
  nativeName: "restart",
325
- description: "Restart Poolbot.",
378
+ description: "Restart Pool Bot.",
326
379
  textAlias: "/restart",
327
380
  category: "tools",
328
381
  }),
@@ -376,9 +429,9 @@ function buildChatCommands() {
376
429
  }),
377
430
  defineChatCommand({
378
431
  key: "compact",
432
+ nativeName: "compact",
379
433
  description: "Compact the session context.",
380
434
  textAlias: "/compact",
381
- scope: "text",
382
435
  category: "session",
383
436
  args: [
384
437
  {
@@ -461,12 +514,31 @@ function buildChatCommands() {
461
514
  category: "options",
462
515
  args: [
463
516
  {
464
- name: "options",
465
- description: "host=... security=... ask=... node=...",
517
+ name: "host",
518
+ description: "sandbox, gateway, or node",
519
+ type: "string",
520
+ choices: ["sandbox", "gateway", "node"],
521
+ },
522
+ {
523
+ name: "security",
524
+ description: "deny, allowlist, or full",
525
+ type: "string",
526
+ choices: ["deny", "allowlist", "full"],
527
+ },
528
+ {
529
+ name: "ask",
530
+ description: "off, on-miss, or always",
531
+ type: "string",
532
+ choices: ["off", "on-miss", "always"],
533
+ },
534
+ {
535
+ name: "node",
536
+ description: "Node id or name",
466
537
  type: "string",
467
538
  },
468
539
  ],
469
540
  argsParsing: "none",
541
+ formatArgs: COMMAND_ARG_FORMATTERS.exec,
470
542
  }),
471
543
  defineChatCommand({
472
544
  key: "model",
@@ -548,13 +620,15 @@ function buildChatCommands() {
548
620
  registerAlias(commands, "verbose", "/v");
549
621
  registerAlias(commands, "reasoning", "/reason");
550
622
  registerAlias(commands, "elevated", "/elev");
623
+ registerAlias(commands, "steer", "/tell");
551
624
  assertCommandRegistry(commands);
552
625
  return commands;
553
626
  }
554
627
  export function getChatCommands() {
555
628
  const registry = getActivePluginRegistry();
556
- if (cachedCommands && registry === cachedRegistry)
629
+ if (cachedCommands && registry === cachedRegistry) {
557
630
  return cachedCommands;
631
+ }
558
632
  const commands = buildChatCommands();
559
633
  cachedCommands = commands;
560
634
  cachedRegistry = registry;
@@ -1,40 +1,59 @@
1
- import { finalizeInboundContext } from "./reply/inbound-context.js";
2
1
  import { dispatchReplyFromConfig } from "./reply/dispatch-from-config.js";
2
+ import { finalizeInboundContext } from "./reply/inbound-context.js";
3
3
  import { createReplyDispatcher, createReplyDispatcherWithTyping, } from "./reply/reply-dispatcher.js";
4
+ export async function withReplyDispatcher(params) {
5
+ try {
6
+ return await params.run();
7
+ }
8
+ finally {
9
+ // Ensure dispatcher reservations are always released on every exit path.
10
+ params.dispatcher.markComplete();
11
+ try {
12
+ await params.dispatcher.waitForIdle();
13
+ }
14
+ finally {
15
+ await params.onSettled?.();
16
+ }
17
+ }
18
+ }
4
19
  export async function dispatchInboundMessage(params) {
5
20
  const finalized = finalizeInboundContext(params.ctx);
6
- return await dispatchReplyFromConfig({
7
- ctx: finalized,
8
- cfg: params.cfg,
21
+ return await withReplyDispatcher({
9
22
  dispatcher: params.dispatcher,
10
- replyOptions: params.replyOptions,
11
- replyResolver: params.replyResolver,
23
+ run: () => dispatchReplyFromConfig({
24
+ ctx: finalized,
25
+ cfg: params.cfg,
26
+ dispatcher: params.dispatcher,
27
+ replyOptions: params.replyOptions,
28
+ replyResolver: params.replyResolver,
29
+ }),
12
30
  });
13
31
  }
14
32
  export async function dispatchInboundMessageWithBufferedDispatcher(params) {
15
33
  const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping(params.dispatcherOptions);
16
- const result = await dispatchInboundMessage({
17
- ctx: params.ctx,
18
- cfg: params.cfg,
19
- dispatcher,
20
- replyResolver: params.replyResolver,
21
- replyOptions: {
22
- ...params.replyOptions,
23
- ...replyOptions,
24
- },
25
- });
26
- markDispatchIdle();
27
- return result;
34
+ try {
35
+ return await dispatchInboundMessage({
36
+ ctx: params.ctx,
37
+ cfg: params.cfg,
38
+ dispatcher,
39
+ replyResolver: params.replyResolver,
40
+ replyOptions: {
41
+ ...params.replyOptions,
42
+ ...replyOptions,
43
+ },
44
+ });
45
+ }
46
+ finally {
47
+ markDispatchIdle();
48
+ }
28
49
  }
29
50
  export async function dispatchInboundMessageWithDispatcher(params) {
30
51
  const dispatcher = createReplyDispatcher(params.dispatcherOptions);
31
- const result = await dispatchInboundMessage({
52
+ return await dispatchInboundMessage({
32
53
  ctx: params.ctx,
33
54
  cfg: params.cfg,
34
55
  dispatcher,
35
56
  replyResolver: params.replyResolver,
36
57
  replyOptions: params.replyOptions,
37
58
  });
38
- await dispatcher.waitForIdle();
39
- return result;
40
59
  }
@@ -1,27 +1,76 @@
1
1
  import { resolveSessionAgentId } from "../../agents/agent-scope.js";
2
2
  import { abortEmbeddedPiRun } from "../../agents/pi-embedded.js";
3
- import { listSubagentRunsForRequester } from "../../agents/subagent-registry.js";
3
+ import { listSubagentRunsForRequester, markSubagentRunTerminated, } from "../../agents/subagent-registry.js";
4
+ import { resolveInternalSessionKey, resolveMainSessionAlias, } from "../../agents/tools/sessions-helpers.js";
4
5
  import { loadSessionStore, resolveStorePath, updateSessionStore, } from "../../config/sessions.js";
6
+ import { logVerbose } from "../../globals.js";
5
7
  import { parseAgentSessionKey } from "../../routing/session-key.js";
6
8
  import { resolveCommandAuthorization } from "../command-auth.js";
7
9
  import { normalizeCommandBody } from "../commands-registry.js";
8
- import { logVerbose } from "../../globals.js";
9
10
  import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
10
11
  import { clearSessionQueues } from "./queue.js";
11
- import { resolveInternalSessionKey, resolveMainSessionAlias, } from "../../agents/tools/sessions-helpers.js";
12
12
  const ABORT_TRIGGERS = new Set(["stop", "esc", "abort", "wait", "exit", "interrupt"]);
13
13
  const ABORT_MEMORY = new Map();
14
+ const ABORT_MEMORY_MAX = 2000;
14
15
  export function isAbortTrigger(text) {
15
- if (!text)
16
+ if (!text) {
16
17
  return false;
18
+ }
17
19
  const normalized = text.trim().toLowerCase();
18
20
  return ABORT_TRIGGERS.has(normalized);
19
21
  }
22
+ export function isAbortRequestText(text, options) {
23
+ if (!text) {
24
+ return false;
25
+ }
26
+ const normalized = normalizeCommandBody(text, options).trim();
27
+ if (!normalized) {
28
+ return false;
29
+ }
30
+ return normalized.toLowerCase() === "/stop" || isAbortTrigger(normalized);
31
+ }
20
32
  export function getAbortMemory(key) {
21
- return ABORT_MEMORY.get(key);
33
+ const normalized = key.trim();
34
+ if (!normalized) {
35
+ return undefined;
36
+ }
37
+ return ABORT_MEMORY.get(normalized);
38
+ }
39
+ function pruneAbortMemory() {
40
+ if (ABORT_MEMORY.size <= ABORT_MEMORY_MAX) {
41
+ return;
42
+ }
43
+ const excess = ABORT_MEMORY.size - ABORT_MEMORY_MAX;
44
+ let removed = 0;
45
+ for (const entryKey of ABORT_MEMORY.keys()) {
46
+ ABORT_MEMORY.delete(entryKey);
47
+ removed += 1;
48
+ if (removed >= excess) {
49
+ break;
50
+ }
51
+ }
22
52
  }
23
53
  export function setAbortMemory(key, value) {
24
- ABORT_MEMORY.set(key, value);
54
+ const normalized = key.trim();
55
+ if (!normalized) {
56
+ return;
57
+ }
58
+ if (!value) {
59
+ ABORT_MEMORY.delete(normalized);
60
+ return;
61
+ }
62
+ // Refresh insertion order so active keys are less likely to be evicted.
63
+ if (ABORT_MEMORY.has(normalized)) {
64
+ ABORT_MEMORY.delete(normalized);
65
+ }
66
+ ABORT_MEMORY.set(normalized, true);
67
+ pruneAbortMemory();
68
+ }
69
+ export function getAbortMemorySizeForTest() {
70
+ return ABORT_MEMORY.size;
71
+ }
72
+ export function resetAbortMemoryForTest() {
73
+ ABORT_MEMORY.clear();
25
74
  }
26
75
  export function formatAbortReplyText(stoppedSubagents) {
27
76
  if (typeof stoppedSubagents !== "number" || stoppedSubagents <= 0) {
@@ -31,58 +80,76 @@ export function formatAbortReplyText(stoppedSubagents) {
31
80
  return `⚙️ Agent was aborted. Stopped ${stoppedSubagents} ${label}.`;
32
81
  }
33
82
  function resolveSessionEntryForKey(store, sessionKey) {
34
- if (!store || !sessionKey)
83
+ if (!store || !sessionKey) {
35
84
  return {};
85
+ }
36
86
  const direct = store[sessionKey];
37
- if (direct)
87
+ if (direct) {
38
88
  return { entry: direct, key: sessionKey };
89
+ }
39
90
  return {};
40
91
  }
41
92
  function resolveAbortTargetKey(ctx) {
42
93
  const target = ctx.CommandTargetSessionKey?.trim();
43
- if (target)
94
+ if (target) {
44
95
  return target;
96
+ }
45
97
  const sessionKey = ctx.SessionKey?.trim();
46
98
  return sessionKey || undefined;
47
99
  }
48
100
  function normalizeRequesterSessionKey(cfg, key) {
49
101
  const cleaned = key?.trim();
50
- if (!cleaned)
102
+ if (!cleaned) {
51
103
  return undefined;
104
+ }
52
105
  const { mainKey, alias } = resolveMainSessionAlias(cfg);
53
106
  return resolveInternalSessionKey({ key: cleaned, alias, mainKey });
54
107
  }
55
108
  export function stopSubagentsForRequester(params) {
56
109
  const requesterKey = normalizeRequesterSessionKey(params.cfg, params.requesterSessionKey);
57
- if (!requesterKey)
110
+ if (!requesterKey) {
58
111
  return { stopped: 0 };
112
+ }
59
113
  const runs = listSubagentRunsForRequester(requesterKey);
60
- if (runs.length === 0)
114
+ if (runs.length === 0) {
61
115
  return { stopped: 0 };
116
+ }
62
117
  const storeCache = new Map();
63
118
  const seenChildKeys = new Set();
64
119
  let stopped = 0;
65
120
  for (const run of runs) {
66
- if (run.endedAt)
67
- continue;
68
121
  const childKey = run.childSessionKey?.trim();
69
- if (!childKey || seenChildKeys.has(childKey))
122
+ if (!childKey || seenChildKeys.has(childKey)) {
70
123
  continue;
71
- seenChildKeys.add(childKey);
72
- const cleared = clearSessionQueues([childKey]);
73
- const parsed = parseAgentSessionKey(childKey);
74
- const storePath = resolveStorePath(params.cfg.session?.store, { agentId: parsed?.agentId });
75
- let store = storeCache.get(storePath);
76
- if (!store) {
77
- store = loadSessionStore(storePath);
78
- storeCache.set(storePath, store);
79
124
  }
80
- const entry = store[childKey];
81
- const sessionId = entry?.sessionId;
82
- const aborted = sessionId ? abortEmbeddedPiRun(sessionId) : false;
83
- if (aborted || cleared.followupCleared > 0 || cleared.laneCleared > 0) {
84
- stopped += 1;
125
+ seenChildKeys.add(childKey);
126
+ if (!run.endedAt) {
127
+ const cleared = clearSessionQueues([childKey]);
128
+ const parsed = parseAgentSessionKey(childKey);
129
+ const storePath = resolveStorePath(params.cfg.session?.store, { agentId: parsed?.agentId });
130
+ let store = storeCache.get(storePath);
131
+ if (!store) {
132
+ store = loadSessionStore(storePath);
133
+ storeCache.set(storePath, store);
134
+ }
135
+ const entry = store[childKey];
136
+ const sessionId = entry?.sessionId;
137
+ const aborted = sessionId ? abortEmbeddedPiRun(sessionId) : false;
138
+ const markedTerminated = markSubagentRunTerminated({
139
+ runId: run.runId,
140
+ childSessionKey: childKey,
141
+ reason: "killed",
142
+ }) > 0;
143
+ if (markedTerminated || aborted || cleared.followupCleared > 0 || cleared.laneCleared > 0) {
144
+ stopped += 1;
145
+ }
85
146
  }
147
+ // Cascade: also stop any sub-sub-agents spawned by this child.
148
+ const cascadeResult = stopSubagentsForRequester({
149
+ cfg: params.cfg,
150
+ requesterSessionKey: childKey,
151
+ });
152
+ stopped += cascadeResult.stopped;
86
153
  }
87
154
  if (stopped > 0) {
88
155
  logVerbose(`abort: stopped ${stopped} subagent run(s) for ${requesterKey}`);
@@ -100,18 +167,19 @@ export async function tryFastAbortFromMessage(params) {
100
167
  const raw = stripStructuralPrefixes(ctx.CommandBody ?? ctx.RawBody ?? ctx.Body ?? "");
101
168
  const isGroup = ctx.ChatType?.trim().toLowerCase() === "group";
102
169
  const stripped = isGroup ? stripMentions(raw, ctx, cfg, agentId) : raw;
103
- const normalized = normalizeCommandBody(stripped);
104
- const abortRequested = normalized === "/stop" || isAbortTrigger(stripped);
105
- if (!abortRequested)
170
+ const abortRequested = isAbortRequestText(stripped);
171
+ if (!abortRequested) {
106
172
  return { handled: false, aborted: false };
173
+ }
107
174
  const commandAuthorized = ctx.CommandAuthorized;
108
175
  const auth = resolveCommandAuthorization({
109
176
  ctx,
110
177
  cfg,
111
178
  commandAuthorized,
112
179
  });
113
- if (!auth.isAuthorizedSender)
180
+ if (!auth.isAuthorizedSender) {
114
181
  return { handled: false, aborted: false };
182
+ }
115
183
  const abortKey = targetKey ?? auth.from ?? auth.to;
116
184
  const requesterSessionKey = targetKey ?? ctx.SessionKey ?? abortKey;
117
185
  if (targetKey) {
@@ -130,8 +198,9 @@ export async function tryFastAbortFromMessage(params) {
130
198
  store[key] = entry;
131
199
  await updateSessionStore(storePath, (nextStore) => {
132
200
  const nextEntry = nextStore[key] ?? entry;
133
- if (!nextEntry)
201
+ if (!nextEntry) {
134
202
  return;
203
+ }
135
204
  nextEntry.abortedLastRun = true;
136
205
  nextEntry.updatedAt = Date.now();
137
206
  nextStore[key] = nextEntry;