@poolzin/pool-bot 2026.2.0 → 2026.2.2

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 (258) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README-header.png +0 -0
  3. package/dist/agents/bash-tools.exec.js +76 -25
  4. package/dist/agents/cli-runner/helpers.js +9 -11
  5. package/dist/agents/context.js +1 -1
  6. package/dist/agents/identity.js +47 -7
  7. package/dist/agents/memory-search.js +25 -8
  8. package/dist/agents/model-catalog.js +1 -1
  9. package/dist/agents/model-selection.js +21 -0
  10. package/dist/agents/pi-embedded-block-chunker.js +117 -42
  11. package/dist/agents/pi-embedded-helpers/errors.js +183 -78
  12. package/dist/agents/pi-embedded-helpers.js +1 -1
  13. package/dist/agents/pi-embedded-runner/compact.js +8 -10
  14. package/dist/agents/pi-embedded-runner/model.js +62 -3
  15. package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
  16. package/dist/agents/pi-embedded-runner/run.js +199 -46
  17. package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
  18. package/dist/agents/pi-embedded-subscribe.js +118 -29
  19. package/dist/agents/pi-tools.js +10 -5
  20. package/dist/agents/poolbot-tools.js +15 -10
  21. package/dist/agents/sandbox-paths.js +31 -0
  22. package/dist/agents/session-tool-result-guard.js +94 -15
  23. package/dist/agents/shell-utils.js +51 -0
  24. package/dist/agents/skills/bundled-context.js +23 -0
  25. package/dist/agents/skills/bundled-dir.js +41 -7
  26. package/dist/agents/skills-install.js +60 -23
  27. package/dist/agents/subagent-announce.js +79 -34
  28. package/dist/agents/tool-policy.conformance.js +14 -0
  29. package/dist/agents/tool-policy.js +24 -0
  30. package/dist/agents/tools/cron-tool.js +166 -19
  31. package/dist/agents/tools/discord-actions-presence.js +78 -0
  32. package/dist/agents/tools/image-tool.js +1 -1
  33. package/dist/agents/tools/message-tool.js +56 -2
  34. package/dist/agents/tools/sessions-history-tool.js +69 -1
  35. package/dist/agents/tools/web-search.js +211 -42
  36. package/dist/agents/usage.js +23 -1
  37. package/dist/agents/workspace-run.js +67 -0
  38. package/dist/agents/workspace-templates.js +44 -0
  39. package/dist/auto-reply/command-auth.js +121 -6
  40. package/dist/auto-reply/envelope.js +74 -82
  41. package/dist/auto-reply/reply/commands-compact.js +1 -0
  42. package/dist/auto-reply/reply/commands-context-report.js +1 -0
  43. package/dist/auto-reply/reply/commands-context.js +1 -0
  44. package/dist/auto-reply/reply/commands-models.js +107 -60
  45. package/dist/auto-reply/reply/commands-ptt.js +171 -0
  46. package/dist/auto-reply/reply/get-reply-run.js +2 -1
  47. package/dist/auto-reply/reply/inbound-context.js +5 -1
  48. package/dist/auto-reply/reply/mentions.js +1 -1
  49. package/dist/auto-reply/reply/model-selection.js +3 -3
  50. package/dist/auto-reply/thinking.js +88 -43
  51. package/dist/browser/bridge-server.js +13 -0
  52. package/dist/browser/cdp.helpers.js +38 -24
  53. package/dist/browser/client-fetch.js +50 -7
  54. package/dist/browser/config.js +1 -10
  55. package/dist/browser/extension-relay.js +101 -40
  56. package/dist/browser/pw-ai.js +1 -1
  57. package/dist/browser/pw-session.js +143 -8
  58. package/dist/browser/pw-tools-core.interactions.js +125 -27
  59. package/dist/browser/pw-tools-core.responses.js +1 -1
  60. package/dist/browser/pw-tools-core.state.js +1 -1
  61. package/dist/browser/routes/agent.act.js +86 -41
  62. package/dist/browser/routes/dispatcher.js +4 -4
  63. package/dist/browser/screenshot.js +1 -1
  64. package/dist/browser/server.js +13 -0
  65. package/dist/build-info.json +3 -3
  66. package/dist/canvas-host/a2ui/index.html +28 -28
  67. package/dist/channels/reply-prefix.js +8 -1
  68. package/dist/cli/cron-cli/register.cron-add.js +61 -40
  69. package/dist/cli/cron-cli/register.cron-edit.js +60 -34
  70. package/dist/cli/cron-cli/shared.js +56 -41
  71. package/dist/cli/dns-cli.js +26 -14
  72. package/dist/cli/gateway-cli/register.js +37 -19
  73. package/dist/cli/memory-cli.js +5 -5
  74. package/dist/cli/parse-bytes.js +37 -0
  75. package/dist/cli/update-cli.js +173 -52
  76. package/dist/commands/agent.js +1 -0
  77. package/dist/commands/auth-choice.apply.oauth.js +1 -1
  78. package/dist/commands/doctor-config-flow.js +61 -5
  79. package/dist/commands/doctor-state-migrations.js +1 -1
  80. package/dist/commands/health.js +1 -1
  81. package/dist/commands/model-allowlist.js +29 -0
  82. package/dist/commands/model-picker.js +2 -1
  83. package/dist/commands/models/list.registry.js +1 -1
  84. package/dist/commands/models/list.status-command.js +43 -23
  85. package/dist/commands/models/shared.js +15 -0
  86. package/dist/commands/onboard-custom.js +384 -0
  87. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
  88. package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
  89. package/dist/commands/onboard-skills.js +63 -38
  90. package/dist/commands/openai-model-default.js +41 -0
  91. package/dist/compat/legacy-names.js +2 -0
  92. package/dist/config/defaults.js +3 -2
  93. package/dist/config/paths.js +136 -35
  94. package/dist/config/plugin-auto-enable.js +21 -5
  95. package/dist/config/redact-snapshot.js +153 -0
  96. package/dist/config/schema.field-metadata.js +590 -0
  97. package/dist/config/schema.js +2 -2
  98. package/dist/config/sessions/store.js +291 -23
  99. package/dist/config/zod-schema.agent-defaults.js +3 -0
  100. package/dist/config/zod-schema.agent-runtime.js +13 -2
  101. package/dist/config/zod-schema.providers-core.js +142 -0
  102. package/dist/config/zod-schema.session.js +3 -0
  103. package/dist/control-ui/assets/{index-CIRDm-Lu.css → index-CSfXd2LO.css} +1 -1
  104. package/dist/control-ui/assets/{index-CmNMuoem.js → index-HRr1grwl.js} +446 -413
  105. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -0
  106. package/dist/control-ui/index.html +4 -4
  107. package/dist/cron/delivery.js +57 -0
  108. package/dist/cron/isolated-agent/delivery-target.js +18 -3
  109. package/dist/cron/isolated-agent/helpers.js +22 -5
  110. package/dist/cron/isolated-agent/run.js +172 -63
  111. package/dist/cron/isolated-agent/session.js +2 -0
  112. package/dist/cron/normalize.js +356 -28
  113. package/dist/cron/parse.js +10 -5
  114. package/dist/cron/run-log.js +35 -10
  115. package/dist/cron/schedule.js +41 -6
  116. package/dist/cron/service/jobs.js +208 -35
  117. package/dist/cron/service/ops.js +72 -16
  118. package/dist/cron/service/state.js +2 -0
  119. package/dist/cron/service/store.js +386 -14
  120. package/dist/cron/service/timer.js +390 -147
  121. package/dist/cron/session-reaper.js +86 -0
  122. package/dist/cron/store.js +23 -8
  123. package/dist/cron/validate-timestamp.js +43 -0
  124. package/dist/discord/monitor/agent-components.js +438 -0
  125. package/dist/discord/monitor/allow-list.js +28 -5
  126. package/dist/discord/monitor/gateway-registry.js +29 -0
  127. package/dist/discord/monitor/native-command.js +44 -23
  128. package/dist/discord/monitor/sender-identity.js +45 -0
  129. package/dist/discord/pluralkit.js +27 -0
  130. package/dist/discord/send.outbound.js +92 -5
  131. package/dist/discord/send.shared.js +60 -23
  132. package/dist/discord/targets.js +84 -1
  133. package/dist/entry.js +15 -9
  134. package/dist/extensionAPI.js +8 -0
  135. package/dist/gateway/control-ui.js +8 -1
  136. package/dist/gateway/hooks-mapping.js +3 -0
  137. package/dist/gateway/hooks.js +65 -0
  138. package/dist/gateway/net.js +96 -31
  139. package/dist/gateway/node-command-policy.js +50 -15
  140. package/dist/gateway/origin-check.js +56 -0
  141. package/dist/gateway/protocol/client-info.js +9 -0
  142. package/dist/gateway/protocol/index.js +9 -2
  143. package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
  144. package/dist/gateway/protocol/schema/cron.js +22 -10
  145. package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
  146. package/dist/gateway/protocol/schema/sessions.js +12 -0
  147. package/dist/gateway/server/hooks.js +1 -1
  148. package/dist/gateway/server-broadcast.js +26 -9
  149. package/dist/gateway/server-chat.js +112 -23
  150. package/dist/gateway/server-discovery-runtime.js +10 -2
  151. package/dist/gateway/server-http.js +109 -11
  152. package/dist/gateway/server-methods/agent-timestamp.js +60 -0
  153. package/dist/gateway/server-methods/agents.js +321 -2
  154. package/dist/gateway/server-methods/usage.js +559 -16
  155. package/dist/gateway/server-runtime-state.js +22 -8
  156. package/dist/gateway/server-startup-memory.js +16 -0
  157. package/dist/gateway/server.impl.js +5 -1
  158. package/dist/gateway/session-utils.fs.js +23 -25
  159. package/dist/gateway/session-utils.js +20 -10
  160. package/dist/gateway/sessions-patch.js +7 -22
  161. package/dist/gateway/test-helpers.mocks.js +11 -7
  162. package/dist/gateway/test-helpers.server.js +35 -2
  163. package/dist/imessage/constants.js +2 -0
  164. package/dist/imessage/monitor/deliver.js +4 -1
  165. package/dist/imessage/monitor/monitor-provider.js +51 -1
  166. package/dist/infra/bonjour-discovery.js +131 -70
  167. package/dist/infra/control-ui-assets.js +134 -12
  168. package/dist/infra/errors.js +12 -0
  169. package/dist/infra/exec-approvals.js +266 -57
  170. package/dist/infra/format-time/format-datetime.js +79 -0
  171. package/dist/infra/format-time/format-duration.js +81 -0
  172. package/dist/infra/format-time/format-relative.js +80 -0
  173. package/dist/infra/heartbeat-runner.js +140 -49
  174. package/dist/infra/home-dir.js +54 -0
  175. package/dist/infra/net/fetch-guard.js +122 -0
  176. package/dist/infra/net/ssrf.js +65 -29
  177. package/dist/infra/outbound/abort.js +14 -0
  178. package/dist/infra/outbound/message-action-runner.js +77 -13
  179. package/dist/infra/outbound/outbound-session.js +143 -37
  180. package/dist/infra/poolbot-root.js +43 -1
  181. package/dist/infra/session-cost-usage.js +631 -41
  182. package/dist/infra/state-migrations.js +317 -47
  183. package/dist/infra/update-global.js +35 -0
  184. package/dist/infra/update-runner.js +149 -43
  185. package/dist/infra/warning-filter.js +65 -0
  186. package/dist/infra/widearea-dns.js +30 -9
  187. package/dist/logging/redact-identifier.js +12 -0
  188. package/dist/media/fetch.js +81 -58
  189. package/dist/media/store.js +2 -0
  190. package/dist/media-understanding/apply.js +403 -3
  191. package/dist/media-understanding/attachments.js +38 -27
  192. package/dist/media-understanding/defaults.js +16 -0
  193. package/dist/media-understanding/providers/deepgram/audio.js +22 -14
  194. package/dist/media-understanding/providers/google/audio.js +24 -17
  195. package/dist/media-understanding/providers/google/video.js +24 -17
  196. package/dist/media-understanding/providers/image.js +3 -3
  197. package/dist/media-understanding/providers/index.js +4 -1
  198. package/dist/media-understanding/providers/openai/audio.js +22 -14
  199. package/dist/media-understanding/providers/shared.js +16 -11
  200. package/dist/media-understanding/providers/zai/index.js +6 -0
  201. package/dist/media-understanding/runner.js +158 -90
  202. package/dist/memory/batch-voyage.js +277 -0
  203. package/dist/memory/embeddings-voyage.js +75 -0
  204. package/dist/memory/embeddings.js +28 -16
  205. package/dist/memory/internal.js +101 -18
  206. package/dist/memory/manager.js +154 -48
  207. package/dist/memory/search-manager.js +173 -0
  208. package/dist/memory/session-files.js +9 -3
  209. package/dist/node-host/runner.js +34 -24
  210. package/dist/node-host/with-timeout.js +27 -0
  211. package/dist/plugins/commands.js +5 -1
  212. package/dist/plugins/config-state.js +86 -7
  213. package/dist/plugins/source-display.js +51 -0
  214. package/dist/process/exec.js +20 -2
  215. package/dist/routing/resolve-route.js +12 -0
  216. package/dist/routing/session-key.js +15 -0
  217. package/dist/runtime.js +2 -0
  218. package/dist/security/audit-extra.async.js +601 -0
  219. package/dist/security/audit-extra.js +2 -830
  220. package/dist/security/audit-extra.sync.js +505 -0
  221. package/dist/security/channel-metadata.js +34 -0
  222. package/dist/security/external-content.js +88 -6
  223. package/dist/security/skill-scanner.js +330 -0
  224. package/dist/sessions/session-key-utils.js +7 -0
  225. package/dist/signal/monitor/event-handler.js +80 -1
  226. package/dist/slack/monitor/media.js +85 -15
  227. package/dist/tailscale/detect.js +1 -2
  228. package/dist/telegram/bot/helpers.js +109 -28
  229. package/dist/telegram/bot-handlers.js +144 -3
  230. package/dist/telegram/bot-message-context.js +37 -10
  231. package/dist/telegram/bot-message-dispatch.js +54 -17
  232. package/dist/telegram/bot-native-commands.js +86 -29
  233. package/dist/telegram/bot.js +30 -29
  234. package/dist/telegram/model-buttons.js +163 -0
  235. package/dist/telegram/monitor.js +110 -85
  236. package/dist/telegram/send.js +129 -47
  237. package/dist/terminal/restore.js +45 -0
  238. package/dist/test-helpers/state-dir-env.js +16 -0
  239. package/dist/tts/tts.js +12 -6
  240. package/dist/tui/tui-session-actions.js +166 -54
  241. package/dist/utils/fetch-timeout.js +20 -0
  242. package/dist/utils/normalize-secret-input.js +19 -0
  243. package/dist/utils/transcript-tools.js +58 -0
  244. package/dist/utils.js +45 -14
  245. package/dist/version.js +42 -5
  246. package/dist/wizard/clack-prompter.js +9 -6
  247. package/extensions/googlechat/node_modules/.bin/poolbot +21 -0
  248. package/extensions/googlechat/package.json +2 -2
  249. package/extensions/line/node_modules/.bin/poolbot +21 -0
  250. package/extensions/line/package.json +1 -1
  251. package/extensions/matrix/node_modules/.bin/poolbot +21 -0
  252. package/extensions/matrix/package.json +1 -1
  253. package/extensions/memory-core/node_modules/.bin/poolbot +21 -0
  254. package/extensions/memory-core/package.json +4 -1
  255. package/extensions/twitch/node_modules/.bin/poolbot +21 -0
  256. package/extensions/twitch/package.json +1 -1
  257. package/package.json +183 -24
  258. package/dist/control-ui/assets/index-CmNMuoem.js.map +0 -1
