@intent-systems/nexus 2026.1.5-3

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 (827) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/LICENSE +21 -0
  3. package/README-header.png +0 -0
  4. package/README.md +462 -0
  5. package/dist/agents/agent-paths.js +16 -0
  6. package/dist/agents/agent-scope.js +44 -0
  7. package/dist/agents/auth-profiles.js +626 -0
  8. package/dist/agents/bash-process-registry.js +126 -0
  9. package/dist/agents/bash-tools.js +838 -0
  10. package/dist/agents/chutes-oauth.js +47 -0
  11. package/dist/agents/clawdbot-tools.js +62 -0
  12. package/dist/agents/context.js +34 -0
  13. package/dist/agents/defaults.js +6 -0
  14. package/dist/agents/memory-search.js +80 -0
  15. package/dist/agents/model-auth.js +115 -0
  16. package/dist/agents/model-catalog.js +55 -0
  17. package/dist/agents/model-fallback.js +210 -0
  18. package/dist/agents/model-scan.js +263 -0
  19. package/dist/agents/model-selection.js +152 -0
  20. package/dist/agents/models-config.js +171 -0
  21. package/dist/agents/nexus-tools.js +46 -0
  22. package/dist/agents/pi-embedded-block-chunker.js +188 -0
  23. package/dist/agents/pi-embedded-helpers.js +139 -0
  24. package/dist/agents/pi-embedded-runner.js +932 -0
  25. package/dist/agents/pi-embedded-subscribe.js +541 -0
  26. package/dist/agents/pi-embedded-utils.js +20 -0
  27. package/dist/agents/pi-embedded.js +1 -0
  28. package/dist/agents/pi-extensions/compaction-safeguard.js +140 -0
  29. package/dist/agents/pi-tool-definition-adapter.js +17 -0
  30. package/dist/agents/pi-tools.js +510 -0
  31. package/dist/agents/pi-tools.schema.js +358 -0
  32. package/dist/agents/sandbox-paths.js +68 -0
  33. package/dist/agents/sandbox.js +667 -0
  34. package/dist/agents/shell-utils.js +53 -0
  35. package/dist/agents/skill-runner.js +224 -0
  36. package/dist/agents/skill-state.js +164 -0
  37. package/dist/agents/skill-tools.js +191 -0
  38. package/dist/agents/skill-usage.js +43 -0
  39. package/dist/agents/skills-install.js +244 -0
  40. package/dist/agents/skills-status.js +157 -0
  41. package/dist/agents/skills.js +472 -0
  42. package/dist/agents/subagent-registry.js +321 -0
  43. package/dist/agents/subagent-registry.store.js +47 -0
  44. package/dist/agents/system-prompt.js +179 -0
  45. package/dist/agents/timeout.js +26 -0
  46. package/dist/agents/tool-display.js +155 -0
  47. package/dist/agents/tool-display.json +236 -0
  48. package/dist/agents/tool-images.js +138 -0
  49. package/dist/agents/tool-policy.js +87 -0
  50. package/dist/agents/tools/agent-step.js +41 -0
  51. package/dist/agents/tools/browser-tool.js +295 -0
  52. package/dist/agents/tools/canvas-tool.js +193 -0
  53. package/dist/agents/tools/common.js +88 -0
  54. package/dist/agents/tools/cron-tool.js +141 -0
  55. package/dist/agents/tools/discord-actions-guild.js +186 -0
  56. package/dist/agents/tools/discord-actions-messaging.js +313 -0
  57. package/dist/agents/tools/discord-actions-moderation.js +70 -0
  58. package/dist/agents/tools/discord-actions.js +56 -0
  59. package/dist/agents/tools/discord-schema.js +199 -0
  60. package/dist/agents/tools/discord-tool.js +16 -0
  61. package/dist/agents/tools/gateway-tool.js +46 -0
  62. package/dist/agents/tools/gateway.js +28 -0
  63. package/dist/agents/tools/image-tool.js +140 -0
  64. package/dist/agents/tools/memory-tool.js +92 -0
  65. package/dist/agents/tools/nodes-tool.js +413 -0
  66. package/dist/agents/tools/nodes-utils.js +92 -0
  67. package/dist/agents/tools/sessions-announce-target.js +35 -0
  68. package/dist/agents/tools/sessions-helpers.js +88 -0
  69. package/dist/agents/tools/sessions-history-tool.js +137 -0
  70. package/dist/agents/tools/sessions-list-tool.js +196 -0
  71. package/dist/agents/tools/sessions-send-helpers.js +103 -0
  72. package/dist/agents/tools/sessions-send-tool.js +371 -0
  73. package/dist/agents/tools/sessions-spawn-tool.js +319 -0
  74. package/dist/agents/tools/slack-actions.js +129 -0
  75. package/dist/agents/tools/slack-schema.js +59 -0
  76. package/dist/agents/tools/slack-tool.js +16 -0
  77. package/dist/agents/tools/telegram-actions.js +159 -0
  78. package/dist/agents/tools/telegram-schema.js +28 -0
  79. package/dist/agents/tools/telegram-tool.js +16 -0
  80. package/dist/agents/tools/whatsapp-login-tool.js +63 -0
  81. package/dist/agents/usage.js +58 -0
  82. package/dist/agents/workspace.js +264 -0
  83. package/dist/auto-reply/chunk.js +177 -0
  84. package/dist/auto-reply/command-auth.js +44 -0
  85. package/dist/auto-reply/command-detection.js +22 -0
  86. package/dist/auto-reply/envelope.js +30 -0
  87. package/dist/auto-reply/group-activation.js +20 -0
  88. package/dist/auto-reply/heartbeat.js +58 -0
  89. package/dist/auto-reply/model.js +22 -0
  90. package/dist/auto-reply/reply/abort.js +14 -0
  91. package/dist/auto-reply/reply/agent-runner.js +426 -0
  92. package/dist/auto-reply/reply/bash-command.js +314 -0
  93. package/dist/auto-reply/reply/block-streaming.js +34 -0
  94. package/dist/auto-reply/reply/body.js +29 -0
  95. package/dist/auto-reply/reply/commands.js +332 -0
  96. package/dist/auto-reply/reply/directive-handling.js +626 -0
  97. package/dist/auto-reply/reply/directives.js +59 -0
  98. package/dist/auto-reply/reply/dispatch-from-config.js +23 -0
  99. package/dist/auto-reply/reply/followup-runner.js +181 -0
  100. package/dist/auto-reply/reply/groups.js +152 -0
  101. package/dist/auto-reply/reply/mentions.js +64 -0
  102. package/dist/auto-reply/reply/model-selection.js +209 -0
  103. package/dist/auto-reply/reply/queue.js +399 -0
  104. package/dist/auto-reply/reply/reply-dispatcher.js +68 -0
  105. package/dist/auto-reply/reply/reply-tags.js +26 -0
  106. package/dist/auto-reply/reply/session-updates.js +103 -0
  107. package/dist/auto-reply/reply/session.js +169 -0
  108. package/dist/auto-reply/reply/typing.js +125 -0
  109. package/dist/auto-reply/reply.js +655 -0
  110. package/dist/auto-reply/send-policy.js +28 -0
  111. package/dist/auto-reply/status.js +197 -0
  112. package/dist/auto-reply/templating.js +9 -0
  113. package/dist/auto-reply/thinking.js +49 -0
  114. package/dist/auto-reply/tokens.js +2 -0
  115. package/dist/auto-reply/tool-meta.js +74 -0
  116. package/dist/auto-reply/transcription.js +57 -0
  117. package/dist/auto-reply/types.js +1 -0
  118. package/dist/browser/bridge-server.js +37 -0
  119. package/dist/browser/cdp.js +382 -0
  120. package/dist/browser/chrome.js +432 -0
  121. package/dist/browser/client-actions-core.js +67 -0
  122. package/dist/browser/client-actions-observe.js +24 -0
  123. package/dist/browser/client-actions-types.js +1 -0
  124. package/dist/browser/client-actions.js +3 -0
  125. package/dist/browser/client-fetch.js +43 -0
  126. package/dist/browser/client.js +105 -0
  127. package/dist/browser/config.js +155 -0
  128. package/dist/browser/constants.js +5 -0
  129. package/dist/browser/profiles-service.js +124 -0
  130. package/dist/browser/profiles.js +96 -0
  131. package/dist/browser/pw-ai.js +2 -0
  132. package/dist/browser/pw-session.js +144 -0
  133. package/dist/browser/pw-tools-core.js +363 -0
  134. package/dist/browser/routes/agent.js +535 -0
  135. package/dist/browser/routes/basic.js +155 -0
  136. package/dist/browser/routes/index.js +8 -0
  137. package/dist/browser/routes/tabs.js +105 -0
  138. package/dist/browser/routes/utils.js +62 -0
  139. package/dist/browser/screenshot.js +40 -0
  140. package/dist/browser/server-context.js +377 -0
  141. package/dist/browser/server.js +81 -0
  142. package/dist/browser/target-id.js +18 -0
  143. package/dist/browser/trash.js +21 -0
  144. package/dist/canvas-host/a2ui/a2ui.bundle.js +17768 -0
  145. package/dist/canvas-host/a2ui/index.html +246 -0
  146. package/dist/canvas-host/a2ui.js +187 -0
  147. package/dist/canvas-host/server.js +382 -0
  148. package/dist/channel-web.js +8 -0
  149. package/dist/cli/browser-cli-actions-input.js +459 -0
  150. package/dist/cli/browser-cli-actions-observe.js +56 -0
  151. package/dist/cli/browser-cli-examples.js +31 -0
  152. package/dist/cli/browser-cli-inspect.js +97 -0
  153. package/dist/cli/browser-cli-manage.js +286 -0
  154. package/dist/cli/browser-cli-shared.js +1 -0
  155. package/dist/cli/browser-cli.js +26 -0
  156. package/dist/cli/canvas-cli.js +416 -0
  157. package/dist/cli/cloud-cli.js +336 -0
  158. package/dist/cli/credential-cli.js +227 -0
  159. package/dist/cli/cron-cli.js +454 -0
  160. package/dist/cli/deps.js +17 -0
  161. package/dist/cli/dns-cli.js +180 -0
  162. package/dist/cli/gateway-cli.js +665 -0
  163. package/dist/cli/gateway-rpc.js +20 -0
  164. package/dist/cli/hooks-cli.js +135 -0
  165. package/dist/cli/memory-cli.js +101 -0
  166. package/dist/cli/models-cli.js +248 -0
  167. package/dist/cli/nodes-camera.js +57 -0
  168. package/dist/cli/nodes-canvas.js +26 -0
  169. package/dist/cli/nodes-cli.js +946 -0
  170. package/dist/cli/nodes-screen.js +37 -0
  171. package/dist/cli/pairing-cli.js +100 -0
  172. package/dist/cli/parse-duration.js +20 -0
  173. package/dist/cli/plugins-cli.js +158 -0
  174. package/dist/cli/ports.js +97 -0
  175. package/dist/cli/profile.js +81 -0
  176. package/dist/cli/program.js +162 -0
  177. package/dist/cli/prompt.js +19 -0
  178. package/dist/cli/run-main.js +48 -0
  179. package/dist/cli/skills-cli.js +132 -0
  180. package/dist/cli/skills-hub-cli.js +1093 -0
  181. package/dist/cli/telegram-cli.js +56 -0
  182. package/dist/cli/tool-connector-cli.js +118 -0
  183. package/dist/cli/tui-cli.js +35 -0
  184. package/dist/cli/upstream-sync-cli.js +2833 -0
  185. package/dist/cli/usage-cli.js +24 -0
  186. package/dist/cli/wait.js +8 -0
  187. package/dist/commands/agent-via-gateway.js +115 -0
  188. package/dist/commands/agent.js +665 -0
  189. package/dist/commands/antigravity-oauth.js +327 -0
  190. package/dist/commands/auth-choice-options.js +80 -0
  191. package/dist/commands/auth-choice.js +134 -0
  192. package/dist/commands/auth-token.js +31 -0
  193. package/dist/commands/bootstrap-preset.js +214 -0
  194. package/dist/commands/capabilities.js +36 -0
  195. package/dist/commands/chutes-oauth.js +144 -0
  196. package/dist/commands/claude-md.js +137 -0
  197. package/dist/commands/config-view.js +11 -0
  198. package/dist/commands/configure.js +648 -0
  199. package/dist/commands/credential.js +236 -0
  200. package/dist/commands/cursor-rules.js +230 -0
  201. package/dist/commands/doctor-state-migrations.js +358 -0
  202. package/dist/commands/doctor-ui.js +113 -0
  203. package/dist/commands/doctor.js +673 -0
  204. package/dist/commands/health.js +112 -0
  205. package/dist/commands/identity.js +54 -0
  206. package/dist/commands/init.js +167 -0
  207. package/dist/commands/models/aliases.js +85 -0
  208. package/dist/commands/models/fallbacks.js +123 -0
  209. package/dist/commands/models/image-fallbacks.js +123 -0
  210. package/dist/commands/models/list.js +347 -0
  211. package/dist/commands/models/scan.js +271 -0
  212. package/dist/commands/models/set-image.js +27 -0
  213. package/dist/commands/models/set.js +27 -0
  214. package/dist/commands/models/shared.js +73 -0
  215. package/dist/commands/models.js +7 -0
  216. package/dist/commands/onboard-auth.js +101 -0
  217. package/dist/commands/onboard-channels.js +814 -0
  218. package/dist/commands/onboard-eve-identity.js +98 -0
  219. package/dist/commands/onboard-github.js +153 -0
  220. package/dist/commands/onboard-helpers.js +303 -0
  221. package/dist/commands/onboard-interactive.js +17 -0
  222. package/dist/commands/onboard-non-interactive.js +228 -0
  223. package/dist/commands/onboard-providers.js +829 -0
  224. package/dist/commands/onboard-quickstart.js +185 -0
  225. package/dist/commands/onboard-remote.js +120 -0
  226. package/dist/commands/onboard-skills.js +148 -0
  227. package/dist/commands/onboard-types.js +1 -0
  228. package/dist/commands/onboard.js +19 -0
  229. package/dist/commands/openai-codex-model-default.js +38 -0
  230. package/dist/commands/poll.js +64 -0
  231. package/dist/commands/quest.js +27 -0
  232. package/dist/commands/reset.js +61 -0
  233. package/dist/commands/send.js +124 -0
  234. package/dist/commands/sessions-ingest.js +359 -0
  235. package/dist/commands/sessions.js +212 -0
  236. package/dist/commands/setup.js +59 -0
  237. package/dist/commands/signal-install.js +135 -0
  238. package/dist/commands/skills-manifest.js +235 -0
  239. package/dist/commands/status.js +139 -0
  240. package/dist/commands/suggestions.js +54 -0
  241. package/dist/commands/systemd-linger.js +71 -0
  242. package/dist/commands/update.js +16 -0
  243. package/dist/commands/usage-upload.js +27 -0
  244. package/dist/config/config.js +6 -0
  245. package/dist/config/defaults.js +140 -0
  246. package/dist/config/group-policy.js +49 -0
  247. package/dist/config/includes.js +183 -0
  248. package/dist/config/io.js +188 -0
  249. package/dist/config/legacy-migrate.js +13 -0
  250. package/dist/config/legacy.js +425 -0
  251. package/dist/config/paths.js +82 -0
  252. package/dist/config/port-defaults.js +32 -0
  253. package/dist/config/schema.js +173 -0
  254. package/dist/config/sessions.js +611 -0
  255. package/dist/config/talk.js +31 -0
  256. package/dist/config/types.js +1 -0
  257. package/dist/config/validation.js +29 -0
  258. package/dist/config/zod-schema.js +1110 -0
  259. package/dist/control-ui/assets/index-D8Q5AI4D.js +2393 -0
  260. package/dist/control-ui/assets/index-D8Q5AI4D.js.map +1 -0
  261. package/dist/control-ui/assets/index-g06q5Xc3.css +1 -0
  262. package/dist/control-ui/favicon.ico +0 -0
  263. package/dist/control-ui/index.html +16 -0
  264. package/dist/cron/isolated-agent.js +529 -0
  265. package/dist/cron/normalize.js +73 -0
  266. package/dist/cron/parse.js +24 -0
  267. package/dist/cron/run-log.js +72 -0
  268. package/dist/cron/schedule.js +24 -0
  269. package/dist/cron/service.js +471 -0
  270. package/dist/cron/store.js +43 -0
  271. package/dist/cron/types.js +1 -0
  272. package/dist/daemon/constants.js +10 -0
  273. package/dist/daemon/launchd.js +295 -0
  274. package/dist/daemon/legacy.js +63 -0
  275. package/dist/daemon/program-args.js +141 -0
  276. package/dist/daemon/schtasks.js +269 -0
  277. package/dist/daemon/service.js +69 -0
  278. package/dist/daemon/systemd.js +332 -0
  279. package/dist/discord/index.js +2 -0
  280. package/dist/discord/monitor.js +1089 -0
  281. package/dist/discord/probe.js +54 -0
  282. package/dist/discord/send.js +652 -0
  283. package/dist/discord/token.js +8 -0
  284. package/dist/entry.js +16 -0
  285. package/dist/gateway/auth.js +121 -0
  286. package/dist/gateway/call.js +103 -0
  287. package/dist/gateway/chat-attachments.js +41 -0
  288. package/dist/gateway/client.js +180 -0
  289. package/dist/gateway/config-reload.js +274 -0
  290. package/dist/gateway/control-ui.js +184 -0
  291. package/dist/gateway/hooks-mapping.js +282 -0
  292. package/dist/gateway/hooks.js +168 -0
  293. package/dist/gateway/net.js +29 -0
  294. package/dist/gateway/protocol/index.js +62 -0
  295. package/dist/gateway/protocol/schema.js +577 -0
  296. package/dist/gateway/server-bridge-subscriptions.js +93 -0
  297. package/dist/gateway/server-bridge.js +1066 -0
  298. package/dist/gateway/server-browser.js +11 -0
  299. package/dist/gateway/server-channels.js +680 -0
  300. package/dist/gateway/server-chat.js +159 -0
  301. package/dist/gateway/server-constants.js +8 -0
  302. package/dist/gateway/server-discovery.js +62 -0
  303. package/dist/gateway/server-http.js +165 -0
  304. package/dist/gateway/server-methods/agent-job.js +114 -0
  305. package/dist/gateway/server-methods/agent.js +254 -0
  306. package/dist/gateway/server-methods/channels.js +239 -0
  307. package/dist/gateway/server-methods/chat.js +207 -0
  308. package/dist/gateway/server-methods/config.js +50 -0
  309. package/dist/gateway/server-methods/connect.js +6 -0
  310. package/dist/gateway/server-methods/cron.js +89 -0
  311. package/dist/gateway/server-methods/health.js +28 -0
  312. package/dist/gateway/server-methods/models.js +16 -0
  313. package/dist/gateway/server-methods/nodes.js +294 -0
  314. package/dist/gateway/server-methods/providers.js +257 -0
  315. package/dist/gateway/server-methods/send.js +254 -0
  316. package/dist/gateway/server-methods/sessions.js +382 -0
  317. package/dist/gateway/server-methods/skills.js +83 -0
  318. package/dist/gateway/server-methods/system.js +118 -0
  319. package/dist/gateway/server-methods/talk.js +22 -0
  320. package/dist/gateway/server-methods/types.js +1 -0
  321. package/dist/gateway/server-methods/voicewake.js +30 -0
  322. package/dist/gateway/server-methods/web.js +81 -0
  323. package/dist/gateway/server-methods/wizard.js +100 -0
  324. package/dist/gateway/server-methods.js +53 -0
  325. package/dist/gateway/server-providers.js +687 -0
  326. package/dist/gateway/server-shared.js +1 -0
  327. package/dist/gateway/server-utils.js +35 -0
  328. package/dist/gateway/server.js +1478 -0
  329. package/dist/gateway/session-utils.js +355 -0
  330. package/dist/gateway/ws-log.js +343 -0
  331. package/dist/gateway/ws-logging.js +8 -0
  332. package/dist/globals.js +41 -0
  333. package/dist/hooks/gmail-ops.js +236 -0
  334. package/dist/hooks/gmail-setup-utils.js +278 -0
  335. package/dist/hooks/gmail-watcher.js +190 -0
  336. package/dist/hooks/gmail.js +177 -0
  337. package/dist/imessage/client.js +165 -0
  338. package/dist/imessage/index.js +3 -0
  339. package/dist/imessage/monitor.js +365 -0
  340. package/dist/imessage/probe.js +26 -0
  341. package/dist/imessage/send.js +83 -0
  342. package/dist/imessage/targets.js +176 -0
  343. package/dist/index.js +55 -0
  344. package/dist/infra/agent-events.js +46 -0
  345. package/dist/infra/binaries.js +9 -0
  346. package/dist/infra/bonjour-discovery.js +163 -0
  347. package/dist/infra/bonjour.js +200 -0
  348. package/dist/infra/bridge/server.js +564 -0
  349. package/dist/infra/canvas-host-url.js +54 -0
  350. package/dist/infra/channel-summary.js +78 -0
  351. package/dist/infra/control-ui-assets.js +112 -0
  352. package/dist/infra/dotenv.js +15 -0
  353. package/dist/infra/env.js +8 -0
  354. package/dist/infra/errors.js +28 -0
  355. package/dist/infra/event-log.js +251 -0
  356. package/dist/infra/gateway-lock.js +8 -0
  357. package/dist/infra/git-commit.js +91 -0
  358. package/dist/infra/heartbeat-events.js +21 -0
  359. package/dist/infra/heartbeat-runner.js +458 -0
  360. package/dist/infra/heartbeat-wake.js +61 -0
  361. package/dist/infra/is-main.js +37 -0
  362. package/dist/infra/json-file.js +21 -0
  363. package/dist/infra/machine-name.js +40 -0
  364. package/dist/infra/nexus-root.js +56 -0
  365. package/dist/infra/node-pairing.js +212 -0
  366. package/dist/infra/path-env.js +93 -0
  367. package/dist/infra/ports.js +87 -0
  368. package/dist/infra/provider-summary.js +80 -0
  369. package/dist/infra/provider-usage.auth.js +189 -0
  370. package/dist/infra/provider-usage.fetch.claude.js +129 -0
  371. package/dist/infra/provider-usage.fetch.codex.js +62 -0
  372. package/dist/infra/provider-usage.fetch.copilot.js +42 -0
  373. package/dist/infra/provider-usage.fetch.gemini.js +57 -0
  374. package/dist/infra/provider-usage.fetch.js +6 -0
  375. package/dist/infra/provider-usage.fetch.minimax.js +214 -0
  376. package/dist/infra/provider-usage.fetch.shared.js +11 -0
  377. package/dist/infra/provider-usage.fetch.zai.js +62 -0
  378. package/dist/infra/provider-usage.format.js +77 -0
  379. package/dist/infra/provider-usage.js +145 -0
  380. package/dist/infra/provider-usage.load.js +54 -0
  381. package/dist/infra/provider-usage.shared.js +19 -0
  382. package/dist/infra/provider-usage.types.js +1 -0
  383. package/dist/infra/restart.js +29 -0
  384. package/dist/infra/retry.js +16 -0
  385. package/dist/infra/runtime-guard.js +59 -0
  386. package/dist/infra/shell-env.js +88 -0
  387. package/dist/infra/system-events.js +71 -0
  388. package/dist/infra/system-presence.js +217 -0
  389. package/dist/infra/tailnet.js +46 -0
  390. package/dist/infra/tailscale.js +149 -0
  391. package/dist/infra/unhandled-rejections.js +19 -0
  392. package/dist/infra/usage-suggestions.js +241 -0
  393. package/dist/infra/usage-upload.js +290 -0
  394. package/dist/infra/voicewake.js +78 -0
  395. package/dist/infra/widearea-dns.js +123 -0
  396. package/dist/infra/ws.js +13 -0
  397. package/dist/logger.js +52 -0
  398. package/dist/logging.js +506 -0
  399. package/dist/macos/gateway-daemon.js +145 -0
  400. package/dist/macos/relay.js +49 -0
  401. package/dist/media/constants.js +33 -0
  402. package/dist/media/host.js +42 -0
  403. package/dist/media/image-ops.js +119 -0
  404. package/dist/media/mime.js +123 -0
  405. package/dist/media/parse.js +83 -0
  406. package/dist/media/server.js +64 -0
  407. package/dist/media/store.js +139 -0
  408. package/dist/polls.js +43 -0
  409. package/dist/process/command-queue.js +97 -0
  410. package/dist/process/exec.js +75 -0
  411. package/dist/provider-web.js +8 -0
  412. package/dist/providers/github-copilot-auth.js +123 -0
  413. package/dist/providers/github-copilot-models.js +35 -0
  414. package/dist/providers/github-copilot-token.js +11 -0
  415. package/dist/providers/location.js +48 -0
  416. package/dist/providers/web/index.js +2 -0
  417. package/dist/runtime.js +8 -0
  418. package/dist/sessions/level-overrides.js +9 -0
  419. package/dist/sessions/send-policy.js +68 -0
  420. package/dist/signal/client.js +134 -0
  421. package/dist/signal/daemon.js +69 -0
  422. package/dist/signal/index.js +3 -0
  423. package/dist/signal/monitor.js +411 -0
  424. package/dist/signal/probe.js +46 -0
  425. package/dist/signal/send.js +91 -0
  426. package/dist/slack/actions.js +97 -0
  427. package/dist/slack/index.js +5 -0
  428. package/dist/slack/monitor.js +1270 -0
  429. package/dist/slack/probe.js +47 -0
  430. package/dist/slack/send.js +131 -0
  431. package/dist/slack/token.js +10 -0
  432. package/dist/telegram/allowed-updates.js +8 -0
  433. package/dist/telegram/bot.js +724 -0
  434. package/dist/telegram/download.js +34 -0
  435. package/dist/telegram/index.js +4 -0
  436. package/dist/telegram/monitor.js +47 -0
  437. package/dist/telegram/pairing-store.js +77 -0
  438. package/dist/telegram/probe.js +63 -0
  439. package/dist/telegram/proxy.js +9 -0
  440. package/dist/telegram/reaction-level.js +45 -0
  441. package/dist/telegram/send.js +151 -0
  442. package/dist/telegram/sent-message-cache.js +65 -0
  443. package/dist/telegram/token.js +30 -0
  444. package/dist/telegram/update-offset-store.js +61 -0
  445. package/dist/telegram/webhook-set.js +12 -0
  446. package/dist/telegram/webhook.js +56 -0
  447. package/dist/tui/commands.js +87 -0
  448. package/dist/tui/components/assistant-message.js +16 -0
  449. package/dist/tui/components/chat-log.js +92 -0
  450. package/dist/tui/components/custom-editor.js +55 -0
  451. package/dist/tui/components/selectors.js +8 -0
  452. package/dist/tui/components/tool-execution.js +111 -0
  453. package/dist/tui/components/user-message.js +17 -0
  454. package/dist/tui/gateway-chat.js +140 -0
  455. package/dist/tui/theme/theme.js +80 -0
  456. package/dist/tui/tui.js +708 -0
  457. package/dist/utils.js +153 -0
  458. package/dist/version.js +18 -0
  459. package/dist/web/accounts.js +86 -0
  460. package/dist/web/active-listener.js +25 -0
  461. package/dist/web/auto-reply.js +1256 -0
  462. package/dist/web/inbound.js +649 -0
  463. package/dist/web/login-qr.js +230 -0
  464. package/dist/web/login.js +71 -0
  465. package/dist/web/media.js +175 -0
  466. package/dist/web/outbound.js +102 -0
  467. package/dist/web/qr-image.js +97 -0
  468. package/dist/web/reconnect.js +60 -0
  469. package/dist/web/session.js +370 -0
  470. package/dist/wizard/clack-prompter.js +56 -0
  471. package/dist/wizard/onboarding.js +620 -0
  472. package/dist/wizard/prompts.js +6 -0
  473. package/dist/wizard/session.js +203 -0
  474. package/docs/AGENTS.default.md +116 -0
  475. package/docs/CAPABILITIES.md +444 -0
  476. package/docs/CNAME +1 -0
  477. package/docs/NEXUS_CORE_REWRITE_SPEC.md +226 -0
  478. package/docs/RELEASING.md +69 -0
  479. package/docs/_config.yml +53 -0
  480. package/docs/_layouts/default.html +145 -0
  481. package/docs/agent-assisted-install.md +95 -0
  482. package/docs/agent-loop.md +61 -0
  483. package/docs/agent-send.md +21 -0
  484. package/docs/agent.md +108 -0
  485. package/docs/android.md +133 -0
  486. package/docs/architecture.md +114 -0
  487. package/docs/assets/markdown.css +133 -0
  488. package/docs/assets/pixel-lobster.svg +60 -0
  489. package/docs/assets/terminal.css +470 -0
  490. package/docs/assets/theme.js +55 -0
  491. package/docs/audio.md +48 -0
  492. package/docs/automation/nexus-sync.md +371 -0
  493. package/docs/background-process.md +74 -0
  494. package/docs/bash.md +32 -0
  495. package/docs/bedrock.md +71 -0
  496. package/docs/bonjour.md +159 -0
  497. package/docs/browser-linux-troubleshooting.md +114 -0
  498. package/docs/browser.md +293 -0
  499. package/docs/bun.md +56 -0
  500. package/docs/camera.md +152 -0
  501. package/docs/clawd.md +212 -0
  502. package/docs/concepts/usage-tracking.md +29 -0
  503. package/docs/configuration.md +1666 -0
  504. package/docs/control-ui.md +83 -0
  505. package/docs/cron.md +385 -0
  506. package/docs/dashboard.md +17 -0
  507. package/docs/device-models.md +46 -0
  508. package/docs/discord.md +308 -0
  509. package/docs/discovery.md +112 -0
  510. package/docs/docker.md +258 -0
  511. package/docs/docs.json +105 -0
  512. package/docs/doctor.md +68 -0
  513. package/docs/elevated.md +31 -0
  514. package/docs/faq.md +736 -0
  515. package/docs/feature-inventory/overview.md +141 -0
  516. package/docs/feature-inventory/rollout-checklist.md +53 -0
  517. package/docs/feature-inventory/test-matrix.md +87 -0
  518. package/docs/feature-inventory.md +9 -0
  519. package/docs/gateway/configuration-examples.md +221 -0
  520. package/docs/gateway/configuration.md +172 -0
  521. package/docs/gateway/cron.md +61 -0
  522. package/docs/gateway/heartbeat.md +207 -0
  523. package/docs/gateway/pairing.md +109 -0
  524. package/docs/gateway-lock.md +28 -0
  525. package/docs/gateway.md +227 -0
  526. package/docs/gmail-pubsub.md +191 -0
  527. package/docs/grammy.md +27 -0
  528. package/docs/group-messages.md +73 -0
  529. package/docs/groups.md +130 -0
  530. package/docs/health.md +28 -0
  531. package/docs/heartbeat.md +73 -0
  532. package/docs/home-userspace.md +277 -0
  533. package/docs/hubs.md +148 -0
  534. package/docs/images.md +51 -0
  535. package/docs/imessage.md +94 -0
  536. package/docs/index.md +196 -0
  537. package/docs/ios.md +372 -0
  538. package/docs/linux.md +11 -0
  539. package/docs/location-command.md +95 -0
  540. package/docs/location.md +46 -0
  541. package/docs/logging.md +110 -0
  542. package/docs/lore.md +131 -0
  543. package/docs/mac/bun.md +133 -0
  544. package/docs/mac/canvas.md +161 -0
  545. package/docs/mac/child-process.md +72 -0
  546. package/docs/mac/dev-setup.md +81 -0
  547. package/docs/mac/health.md +28 -0
  548. package/docs/mac/icon.md +26 -0
  549. package/docs/mac/logging.md +51 -0
  550. package/docs/mac/menu-bar.md +69 -0
  551. package/docs/mac/peekaboo.md +170 -0
  552. package/docs/mac/permissions.md +40 -0
  553. package/docs/mac/release.md +76 -0
  554. package/docs/mac/remote.md +57 -0
  555. package/docs/mac/signing.md +41 -0
  556. package/docs/mac/skills.md +27 -0
  557. package/docs/mac/voice-overlay.md +52 -0
  558. package/docs/mac/voicewake.md +56 -0
  559. package/docs/mac/webchat.md +27 -0
  560. package/docs/mac/xpc.md +40 -0
  561. package/docs/macos.md +104 -0
  562. package/docs/model-failover.md +75 -0
  563. package/docs/models.md +91 -0
  564. package/docs/multi-agent.md +74 -0
  565. package/docs/nix.md +95 -0
  566. package/docs/nodes.md +157 -0
  567. package/docs/onboarding-config-protocol.md +34 -0
  568. package/docs/onboarding.md +189 -0
  569. package/docs/pairing.md +85 -0
  570. package/docs/plans/cron-add-hardening.md +72 -0
  571. package/docs/plans/group-policy-hardening.md +121 -0
  572. package/docs/poll.md +52 -0
  573. package/docs/prereqs.md +67 -0
  574. package/docs/presence.md +133 -0
  575. package/docs/proposals/model-config.md +147 -0
  576. package/docs/provider-routing.md +25 -0
  577. package/docs/queue.md +78 -0
  578. package/docs/reference/templates/AGENTS.md +164 -0
  579. package/docs/remote-gateway-readme.md +153 -0
  580. package/docs/remote.md +61 -0
  581. package/docs/research/memory.md +227 -0
  582. package/docs/rpc.md +35 -0
  583. package/docs/security.md +200 -0
  584. package/docs/session-ingestion.md +119 -0
  585. package/docs/session-tool.md +154 -0
  586. package/docs/session.md +85 -0
  587. package/docs/sessions.md +8 -0
  588. package/docs/setup.md +131 -0
  589. package/docs/showcase.md +37 -0
  590. package/docs/signal.md +122 -0
  591. package/docs/skills-config.md +58 -0
  592. package/docs/skills.md +153 -0
  593. package/docs/slack.md +221 -0
  594. package/docs/subagents.md +72 -0
  595. package/docs/tailscale.md +71 -0
  596. package/docs/talk.md +79 -0
  597. package/docs/telegram.md +96 -0
  598. package/docs/templates/AGENTS.md +286 -0
  599. package/docs/templates/BOOTSTRAP.md +35 -0
  600. package/docs/templates/IDENTITY.md +17 -0
  601. package/docs/templates/PROFILE.md +14 -0
  602. package/docs/templates/SOUL.md +41 -0
  603. package/docs/templates/TOOLS.md +41 -0
  604. package/docs/templates/USER.md +8 -0
  605. package/docs/test.md +43 -0
  606. package/docs/testing-onboarding-quickstart.md +76 -0
  607. package/docs/testing-philosophy.md +211 -0
  608. package/docs/thinking.md +46 -0
  609. package/docs/timezone.md +40 -0
  610. package/docs/tools.md +346 -0
  611. package/docs/troubleshooting.md +257 -0
  612. package/docs/tui.md +71 -0
  613. package/docs/typebox.md +42 -0
  614. package/docs/updating.md +138 -0
  615. package/docs/usage-cloud-aggregation-spec.md +133 -0
  616. package/docs/usage-suggestions-pipeline.md +126 -0
  617. package/docs/voicewake.md +61 -0
  618. package/docs/web.md +115 -0
  619. package/docs/webchat.md +34 -0
  620. package/docs/webhook.md +132 -0
  621. package/docs/whatsapp-clawd.jpg +0 -0
  622. package/docs/whatsapp.md +170 -0
  623. package/docs/windows.md +11 -0
  624. package/docs/wizard.md +167 -0
  625. package/package.json +209 -0
  626. package/skills/1password/SKILL.md +54 -0
  627. package/skills/1password/docs/setup.md +85 -0
  628. package/skills/1password/docs/troubleshooting.md +63 -0
  629. package/skills/1password/references/cli-examples.md +29 -0
  630. package/skills/1password/references/get-started.md +17 -0
  631. package/skills/agent-browser/SKILL.md +450 -0
  632. package/skills/agent-browser/docs/browser-use-eval.md +95 -0
  633. package/skills/agent-browser/docs/first-tests.md +261 -0
  634. package/skills/agent-browser/docs/wordle-nyt-eval.js +32 -0
  635. package/skills/aix/SKILL.md +93 -0
  636. package/skills/aix/docs/embeddings.md +40 -0
  637. package/skills/aix/docs/setup.md +58 -0
  638. package/skills/aix/docs/troubleshooting.md +41 -0
  639. package/skills/aix/references/sql.md +48 -0
  640. package/skills/apple-notes/SKILL.md +50 -0
  641. package/skills/apple-reminders/SKILL.md +67 -0
  642. package/skills/bear-notes/SKILL.md +79 -0
  643. package/skills/bird/SKILL.md +32 -0
  644. package/skills/bird/docs/auth.md +31 -0
  645. package/skills/bird/docs/troubleshooting.md +31 -0
  646. package/skills/blogwatcher/SKILL.md +46 -0
  647. package/skills/blucli/SKILL.md +27 -0
  648. package/skills/brave-search/SKILL.md +36 -0
  649. package/skills/brave-search/docs/setup.md +40 -0
  650. package/skills/brave-search/docs/troubleshooting.md +37 -0
  651. package/skills/brave-search/docs/usage.md +28 -0
  652. package/skills/brave-search/scripts/content.mjs +53 -0
  653. package/skills/brave-search/scripts/search.mjs +79 -0
  654. package/skills/browser-use-agent-sdk/SKILL.md +90 -0
  655. package/skills/camsnap/SKILL.md +25 -0
  656. package/skills/clawdhub/SKILL.md +53 -0
  657. package/skills/coding-agent/SKILL.md +274 -0
  658. package/skills/comms/SKILL.md +249 -0
  659. package/skills/comms/docs/adapters.md +54 -0
  660. package/skills/comms/docs/setup.md +56 -0
  661. package/skills/comms/docs/troubleshooting.md +44 -0
  662. package/skills/comms/references/schema.md +49 -0
  663. package/skills/computer-use/SKILL.md +204 -0
  664. package/skills/computer-use/docs/open-interpreter.md +26 -0
  665. package/skills/computer-use/docs/peekaboo.md +26 -0
  666. package/skills/computer-use/docs/setup.md +47 -0
  667. package/skills/computer-use/docs/troubleshooting.md +33 -0
  668. package/skills/discord/SKILL.md +370 -0
  669. package/skills/eightctl/SKILL.md +29 -0
  670. package/skills/eve/SKILL.md +215 -0
  671. package/skills/eve/docs/dual-account.md +84 -0
  672. package/skills/eve/docs/intelligence.md +58 -0
  673. package/skills/eve/docs/setup.md +60 -0
  674. package/skills/eve/docs/troubleshooting.md +54 -0
  675. package/skills/eve/scripts/setup-dual-account.sh +125 -0
  676. package/skills/filesystem/SKILL.md +217 -0
  677. package/skills/food-order/SKILL.md +41 -0
  678. package/skills/gemini/SKILL.md +23 -0
  679. package/skills/gh/SKILL.md +22 -0
  680. package/skills/gh/docs/usage.md +41 -0
  681. package/skills/gifgrep/SKILL.md +47 -0
  682. package/skills/github/SKILL.md +26 -0
  683. package/skills/github/docs/setup.md +21 -0
  684. package/skills/github/docs/troubleshooting.md +24 -0
  685. package/skills/gog/SKILL.md +104 -0
  686. package/skills/gog/docs/portability.md +94 -0
  687. package/skills/gog/docs/setup.md +76 -0
  688. package/skills/gog/docs/troubleshooting.md +94 -0
  689. package/skills/gog/scripts/cdp/README.md +90 -0
  690. package/skills/gog/scripts/cdp/add_test_users.py +69 -0
  691. package/skills/gog/scripts/cdp/auth_add_accounts.py +209 -0
  692. package/skills/gog/scripts/cdp/auth_add_accounts_manual.py +206 -0
  693. package/skills/gog/scripts/cdp/create_oauth_client.py +165 -0
  694. package/skills/gog/scripts/cdp/launch_cdp_chrome.sh +58 -0
  695. package/skills/google-oauth/SKILL.md +94 -0
  696. package/skills/goplaces/SKILL.md +30 -0
  697. package/skills/imsg/SKILL.md +25 -0
  698. package/skills/json-render/SKILL.md +154 -0
  699. package/skills/json-render/assets/components/README.md +21 -0
  700. package/skills/json-render/assets/components/catalog.ts +78 -0
  701. package/skills/json-render/assets/components/registry.tsx +172 -0
  702. package/skills/json-render/assets/demo/App.css +397 -0
  703. package/skills/json-render/assets/demo/App.tsx +897 -0
  704. package/skills/json-render/assets/demo/README.md +22 -0
  705. package/skills/json-render/assets/demo/catalog.ts +78 -0
  706. package/skills/json-render/assets/demo/data/nexus-core.json +31 -0
  707. package/skills/json-render/assets/demo/index.css +27 -0
  708. package/skills/json-render/assets/demo/registry.tsx +150 -0
  709. package/skills/json-render/docs/nexus-state-demo.md +84 -0
  710. package/skills/json-render/docs/shadcn-preset.md +33 -0
  711. package/skills/json-render/scripts/create-vite-demo.sh +45 -0
  712. package/skills/json-render/scripts/llm-server/README.md +33 -0
  713. package/skills/json-render/scripts/llm-server/catalog.ts +78 -0
  714. package/skills/json-render/scripts/llm-server/package-lock.json +702 -0
  715. package/skills/json-render/scripts/llm-server/package.json +18 -0
  716. package/skills/json-render/scripts/llm-server/server.ts +285 -0
  717. package/skills/local-places/SERVER_README.md +101 -0
  718. package/skills/local-places/SKILL.md +91 -0
  719. package/skills/local-places/pyproject.toml +27 -0
  720. package/skills/local-places/src/local_places/__init__.py +2 -0
  721. package/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  722. package/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  723. package/skills/local-places/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  724. package/skills/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  725. package/skills/local-places/src/local_places/google_places.py +314 -0
  726. package/skills/local-places/src/local_places/main.py +65 -0
  727. package/skills/local-places/src/local_places/schemas.py +107 -0
  728. package/skills/mcporter/SKILL.md +38 -0
  729. package/skills/model-usage/SKILL.md +45 -0
  730. package/skills/model-usage/references/codexbar-cli.md +28 -0
  731. package/skills/model-usage/scripts/model_usage.py +310 -0
  732. package/skills/nano-banana-pro/SKILL.md +30 -0
  733. package/skills/nano-banana-pro/scripts/generate_image.py +169 -0
  734. package/skills/nano-pdf/SKILL.md +20 -0
  735. package/skills/nexus-cloud/SKILL.md +53 -0
  736. package/skills/nexus-cloud/docs/security.md +24 -0
  737. package/skills/nexus-cloud/docs/setup.md +51 -0
  738. package/skills/nexus-cloud/docs/troubleshooting.md +28 -0
  739. package/skills/notion/SKILL.md +156 -0
  740. package/skills/obsidian/SKILL.md +55 -0
  741. package/skills/onboarding/SKILL.md +515 -0
  742. package/skills/onboarding/docs/CAPABILITIES.md +444 -0
  743. package/skills/onboarding/docs/CAPABILITY_TAXONOMY.md +608 -0
  744. package/skills/onboarding/docs/CLI_GRAMMAR.md +797 -0
  745. package/skills/onboarding/docs/CLI_GRAMMAR_CREDENTIALS.md +632 -0
  746. package/skills/onboarding/docs/CLI_GRAMMAR_ONBOARDING.md +815 -0
  747. package/skills/onboarding/docs/CLI_GRAMMAR_SKILLS.md +449 -0
  748. package/skills/onboarding/docs/DOCUMENTATION_OVERVIEW.md +290 -0
  749. package/skills/onboarding/docs/ENTITY_MODEL.md +582 -0
  750. package/skills/onboarding/docs/GOAL_STATE_ARCHITECTURE.md +395 -0
  751. package/skills/onboarding/docs/NEXUS_SYSTEM_OVERVIEW.md +476 -0
  752. package/skills/onboarding/docs/SKILLS_HUB_SPEC.md +477 -0
  753. package/skills/onboarding/docs/SKILLS_SPECIFICATION.md +947 -0
  754. package/skills/onboarding/docs/SKILL_GATEWAY_DESIGN.md +702 -0
  755. package/skills/onboarding/docs/SKILL_GATEWAY_PRD.md +278 -0
  756. package/skills/onboarding/docs/SKILL_INVENTORY.md +266 -0
  757. package/skills/onboarding/docs/STATE_ARCHITECTURE.md +547 -0
  758. package/skills/onboarding/docs/TROUBLESHOOTING.md +363 -0
  759. package/skills/onboarding/docs/USER_JOURNEY.md +797 -0
  760. package/skills/onboarding/docs/WOW_MOMENTS.md +232 -0
  761. package/skills/onboarding/docs/agent-apple-id.md +289 -0
  762. package/skills/onboarding/docs/skill-deep-dives/1password.md +367 -0
  763. package/skills/onboarding/docs/skill-deep-dives/TEMPLATE.md +197 -0
  764. package/skills/onboarding/docs/skill-deep-dives/aix.md +498 -0
  765. package/skills/onboarding/docs/skill-deep-dives/bird.md +357 -0
  766. package/skills/onboarding/docs/skill-deep-dives/brave-search.md +601 -0
  767. package/skills/onboarding/docs/skill-deep-dives/comms.md +607 -0
  768. package/skills/onboarding/docs/skill-deep-dives/computer-use.md +599 -0
  769. package/skills/onboarding/docs/skill-deep-dives/cron-and-heartbeat.md +576 -0
  770. package/skills/onboarding/docs/skill-deep-dives/eve.md +711 -0
  771. package/skills/onboarding/docs/skill-deep-dives/github.md +333 -0
  772. package/skills/onboarding/docs/skill-deep-dives/gog.md +640 -0
  773. package/skills/onboarding/docs/skill-deep-dives/homebrew-prereqs.md +785 -0
  774. package/skills/onboarding/docs/skill-deep-dives/nexus-cloud.md +689 -0
  775. package/skills/onboarding/docs/skill-deep-dives/qmd.md +742 -0
  776. package/skills/onboarding/docs/skill-deep-dives/telegram.md +379 -0
  777. package/skills/onboarding/docs/skill-deep-dives/wacli.md +399 -0
  778. package/skills/onboarding/docs/skill-deep-dives/weather.md +513 -0
  779. package/skills/onboarding/scripts/ralph/prd.json +215 -0
  780. package/skills/onboarding/scripts/ralph/progress.txt +99 -0
  781. package/skills/onboarding/scripts/ralph/prompt.md +87 -0
  782. package/skills/onboarding/scripts/ralph/ralph.log +84 -0
  783. package/skills/onboarding/scripts/ralph/ralph.sh +45 -0
  784. package/skills/onboarding/scripts/setup-cursor-skills.sh +40 -0
  785. package/skills/openai-image-gen/SKILL.md +31 -0
  786. package/skills/openai-image-gen/scripts/gen.py +173 -0
  787. package/skills/openai-whisper/SKILL.md +19 -0
  788. package/skills/openai-whisper-api/SKILL.md +43 -0
  789. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  790. package/skills/openhue/SKILL.md +30 -0
  791. package/skills/oracle/SKILL.md +105 -0
  792. package/skills/ordercli/SKILL.md +47 -0
  793. package/skills/peekaboo/SKILL.md +153 -0
  794. package/skills/qmd/SKILL.md +32 -0
  795. package/skills/qmd/docs/mcp.md +30 -0
  796. package/skills/qmd/docs/ollama.md +42 -0
  797. package/skills/qmd/docs/setup.md +44 -0
  798. package/skills/sag/SKILL.md +62 -0
  799. package/skills/skill-cli-template/SKILL.md +109 -0
  800. package/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-311.pyc +0 -0
  801. package/skills/slack/SKILL.md +144 -0
  802. package/skills/songsee/SKILL.md +29 -0
  803. package/skills/sonoscli/SKILL.md +26 -0
  804. package/skills/spotify-player/SKILL.md +34 -0
  805. package/skills/summarize/SKILL.md +49 -0
  806. package/skills/telegram/SKILL.md +20 -0
  807. package/skills/telegram/docs/pairing.md +30 -0
  808. package/skills/telegram/docs/setup.md +41 -0
  809. package/skills/telegram/docs/webhook.md +17 -0
  810. package/skills/things-mac/SKILL.md +61 -0
  811. package/skills/tmux/SKILL.md +121 -0
  812. package/skills/tmux/scripts/find-sessions.sh +112 -0
  813. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  814. package/skills/trello/SKILL.md +84 -0
  815. package/skills/upstream-sync/SKILL.md +151 -0
  816. package/skills/upstream-sync/scripts/auto-port.sh +227 -0
  817. package/skills/upstream-sync/scripts/check-all.sh +88 -0
  818. package/skills/upstream-sync/scripts/check-nexus.sh +146 -0
  819. package/skills/upstream-sync/scripts/check-pi-ai.sh +129 -0
  820. package/skills/video-frames/SKILL.md +29 -0
  821. package/skills/video-frames/scripts/frame.sh +81 -0
  822. package/skills/wacli/SKILL.md +48 -0
  823. package/skills/wacli/docs/auth.md +21 -0
  824. package/skills/wacli/docs/backup.md +9 -0
  825. package/skills/wacli/docs/troubleshooting.md +21 -0
  826. package/skills/weather/SKILL.md +53 -0
  827. package/skills/weather/docs/usage.md +40 -0
