@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,1089 @@
1
+ import { ChannelType, Client, Events, GatewayIntentBits, MessageType, Partials, } from "discord.js";
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 { loadConfig } from "../config/config.js";
9
+ import { resolveStorePath, updateLastRoute } from "../config/sessions.js";
10
+ import { danger, logVerbose, shouldLogVerbose } from "../globals.js";
11
+ import { enqueueSystemEvent } from "../infra/system-events.js";
12
+ import { getChildLogger } from "../logging.js";
13
+ import { detectMime } from "../media/mime.js";
14
+ import { saveMediaBuffer } from "../media/store.js";
15
+ import { readProviderAllowFromStore, upsertProviderPairingRequest, } from "../pairing/pairing-store.js";
16
+ import { resolveAgentRoute } from "../routing/resolve-route.js";
17
+ import { sendMessageDiscord } from "./send.js";
18
+ import { normalizeDiscordToken } from "./token.js";
19
+ export function resolveDiscordReplyTarget(opts) {
20
+ if (opts.replyToMode === "off")
21
+ return undefined;
22
+ const replyToId = opts.replyToId?.trim();
23
+ if (!replyToId)
24
+ return undefined;
25
+ if (opts.replyToMode === "all")
26
+ return replyToId;
27
+ return opts.hasReplied ? undefined : replyToId;
28
+ }
29
+ function summarizeAllowList(list) {
30
+ if (!list || list.length === 0)
31
+ return "any";
32
+ const sample = list.slice(0, 4).map((entry) => String(entry));
33
+ const suffix = list.length > sample.length ? ` (+${list.length - sample.length})` : "";
34
+ return `${sample.join(", ")}${suffix}`;
35
+ }
36
+ function summarizeGuilds(entries) {
37
+ if (!entries || Object.keys(entries).length === 0)
38
+ return "any";
39
+ const keys = Object.keys(entries);
40
+ const sample = keys.slice(0, 4);
41
+ const suffix = keys.length > sample.length ? ` (+${keys.length - sample.length})` : "";
42
+ return `${sample.join(", ")}${suffix}`;
43
+ }
44
+ export async function monitorDiscordProvider(opts = {}) {
45
+ const cfg = loadConfig();
46
+ const token = normalizeDiscordToken(opts.token ??
47
+ process.env.DISCORD_BOT_TOKEN ??
48
+ cfg.discord?.token ??
49
+ undefined);
50
+ if (!token) {
51
+ throw new Error("DISCORD_BOT_TOKEN or discord.token is required for Discord gateway");
52
+ }
53
+ const runtime = opts.runtime ?? {
54
+ log: console.log,
55
+ error: console.error,
56
+ exit: (code) => {
57
+ throw new Error(`exit ${code}`);
58
+ },
59
+ };
60
+ const dmConfig = cfg.discord?.dm;
61
+ const guildEntries = cfg.discord?.guilds;
62
+ const groupPolicy = cfg.discord?.groupPolicy ?? "open";
63
+ const dmPolicy = dmConfig?.policy ?? "pairing";
64
+ const allowFrom = dmConfig?.allowFrom;
65
+ const mediaMaxBytes = (opts.mediaMaxMb ?? cfg.discord?.mediaMaxMb ?? 8) * 1024 * 1024;
66
+ const textLimit = resolveTextChunkLimit(cfg, "discord");
67
+ const mentionRegexes = buildMentionRegexes(cfg);
68
+ const ackReaction = (cfg.messages?.ackReaction ?? "").trim();
69
+ const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
70
+ const historyLimit = Math.max(0, opts.historyLimit ?? cfg.discord?.historyLimit ?? 20);
71
+ const replyToMode = opts.replyToMode ?? cfg.discord?.replyToMode ?? "off";
72
+ const dmEnabled = dmConfig?.enabled ?? true;
73
+ const groupDmEnabled = dmConfig?.groupEnabled ?? false;
74
+ const groupDmChannels = dmConfig?.groupChannels;
75
+ if (shouldLogVerbose()) {
76
+ logVerbose(`discord: config dm=${dmEnabled ? "on" : "off"} dmPolicy=${dmPolicy} allowFrom=${summarizeAllowList(allowFrom)} groupDm=${groupDmEnabled ? "on" : "off"} groupDmChannels=${summarizeAllowList(groupDmChannels)} groupPolicy=${groupPolicy} guilds=${summarizeGuilds(guildEntries)} historyLimit=${historyLimit} mediaMaxMb=${Math.round(mediaMaxBytes / (1024 * 1024))}`);
77
+ }
78
+ const client = new Client({
79
+ intents: [
80
+ GatewayIntentBits.Guilds,
81
+ GatewayIntentBits.GuildMessages,
82
+ GatewayIntentBits.GuildMessageReactions,
83
+ GatewayIntentBits.MessageContent,
84
+ GatewayIntentBits.DirectMessages,
85
+ GatewayIntentBits.DirectMessageReactions,
86
+ ],
87
+ partials: [
88
+ Partials.Channel,
89
+ Partials.Message,
90
+ Partials.Reaction,
91
+ Partials.User,
92
+ ],
93
+ });
94
+ const logger = getChildLogger({ module: "discord-auto-reply" });
95
+ const guildHistories = new Map();
96
+ client.once(Events.ClientReady, () => {
97
+ runtime.log?.(`logged in as ${client.user?.tag ?? "unknown"}`);
98
+ });
99
+ client.on(Events.Error, (err) => {
100
+ runtime.error?.(danger(`client error: ${String(err)}`));
101
+ });
102
+ client.on(Events.MessageCreate, async (message) => {
103
+ try {
104
+ if (message.author?.bot)
105
+ return;
106
+ if (!message.author)
107
+ return;
108
+ // Discord.js typing excludes GroupDM for message.channel.type; widen for runtime check.
109
+ const channelType = message.channel.type;
110
+ const isGroupDm = channelType === ChannelType.GroupDM;
111
+ const isDirectMessage = channelType === ChannelType.DM;
112
+ const isGuildMessage = Boolean(message.guild);
113
+ if (isGroupDm && !groupDmEnabled) {
114
+ logVerbose("discord: drop group dm (group dms disabled)");
115
+ return;
116
+ }
117
+ if (isDirectMessage && !dmEnabled) {
118
+ logVerbose("discord: drop dm (dms disabled)");
119
+ return;
120
+ }
121
+ if (isDirectMessage && dmPolicy === "disabled") {
122
+ logVerbose("discord: drop dm (dmPolicy: disabled)");
123
+ return;
124
+ }
125
+ const botId = client.user?.id;
126
+ const forwardedSnapshot = resolveForwardedSnapshot(message);
127
+ const forwardedText = forwardedSnapshot
128
+ ? resolveDiscordSnapshotText(forwardedSnapshot.snapshot)
129
+ : "";
130
+ const baseText = resolveDiscordMessageText(message, forwardedText);
131
+ const wasMentioned = !isDirectMessage &&
132
+ (Boolean(botId && message.mentions.has(botId)) ||
133
+ matchesMentionPatterns(baseText, mentionRegexes));
134
+ if (shouldLogVerbose()) {
135
+ logVerbose(`discord: inbound id=${message.id} guild=${message.guild?.id ?? "dm"} channel=${message.channelId} mention=${wasMentioned ? "yes" : "no"} type=${isDirectMessage ? "dm" : isGroupDm ? "group-dm" : "guild"} content=${baseText ? "yes" : "no"}`);
136
+ }
137
+ if (isGuildMessage &&
138
+ (message.type === MessageType.ChatInputCommand ||
139
+ message.type === MessageType.ContextMenuCommand)) {
140
+ logVerbose("discord: drop channel command message");
141
+ return;
142
+ }
143
+ const guildInfo = isGuildMessage
144
+ ? resolveDiscordGuildEntry({
145
+ guild: message.guild,
146
+ guildEntries,
147
+ })
148
+ : null;
149
+ if (isGuildMessage &&
150
+ guildEntries &&
151
+ Object.keys(guildEntries).length > 0 &&
152
+ !guildInfo) {
153
+ logVerbose(`Blocked discord guild ${message.guild?.id ?? "unknown"} (not in discord.guilds)`);
154
+ return;
155
+ }
156
+ const channelName = (isGuildMessage || isGroupDm) && "name" in message.channel
157
+ ? message.channel.name
158
+ : undefined;
159
+ const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
160
+ const guildSlug = guildInfo?.slug ||
161
+ (message.guild?.name ? normalizeDiscordSlug(message.guild.name) : "");
162
+ const channelConfig = isGuildMessage
163
+ ? resolveDiscordChannelConfig({
164
+ guildInfo,
165
+ channelId: message.channelId,
166
+ channelName,
167
+ channelSlug,
168
+ })
169
+ : null;
170
+ const groupDmAllowed = isGroupDm &&
171
+ resolveGroupDmAllow({
172
+ channels: groupDmChannels,
173
+ channelId: message.channelId,
174
+ channelName,
175
+ channelSlug,
176
+ });
177
+ if (isGroupDm && !groupDmAllowed)
178
+ return;
179
+ const channelAllowlistConfigured = Boolean(guildInfo?.channels) &&
180
+ Object.keys(guildInfo?.channels ?? {}).length > 0;
181
+ const channelAllowed = channelConfig?.allowed !== false;
182
+ if (isGuildMessage &&
183
+ !isDiscordGroupAllowedByPolicy({
184
+ groupPolicy,
185
+ channelAllowlistConfigured,
186
+ channelAllowed,
187
+ })) {
188
+ if (groupPolicy === "disabled") {
189
+ logVerbose("discord: drop guild message (groupPolicy: disabled)");
190
+ }
191
+ else if (!channelAllowlistConfigured) {
192
+ logVerbose("discord: drop guild message (groupPolicy: allowlist, no channel allowlist)");
193
+ }
194
+ else {
195
+ logVerbose(`Blocked discord channel ${message.channelId} not in guild channel allowlist (groupPolicy: allowlist)`);
196
+ }
197
+ return;
198
+ }
199
+ if (isGuildMessage && channelConfig?.allowed === false) {
200
+ logVerbose(`Blocked discord channel ${message.channelId} not in guild channel allowlist`);
201
+ return;
202
+ }
203
+ if (isGuildMessage && historyLimit > 0 && baseText) {
204
+ const history = guildHistories.get(message.channelId) ?? [];
205
+ history.push({
206
+ sender: message.member?.displayName ?? message.author.tag,
207
+ body: baseText,
208
+ timestamp: message.createdTimestamp,
209
+ messageId: message.id,
210
+ });
211
+ while (history.length > historyLimit)
212
+ history.shift();
213
+ guildHistories.set(message.channelId, history);
214
+ }
215
+ const resolvedRequireMention = channelConfig?.requireMention ?? guildInfo?.requireMention ?? true;
216
+ const hasAnyMention = Boolean(!isDirectMessage &&
217
+ (message.mentions?.everyone ||
218
+ (message.mentions?.users?.size ?? 0) > 0 ||
219
+ (message.mentions?.roles?.size ?? 0) > 0));
220
+ const commandAuthorized = resolveDiscordCommandAuthorized({
221
+ isDirectMessage,
222
+ allowFrom,
223
+ guildInfo,
224
+ author: message.author,
225
+ });
226
+ const shouldBypassMention = isGuildMessage &&
227
+ resolvedRequireMention &&
228
+ !wasMentioned &&
229
+ !hasAnyMention &&
230
+ commandAuthorized &&
231
+ hasControlCommand(baseText);
232
+ const canDetectMention = Boolean(botId) || mentionRegexes.length > 0;
233
+ if (isGuildMessage && resolvedRequireMention && canDetectMention) {
234
+ if (!wasMentioned && !shouldBypassMention) {
235
+ logVerbose(`discord: drop guild message (mention required, botId=${botId})`);
236
+ logger.info({
237
+ channelId: message.channelId,
238
+ reason: "no-mention",
239
+ }, "discord: skipping guild message");
240
+ return;
241
+ }
242
+ }
243
+ if (isGuildMessage) {
244
+ const userAllow = guildInfo?.users;
245
+ if (Array.isArray(userAllow) && userAllow.length > 0) {
246
+ const users = normalizeDiscordAllowList(userAllow, [
247
+ "discord:",
248
+ "user:",
249
+ ]);
250
+ const userOk = !users ||
251
+ allowListMatches(users, {
252
+ id: message.author.id,
253
+ name: message.author.username,
254
+ tag: message.author.tag,
255
+ });
256
+ if (!userOk) {
257
+ logVerbose(`Blocked discord guild sender ${message.author.id} (not in guild users allowlist)`);
258
+ return;
259
+ }
260
+ }
261
+ }
262
+ if (isDirectMessage && dmPolicy !== "open") {
263
+ const storeAllowFrom = await readProviderAllowFromStore("discord").catch(() => []);
264
+ const effectiveAllowFrom = Array.from(new Set([...(allowFrom ?? []), ...storeAllowFrom]));
265
+ const allowList = normalizeDiscordAllowList(effectiveAllowFrom, [
266
+ "discord:",
267
+ "user:",
268
+ ]);
269
+ const permitted = allowList != null &&
270
+ allowListMatches(allowList, {
271
+ id: message.author.id,
272
+ name: message.author.username,
273
+ tag: message.author.tag,
274
+ });
275
+ if (!permitted) {
276
+ if (dmPolicy === "pairing") {
277
+ const { code } = await upsertProviderPairingRequest({
278
+ provider: "discord",
279
+ id: message.author.id,
280
+ meta: {
281
+ username: message.author.username,
282
+ tag: message.author.tag,
283
+ },
284
+ });
285
+ logVerbose(`discord pairing request sender=${message.author.id} tag=${message.author.tag} code=${code}`);
286
+ try {
287
+ await message.reply([
288
+ "Nexus: access not configured.",
289
+ "",
290
+ `Pairing code: ${code}`,
291
+ "",
292
+ "Ask the bot owner to approve with:",
293
+ "nexus pairing approve --provider discord <code>",
294
+ ].join("\n"));
295
+ }
296
+ catch (err) {
297
+ logVerbose(`discord pairing reply failed for ${message.author.id}: ${String(err)}`);
298
+ }
299
+ }
300
+ else {
301
+ logVerbose(`Blocked unauthorized discord sender ${message.author.id} (dmPolicy=${dmPolicy})`);
302
+ }
303
+ return;
304
+ }
305
+ }
306
+ const route = resolveAgentRoute({
307
+ cfg,
308
+ provider: "discord",
309
+ guildId: message.guildId ?? undefined,
310
+ peer: {
311
+ kind: isDirectMessage ? "dm" : "channel",
312
+ id: isDirectMessage ? message.author.id : message.channelId,
313
+ },
314
+ });
315
+ const systemText = resolveDiscordSystemEvent(message);
316
+ if (systemText) {
317
+ enqueueSystemEvent(systemText, {
318
+ sessionKey: route.sessionKey,
319
+ contextKey: `discord:system:${message.channelId}:${message.id}`,
320
+ });
321
+ return;
322
+ }
323
+ const media = await resolveMedia(message, mediaMaxBytes);
324
+ const text = message.content?.trim() ??
325
+ media?.placeholder ??
326
+ message.embeds[0]?.description ??
327
+ (forwardedSnapshot ? "<forwarded message>" : "");
328
+ if (!text) {
329
+ logVerbose(`discord: drop message ${message.id} (empty content)`);
330
+ return;
331
+ }
332
+ const shouldAckReaction = () => {
333
+ if (!ackReaction)
334
+ return false;
335
+ if (ackReactionScope === "all")
336
+ return true;
337
+ if (ackReactionScope === "direct")
338
+ return isDirectMessage;
339
+ const isGroupChat = isGuildMessage || isGroupDm;
340
+ if (ackReactionScope === "group-all")
341
+ return isGroupChat;
342
+ if (ackReactionScope === "group-mentions") {
343
+ if (!isGuildMessage)
344
+ return false;
345
+ if (!resolvedRequireMention)
346
+ return false;
347
+ if (!canDetectMention)
348
+ return false;
349
+ return wasMentioned || shouldBypassMention;
350
+ }
351
+ return false;
352
+ };
353
+ if (shouldAckReaction()) {
354
+ message.react(ackReaction).catch((err) => {
355
+ logVerbose(`discord react failed for channel ${message.channelId}: ${String(err)}`);
356
+ });
357
+ }
358
+ const fromLabel = isDirectMessage
359
+ ? buildDirectLabel(message)
360
+ : buildGuildLabel(message);
361
+ const groupRoom = isGuildMessage && channelSlug ? `#${channelSlug}` : undefined;
362
+ const groupSubject = isDirectMessage ? undefined : groupRoom;
363
+ const messageText = text;
364
+ let combinedBody = formatAgentEnvelope({
365
+ provider: "Discord",
366
+ from: fromLabel,
367
+ timestamp: message.createdTimestamp,
368
+ body: messageText,
369
+ });
370
+ let shouldClearHistory = false;
371
+ if (!isDirectMessage) {
372
+ const history = historyLimit > 0 ? (guildHistories.get(message.channelId) ?? []) : [];
373
+ const historyWithoutCurrent = history.length > 0 ? history.slice(0, -1) : [];
374
+ if (historyWithoutCurrent.length > 0) {
375
+ const historyText = historyWithoutCurrent
376
+ .map((entry) => formatAgentEnvelope({
377
+ provider: "Discord",
378
+ from: fromLabel,
379
+ timestamp: entry.timestamp,
380
+ body: `${entry.sender}: ${entry.body} [id:${entry.messageId ?? "unknown"} channel:${message.channelId}]`,
381
+ }))
382
+ .join("\n");
383
+ combinedBody = `[Chat messages since your last reply - for context]\n${historyText}\n\n[Current message - respond to this]\n${combinedBody}`;
384
+ }
385
+ const name = message.author.tag;
386
+ const id = message.author.id;
387
+ combinedBody = `${combinedBody}\n[from: ${name} user id:${id}]`;
388
+ shouldClearHistory = true;
389
+ }
390
+ const replyContext = await resolveReplyContext(message);
391
+ if (replyContext) {
392
+ combinedBody = `[Replied message - for context]\n${replyContext}\n\n${combinedBody}`;
393
+ }
394
+ if (forwardedSnapshot) {
395
+ const forwarderName = message.author.tag ?? message.author.username;
396
+ const forwarder = forwarderName
397
+ ? `${forwarderName} id:${message.author.id}`
398
+ : message.author.id;
399
+ const snapshotText = resolveDiscordSnapshotText(forwardedSnapshot.snapshot) ||
400
+ "<forwarded message>";
401
+ const forwardMetaParts = [
402
+ forwardedSnapshot.messageId
403
+ ? `forwarded message id: ${forwardedSnapshot.messageId}`
404
+ : null,
405
+ forwardedSnapshot.channelId
406
+ ? `channel: ${forwardedSnapshot.channelId}`
407
+ : null,
408
+ forwardedSnapshot.guildId
409
+ ? `guild: ${forwardedSnapshot.guildId}`
410
+ : null,
411
+ typeof forwardedSnapshot.snapshot.type === "number"
412
+ ? `snapshot type: ${forwardedSnapshot.snapshot.type}`
413
+ : null,
414
+ ].filter((entry) => Boolean(entry));
415
+ const forwardedBody = forwardMetaParts.length
416
+ ? `${snapshotText}\n[${forwardMetaParts.join(" ")}]`
417
+ : snapshotText;
418
+ const forwardedEnvelope = formatAgentEnvelope({
419
+ provider: "Discord",
420
+ from: `Forwarded by ${forwarder}`,
421
+ timestamp: forwardedSnapshot.snapshot.createdTimestamp ??
422
+ message.createdTimestamp ??
423
+ undefined,
424
+ body: forwardedBody,
425
+ });
426
+ combinedBody = `[Forwarded message]\n${forwardedEnvelope}\n\n${combinedBody}`;
427
+ }
428
+ const ctxPayload = {
429
+ Body: combinedBody,
430
+ From: isDirectMessage
431
+ ? `discord:${message.author.id}`
432
+ : `group:${message.channelId}`,
433
+ To: `channel:${message.channelId}`,
434
+ SessionKey: route.sessionKey,
435
+ AccountId: route.accountId,
436
+ ChatType: isDirectMessage ? "direct" : "group",
437
+ SenderName: message.member?.displayName ?? message.author.tag,
438
+ SenderId: message.author.id,
439
+ SenderUsername: message.author.username,
440
+ SenderTag: message.author.tag,
441
+ GroupSubject: groupSubject,
442
+ GroupRoom: groupRoom,
443
+ GroupSpace: isGuildMessage
444
+ ? (guildInfo?.id ?? guildSlug) || undefined
445
+ : undefined,
446
+ Provider: "discord",
447
+ WasMentioned: wasMentioned,
448
+ MessageSid: message.id,
449
+ Timestamp: message.createdTimestamp,
450
+ MediaPath: media?.path,
451
+ MediaType: media?.contentType,
452
+ MediaUrl: media?.path,
453
+ CommandAuthorized: commandAuthorized,
454
+ };
455
+ const replyTarget = ctxPayload.To ?? undefined;
456
+ if (!replyTarget) {
457
+ runtime.error?.(danger("discord: missing reply target"));
458
+ return;
459
+ }
460
+ if (isDirectMessage) {
461
+ const sessionCfg = cfg.session;
462
+ const storePath = resolveStorePath(sessionCfg?.store, {
463
+ agentId: route.agentId,
464
+ });
465
+ await updateLastRoute({
466
+ storePath,
467
+ sessionKey: route.mainSessionKey,
468
+ provider: "discord",
469
+ to: `user:${message.author.id}`,
470
+ accountId: route.accountId,
471
+ });
472
+ }
473
+ if (shouldLogVerbose()) {
474
+ const preview = combinedBody.slice(0, 200).replace(/\n/g, "\\n");
475
+ logVerbose(`discord inbound: channel=${message.channelId} from=${ctxPayload.From} preview="${preview}"`);
476
+ }
477
+ let didSendReply = false;
478
+ let typingController;
479
+ const dispatcher = createReplyDispatcher({
480
+ responsePrefix: cfg.messages?.responsePrefix,
481
+ deliver: async (payload) => {
482
+ await deliverReplies({
483
+ replies: [payload],
484
+ target: replyTarget,
485
+ token,
486
+ runtime,
487
+ replyToMode,
488
+ textLimit,
489
+ });
490
+ didSendReply = true;
491
+ },
492
+ onIdle: () => {
493
+ typingController?.markDispatchIdle();
494
+ },
495
+ onError: (err, info) => {
496
+ runtime.error?.(danger(`discord ${info.kind} reply failed: ${String(err)}`));
497
+ },
498
+ });
499
+ const { queuedFinal, counts } = await dispatchReplyFromConfig({
500
+ ctx: ctxPayload,
501
+ cfg,
502
+ dispatcher,
503
+ replyOptions: {
504
+ onReplyStart: () => sendTyping(message),
505
+ onTypingController: (typing) => {
506
+ typingController = typing;
507
+ },
508
+ },
509
+ });
510
+ typingController?.markDispatchIdle();
511
+ if (!queuedFinal) {
512
+ if (isGuildMessage &&
513
+ shouldClearHistory &&
514
+ historyLimit > 0 &&
515
+ didSendReply) {
516
+ guildHistories.set(message.channelId, []);
517
+ }
518
+ return;
519
+ }
520
+ didSendReply = true;
521
+ if (shouldLogVerbose()) {
522
+ const finalCount = counts.final;
523
+ logVerbose(`discord: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${replyTarget}`);
524
+ }
525
+ if (isGuildMessage &&
526
+ shouldClearHistory &&
527
+ historyLimit > 0 &&
528
+ didSendReply) {
529
+ guildHistories.set(message.channelId, []);
530
+ }
531
+ }
532
+ catch (err) {
533
+ runtime.error?.(danger(`handler failed: ${String(err)}`));
534
+ }
535
+ });
536
+ const handleReactionEvent = async (reaction, user, action) => {
537
+ try {
538
+ if (!user || user.bot)
539
+ return;
540
+ const resolvedReaction = reaction.partial
541
+ ? await reaction.fetch()
542
+ : reaction;
543
+ const message = resolvedReaction.message
544
+ .partial
545
+ ? await resolvedReaction.message.fetch()
546
+ : resolvedReaction.message;
547
+ const guild = message.guild;
548
+ if (!guild)
549
+ return;
550
+ const guildInfo = resolveDiscordGuildEntry({
551
+ guild,
552
+ guildEntries,
553
+ });
554
+ if (guildEntries && Object.keys(guildEntries).length > 0 && !guildInfo) {
555
+ return;
556
+ }
557
+ const channelName = "name" in message.channel
558
+ ? (message.channel.name ?? undefined)
559
+ : undefined;
560
+ const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
561
+ const channelConfig = resolveDiscordChannelConfig({
562
+ guildInfo,
563
+ channelId: message.channelId,
564
+ channelName,
565
+ channelSlug,
566
+ });
567
+ if (channelConfig?.allowed === false)
568
+ return;
569
+ const botId = client.user?.id;
570
+ if (botId && user.id === botId)
571
+ return;
572
+ const reactionMode = guildInfo?.reactionNotifications ?? "own";
573
+ const shouldNotify = shouldEmitDiscordReactionNotification({
574
+ mode: reactionMode,
575
+ botId,
576
+ messageAuthorId: message.author?.id,
577
+ userId: user.id,
578
+ userName: user.username,
579
+ userTag: user.tag,
580
+ allowlist: guildInfo?.users,
581
+ });
582
+ if (!shouldNotify)
583
+ return;
584
+ const emojiLabel = formatDiscordReactionEmoji(resolvedReaction);
585
+ const actorLabel = user.tag ?? user.username ?? user.id;
586
+ const guildSlug = guildInfo?.slug ||
587
+ (guild.name ? normalizeDiscordSlug(guild.name) : guild.id);
588
+ const channelLabel = channelSlug
589
+ ? `#${channelSlug}`
590
+ : channelName
591
+ ? `#${normalizeDiscordSlug(channelName)}`
592
+ : `#${message.channelId}`;
593
+ const authorLabel = message.author?.tag ?? message.author?.username;
594
+ const baseText = `Discord reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${message.id}`;
595
+ const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
596
+ const route = resolveAgentRoute({
597
+ cfg,
598
+ provider: "discord",
599
+ guildId: guild.id,
600
+ peer: { kind: "channel", id: message.channelId },
601
+ });
602
+ enqueueSystemEvent(text, {
603
+ sessionKey: route.sessionKey,
604
+ contextKey: `discord:reaction:${action}:${message.id}:${user.id}:${emojiLabel}`,
605
+ });
606
+ }
607
+ catch (err) {
608
+ runtime.error?.(danger(`discord reaction handler failed: ${String(err)}`));
609
+ }
610
+ };
611
+ client.on(Events.MessageReactionAdd, async (reaction, user) => {
612
+ await handleReactionEvent(reaction, user, "added");
613
+ });
614
+ client.on(Events.MessageReactionRemove, async (reaction, user) => {
615
+ await handleReactionEvent(reaction, user, "removed");
616
+ });
617
+ await client.login(token);
618
+ await new Promise((resolve, reject) => {
619
+ const onAbort = () => {
620
+ cleanup();
621
+ void client.destroy();
622
+ resolve();
623
+ };
624
+ const onError = (err) => {
625
+ cleanup();
626
+ reject(err);
627
+ };
628
+ const cleanup = () => {
629
+ opts.abortSignal?.removeEventListener("abort", onAbort);
630
+ client.off(Events.Error, onError);
631
+ };
632
+ opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
633
+ client.on(Events.Error, onError);
634
+ });
635
+ }
636
+ async function resolveMedia(message, maxBytes) {
637
+ const attachment = message.attachments.first();
638
+ if (!attachment)
639
+ return null;
640
+ const res = await fetch(attachment.url);
641
+ if (!res.ok) {
642
+ throw new Error(`Failed to download discord attachment: HTTP ${res.status}`);
643
+ }
644
+ const buffer = Buffer.from(await res.arrayBuffer());
645
+ const mime = await detectMime({
646
+ buffer,
647
+ headerMime: attachment.contentType ?? res.headers.get("content-type"),
648
+ filePath: attachment.name ?? attachment.url,
649
+ });
650
+ const saved = await saveMediaBuffer(buffer, mime, "inbound", maxBytes);
651
+ return {
652
+ path: saved.path,
653
+ contentType: saved.contentType,
654
+ placeholder: inferPlaceholder(attachment),
655
+ };
656
+ }
657
+ function inferPlaceholder(attachment) {
658
+ const mime = attachment.contentType ?? "";
659
+ if (mime.startsWith("image/"))
660
+ return "<media:image>";
661
+ if (mime.startsWith("video/"))
662
+ return "<media:video>";
663
+ if (mime.startsWith("audio/"))
664
+ return "<media:audio>";
665
+ return "<media:document>";
666
+ }
667
+ function resolveDiscordMessageText(message, fallbackText) {
668
+ const attachment = message.attachments.first();
669
+ return (message.content?.trim() ||
670
+ (attachment ? inferPlaceholder(attachment) : "") ||
671
+ message.embeds[0]?.description ||
672
+ fallbackText?.trim() ||
673
+ "");
674
+ }
675
+ function resolveDiscordSnapshotText(snapshot) {
676
+ return snapshot.content?.trim() || snapshot.embeds[0]?.description || "";
677
+ }
678
+ async function resolveReplyContext(message) {
679
+ if (!message.reference?.messageId)
680
+ return null;
681
+ try {
682
+ const referenced = await message.fetchReference();
683
+ if (!referenced?.author)
684
+ return null;
685
+ const referencedText = resolveDiscordMessageText(referenced);
686
+ if (!referencedText)
687
+ return null;
688
+ const channelType = referenced.channel.type;
689
+ const isDirectMessage = channelType === ChannelType.DM;
690
+ const fromLabel = isDirectMessage
691
+ ? buildDirectLabel(referenced)
692
+ : (referenced.member?.displayName ?? referenced.author.tag);
693
+ const body = `${referencedText}\n[discord message id: ${referenced.id} channel: ${referenced.channelId} from: ${referenced.author.tag} user id:${referenced.author.id}]`;
694
+ return formatAgentEnvelope({
695
+ provider: "Discord",
696
+ from: fromLabel,
697
+ timestamp: referenced.createdTimestamp,
698
+ body,
699
+ });
700
+ }
701
+ catch (err) {
702
+ logVerbose(`discord: failed to fetch reply context for ${message.id}: ${String(err)}`);
703
+ return null;
704
+ }
705
+ }
706
+ function buildDirectLabel(message) {
707
+ const username = message.author.tag;
708
+ return `${username} user id:${message.author.id}`;
709
+ }
710
+ function buildGuildLabel(message) {
711
+ const channelName = "name" in message.channel ? message.channel.name : message.channelId;
712
+ return `${message.guild?.name ?? "Guild"} #${channelName} channel id:${message.channelId}`;
713
+ }
714
+ function resolveDiscordSystemEvent(message) {
715
+ switch (message.type) {
716
+ case MessageType.ChannelPinnedMessage:
717
+ return buildDiscordSystemEvent(message, "pinned a message");
718
+ case MessageType.RecipientAdd:
719
+ return buildDiscordSystemEvent(message, "added a recipient");
720
+ case MessageType.RecipientRemove:
721
+ return buildDiscordSystemEvent(message, "removed a recipient");
722
+ case MessageType.UserJoin:
723
+ return buildDiscordSystemEvent(message, "user joined");
724
+ case MessageType.GuildBoost:
725
+ return buildDiscordSystemEvent(message, "boosted the server");
726
+ case MessageType.GuildBoostTier1:
727
+ return buildDiscordSystemEvent(message, "boosted the server (Tier 1 reached)");
728
+ case MessageType.GuildBoostTier2:
729
+ return buildDiscordSystemEvent(message, "boosted the server (Tier 2 reached)");
730
+ case MessageType.GuildBoostTier3:
731
+ return buildDiscordSystemEvent(message, "boosted the server (Tier 3 reached)");
732
+ case MessageType.ThreadCreated:
733
+ return buildDiscordSystemEvent(message, "created a thread");
734
+ case MessageType.AutoModerationAction:
735
+ return buildDiscordSystemEvent(message, "auto moderation action");
736
+ case MessageType.GuildIncidentAlertModeEnabled:
737
+ return buildDiscordSystemEvent(message, "raid protection enabled");
738
+ case MessageType.GuildIncidentAlertModeDisabled:
739
+ return buildDiscordSystemEvent(message, "raid protection disabled");
740
+ case MessageType.GuildIncidentReportRaid:
741
+ return buildDiscordSystemEvent(message, "raid reported");
742
+ case MessageType.GuildIncidentReportFalseAlarm:
743
+ return buildDiscordSystemEvent(message, "raid report marked false alarm");
744
+ case MessageType.StageStart:
745
+ return buildDiscordSystemEvent(message, "stage started");
746
+ case MessageType.StageEnd:
747
+ return buildDiscordSystemEvent(message, "stage ended");
748
+ case MessageType.StageSpeaker:
749
+ return buildDiscordSystemEvent(message, "stage speaker updated");
750
+ case MessageType.StageTopic:
751
+ return buildDiscordSystemEvent(message, "stage topic updated");
752
+ case MessageType.PollResult:
753
+ return buildDiscordSystemEvent(message, "poll results posted");
754
+ case MessageType.PurchaseNotification:
755
+ return buildDiscordSystemEvent(message, "purchase notification");
756
+ default:
757
+ return null;
758
+ }
759
+ }
760
+ function resolveForwardedSnapshot(message) {
761
+ const snapshots = message.messageSnapshots;
762
+ if (!snapshots || snapshots.size === 0)
763
+ return null;
764
+ const snapshot = snapshots.first();
765
+ if (!snapshot)
766
+ return null;
767
+ const reference = message.reference;
768
+ return {
769
+ snapshot,
770
+ messageId: reference?.messageId ?? undefined,
771
+ channelId: reference?.channelId ?? undefined,
772
+ guildId: reference?.guildId ?? undefined,
773
+ };
774
+ }
775
+ function buildDiscordSystemEvent(message, action) {
776
+ const channelName = "name" in message.channel ? message.channel.name : message.channelId;
777
+ const channelType = message.channel.type;
778
+ const location = message.guild?.name
779
+ ? `${message.guild.name} #${channelName}`
780
+ : channelType === ChannelType.GroupDM
781
+ ? `Group DM #${channelName}`
782
+ : "DM";
783
+ const authorLabel = message.author?.tag ?? message.author?.username;
784
+ const actor = authorLabel ? `${authorLabel} ` : "";
785
+ return `Discord system: ${actor}${action} in ${location}`;
786
+ }
787
+ function formatDiscordReactionEmoji(reaction) {
788
+ if (typeof reaction.emoji.toString === "function") {
789
+ const rendered = reaction.emoji.toString();
790
+ if (rendered && rendered !== "[object Object]")
791
+ return rendered;
792
+ }
793
+ if (reaction.emoji.id && reaction.emoji.name) {
794
+ return `${reaction.emoji.name}:${reaction.emoji.id}`;
795
+ }
796
+ return reaction.emoji.name ?? "emoji";
797
+ }
798
+ export function normalizeDiscordAllowList(raw, prefixes) {
799
+ if (!raw || raw.length === 0)
800
+ return null;
801
+ const ids = new Set();
802
+ const names = new Set();
803
+ let allowAll = false;
804
+ for (const rawEntry of raw) {
805
+ let entry = String(rawEntry).trim();
806
+ if (!entry)
807
+ continue;
808
+ if (entry === "*") {
809
+ allowAll = true;
810
+ continue;
811
+ }
812
+ for (const prefix of prefixes) {
813
+ if (entry.toLowerCase().startsWith(prefix)) {
814
+ entry = entry.slice(prefix.length);
815
+ break;
816
+ }
817
+ }
818
+ const mentionMatch = entry.match(/^<[@#][!]?(\d+)>$/);
819
+ if (mentionMatch?.[1]) {
820
+ ids.add(mentionMatch[1]);
821
+ continue;
822
+ }
823
+ entry = entry.trim();
824
+ if (entry.startsWith("@") || entry.startsWith("#")) {
825
+ entry = entry.slice(1);
826
+ }
827
+ if (/^\d+$/.test(entry)) {
828
+ ids.add(entry);
829
+ continue;
830
+ }
831
+ const normalized = normalizeDiscordName(entry);
832
+ if (normalized)
833
+ names.add(normalized);
834
+ const slugged = normalizeDiscordSlug(entry);
835
+ if (slugged)
836
+ names.add(slugged);
837
+ }
838
+ if (!allowAll && ids.size === 0 && names.size === 0)
839
+ return null;
840
+ return { allowAll, ids, names };
841
+ }
842
+ function normalizeDiscordName(value) {
843
+ if (!value)
844
+ return "";
845
+ return value.trim().toLowerCase();
846
+ }
847
+ export function normalizeDiscordSlug(value) {
848
+ if (!value)
849
+ return "";
850
+ let text = value.trim().toLowerCase();
851
+ if (!text)
852
+ return "";
853
+ text = text.replace(/^[@#]+/, "");
854
+ text = text.replace(/[\s_]+/g, "-");
855
+ text = text.replace(/[^a-z0-9-]+/g, "-");
856
+ text = text.replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
857
+ return text;
858
+ }
859
+ export function allowListMatches(allowList, candidates) {
860
+ if (allowList.allowAll)
861
+ return true;
862
+ const { id, name, tag } = candidates;
863
+ if (id && allowList.ids.has(id))
864
+ return true;
865
+ const normalizedName = normalizeDiscordName(name);
866
+ if (normalizedName && allowList.names.has(normalizedName))
867
+ return true;
868
+ const normalizedTag = normalizeDiscordName(tag);
869
+ if (normalizedTag && allowList.names.has(normalizedTag))
870
+ return true;
871
+ const slugName = normalizeDiscordSlug(name);
872
+ if (slugName && allowList.names.has(slugName))
873
+ return true;
874
+ const slugTag = normalizeDiscordSlug(tag);
875
+ if (slugTag && allowList.names.has(slugTag))
876
+ return true;
877
+ return false;
878
+ }
879
+ function resolveDiscordCommandAuthorized(params) {
880
+ const { isDirectMessage, allowFrom, guildInfo, author } = params;
881
+ if (isDirectMessage) {
882
+ if (!Array.isArray(allowFrom) || allowFrom.length === 0)
883
+ return true;
884
+ const allowList = normalizeDiscordAllowList(allowFrom, [
885
+ "discord:",
886
+ "user:",
887
+ ]);
888
+ if (!allowList)
889
+ return true;
890
+ return allowListMatches(allowList, {
891
+ id: author.id,
892
+ name: author.username,
893
+ tag: author.tag,
894
+ });
895
+ }
896
+ const users = guildInfo?.users;
897
+ if (!Array.isArray(users) || users.length === 0)
898
+ return true;
899
+ const allowList = normalizeDiscordAllowList(users, ["discord:", "user:"]);
900
+ if (!allowList)
901
+ return true;
902
+ return allowListMatches(allowList, {
903
+ id: author.id,
904
+ name: author.username,
905
+ tag: author.tag,
906
+ });
907
+ }
908
+ export function shouldEmitDiscordReactionNotification(params) {
909
+ const { mode, botId, messageAuthorId, userId, userName, userTag, allowlist } = params;
910
+ const effectiveMode = mode ?? "own";
911
+ if (effectiveMode === "off")
912
+ return false;
913
+ if (effectiveMode === "own") {
914
+ if (!botId || !messageAuthorId)
915
+ return false;
916
+ return messageAuthorId === botId;
917
+ }
918
+ if (effectiveMode === "allowlist") {
919
+ if (!Array.isArray(allowlist) || allowlist.length === 0)
920
+ return false;
921
+ const users = normalizeDiscordAllowList(allowlist, ["discord:", "user:"]);
922
+ if (!users)
923
+ return false;
924
+ return allowListMatches(users, {
925
+ id: userId,
926
+ name: userName ?? undefined,
927
+ tag: userTag ?? undefined,
928
+ });
929
+ }
930
+ return true;
931
+ }
932
+ export function resolveDiscordGuildEntry(params) {
933
+ const { guild, guildEntries } = params;
934
+ if (!guild || !guildEntries || Object.keys(guildEntries).length === 0) {
935
+ return null;
936
+ }
937
+ const guildId = guild.id;
938
+ const guildSlug = normalizeDiscordSlug(guild.name);
939
+ const direct = guildEntries[guildId];
940
+ if (direct) {
941
+ return {
942
+ id: guildId,
943
+ slug: direct.slug ?? guildSlug,
944
+ requireMention: direct.requireMention,
945
+ reactionNotifications: direct.reactionNotifications,
946
+ users: direct.users,
947
+ channels: direct.channels,
948
+ };
949
+ }
950
+ if (guildSlug && guildEntries[guildSlug]) {
951
+ const entry = guildEntries[guildSlug];
952
+ return {
953
+ id: guildId,
954
+ slug: entry.slug ?? guildSlug,
955
+ requireMention: entry.requireMention,
956
+ reactionNotifications: entry.reactionNotifications,
957
+ users: entry.users,
958
+ channels: entry.channels,
959
+ };
960
+ }
961
+ const matchBySlug = Object.entries(guildEntries).find(([, entry]) => {
962
+ const entrySlug = normalizeDiscordSlug(entry.slug);
963
+ return entrySlug && entrySlug === guildSlug;
964
+ });
965
+ if (matchBySlug) {
966
+ const entry = matchBySlug[1];
967
+ return {
968
+ id: guildId,
969
+ slug: entry.slug ?? guildSlug,
970
+ requireMention: entry.requireMention,
971
+ reactionNotifications: entry.reactionNotifications,
972
+ users: entry.users,
973
+ channels: entry.channels,
974
+ };
975
+ }
976
+ const wildcard = guildEntries["*"];
977
+ if (wildcard) {
978
+ return {
979
+ id: guildId,
980
+ slug: wildcard.slug ?? guildSlug,
981
+ requireMention: wildcard.requireMention,
982
+ reactionNotifications: wildcard.reactionNotifications,
983
+ users: wildcard.users,
984
+ channels: wildcard.channels,
985
+ };
986
+ }
987
+ return null;
988
+ }
989
+ export function resolveDiscordChannelConfig(params) {
990
+ const { guildInfo, channelId, channelName, channelSlug } = params;
991
+ const channelEntries = guildInfo?.channels;
992
+ if (channelEntries && Object.keys(channelEntries).length > 0) {
993
+ const entry = channelEntries[channelId] ??
994
+ (channelSlug
995
+ ? (channelEntries[channelSlug] ?? channelEntries[`#${channelSlug}`])
996
+ : undefined) ??
997
+ (channelName
998
+ ? channelEntries[normalizeDiscordSlug(channelName)]
999
+ : undefined);
1000
+ if (!entry)
1001
+ return { allowed: false };
1002
+ return {
1003
+ allowed: entry.allow !== false,
1004
+ requireMention: entry.requireMention,
1005
+ };
1006
+ }
1007
+ return { allowed: true };
1008
+ }
1009
+ export function isDiscordGroupAllowedByPolicy(params) {
1010
+ const { groupPolicy, channelAllowlistConfigured, channelAllowed } = params;
1011
+ if (groupPolicy === "disabled")
1012
+ return false;
1013
+ if (groupPolicy === "open")
1014
+ return true;
1015
+ if (!channelAllowlistConfigured)
1016
+ return false;
1017
+ return channelAllowed;
1018
+ }
1019
+ export function resolveGroupDmAllow(params) {
1020
+ const { channels, channelId, channelName, channelSlug } = params;
1021
+ if (!channels || channels.length === 0)
1022
+ return true;
1023
+ const allowList = normalizeDiscordAllowList(channels, ["channel:"]);
1024
+ if (!allowList)
1025
+ return true;
1026
+ return allowListMatches(allowList, {
1027
+ id: channelId,
1028
+ name: channelSlug || channelName,
1029
+ });
1030
+ }
1031
+ async function sendTyping(message) {
1032
+ try {
1033
+ const channel = message.channel;
1034
+ if (channel.isSendable()) {
1035
+ await channel.sendTyping();
1036
+ }
1037
+ }
1038
+ catch {
1039
+ /* ignore */
1040
+ }
1041
+ }
1042
+ async function deliverReplies({ replies, target, token, runtime, replyToMode, textLimit, }) {
1043
+ let hasReplied = false;
1044
+ const chunkLimit = Math.min(textLimit, 2000);
1045
+ for (const payload of replies) {
1046
+ const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
1047
+ const text = payload.text ?? "";
1048
+ const replyToId = payload.replyToId;
1049
+ if (!text && mediaList.length === 0)
1050
+ continue;
1051
+ if (mediaList.length === 0) {
1052
+ for (const chunk of chunkMarkdownText(text, chunkLimit)) {
1053
+ const replyTo = resolveDiscordReplyTarget({
1054
+ replyToMode,
1055
+ replyToId,
1056
+ hasReplied,
1057
+ });
1058
+ await sendMessageDiscord(target, chunk, {
1059
+ token,
1060
+ replyTo,
1061
+ });
1062
+ if (replyTo && !hasReplied) {
1063
+ hasReplied = true;
1064
+ }
1065
+ }
1066
+ }
1067
+ else {
1068
+ let first = true;
1069
+ for (const mediaUrl of mediaList) {
1070
+ const caption = first ? text : "";
1071
+ first = false;
1072
+ const replyTo = resolveDiscordReplyTarget({
1073
+ replyToMode,
1074
+ replyToId,
1075
+ hasReplied,
1076
+ });
1077
+ await sendMessageDiscord(target, caption, {
1078
+ token,
1079
+ mediaUrl,
1080
+ replyTo,
1081
+ });
1082
+ if (replyTo && !hasReplied) {
1083
+ hasReplied = true;
1084
+ }
1085
+ }
1086
+ }
1087
+ runtime.log?.(`delivered reply to ${target}`);
1088
+ }
1089
+ }