@@ -0,0 +1,27 @@
1
+ export async function withTimeout(work, timeoutMs, label) {
2
+ const resolved = typeof timeoutMs === "number" && Number.isFinite(timeoutMs)
3
+ ? Math.max(1, Math.floor(timeoutMs))
4
+ : undefined;
5
+ if (!resolved) {
6
+ return await work(undefined);
7
+ }
8
+ const abortCtrl = new AbortController();
9
+ const timeoutError = new Error(`${label ?? "request"} timed out`);
10
+ const timer = setTimeout(() => abortCtrl.abort(timeoutError), resolved);
11
+ let abortListener;
12
+ const abortPromise = abortCtrl.signal.aborted
13
+ ? Promise.reject(abortCtrl.signal.reason ?? timeoutError)
14
+ : new Promise((_, reject) => {
15
+ abortListener = () => reject(abortCtrl.signal.reason ?? timeoutError);
16
+ abortCtrl.signal.addEventListener("abort", abortListener, { once: true });
17
+ });
18
+ try {
19
+ return await Promise.race([work(abortCtrl.signal), abortPromise]);
20
+ }
21
+ finally {
22
+ clearTimeout(timer);
23
+ if (abortListener) {
24
+ abortCtrl.signal.removeEventListener("abort", abortListener);
25
+ }
26
+ }
27
+ }
@@ -172,7 +172,7 @@ function sanitizeArgs(args) {
172
172
  * specific use case. This function provides basic defense-in-depth sanitization.
173
173
  */
174
174
  export async function executePluginCommand(params) {
175
- const { command, args, senderId, channel, isAuthorizedSender, commandBody, config } = params;
175
+ const { command, args, senderId, channel, isAuthorizedSender, commandBody, config, from, to, accountId, messageThreadId, } = params;
176
176
  // Check authorization
177
177
  const requireAuth = command.requireAuth !== false; // Default to true
178
178
  if (requireAuth && !isAuthorizedSender) {
@@ -188,6 +188,10 @@ export async function executePluginCommand(params) {
188
188
  args: sanitizedArgs,
189
189
  commandBody,
190
190
  config,
191
+ from,
192
+ to,
193
+ accountId,
194
+ messageThreadId,
191
195
  };
192
196
  // Lock registry during execution to prevent concurrent modifications
193
197
  registryLocked = true;
@@ -1,18 +1,26 @@
1
1
  import { defaultSlotIdForKey } from "./slots.js";
2
- export const BUNDLED_ENABLED_BY_DEFAULT = new Set();
2
+ export const BUNDLED_ENABLED_BY_DEFAULT = new Set([
3
+ "device-pair",
4
+ "phone-control",
5
+ "talk-voice",
6
+ ]);
3
7
  const normalizeList = (value) => {
4
- if (!Array.isArray(value))
8
+ if (!Array.isArray(value)) {
5
9
  return [];
10
+ }
6
11
  return value.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean);
7
12
  };
8
13
  const normalizeSlotValue = (value) => {
9
- if (typeof value !== "string")
14
+ if (typeof value !== "string") {
10
15
  return undefined;
16
+ }
11
17
  const trimmed = value.trim();
12
- if (!trimmed)
18
+ if (!trimmed) {
13
19
  return undefined;
14
- if (trimmed.toLowerCase() === "none")
20
+ }
21
+ if (trimmed.toLowerCase() === "none") {
15
22
  return null;
23
+ }
16
24
  return trimmed;
17
25
  };
18
26
  const normalizePluginEntries = (entries) => {
@@ -21,8 +29,9 @@ const normalizePluginEntries = (entries) => {
21
29
  }
22
30
  const normalized = {};
23
31
  for (const [key, value] of Object.entries(entries)) {
24
- if (!key.trim())
32
+ if (!key.trim()) {
25
33
  continue;
34
+ }
26
35
  if (!value || typeof value !== "object" || Array.isArray(value)) {
27
36
  normalized[key] = {};
28
37
  continue;
@@ -48,6 +57,75 @@ export const normalizePluginsConfig = (config) => {
48
57
  entries: normalizePluginEntries(config?.entries),
49
58
  };
50
59
  };
60
+ const hasExplicitMemorySlot = (plugins) => Boolean(plugins?.slots && Object.prototype.hasOwnProperty.call(plugins.slots, "memory"));
61
+ const hasExplicitMemoryEntry = (plugins) => Boolean(plugins?.entries && Object.prototype.hasOwnProperty.call(plugins.entries, "memory-core"));
62
+ const hasExplicitPluginConfig = (plugins) => {
63
+ if (!plugins) {
64
+ return false;
65
+ }
66
+ if (typeof plugins.enabled === "boolean") {
67
+ return true;
68
+ }
69
+ if (Array.isArray(plugins.allow) && plugins.allow.length > 0) {
70
+ return true;
71
+ }
72
+ if (Array.isArray(plugins.deny) && plugins.deny.length > 0) {
73
+ return true;
74
+ }
75
+ if (plugins.load?.paths && Array.isArray(plugins.load.paths) && plugins.load.paths.length > 0) {
76
+ return true;
77
+ }
78
+ if (plugins.slots && Object.keys(plugins.slots).length > 0) {
79
+ return true;
80
+ }
81
+ if (plugins.entries && Object.keys(plugins.entries).length > 0) {
82
+ return true;
83
+ }
84
+ return false;
85
+ };
86
+ export function applyTestPluginDefaults(cfg, env = process.env) {
87
+ if (!env.VITEST) {
88
+ return cfg;
89
+ }
90
+ const plugins = cfg.plugins;
91
+ const explicitConfig = hasExplicitPluginConfig(plugins);
92
+ if (explicitConfig) {
93
+ if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) {
94
+ return cfg;
95
+ }
96
+ return {
97
+ ...cfg,
98
+ plugins: {
99
+ ...plugins,
100
+ slots: {
101
+ ...plugins?.slots,
102
+ memory: "none",
103
+ },
104
+ },
105
+ };
106
+ }
107
+ return {
108
+ ...cfg,
109
+ plugins: {
110
+ ...plugins,
111
+ enabled: false,
112
+ slots: {
113
+ ...plugins?.slots,
114
+ memory: "none",
115
+ },
116
+ },
117
+ };
118
+ }
119
+ export function isTestDefaultMemorySlotDisabled(cfg, env = process.env) {
120
+ if (!env.VITEST) {
121
+ return false;
122
+ }
123
+ const plugins = cfg.plugins;
124
+ if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) {
125
+ return false;
126
+ }
127
+ return true;
128
+ }
51
129
  export function resolveEnableState(id, origin, config) {
52
130
  if (!config.enabled) {
53
131
  return { enabled: false, reason: "plugins disabled" };
@@ -77,8 +155,9 @@ export function resolveEnableState(id, origin, config) {
77
155
  return { enabled: true };
78
156
  }
79
157
  export function resolveMemorySlotDecision(params) {
80
- if (params.kind !== "memory")
158
+ if (params.kind !== "memory") {
81
159
  return { enabled: true };
160
+ }
82
161
  if (params.slot === null) {
83
162
  return { enabled: false, reason: "memory slot disabled" };
84
163
  }
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { resolveConfigDir, shortenHomeInString } from "../utils.js";
3
+ import { resolveBundledPluginsDir } from "./bundled-dir.js";
4
+ function tryRelative(root, filePath) {
5
+ const rel = path.relative(root, filePath);
6
+ if (!rel || rel === ".") {
7
+ return null;
8
+ }
9
+ if (rel === "..") {
10
+ return null;
11
+ }
12
+ if (rel.startsWith(`..${path.sep}`) || rel.startsWith("../") || rel.startsWith("..\\")) {
13
+ return null;
14
+ }
15
+ if (path.isAbsolute(rel)) {
16
+ return null;
17
+ }
18
+ // Normalize to forward slashes for display (path.relative uses backslashes on Windows)
19
+ return rel.replaceAll("\\", "/");
20
+ }
21
+ export function resolvePluginSourceRoots(params) {
22
+ const stock = resolveBundledPluginsDir();
23
+ const global = path.join(resolveConfigDir(), "extensions");
24
+ const workspace = params.workspaceDir
25
+ ? path.join(params.workspaceDir, ".poolbot", "extensions")
26
+ : undefined;
27
+ return { stock, global, workspace };
28
+ }
29
+ export function formatPluginSourceForTable(plugin, roots) {
30
+ const raw = plugin.source;
31
+ if (plugin.origin === "bundled" && roots.stock) {
32
+ const rel = tryRelative(roots.stock, raw);
33
+ if (rel) {
34
+ return { value: `stock:${rel}`, rootKey: "stock" };
35
+ }
36
+ }
37
+ if (plugin.origin === "workspace" && roots.workspace) {
38
+ const rel = tryRelative(roots.workspace, raw);
39
+ if (rel) {
40
+ return { value: `workspace:${rel}`, rootKey: "workspace" };
41
+ }
42
+ }
43
+ if (plugin.origin === "global" && roots.global) {
44
+ const rel = tryRelative(roots.global, raw);
45
+ if (rel) {
46
+ return { value: `global:${rel}`, rootKey: "global" };
47
+ }
48
+ }
49
+ // Keep this stable/pasteable; only ~-shorten.
50
+ return { value: shortenHomeInString(raw) };
51
+ }
@@ -5,6 +5,24 @@ import { danger, shouldLogVerbose } from "../globals.js";
5
5
  import { logDebug, logError } from "../logger.js";
6
6
  import { resolveCommandStdio } from "./spawn-utils.js";
7
7
  const execFileAsync = promisify(execFile);
8
+ /**
9
+ * Resolves a command for Windows compatibility.
10
+ * On Windows, non-.exe commands (like npm, pnpm) require their .cmd extension.
11
+ */
12
+ function resolveCommand(command) {
13
+ if (process.platform !== "win32")
14
+ return command;
15
+ const basename = path.basename(command).toLowerCase();
16
+ // Skip if already has an extension (.cmd, .exe, .bat, etc.)
17
+ const ext = path.extname(basename);
18
+ if (ext)
19
+ return command;
20
+ // Common npm-related commands that need .cmd extension on Windows
21
+ const cmdCommands = ["npm", "pnpm", "yarn", "npx"];
22
+ if (cmdCommands.includes(basename))
23
+ return `${command}.cmd`;
24
+ return command;
25
+ }
8
26
  // Simple promise-wrapped execFile with optional verbosity logging.
9
27
  export async function runExec(command, args, opts = 10_000) {
10
28
  const options = typeof opts === "number"
@@ -15,7 +33,7 @@ export async function runExec(command, args, opts = 10_000) {
15
33
  encoding: "utf8",
16
34
  };
17
35
  try {
18
- const { stdout, stderr } = await execFileAsync(command, args, options);
36
+ const { stdout, stderr } = await execFileAsync(resolveCommand(command), args, options);
19
37
  if (shouldLogVerbose()) {
20
38
  if (stdout.trim())
21
39
  logDebug(stdout.trim());
@@ -54,7 +72,7 @@ export async function runCommandWithTimeout(argv, optionsOrTimeout) {
54
72
  resolvedEnv.npm_config_fund = "false";
55
73
  }
56
74
  const stdio = resolveCommandStdio({ hasInput, preferInherit: true });
57
- const child = spawn(argv[0], argv.slice(1), {
75
+ const child = spawn(resolveCommand(argv[0]), argv.slice(1), {
58
76
  stdio,
59
77
  cwd,
60
78
  env: resolvedEnv,
@@ -27,6 +27,7 @@ export function buildAgentSessionKey(params) {
27
27
  agentId: params.agentId,
28
28
  mainKey: DEFAULT_MAIN_KEY,
29
29
  channel,
30
+ accountId: params.accountId,
30
31
  peerKind: peer?.kind ?? "dm",
31
32
  peerId: peer ? normalizeId(peer.id) || "unknown" : null,
32
33
  dmScope: params.dmScope,
@@ -98,6 +99,7 @@ export function resolveAgentRoute(input) {
98
99
  const sessionKey = buildAgentSessionKey({
99
100
  agentId: resolvedAgentId,
100
101
  channel,
102
+ accountId,
101
103
  peer,
102
104
  dmScope,
103
105
  identityLinks,
@@ -120,6 +122,16 @@ export function resolveAgentRoute(input) {
120
122
  if (peerMatch)
121
123
  return choose(peerMatch.agentId, "binding.peer");
122
124
  }
125
+ // Thread parent inheritance: if peer (thread) didn't match, check parent peer binding
126
+ const parentPeer = input.parentPeer
127
+ ? { kind: input.parentPeer.kind, id: normalizeId(input.parentPeer.id) }
128
+ : null;
129
+ if (parentPeer && parentPeer.id) {
130
+ const parentPeerMatch = bindings.find((b) => matchesPeer(b.match, parentPeer));
131
+ if (parentPeerMatch) {
132
+ return choose(parentPeerMatch.agentId, "binding.peer.parent");
133
+ }
134
+ }
123
135
  if (guildId) {
124
136
  const guildMatch = bindings.find((b) => matchesGuild(b.match, guildId));
125
137
  if (guildMatch)
@@ -38,6 +38,16 @@ export function resolveAgentIdFromSessionKey(sessionKey) {
38
38
  const parsed = parseAgentSessionKey(sessionKey);
39
39
  return normalizeAgentId(parsed?.agentId ?? DEFAULT_AGENT_ID);
40
40
  }
41
+ export function classifySessionKeyShape(sessionKey) {
42
+ const raw = (sessionKey ?? "").trim();
43
+ if (!raw) {
44
+ return "missing";
45
+ }
46
+ if (parseAgentSessionKey(raw)) {
47
+ return "agent";
48
+ }
49
+ return raw.toLowerCase().startsWith("agent:") ? "malformed_agent" : "legacy_or_alias";
50
+ }
41
51
  export function normalizeAgentId(value) {
42
52
  const trimmed = (value ?? "").trim();
43
53
  if (!trimmed)
@@ -99,6 +109,11 @@ export function buildAgentPeerSessionKey(params) {
99
109
  if (linkedPeerId)
100
110
  peerId = linkedPeerId;
101
111
  peerId = peerId.toLowerCase();
112
+ if (dmScope === "per-account-channel-peer" && peerId) {
113
+ const channel = (params.channel ?? "").trim().toLowerCase() || "unknown";
114
+ const accountId = normalizeAccountId(params.accountId);
115
+ return `agent:${normalizeAgentId(params.agentId)}:${channel}:${accountId}:dm:${peerId}`;
116
+ }
102
117
  if (dmScope === "per-channel-peer" && peerId) {
103
118
  const channel = (params.channel ?? "").trim().toLowerCase() || "unknown";
104
119
  return `agent:${normalizeAgentId(params.agentId)}:${channel}:dm:${peerId}`;
package/dist/runtime.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { clearActiveProgressLine } from "./terminal/progress-line.js";
2
+ import { restoreTerminalState } from "./terminal/restore.js";
2
3
  export const defaultRuntime = {
3
4
  log: (...args) => {
4
5
  clearActiveProgressLine();
@@ -9,6 +10,7 @@ export const defaultRuntime = {
9
10
  console.error(...args);
10
11
  },
11
12
  exit: (code) => {
13
+ restoreTerminalState("runtime exit");
12
14
  process.exit(code);
13
15
  throw new Error("unreachable"); // satisfies tests when mocked
14
16
  },