@@ -0,0 +1,1270 @@
1
+ import { App, } from "@slack/bolt";
2
+ import { chunkMarkdownText, resolveTextChunkLimit, } from "../auto-reply/chunk.js";
3
+ import { hasControlCommand } from "../auto-reply/command-detection.js";
4
+ import { formatAgentEnvelope } from "../auto-reply/envelope.js";
5
+ import { dispatchReplyFromConfig } from "../auto-reply/reply/dispatch-from-config.js";
6
+ import { buildMentionRegexes, matchesMentionPatterns, } from "../auto-reply/reply/mentions.js";
7
+ import { createReplyDispatcher } from "../auto-reply/reply/reply-dispatcher.js";
8
+ import { getReplyFromConfig } from "../auto-reply/reply.js";
9
+ import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
10
+ import { loadConfig } from "../config/config.js";
11
+ import { resolveSessionKey, resolveStorePath, updateLastRoute, } from "../config/sessions.js";
12
+ import { danger, logVerbose, shouldLogVerbose } from "../globals.js";
13
+ import { enqueueSystemEvent } from "../infra/system-events.js";
14
+ import { getChildLogger } from "../logging.js";
15
+ import { detectMime } from "../media/mime.js";
16
+ import { saveMediaBuffer } from "../media/store.js";
17
+ import { readProviderAllowFromStore, upsertProviderPairingRequest, } from "../pairing/pairing-store.js";
18
+ import { resolveAgentRoute } from "../routing/resolve-route.js";
19
+ import { reactSlackMessage } from "./actions.js";
20
+ import { sendMessageSlack } from "./send.js";
21
+ import { resolveSlackAppToken, resolveSlackBotToken } from "./token.js";
22
+ function normalizeSlackSlug(raw) {
23
+ const trimmed = raw?.trim().toLowerCase() ?? "";
24
+ if (!trimmed)
25
+ return "";
26
+ const dashed = trimmed.replace(/\s+/g, "-");
27
+ const cleaned = dashed.replace(/[^a-z0-9#@._+-]+/g, "-");
28
+ return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
29
+ }
30
+ function normalizeSlackSlashCommandName(raw) {
31
+ const trimmed = raw?.trim().toLowerCase() ?? "";
32
+ if (!trimmed)
33
+ return "";
34
+ const stripped = trimmed.startsWith("/") ? trimmed.slice(1) : trimmed;
35
+ return normalizeSlackSlug(stripped);
36
+ }
37
+ function normalizeAllowList(list) {
38
+ return (list ?? []).map((entry) => String(entry).trim()).filter(Boolean);
39
+ }
40
+ function normalizeAllowListLower(list) {
41
+ return normalizeAllowList(list).map((entry) => entry.toLowerCase());
42
+ }
43
+ function allowListMatches(params) {
44
+ const allowList = params.allowList;
45
+ if (allowList.length === 0)
46
+ return false;
47
+ if (allowList.includes("*"))
48
+ return true;
49
+ const id = params.id?.toLowerCase();
50
+ const name = params.name?.toLowerCase();
51
+ const slug = normalizeSlackSlug(name);
52
+ const candidates = [
53
+ id,
54
+ id ? `slack:${id}` : undefined,
55
+ id ? `user:${id}` : undefined,
56
+ name,
57
+ name ? `slack:${name}` : undefined,
58
+ slug,
59
+ ].filter(Boolean);
60
+ return candidates.some((value) => allowList.includes(value));
61
+ }
62
+ function resolveSlackSlashCommandConfig(raw) {
63
+ const rawName = raw?.name?.trim() || "nexus";
64
+ const normalizedName = normalizeSlackSlashCommandName(rawName);
65
+ const name = normalizedName || "nexus";
66
+ return {
67
+ enabled: raw?.enabled === true,
68
+ name: raw?.name?.trim() || "clawd",
69
+ sessionPrefix: raw?.sessionPrefix?.trim() || "slack:slash",
70
+ ephemeral: raw?.ephemeral !== false,
71
+ };
72
+ }
73
+ function shouldEmitSlackReactionNotification(params) {
74
+ const { mode, botId, messageAuthorId, userId, userName, allowlist } = params;
75
+ const effectiveMode = mode ?? "own";
76
+ if (effectiveMode === "off")
77
+ return false;
78
+ if (effectiveMode === "own") {
79
+ if (!botId || !messageAuthorId)
80
+ return false;
81
+ return messageAuthorId === botId;
82
+ }
83
+ if (effectiveMode === "allowlist") {
84
+ if (!Array.isArray(allowlist) || allowlist.length === 0)
85
+ return false;
86
+ const users = normalizeAllowListLower(allowlist);
87
+ return allowListMatches({
88
+ allowList: users,
89
+ id: userId,
90
+ name: userName ?? undefined,
91
+ });
92
+ }
93
+ return true;
94
+ }
95
+ function resolveSlackChannelLabel(params) {
96
+ const channelName = params.channelName?.trim();
97
+ if (channelName) {
98
+ const slug = normalizeSlackSlug(channelName);
99
+ return `#${slug || channelName}`;
100
+ }
101
+ const channelId = params.channelId?.trim();
102
+ return channelId ? `#${channelId}` : "unknown channel";
103
+ }
104
+ function resolveSlackChannelConfig(params) {
105
+ const { channelId, channelName, channels } = params;
106
+ const entries = channels ?? {};
107
+ const keys = Object.keys(entries);
108
+ const normalizedName = channelName ? normalizeSlackSlug(channelName) : "";
109
+ const directName = channelName ? channelName.trim() : "";
110
+ const candidates = [
111
+ channelId,
112
+ channelName ? `#${directName}` : "",
113
+ directName,
114
+ normalizedName,
115
+ ].filter(Boolean);
116
+ let matched;
117
+ for (const candidate of candidates) {
118
+ if (candidate && entries[candidate]) {
119
+ matched = entries[candidate];
120
+ break;
121
+ }
122
+ }
123
+ const fallback = entries["*"];
124
+ if (keys.length === 0) {
125
+ return { allowed: true, requireMention: true };
126
+ }
127
+ if (!matched && !fallback) {
128
+ return { allowed: false, requireMention: true };
129
+ }
130
+ const resolved = matched ?? fallback ?? {};
131
+ const allowed = resolved.allow ?? true;
132
+ const requireMention = resolved.requireMention ?? fallback?.requireMention ?? true;
133
+ return { allowed, requireMention };
134
+ }
135
+ async function resolveSlackMedia(params) {
136
+ const files = params.files ?? [];
137
+ for (const file of files) {
138
+ const url = file.url_private_download ?? file.url_private;
139
+ if (!url)
140
+ continue;
141
+ try {
142
+ const res = await fetch(url, {
143
+ headers: { Authorization: `Bearer ${params.token}` },
144
+ });
145
+ if (!res.ok)
146
+ continue;
147
+ const buffer = Buffer.from(await res.arrayBuffer());
148
+ if (buffer.byteLength > params.maxBytes)
149
+ continue;
150
+ const contentType = await detectMime({
151
+ buffer,
152
+ headerMime: res.headers.get("content-type"),
153
+ filePath: file.name,
154
+ });
155
+ const saved = await saveMediaBuffer(buffer, contentType ?? file.mimetype, "inbound", params.maxBytes);
156
+ return {
157
+ path: saved.path,
158
+ contentType: saved.contentType,
159
+ placeholder: file.name ? `[Slack file: ${file.name}]` : "[Slack file]",
160
+ };
161
+ }
162
+ catch {
163
+ // Ignore download failures and fall through to the next file.
164
+ }
165
+ }
166
+ return null;
167
+ }
168
+ export async function monitorSlackProvider(opts = {}) {
169
+ const cfg = loadConfig();
170
+ const sessionCfg = cfg.session;
171
+ const sessionScope = sessionCfg?.scope ?? "per-sender";
172
+ const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main";
173
+ const resolveSlackSystemEventSessionKey = (params) => {
174
+ const channelId = params.channelId?.trim() ?? "";
175
+ if (!channelId)
176
+ return mainKey;
177
+ const channelType = params.channelType?.trim().toLowerCase() ?? "";
178
+ const isRoom = channelType === "channel" || channelType === "group";
179
+ const isGroup = channelType === "mpim";
180
+ const from = isRoom
181
+ ? `slack:channel:${channelId}`
182
+ : isGroup
183
+ ? `slack:group:${channelId}`
184
+ : `slack:${channelId}`;
185
+ const chatType = isRoom ? "room" : isGroup ? "group" : "direct";
186
+ return resolveSessionKey(sessionScope, { From: from, ChatType: chatType, Provider: "slack" }, mainKey);
187
+ };
188
+ const botToken = resolveSlackBotToken(opts.botToken ??
189
+ process.env.SLACK_BOT_TOKEN ??
190
+ cfg.slack?.botToken ??
191
+ undefined);
192
+ const appToken = resolveSlackAppToken(opts.appToken ??
193
+ process.env.SLACK_APP_TOKEN ??
194
+ cfg.slack?.appToken ??
195
+ undefined);
196
+ if (!botToken || !appToken) {
197
+ throw new Error("SLACK_BOT_TOKEN and SLACK_APP_TOKEN (or slack.botToken/slack.appToken) are required for Slack socket mode");
198
+ }
199
+ const runtime = opts.runtime ?? {
200
+ log: console.log,
201
+ error: console.error,
202
+ exit: (code) => {
203
+ throw new Error(`exit ${code}`);
204
+ },
205
+ };
206
+ const dmConfig = cfg.slack?.dm;
207
+ const dmPolicy = dmConfig?.policy ?? "pairing";
208
+ const allowFrom = normalizeAllowList(dmConfig?.allowFrom);
209
+ const groupDmEnabled = dmConfig?.groupEnabled ?? false;
210
+ const groupDmChannels = normalizeAllowList(dmConfig?.groupChannels);
211
+ const channelsConfig = cfg.slack?.channels;
212
+ const dmEnabled = dmConfig?.enabled ?? true;
213
+ const groupPolicy = cfg.slack?.groupPolicy ?? "open";
214
+ const reactionMode = cfg.slack?.reactionNotifications ?? "own";
215
+ const reactionAllowlist = cfg.slack?.reactionAllowlist ?? [];
216
+ const slashCommand = resolveSlackSlashCommandConfig(opts.slashCommand ?? cfg.slack?.slashCommand);
217
+ const textLimit = resolveTextChunkLimit(cfg, "slack");
218
+ const mentionRegexes = buildMentionRegexes(cfg);
219
+ const ackReaction = (cfg.messages?.ackReaction ?? "").trim();
220
+ const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
221
+ const mediaMaxBytes = (opts.mediaMaxMb ?? cfg.slack?.mediaMaxMb ?? 20) * 1024 * 1024;
222
+ const logger = getChildLogger({ module: "slack-auto-reply" });
223
+ const channelCache = new Map();
224
+ const userCache = new Map();
225
+ const seenMessages = new Map();
226
+ const markMessageSeen = (channelId, ts) => {
227
+ if (!channelId || !ts)
228
+ return false;
229
+ const key = `${channelId}:${ts}`;
230
+ if (seenMessages.has(key))
231
+ return true;
232
+ seenMessages.set(key, Date.now());
233
+ if (seenMessages.size > 500) {
234
+ const cutoff = Date.now() - 60_000;
235
+ for (const [entry, seenAt] of seenMessages) {
236
+ if (seenAt < cutoff || seenMessages.size > 450) {
237
+ seenMessages.delete(entry);
238
+ }
239
+ else {
240
+ break;
241
+ }
242
+ }
243
+ }
244
+ return false;
245
+ };
246
+ const app = new App({
247
+ token: botToken,
248
+ appToken,
249
+ socketMode: true,
250
+ });
251
+ let botUserId = "";
252
+ let teamId = "";
253
+ try {
254
+ const auth = await app.client.auth.test({ token: botToken });
255
+ botUserId = auth.user_id ?? "";
256
+ teamId = auth.team_id ?? "";
257
+ }
258
+ catch (err) {
259
+ runtime.error?.(danger(`slack auth failed: ${String(err)}`));
260
+ }
261
+ const resolveChannelName = async (channelId) => {
262
+ const cached = channelCache.get(channelId);
263
+ if (cached)
264
+ return cached;
265
+ try {
266
+ const info = await app.client.conversations.info({
267
+ token: botToken,
268
+ channel: channelId,
269
+ });
270
+ const name = info.channel && "name" in info.channel ? info.channel.name : undefined;
271
+ const channel = info.channel ?? undefined;
272
+ const type = channel?.is_im
273
+ ? "im"
274
+ : channel?.is_mpim
275
+ ? "mpim"
276
+ : channel?.is_channel
277
+ ? "channel"
278
+ : channel?.is_group
279
+ ? "group"
280
+ : undefined;
281
+ const entry = { name, type };
282
+ channelCache.set(channelId, entry);
283
+ return entry;
284
+ }
285
+ catch {
286
+ return {};
287
+ }
288
+ };
289
+ const resolveUserName = async (userId) => {
290
+ const cached = userCache.get(userId);
291
+ if (cached)
292
+ return cached;
293
+ try {
294
+ const info = await app.client.users.info({
295
+ token: botToken,
296
+ user: userId,
297
+ });
298
+ const profile = info.user?.profile;
299
+ const name = profile?.display_name ||
300
+ profile?.real_name ||
301
+ info.user?.name ||
302
+ undefined;
303
+ const entry = { name };
304
+ userCache.set(userId, entry);
305
+ return entry;
306
+ }
307
+ catch {
308
+ return {};
309
+ }
310
+ };
311
+ const isChannelAllowed = (params) => {
312
+ const channelType = params.channelType;
313
+ const isDirectMessage = channelType === "im";
314
+ const isGroupDm = channelType === "mpim";
315
+ const isRoom = channelType === "channel" || channelType === "group";
316
+ if (isDirectMessage && !dmEnabled)
317
+ return false;
318
+ if (isGroupDm && !groupDmEnabled)
319
+ return false;
320
+ if (isGroupDm && groupDmChannels.length > 0) {
321
+ const allowList = normalizeAllowListLower(groupDmChannels);
322
+ const candidates = [
323
+ params.channelId,
324
+ params.channelName ? `#${params.channelName}` : undefined,
325
+ params.channelName,
326
+ params.channelName ? normalizeSlackSlug(params.channelName) : undefined,
327
+ ]
328
+ .filter((value) => Boolean(value))
329
+ .map((value) => value.toLowerCase());
330
+ const permitted = allowList.includes("*") ||
331
+ candidates.some((candidate) => allowList.includes(candidate));
332
+ if (!permitted)
333
+ return false;
334
+ }
335
+ if (isRoom && params.channelId) {
336
+ const channelConfig = resolveSlackChannelConfig({
337
+ channelId: params.channelId,
338
+ channelName: params.channelName,
339
+ channels: channelsConfig,
340
+ });
341
+ const channelAllowed = channelConfig?.allowed !== false;
342
+ const channelAllowlistConfigured = Boolean(channelsConfig) && Object.keys(channelsConfig ?? {}).length > 0;
343
+ if (!isSlackRoomAllowedByPolicy({
344
+ groupPolicy,
345
+ channelAllowlistConfigured,
346
+ channelAllowed,
347
+ })) {
348
+ return false;
349
+ }
350
+ if (!channelAllowed)
351
+ return false;
352
+ }
353
+ return true;
354
+ };
355
+ const handleSlackMessage = async (message, opts) => {
356
+ if (opts.source === "message" && message.type !== "message")
357
+ return;
358
+ if (message.bot_id)
359
+ return;
360
+ if (opts.source === "message" &&
361
+ message.subtype &&
362
+ message.subtype !== "file_share") {
363
+ return;
364
+ }
365
+ if (!message.user)
366
+ return;
367
+ if (markMessageSeen(message.channel, message.ts))
368
+ return;
369
+ let channelInfo = {};
370
+ let channelType = message.channel_type;
371
+ if (!channelType || channelType !== "im") {
372
+ channelInfo = await resolveChannelName(message.channel);
373
+ channelType = channelType ?? channelInfo.type;
374
+ }
375
+ const channelName = channelInfo?.name;
376
+ const resolvedChannelType = channelType;
377
+ const isDirectMessage = resolvedChannelType === "im";
378
+ const isGroupDm = resolvedChannelType === "mpim";
379
+ const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
380
+ if (!isChannelAllowed({
381
+ channelId: message.channel,
382
+ channelName,
383
+ channelType: resolvedChannelType,
384
+ })) {
385
+ logVerbose("slack: drop message (channel not allowed)");
386
+ return;
387
+ }
388
+ const storeAllowFrom = await readProviderAllowFromStore("slack").catch(() => []);
389
+ const effectiveAllowFrom = normalizeAllowList([
390
+ ...allowFrom,
391
+ ...storeAllowFrom,
392
+ ]);
393
+ const effectiveAllowFromLower = normalizeAllowListLower(effectiveAllowFrom);
394
+ if (isDirectMessage) {
395
+ if (!dmEnabled || dmPolicy === "disabled") {
396
+ logVerbose("slack: drop dm (dms disabled)");
397
+ return;
398
+ }
399
+ if (dmPolicy !== "open") {
400
+ const permitted = allowListMatches({
401
+ allowList: effectiveAllowFromLower,
402
+ id: message.user,
403
+ });
404
+ if (!permitted) {
405
+ if (dmPolicy === "pairing") {
406
+ const sender = await resolveUserName(message.user);
407
+ const senderName = sender?.name ?? undefined;
408
+ const { code } = await upsertProviderPairingRequest({
409
+ provider: "slack",
410
+ id: message.user,
411
+ meta: { name: senderName },
412
+ });
413
+ logVerbose(`slack pairing request sender=${message.user} name=${senderName ?? "unknown"} code=${code}`);
414
+ try {
415
+ await sendMessageSlack(message.channel, [
416
+ "Nexus: access not configured.",
417
+ "",
418
+ `Pairing code: ${code}`,
419
+ "",
420
+ "Ask the bot owner to approve with:",
421
+ "nexus pairing approve --provider slack <code>",
422
+ ].join("\n"), { token: botToken, client: app.client });
423
+ }
424
+ catch (err) {
425
+ logVerbose(`slack pairing reply failed for ${message.user}: ${String(err)}`);
426
+ }
427
+ }
428
+ else {
429
+ logVerbose(`Blocked unauthorized slack sender ${message.user} (dmPolicy=${dmPolicy})`);
430
+ }
431
+ return;
432
+ }
433
+ }
434
+ }
435
+ const channelConfig = isRoom
436
+ ? resolveSlackChannelConfig({
437
+ channelId: message.channel,
438
+ channelName,
439
+ channels: channelsConfig,
440
+ })
441
+ : null;
442
+ const wasMentioned = opts.wasMentioned ??
443
+ (!isDirectMessage &&
444
+ (Boolean(botUserId && message.text?.includes(`<@${botUserId}>`)) ||
445
+ matchesMentionPatterns(message.text ?? "", mentionRegexes)));
446
+ const sender = await resolveUserName(message.user);
447
+ const senderName = sender?.name ?? message.user;
448
+ const allowList = effectiveAllowFromLower;
449
+ const commandAuthorized = allowList.length === 0 ||
450
+ allowListMatches({
451
+ allowList,
452
+ id: message.user,
453
+ name: senderName,
454
+ });
455
+ const hasAnyMention = /<@[^>]+>/.test(message.text ?? "");
456
+ const shouldBypassMention = isRoom &&
457
+ channelConfig?.requireMention &&
458
+ !wasMentioned &&
459
+ !hasAnyMention &&
460
+ commandAuthorized &&
461
+ hasControlCommand(message.text ?? "");
462
+ const canDetectMention = Boolean(botUserId) || mentionRegexes.length > 0;
463
+ if (isRoom &&
464
+ channelConfig?.requireMention &&
465
+ canDetectMention &&
466
+ !wasMentioned &&
467
+ !shouldBypassMention) {
468
+ logger.info({ channel: message.channel, reason: "no-mention" }, "skipping room message");
469
+ return;
470
+ }
471
+ const media = await resolveSlackMedia({
472
+ files: message.files,
473
+ token: botToken,
474
+ maxBytes: mediaMaxBytes,
475
+ });
476
+ const rawBody = (message.text ?? "").trim() || media?.placeholder || "";
477
+ if (!rawBody)
478
+ return;
479
+ const shouldAckReaction = () => {
480
+ if (!ackReaction)
481
+ return false;
482
+ if (ackReactionScope === "all")
483
+ return true;
484
+ if (ackReactionScope === "direct")
485
+ return isDirectMessage;
486
+ const isGroupChat = isRoom || isGroupDm;
487
+ if (ackReactionScope === "group-all")
488
+ return isGroupChat;
489
+ if (ackReactionScope === "group-mentions") {
490
+ if (!isRoom)
491
+ return false;
492
+ if (!channelConfig?.requireMention)
493
+ return false;
494
+ if (!canDetectMention)
495
+ return false;
496
+ return wasMentioned || shouldBypassMention;
497
+ }
498
+ return false;
499
+ };
500
+ if (shouldAckReaction() && message.ts) {
501
+ reactSlackMessage(message.channel, message.ts, ackReaction, {
502
+ token: botToken,
503
+ client: app.client,
504
+ }).catch((err) => {
505
+ logVerbose(`slack react failed for channel ${message.channel}: ${String(err)}`);
506
+ });
507
+ }
508
+ const roomLabel = channelName ? `#${channelName}` : `#${message.channel}`;
509
+ const preview = rawBody.replace(/\s+/g, " ").slice(0, 160);
510
+ const inboundLabel = isDirectMessage
511
+ ? `Slack DM from ${senderName}`
512
+ : `Slack message in ${roomLabel} from ${senderName}`;
513
+ const slackFrom = isDirectMessage
514
+ ? `slack:${message.user}`
515
+ : isRoom
516
+ ? `slack:channel:${message.channel}`
517
+ : `slack:group:${message.channel}`;
518
+ const route = resolveAgentRoute({
519
+ cfg,
520
+ provider: "slack",
521
+ teamId: teamId || undefined,
522
+ peer: {
523
+ kind: isDirectMessage ? "dm" : isRoom ? "channel" : "group",
524
+ id: isDirectMessage ? (message.user ?? "unknown") : message.channel,
525
+ },
526
+ });
527
+ const sessionKey = route.sessionKey;
528
+ enqueueSystemEvent(`${inboundLabel}: ${preview}`, {
529
+ sessionKey,
530
+ contextKey: `slack:message:${message.channel}:${message.ts ?? "unknown"}`,
531
+ });
532
+ const textWithId = `${rawBody}\n[slack message id: ${message.ts} channel: ${message.channel}]`;
533
+ const body = formatAgentEnvelope({
534
+ provider: "Slack",
535
+ from: senderName,
536
+ timestamp: message.ts ? Math.round(Number(message.ts) * 1000) : undefined,
537
+ body: textWithId,
538
+ });
539
+ const isRoomish = isRoom || isGroupDm;
540
+ const ctxPayload = {
541
+ Body: body,
542
+ From: slackFrom,
543
+ To: isDirectMessage
544
+ ? `user:${message.user}`
545
+ : `channel:${message.channel}`,
546
+ SessionKey: route.sessionKey,
547
+ AccountId: route.accountId,
548
+ ChatType: isDirectMessage ? "direct" : isRoom ? "room" : "group",
549
+ GroupSubject: isRoomish ? roomLabel : undefined,
550
+ SenderName: senderName,
551
+ SenderId: message.user,
552
+ Provider: "slack",
553
+ MessageSid: message.ts,
554
+ ReplyToId: message.thread_ts ?? message.ts,
555
+ Timestamp: message.ts ? Math.round(Number(message.ts) * 1000) : undefined,
556
+ WasMentioned: isRoomish ? wasMentioned : undefined,
557
+ MediaPath: media?.path,
558
+ MediaType: media?.contentType,
559
+ MediaUrl: media?.path,
560
+ CommandAuthorized: commandAuthorized,
561
+ };
562
+ const replyTarget = ctxPayload.To ?? undefined;
563
+ if (!replyTarget) {
564
+ runtime.error?.(danger("slack: missing reply target"));
565
+ return;
566
+ }
567
+ if (isDirectMessage) {
568
+ const sessionCfg = cfg.session;
569
+ const storePath = resolveStorePath(sessionCfg?.store, {
570
+ agentId: route.agentId,
571
+ });
572
+ await updateLastRoute({
573
+ storePath,
574
+ sessionKey: route.mainSessionKey,
575
+ provider: "slack",
576
+ to: `user:${message.user}`,
577
+ accountId: route.accountId,
578
+ });
579
+ }
580
+ if (shouldLogVerbose()) {
581
+ logVerbose(`slack inbound: channel=${message.channel} from=${ctxPayload.From} preview="${preview}"`);
582
+ }
583
+ // Only thread replies if the incoming message was in a thread.
584
+ const incomingThreadTs = message.thread_ts;
585
+ const dispatcher = createReplyDispatcher({
586
+ responsePrefix: cfg.messages?.responsePrefix,
587
+ deliver: async (payload) => {
588
+ await deliverReplies({
589
+ replies: [payload],
590
+ target: replyTarget,
591
+ token: botToken,
592
+ runtime,
593
+ textLimit,
594
+ threadTs: incomingThreadTs,
595
+ });
596
+ },
597
+ onError: (err, info) => {
598
+ runtime.error?.(danger(`slack ${info.kind} reply failed: ${String(err)}`));
599
+ },
600
+ });
601
+ const { queuedFinal, counts } = await dispatchReplyFromConfig({
602
+ ctx: ctxPayload,
603
+ cfg,
604
+ dispatcher,
605
+ });
606
+ if (!queuedFinal)
607
+ return;
608
+ if (shouldLogVerbose()) {
609
+ const finalCount = counts.final;
610
+ logVerbose(`slack: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${replyTarget}`);
611
+ }
612
+ };
613
+ app.event("message", async ({ event }) => {
614
+ try {
615
+ const message = event;
616
+ if (message.subtype === "message_changed") {
617
+ const changed = event;
618
+ const channelId = changed.channel;
619
+ const channelInfo = channelId
620
+ ? await resolveChannelName(channelId)
621
+ : {};
622
+ const channelType = channelInfo?.type;
623
+ if (!isChannelAllowed({
624
+ channelId,
625
+ channelName: channelInfo?.name,
626
+ channelType,
627
+ })) {
628
+ return;
629
+ }
630
+ const messageId = changed.message?.ts ?? changed.previous_message?.ts;
631
+ const label = resolveSlackChannelLabel({
632
+ channelId,
633
+ channelName: channelInfo?.name,
634
+ });
635
+ const sessionKey = resolveSlackSystemEventSessionKey({
636
+ channelId,
637
+ channelType,
638
+ });
639
+ enqueueSystemEvent(`Slack message edited in ${label}.`, {
640
+ sessionKey,
641
+ contextKey: `slack:message:changed:${channelId ?? "unknown"}:${messageId ?? changed.event_ts ?? "unknown"}`,
642
+ });
643
+ return;
644
+ }
645
+ if (message.subtype === "message_deleted") {
646
+ const deleted = event;
647
+ const channelId = deleted.channel;
648
+ const channelInfo = channelId
649
+ ? await resolveChannelName(channelId)
650
+ : {};
651
+ const channelType = channelInfo?.type;
652
+ if (!isChannelAllowed({
653
+ channelId,
654
+ channelName: channelInfo?.name,
655
+ channelType,
656
+ })) {
657
+ return;
658
+ }
659
+ const label = resolveSlackChannelLabel({
660
+ channelId,
661
+ channelName: channelInfo?.name,
662
+ });
663
+ const sessionKey = resolveSlackSystemEventSessionKey({
664
+ channelId,
665
+ channelType,
666
+ });
667
+ enqueueSystemEvent(`Slack message deleted in ${label}.`, {
668
+ sessionKey,
669
+ contextKey: `slack:message:deleted:${channelId ?? "unknown"}:${deleted.deleted_ts ?? deleted.event_ts ?? "unknown"}`,
670
+ });
671
+ return;
672
+ }
673
+ if (message.subtype === "thread_broadcast") {
674
+ const thread = event;
675
+ const channelId = thread.channel;
676
+ const channelInfo = channelId
677
+ ? await resolveChannelName(channelId)
678
+ : {};
679
+ const channelType = channelInfo?.type;
680
+ if (!isChannelAllowed({
681
+ channelId,
682
+ channelName: channelInfo?.name,
683
+ channelType,
684
+ })) {
685
+ return;
686
+ }
687
+ const label = resolveSlackChannelLabel({
688
+ channelId,
689
+ channelName: channelInfo?.name,
690
+ });
691
+ const messageId = thread.message?.ts ?? thread.event_ts;
692
+ const sessionKey = resolveSlackSystemEventSessionKey({
693
+ channelId,
694
+ channelType,
695
+ });
696
+ enqueueSystemEvent(`Slack thread reply broadcast in ${label}.`, {
697
+ sessionKey,
698
+ contextKey: `slack:thread:broadcast:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
699
+ });
700
+ return;
701
+ }
702
+ await handleSlackMessage(message, { source: "message" });
703
+ }
704
+ catch (err) {
705
+ runtime.error?.(danger(`slack handler failed: ${String(err)}`));
706
+ }
707
+ });
708
+ app.event("app_mention", async ({ event }) => {
709
+ try {
710
+ const mention = event;
711
+ await handleSlackMessage(mention, {
712
+ source: "app_mention",
713
+ wasMentioned: true,
714
+ });
715
+ }
716
+ catch (err) {
717
+ runtime.error?.(danger(`slack mention handler failed: ${String(err)}`));
718
+ }
719
+ });
720
+ const handleReactionEvent = async (event, action) => {
721
+ try {
722
+ const item = event.item;
723
+ if (!event.user)
724
+ return;
725
+ if (!item?.channel || !item?.ts)
726
+ return;
727
+ if (item.type && item.type !== "message")
728
+ return;
729
+ if (botUserId && event.user === botUserId)
730
+ return;
731
+ const channelInfo = await resolveChannelName(item.channel);
732
+ const channelType = channelInfo?.type;
733
+ const isDirectMessage = channelType === "im";
734
+ const isGroupDm = channelType === "mpim";
735
+ const isRoom = channelType === "channel" || channelType === "group";
736
+ const channelName = channelInfo?.name;
737
+ if (isDirectMessage && !dmEnabled)
738
+ return;
739
+ if (isGroupDm && !groupDmEnabled)
740
+ return;
741
+ if (isGroupDm && groupDmChannels.length > 0) {
742
+ const allowList = normalizeAllowListLower(groupDmChannels);
743
+ const candidates = [
744
+ item.channel,
745
+ channelName ? `#${channelName}` : undefined,
746
+ channelName,
747
+ channelName ? normalizeSlackSlug(channelName) : undefined,
748
+ ]
749
+ .filter((value) => Boolean(value))
750
+ .map((value) => value.toLowerCase());
751
+ const permitted = allowList.includes("*") ||
752
+ candidates.some((candidate) => allowList.includes(candidate));
753
+ if (!permitted)
754
+ return;
755
+ }
756
+ if (isRoom) {
757
+ const channelConfig = resolveSlackChannelConfig({
758
+ channelId: item.channel,
759
+ channelName,
760
+ channels: channelsConfig,
761
+ });
762
+ if (channelConfig?.allowed === false)
763
+ return;
764
+ }
765
+ const actor = await resolveUserName(event.user);
766
+ const shouldNotify = shouldEmitSlackReactionNotification({
767
+ mode: reactionMode,
768
+ botId: botUserId,
769
+ messageAuthorId: event.item_user ?? undefined,
770
+ userId: event.user,
771
+ userName: actor?.name ?? undefined,
772
+ allowlist: reactionAllowlist,
773
+ });
774
+ if (!shouldNotify)
775
+ return;
776
+ const emojiLabel = event.reaction ?? "emoji";
777
+ const actorLabel = actor?.name ?? event.user;
778
+ const channelLabel = channelName
779
+ ? `#${normalizeSlackSlug(channelName) || channelName}`
780
+ : `#${item.channel}`;
781
+ const authorInfo = event.item_user
782
+ ? await resolveUserName(event.item_user)
783
+ : undefined;
784
+ const authorLabel = authorInfo?.name ?? event.item_user;
785
+ const baseText = `Slack reaction ${action}: :${emojiLabel}: by ${actorLabel} in ${channelLabel} msg ${item.ts}`;
786
+ const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
787
+ const sessionKey = resolveSlackSystemEventSessionKey({
788
+ channelId: item.channel,
789
+ channelType,
790
+ });
791
+ enqueueSystemEvent(text, {
792
+ sessionKey,
793
+ contextKey: `slack:reaction:${action}:${item.channel}:${item.ts}:${event.user}:${emojiLabel}`,
794
+ });
795
+ }
796
+ catch (err) {
797
+ runtime.error?.(danger(`slack reaction handler failed: ${String(err)}`));
798
+ }
799
+ };
800
+ app.event("reaction_added", async ({ event }) => {
801
+ await handleReactionEvent(event, "added");
802
+ });
803
+ app.event("reaction_removed", async ({ event }) => {
804
+ await handleReactionEvent(event, "removed");
805
+ });
806
+ app.event("member_joined_channel", async ({ event }) => {
807
+ try {
808
+ const payload = event;
809
+ const channelId = payload.channel;
810
+ const channelInfo = channelId
811
+ ? await resolveChannelName(channelId)
812
+ : {};
813
+ const channelType = payload.channel_type ?? channelInfo?.type;
814
+ if (!isChannelAllowed({
815
+ channelId,
816
+ channelName: channelInfo?.name,
817
+ channelType,
818
+ })) {
819
+ return;
820
+ }
821
+ const userInfo = payload.user
822
+ ? await resolveUserName(payload.user)
823
+ : {};
824
+ const userLabel = userInfo?.name ?? payload.user ?? "someone";
825
+ const label = resolveSlackChannelLabel({
826
+ channelId,
827
+ channelName: channelInfo?.name,
828
+ });
829
+ const sessionKey = resolveSlackSystemEventSessionKey({
830
+ channelId,
831
+ channelType,
832
+ });
833
+ enqueueSystemEvent(`Slack: ${userLabel} joined ${label}.`, {
834
+ sessionKey,
835
+ contextKey: `slack:member:joined:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`,
836
+ });
837
+ }
838
+ catch (err) {
839
+ runtime.error?.(danger(`slack join handler failed: ${String(err)}`));
840
+ }
841
+ });
842
+ app.event("member_left_channel", async ({ event }) => {
843
+ try {
844
+ const payload = event;
845
+ const channelId = payload.channel;
846
+ const channelInfo = channelId
847
+ ? await resolveChannelName(channelId)
848
+ : {};
849
+ const channelType = payload.channel_type ?? channelInfo?.type;
850
+ if (!isChannelAllowed({
851
+ channelId,
852
+ channelName: channelInfo?.name,
853
+ channelType,
854
+ })) {
855
+ return;
856
+ }
857
+ const userInfo = payload.user
858
+ ? await resolveUserName(payload.user)
859
+ : {};
860
+ const userLabel = userInfo?.name ?? payload.user ?? "someone";
861
+ const label = resolveSlackChannelLabel({
862
+ channelId,
863
+ channelName: channelInfo?.name,
864
+ });
865
+ const sessionKey = resolveSlackSystemEventSessionKey({
866
+ channelId,
867
+ channelType,
868
+ });
869
+ enqueueSystemEvent(`Slack: ${userLabel} left ${label}.`, {
870
+ sessionKey,
871
+ contextKey: `slack:member:left:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`,
872
+ });
873
+ }
874
+ catch (err) {
875
+ runtime.error?.(danger(`slack leave handler failed: ${String(err)}`));
876
+ }
877
+ });
878
+ app.event("channel_created", async ({ event }) => {
879
+ try {
880
+ const payload = event;
881
+ const channelId = payload.channel?.id;
882
+ const channelName = payload.channel?.name;
883
+ if (!isChannelAllowed({
884
+ channelId,
885
+ channelName,
886
+ channelType: "channel",
887
+ })) {
888
+ return;
889
+ }
890
+ const label = resolveSlackChannelLabel({ channelId, channelName });
891
+ const sessionKey = resolveSlackSystemEventSessionKey({
892
+ channelId,
893
+ channelType: "channel",
894
+ });
895
+ enqueueSystemEvent(`Slack channel created: ${label}.`, {
896
+ sessionKey,
897
+ contextKey: `slack:channel:created:${channelId ?? channelName ?? "unknown"}`,
898
+ });
899
+ }
900
+ catch (err) {
901
+ runtime.error?.(danger(`slack channel created handler failed: ${String(err)}`));
902
+ }
903
+ });
904
+ app.event("channel_rename", async ({ event }) => {
905
+ try {
906
+ const payload = event;
907
+ const channelId = payload.channel?.id;
908
+ const channelName = payload.channel?.name_normalized ?? payload.channel?.name;
909
+ if (!isChannelAllowed({
910
+ channelId,
911
+ channelName,
912
+ channelType: "channel",
913
+ })) {
914
+ return;
915
+ }
916
+ const label = resolveSlackChannelLabel({ channelId, channelName });
917
+ const sessionKey = resolveSlackSystemEventSessionKey({
918
+ channelId,
919
+ channelType: "channel",
920
+ });
921
+ enqueueSystemEvent(`Slack channel renamed: ${label}.`, {
922
+ sessionKey,
923
+ contextKey: `slack:channel:renamed:${channelId ?? channelName ?? "unknown"}`,
924
+ });
925
+ }
926
+ catch (err) {
927
+ runtime.error?.(danger(`slack channel rename handler failed: ${String(err)}`));
928
+ }
929
+ });
930
+ app.event("pin_added", async ({ event }) => {
931
+ try {
932
+ const payload = event;
933
+ const channelId = payload.channel_id;
934
+ const channelInfo = channelId
935
+ ? await resolveChannelName(channelId)
936
+ : {};
937
+ if (!isChannelAllowed({
938
+ channelId,
939
+ channelName: channelInfo?.name,
940
+ channelType: channelInfo?.type,
941
+ })) {
942
+ return;
943
+ }
944
+ const label = resolveSlackChannelLabel({
945
+ channelId,
946
+ channelName: channelInfo?.name,
947
+ });
948
+ const userInfo = payload.user
949
+ ? await resolveUserName(payload.user)
950
+ : {};
951
+ const userLabel = userInfo?.name ?? payload.user ?? "someone";
952
+ const itemType = payload.item?.type ?? "item";
953
+ const messageId = payload.item?.message?.ts ?? payload.event_ts;
954
+ const sessionKey = resolveSlackSystemEventSessionKey({
955
+ channelId,
956
+ channelType: channelInfo?.type ?? undefined,
957
+ });
958
+ enqueueSystemEvent(`Slack: ${userLabel} pinned a ${itemType} in ${label}.`, {
959
+ sessionKey,
960
+ contextKey: `slack:pin:added:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
961
+ });
962
+ }
963
+ catch (err) {
964
+ runtime.error?.(danger(`slack pin added handler failed: ${String(err)}`));
965
+ }
966
+ });
967
+ app.event("pin_removed", async ({ event }) => {
968
+ try {
969
+ const payload = event;
970
+ const channelId = payload.channel_id;
971
+ const channelInfo = channelId
972
+ ? await resolveChannelName(channelId)
973
+ : {};
974
+ if (!isChannelAllowed({
975
+ channelId,
976
+ channelName: channelInfo?.name,
977
+ channelType: channelInfo?.type,
978
+ })) {
979
+ return;
980
+ }
981
+ const label = resolveSlackChannelLabel({
982
+ channelId,
983
+ channelName: channelInfo?.name,
984
+ });
985
+ const userInfo = payload.user
986
+ ? await resolveUserName(payload.user)
987
+ : {};
988
+ const userLabel = userInfo?.name ?? payload.user ?? "someone";
989
+ const itemType = payload.item?.type ?? "item";
990
+ const messageId = payload.item?.message?.ts ?? payload.event_ts;
991
+ const sessionKey = resolveSlackSystemEventSessionKey({
992
+ channelId,
993
+ channelType: channelInfo?.type ?? undefined,
994
+ });
995
+ enqueueSystemEvent(`Slack: ${userLabel} unpinned a ${itemType} in ${label}.`, {
996
+ sessionKey,
997
+ contextKey: `slack:pin:removed:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
998
+ });
999
+ }
1000
+ catch (err) {
1001
+ runtime.error?.(danger(`slack pin removed handler failed: ${String(err)}`));
1002
+ }
1003
+ });
1004
+ if (slashCommand.enabled) {
1005
+ app.command(slashCommand.name, async ({ command, ack, respond }) => {
1006
+ try {
1007
+ const prompt = command.text?.trim();
1008
+ if (!prompt) {
1009
+ await ack({
1010
+ text: "Message required.",
1011
+ response_type: "ephemeral",
1012
+ });
1013
+ return;
1014
+ }
1015
+ await ack();
1016
+ if (botUserId && command.user_id === botUserId)
1017
+ return;
1018
+ const channelInfo = await resolveChannelName(command.channel_id);
1019
+ const channelType = channelInfo?.type ??
1020
+ (command.channel_name === "directmessage" ? "im" : undefined);
1021
+ const isDirectMessage = channelType === "im";
1022
+ const isGroupDm = channelType === "mpim";
1023
+ const isRoom = channelType === "channel" || channelType === "group";
1024
+ if (isDirectMessage && !dmEnabled) {
1025
+ await respond({
1026
+ text: "Slack DMs are disabled.",
1027
+ response_type: "ephemeral",
1028
+ });
1029
+ return;
1030
+ }
1031
+ if (isGroupDm && !groupDmEnabled) {
1032
+ await respond({
1033
+ text: "Slack group DMs are disabled.",
1034
+ response_type: "ephemeral",
1035
+ });
1036
+ return;
1037
+ }
1038
+ if (isGroupDm && groupDmChannels.length > 0) {
1039
+ const allowList = normalizeAllowListLower(groupDmChannels);
1040
+ const channelName = channelInfo?.name;
1041
+ const candidates = [
1042
+ command.channel_id,
1043
+ channelName ? `#${channelName}` : undefined,
1044
+ channelName,
1045
+ channelName ? normalizeSlackSlug(channelName) : undefined,
1046
+ ]
1047
+ .filter((value) => Boolean(value))
1048
+ .map((value) => value.toLowerCase());
1049
+ const permitted = allowList.includes("*") ||
1050
+ candidates.some((candidate) => allowList.includes(candidate));
1051
+ if (!permitted) {
1052
+ await respond({
1053
+ text: "This group DM is not allowed.",
1054
+ response_type: "ephemeral",
1055
+ });
1056
+ return;
1057
+ }
1058
+ }
1059
+ if (isDirectMessage) {
1060
+ if (!dmEnabled || dmPolicy === "disabled") {
1061
+ await respond({
1062
+ text: "Slack DMs are disabled.",
1063
+ response_type: "ephemeral",
1064
+ });
1065
+ return;
1066
+ }
1067
+ if (dmPolicy !== "open") {
1068
+ const storeAllowFrom = await readProviderAllowFromStore("slack").catch(() => []);
1069
+ const effectiveAllowFrom = normalizeAllowList([
1070
+ ...allowFrom,
1071
+ ...storeAllowFrom,
1072
+ ]);
1073
+ const sender = await resolveUserName(command.user_id);
1074
+ const permitted = allowListMatches({
1075
+ allowList: normalizeAllowListLower(effectiveAllowFrom),
1076
+ id: command.user_id,
1077
+ name: sender?.name ?? undefined,
1078
+ });
1079
+ if (!permitted) {
1080
+ if (dmPolicy === "pairing") {
1081
+ const senderName = sender?.name ?? undefined;
1082
+ const { code } = await upsertProviderPairingRequest({
1083
+ provider: "slack",
1084
+ id: command.user_id,
1085
+ meta: { name: senderName },
1086
+ });
1087
+ await respond({
1088
+ text: [
1089
+ "Nexus: access not configured.",
1090
+ "",
1091
+ `Pairing code: ${code}`,
1092
+ "",
1093
+ "Ask the bot owner to approve with:",
1094
+ "nexus pairing approve --provider slack <code>",
1095
+ ].join("\n"),
1096
+ response_type: "ephemeral",
1097
+ });
1098
+ }
1099
+ else {
1100
+ await respond({
1101
+ text: "You are not authorized to use this command.",
1102
+ response_type: "ephemeral",
1103
+ });
1104
+ }
1105
+ return;
1106
+ }
1107
+ }
1108
+ }
1109
+ if (isRoom) {
1110
+ const channelConfig = resolveSlackChannelConfig({
1111
+ channelId: command.channel_id,
1112
+ channelName: channelInfo?.name,
1113
+ channels: channelsConfig,
1114
+ });
1115
+ if (channelConfig?.allowed === false) {
1116
+ await respond({
1117
+ text: "This channel is not allowed.",
1118
+ response_type: "ephemeral",
1119
+ });
1120
+ return;
1121
+ }
1122
+ }
1123
+ const sender = await resolveUserName(command.user_id);
1124
+ const senderName = sender?.name ?? command.user_name ?? command.user_id;
1125
+ const channelName = channelInfo?.name;
1126
+ const roomLabel = channelName
1127
+ ? `#${channelName}`
1128
+ : `#${command.channel_id}`;
1129
+ const isRoomish = isRoom || isGroupDm;
1130
+ const route = resolveAgentRoute({
1131
+ cfg,
1132
+ provider: "slack",
1133
+ teamId: teamId || undefined,
1134
+ peer: { kind: "dm", id: command.user_id },
1135
+ });
1136
+ const ctxPayload = {
1137
+ Body: prompt,
1138
+ From: isDirectMessage
1139
+ ? `slack:${command.user_id}`
1140
+ : isRoom
1141
+ ? `slack:channel:${command.channel_id}`
1142
+ : `slack:group:${command.channel_id}`,
1143
+ To: `slash:${command.user_id}`,
1144
+ ChatType: isDirectMessage ? "direct" : isRoom ? "room" : "group",
1145
+ GroupSubject: isRoomish ? roomLabel : undefined,
1146
+ SenderName: senderName,
1147
+ Provider: "slack",
1148
+ WasMentioned: true,
1149
+ MessageSid: command.trigger_id,
1150
+ Timestamp: Date.now(),
1151
+ SessionKey: `agent:${route.agentId}:${slashCommand.sessionPrefix}:${command.user_id}`,
1152
+ AccountId: route.accountId,
1153
+ };
1154
+ const replyResult = await getReplyFromConfig(ctxPayload, undefined, cfg);
1155
+ const replies = replyResult
1156
+ ? Array.isArray(replyResult)
1157
+ ? replyResult
1158
+ : [replyResult]
1159
+ : [];
1160
+ await deliverSlackSlashReplies({
1161
+ replies,
1162
+ respond,
1163
+ ephemeral: slashCommand.ephemeral,
1164
+ textLimit,
1165
+ });
1166
+ }
1167
+ catch (err) {
1168
+ runtime.error?.(danger(`slack slash handler failed: ${String(err)}`));
1169
+ await respond({
1170
+ text: "Sorry, something went wrong handling that command.",
1171
+ response_type: "ephemeral",
1172
+ });
1173
+ }
1174
+ });
1175
+ }
1176
+ const stopOnAbort = () => {
1177
+ if (opts.abortSignal?.aborted)
1178
+ void app.stop();
1179
+ };
1180
+ opts.abortSignal?.addEventListener("abort", stopOnAbort, { once: true });
1181
+ try {
1182
+ await app.start();
1183
+ runtime.log?.("slack socket mode connected");
1184
+ if (opts.abortSignal?.aborted)
1185
+ return;
1186
+ await new Promise((resolve) => {
1187
+ opts.abortSignal?.addEventListener("abort", () => resolve(), {
1188
+ once: true,
1189
+ });
1190
+ });
1191
+ }
1192
+ finally {
1193
+ opts.abortSignal?.removeEventListener("abort", stopOnAbort);
1194
+ await app.stop().catch(() => undefined);
1195
+ }
1196
+ }
1197
+ async function deliverReplies(params) {
1198
+ const chunkLimit = Math.min(params.textLimit, 4000);
1199
+ for (const payload of params.replies) {
1200
+ const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
1201
+ const text = payload.text ?? "";
1202
+ if (!text && mediaList.length === 0)
1203
+ continue;
1204
+ if (mediaList.length === 0) {
1205
+ for (const chunk of chunkMarkdownText(text, chunkLimit)) {
1206
+ const trimmed = chunk.trim();
1207
+ if (!trimmed || trimmed === SILENT_REPLY_TOKEN)
1208
+ continue;
1209
+ await sendMessageSlack(params.target, trimmed, {
1210
+ token: params.token,
1211
+ threadTs: params.threadTs,
1212
+ });
1213
+ }
1214
+ }
1215
+ else {
1216
+ let first = true;
1217
+ for (const mediaUrl of mediaList) {
1218
+ const caption = first ? text : "";
1219
+ first = false;
1220
+ await sendMessageSlack(params.target, caption, {
1221
+ token: params.token,
1222
+ mediaUrl,
1223
+ threadTs: params.threadTs,
1224
+ });
1225
+ }
1226
+ }
1227
+ params.runtime.log?.(`delivered reply to ${params.target}`);
1228
+ }
1229
+ }
1230
+ export function isSlackRoomAllowedByPolicy(params) {
1231
+ const { groupPolicy, channelAllowlistConfigured, channelAllowed } = params;
1232
+ if (groupPolicy === "disabled")
1233
+ return false;
1234
+ if (groupPolicy === "open")
1235
+ return true;
1236
+ if (!channelAllowlistConfigured)
1237
+ return false;
1238
+ return channelAllowed;
1239
+ }
1240
+ async function deliverSlackSlashReplies(params) {
1241
+ const messages = [];
1242
+ const chunkLimit = Math.min(params.textLimit, 4000);
1243
+ for (const payload of params.replies) {
1244
+ const textRaw = payload.text?.trim() ?? "";
1245
+ const text = textRaw && textRaw !== SILENT_REPLY_TOKEN ? textRaw : undefined;
1246
+ const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
1247
+ const combined = [
1248
+ text ?? "",
1249
+ ...mediaList.map((url) => url.trim()).filter(Boolean),
1250
+ ]
1251
+ .filter(Boolean)
1252
+ .join("\n");
1253
+ if (!combined)
1254
+ continue;
1255
+ for (const chunk of chunkMarkdownText(combined, chunkLimit)) {
1256
+ messages.push(chunk);
1257
+ }
1258
+ }
1259
+ if (messages.length === 0) {
1260
+ await params.respond({
1261
+ text: "No response was generated for that command.",
1262
+ response_type: "ephemeral",
1263
+ });
1264
+ return;
1265
+ }
1266
+ const responseType = params.ephemeral ? "ephemeral" : "in_channel";
1267
+ for (const message of messages) {
1268
+ await params.respond({ text: message, response_type: responseType });
1269
+ }
1270
+ }