clawdbot 2026.1.4-1

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 (550) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/LICENSE +21 -0
  3. package/README-header.png +0 -0
  4. package/README.md +297 -0
  5. package/dist/agents/agent-paths.js +17 -0
  6. package/dist/agents/bash-process-registry.js +126 -0
  7. package/dist/agents/bash-tools.js +837 -0
  8. package/dist/agents/clawdbot-tools.js +30 -0
  9. package/dist/agents/clawdis-tools.js +27 -0
  10. package/dist/agents/context.js +34 -0
  11. package/dist/agents/defaults.js +6 -0
  12. package/dist/agents/model-auth.js +112 -0
  13. package/dist/agents/model-catalog.js +55 -0
  14. package/dist/agents/model-fallback.js +191 -0
  15. package/dist/agents/model-scan.js +263 -0
  16. package/dist/agents/model-selection.js +116 -0
  17. package/dist/agents/models-config.js +49 -0
  18. package/dist/agents/pi-embedded-helpers.js +74 -0
  19. package/dist/agents/pi-embedded-runner.js +407 -0
  20. package/dist/agents/pi-embedded-subscribe.js +568 -0
  21. package/dist/agents/pi-embedded-utils.js +20 -0
  22. package/dist/agents/pi-embedded.js +1 -0
  23. package/dist/agents/pi-oauth.js +88 -0
  24. package/dist/agents/pi-tools.js +433 -0
  25. package/dist/agents/sandbox-paths.js +68 -0
  26. package/dist/agents/sandbox.js +644 -0
  27. package/dist/agents/shell-utils.js +53 -0
  28. package/dist/agents/skills-install.js +244 -0
  29. package/dist/agents/skills-status.js +157 -0
  30. package/dist/agents/skills.js +470 -0
  31. package/dist/agents/steerable-agent-loop.js +338 -0
  32. package/dist/agents/steerable-provider-transport.js +48 -0
  33. package/dist/agents/system-prompt.js +104 -0
  34. package/dist/agents/tool-display.js +162 -0
  35. package/dist/agents/tool-images.js +138 -0
  36. package/dist/agents/tools/browser-tool.js +339 -0
  37. package/dist/agents/tools/canvas-tool.js +193 -0
  38. package/dist/agents/tools/common.js +88 -0
  39. package/dist/agents/tools/cron-tool.js +124 -0
  40. package/dist/agents/tools/discord-actions-guild.js +186 -0
  41. package/dist/agents/tools/discord-actions-messaging.js +285 -0
  42. package/dist/agents/tools/discord-actions-moderation.js +70 -0
  43. package/dist/agents/tools/discord-actions.js +56 -0
  44. package/dist/agents/tools/discord-schema.js +199 -0
  45. package/dist/agents/tools/discord-tool.js +16 -0
  46. package/dist/agents/tools/gateway-tool.js +46 -0
  47. package/dist/agents/tools/gateway.js +27 -0
  48. package/dist/agents/tools/image-tool.js +132 -0
  49. package/dist/agents/tools/nodes-tool.js +413 -0
  50. package/dist/agents/tools/nodes-utils.js +92 -0
  51. package/dist/agents/tools/sessions-helpers.js +88 -0
  52. package/dist/agents/tools/sessions-history-tool.js +53 -0
  53. package/dist/agents/tools/sessions-list-tool.js +143 -0
  54. package/dist/agents/tools/sessions-send-helpers.js +100 -0
  55. package/dist/agents/tools/sessions-send-tool.js +347 -0
  56. package/dist/agents/tools/slack-actions.js +129 -0
  57. package/dist/agents/tools/slack-schema.js +59 -0
  58. package/dist/agents/tools/slack-tool.js +16 -0
  59. package/dist/agents/usage.js +39 -0
  60. package/dist/agents/workspace.js +241 -0
  61. package/dist/auto-reply/chunk.js +76 -0
  62. package/dist/auto-reply/envelope.js +38 -0
  63. package/dist/auto-reply/group-activation.js +20 -0
  64. package/dist/auto-reply/heartbeat.js +57 -0
  65. package/dist/auto-reply/model.js +14 -0
  66. package/dist/auto-reply/reply/abort.js +14 -0
  67. package/dist/auto-reply/reply/agent-runner.js +371 -0
  68. package/dist/auto-reply/reply/block-streaming.js +34 -0
  69. package/dist/auto-reply/reply/body.js +29 -0
  70. package/dist/auto-reply/reply/commands.js +207 -0
  71. package/dist/auto-reply/reply/directive-handling.js +361 -0
  72. package/dist/auto-reply/reply/directives.js +47 -0
  73. package/dist/auto-reply/reply/followup-runner.js +149 -0
  74. package/dist/auto-reply/reply/groups.js +91 -0
  75. package/dist/auto-reply/reply/mentions.js +38 -0
  76. package/dist/auto-reply/reply/model-selection.js +114 -0
  77. package/dist/auto-reply/reply/queue.js +399 -0
  78. package/dist/auto-reply/reply/reply-tags.js +26 -0
  79. package/dist/auto-reply/reply/session-updates.js +87 -0
  80. package/dist/auto-reply/reply/session.js +160 -0
  81. package/dist/auto-reply/reply/typing.js +75 -0
  82. package/dist/auto-reply/reply.js +535 -0
  83. package/dist/auto-reply/send-policy.js +28 -0
  84. package/dist/auto-reply/status.js +158 -0
  85. package/dist/auto-reply/templating.js +9 -0
  86. package/dist/auto-reply/thinking.js +49 -0
  87. package/dist/auto-reply/tokens.js +2 -0
  88. package/dist/auto-reply/tool-meta.js +74 -0
  89. package/dist/auto-reply/transcription.js +57 -0
  90. package/dist/auto-reply/types.js +1 -0
  91. package/dist/browser/bridge-server.js +37 -0
  92. package/dist/browser/cdp.js +382 -0
  93. package/dist/browser/chrome.js +432 -0
  94. package/dist/browser/client-actions-core.js +67 -0
  95. package/dist/browser/client-actions-observe.js +24 -0
  96. package/dist/browser/client-actions-types.js +1 -0
  97. package/dist/browser/client-actions.js +3 -0
  98. package/dist/browser/client-fetch.js +43 -0
  99. package/dist/browser/client.js +105 -0
  100. package/dist/browser/config.js +140 -0
  101. package/dist/browser/constants.js +4 -0
  102. package/dist/browser/profiles-service.js +122 -0
  103. package/dist/browser/profiles.js +85 -0
  104. package/dist/browser/pw-ai.js +2 -0
  105. package/dist/browser/pw-session.js +144 -0
  106. package/dist/browser/pw-tools-core.js +363 -0
  107. package/dist/browser/routes/agent.js +535 -0
  108. package/dist/browser/routes/basic.js +155 -0
  109. package/dist/browser/routes/index.js +8 -0
  110. package/dist/browser/routes/tabs.js +105 -0
  111. package/dist/browser/routes/utils.js +62 -0
  112. package/dist/browser/screenshot.js +40 -0
  113. package/dist/browser/server-context.js +377 -0
  114. package/dist/browser/server.js +81 -0
  115. package/dist/browser/target-id.js +18 -0
  116. package/dist/browser/trash.js +21 -0
  117. package/dist/canvas-host/a2ui/.bundle.hash +1 -0
  118. package/dist/canvas-host/a2ui/a2ui.bundle.js +17768 -0
  119. package/dist/canvas-host/a2ui/index.html +246 -0
  120. package/dist/canvas-host/a2ui.js +187 -0
  121. package/dist/canvas-host/server.js +382 -0
  122. package/dist/cli/browser-cli-actions-input.js +459 -0
  123. package/dist/cli/browser-cli-actions-observe.js +56 -0
  124. package/dist/cli/browser-cli-examples.js +31 -0
  125. package/dist/cli/browser-cli-inspect.js +97 -0
  126. package/dist/cli/browser-cli-manage.js +286 -0
  127. package/dist/cli/browser-cli-shared.js +1 -0
  128. package/dist/cli/browser-cli.js +26 -0
  129. package/dist/cli/canvas-cli.js +416 -0
  130. package/dist/cli/cron-cli.js +454 -0
  131. package/dist/cli/deps.js +17 -0
  132. package/dist/cli/dns-cli.js +180 -0
  133. package/dist/cli/gateway-cli.js +489 -0
  134. package/dist/cli/gateway-rpc.js +20 -0
  135. package/dist/cli/hooks-cli.js +135 -0
  136. package/dist/cli/models-cli.js +248 -0
  137. package/dist/cli/nodes-camera.js +57 -0
  138. package/dist/cli/nodes-canvas.js +26 -0
  139. package/dist/cli/nodes-cli.js +946 -0
  140. package/dist/cli/nodes-screen.js +37 -0
  141. package/dist/cli/parse-duration.js +20 -0
  142. package/dist/cli/ports.js +97 -0
  143. package/dist/cli/program.js +406 -0
  144. package/dist/cli/prompt.js +19 -0
  145. package/dist/cli/tui-cli.js +35 -0
  146. package/dist/cli/wait.js +8 -0
  147. package/dist/commands/agent.js +645 -0
  148. package/dist/commands/antigravity-oauth.js +327 -0
  149. package/dist/commands/configure.js +480 -0
  150. package/dist/commands/doctor.js +484 -0
  151. package/dist/commands/health.js +108 -0
  152. package/dist/commands/models/aliases.js +64 -0
  153. package/dist/commands/models/fallbacks.js +99 -0
  154. package/dist/commands/models/image-fallbacks.js +99 -0
  155. package/dist/commands/models/list.js +323 -0
  156. package/dist/commands/models/scan.js +266 -0
  157. package/dist/commands/models/set-image.js +23 -0
  158. package/dist/commands/models/set.js +23 -0
  159. package/dist/commands/models/shared.js +72 -0
  160. package/dist/commands/models.js +7 -0
  161. package/dist/commands/onboard-auth.js +70 -0
  162. package/dist/commands/onboard-helpers.js +295 -0
  163. package/dist/commands/onboard-interactive.js +17 -0
  164. package/dist/commands/onboard-non-interactive.js +202 -0
  165. package/dist/commands/onboard-providers.js +634 -0
  166. package/dist/commands/onboard-remote.js +120 -0
  167. package/dist/commands/onboard-skills.js +148 -0
  168. package/dist/commands/onboard-types.js +1 -0
  169. package/dist/commands/onboard.js +12 -0
  170. package/dist/commands/send.js +124 -0
  171. package/dist/commands/sessions.js +212 -0
  172. package/dist/commands/setup.js +58 -0
  173. package/dist/commands/signal-install.js +135 -0
  174. package/dist/commands/status.js +207 -0
  175. package/dist/commands/update.js +16 -0
  176. package/dist/config/config.js +6 -0
  177. package/dist/config/defaults.js +61 -0
  178. package/dist/config/io.js +147 -0
  179. package/dist/config/legacy-migrate.js +13 -0
  180. package/dist/config/legacy.js +159 -0
  181. package/dist/config/paths.js +71 -0
  182. package/dist/config/schema.js +150 -0
  183. package/dist/config/sessions.js +282 -0
  184. package/dist/config/talk.js +31 -0
  185. package/dist/config/types.js +1 -0
  186. package/dist/config/validation.js +29 -0
  187. package/dist/config/zod-schema.js +831 -0
  188. package/dist/control-ui/assets/index-BFID3yAA.css +1 -0
  189. package/dist/control-ui/assets/index-CE_axlTS.js +2235 -0
  190. package/dist/control-ui/assets/index-CE_axlTS.js.map +1 -0
  191. package/dist/control-ui/index.html +15 -0
  192. package/dist/cron/isolated-agent.js +499 -0
  193. package/dist/cron/run-log.js +72 -0
  194. package/dist/cron/schedule.js +24 -0
  195. package/dist/cron/service.js +471 -0
  196. package/dist/cron/store.js +43 -0
  197. package/dist/cron/types.js +1 -0
  198. package/dist/daemon/constants.js +10 -0
  199. package/dist/daemon/launchd.js +276 -0
  200. package/dist/daemon/legacy.js +63 -0
  201. package/dist/daemon/program-args.js +76 -0
  202. package/dist/daemon/schtasks.js +257 -0
  203. package/dist/daemon/service.js +60 -0
  204. package/dist/daemon/systemd.js +266 -0
  205. package/dist/discord/index.js +2 -0
  206. package/dist/discord/monitor.js +1188 -0
  207. package/dist/discord/probe.js +54 -0
  208. package/dist/discord/send.js +577 -0
  209. package/dist/discord/token.js +8 -0
  210. package/dist/gateway/auth.js +121 -0
  211. package/dist/gateway/call.js +94 -0
  212. package/dist/gateway/chat-attachments.js +41 -0
  213. package/dist/gateway/client.js +180 -0
  214. package/dist/gateway/config-reload.js +274 -0
  215. package/dist/gateway/control-ui.js +184 -0
  216. package/dist/gateway/hooks-mapping.js +282 -0
  217. package/dist/gateway/hooks.js +168 -0
  218. package/dist/gateway/net.js +29 -0
  219. package/dist/gateway/protocol/index.js +61 -0
  220. package/dist/gateway/protocol/schema.js +560 -0
  221. package/dist/gateway/server-bridge-subscriptions.js +93 -0
  222. package/dist/gateway/server-bridge.js +1013 -0
  223. package/dist/gateway/server-browser.js +12 -0
  224. package/dist/gateway/server-chat.js +159 -0
  225. package/dist/gateway/server-constants.js +8 -0
  226. package/dist/gateway/server-discovery.js +62 -0
  227. package/dist/gateway/server-http.js +165 -0
  228. package/dist/gateway/server-methods/agent-job.js +125 -0
  229. package/dist/gateway/server-methods/agent.js +250 -0
  230. package/dist/gateway/server-methods/chat.js +200 -0
  231. package/dist/gateway/server-methods/config.js +50 -0
  232. package/dist/gateway/server-methods/connect.js +6 -0
  233. package/dist/gateway/server-methods/cron.js +83 -0
  234. package/dist/gateway/server-methods/health.js +28 -0
  235. package/dist/gateway/server-methods/models.js +16 -0
  236. package/dist/gateway/server-methods/nodes.js +294 -0
  237. package/dist/gateway/server-methods/providers.js +217 -0
  238. package/dist/gateway/server-methods/send.js +166 -0
  239. package/dist/gateway/server-methods/sessions.js +305 -0
  240. package/dist/gateway/server-methods/skills.js +83 -0
  241. package/dist/gateway/server-methods/system.js +118 -0
  242. package/dist/gateway/server-methods/talk.js +22 -0
  243. package/dist/gateway/server-methods/types.js +1 -0
  244. package/dist/gateway/server-methods/voicewake.js +30 -0
  245. package/dist/gateway/server-methods/web.js +58 -0
  246. package/dist/gateway/server-methods/wizard.js +100 -0
  247. package/dist/gateway/server-methods.js +53 -0
  248. package/dist/gateway/server-providers.js +644 -0
  249. package/dist/gateway/server-shared.js +1 -0
  250. package/dist/gateway/server-utils.js +35 -0
  251. package/dist/gateway/server.js +1437 -0
  252. package/dist/gateway/session-utils.js +216 -0
  253. package/dist/gateway/ws-log.js +349 -0
  254. package/dist/gateway/ws-logging.js +8 -0
  255. package/dist/globals.js +41 -0
  256. package/dist/hooks/gmail-ops.js +236 -0
  257. package/dist/hooks/gmail-setup-utils.js +278 -0
  258. package/dist/hooks/gmail-watcher.js +175 -0
  259. package/dist/hooks/gmail.js +177 -0
  260. package/dist/imessage/client.js +165 -0
  261. package/dist/imessage/index.js +3 -0
  262. package/dist/imessage/monitor.js +272 -0
  263. package/dist/imessage/probe.js +26 -0
  264. package/dist/imessage/send.js +83 -0
  265. package/dist/imessage/targets.js +176 -0
  266. package/dist/index.js +50 -0
  267. package/dist/infra/agent-events.js +46 -0
  268. package/dist/infra/binaries.js +9 -0
  269. package/dist/infra/bonjour-discovery.js +163 -0
  270. package/dist/infra/bonjour.js +200 -0
  271. package/dist/infra/bridge/server.js +562 -0
  272. package/dist/infra/canvas-host-url.js +54 -0
  273. package/dist/infra/env.js +8 -0
  274. package/dist/infra/errors.js +28 -0
  275. package/dist/infra/gateway-lock.js +8 -0
  276. package/dist/infra/heartbeat-events.js +21 -0
  277. package/dist/infra/heartbeat-runner.js +453 -0
  278. package/dist/infra/heartbeat-wake.js +61 -0
  279. package/dist/infra/is-main.js +37 -0
  280. package/dist/infra/machine-name.js +40 -0
  281. package/dist/infra/node-pairing.js +211 -0
  282. package/dist/infra/pam.js +42 -0
  283. package/dist/infra/path-env.js +92 -0
  284. package/dist/infra/ports.js +87 -0
  285. package/dist/infra/provider-summary.js +80 -0
  286. package/dist/infra/restart.js +29 -0
  287. package/dist/infra/retry.js +16 -0
  288. package/dist/infra/runtime-guard.js +59 -0
  289. package/dist/infra/system-events.js +44 -0
  290. package/dist/infra/system-presence.js +216 -0
  291. package/dist/infra/tailnet.js +46 -0
  292. package/dist/infra/tailscale.js +149 -0
  293. package/dist/infra/voicewake.js +77 -0
  294. package/dist/infra/widearea-dns.js +123 -0
  295. package/dist/infra/ws.js +13 -0
  296. package/dist/logger.js +52 -0
  297. package/dist/logging.js +490 -0
  298. package/dist/macos/gateway-daemon.js +141 -0
  299. package/dist/macos/relay.js +46 -0
  300. package/dist/media/constants.js +33 -0
  301. package/dist/media/host.js +42 -0
  302. package/dist/media/image-ops.js +121 -0
  303. package/dist/media/mime.js +115 -0
  304. package/dist/media/parse.js +81 -0
  305. package/dist/media/server.js +64 -0
  306. package/dist/media/store.js +139 -0
  307. package/dist/process/command-queue.js +97 -0
  308. package/dist/process/exec.js +75 -0
  309. package/dist/protocol.schema.json +2918 -0
  310. package/dist/provider-web.js +8 -0
  311. package/dist/providers/web/index.js +2 -0
  312. package/dist/runtime.js +8 -0
  313. package/dist/sessions/send-policy.js +68 -0
  314. package/dist/signal/client.js +134 -0
  315. package/dist/signal/daemon.js +69 -0
  316. package/dist/signal/index.js +3 -0
  317. package/dist/signal/monitor.js +336 -0
  318. package/dist/signal/probe.js +46 -0
  319. package/dist/signal/send.js +91 -0
  320. package/dist/slack/actions.js +97 -0
  321. package/dist/slack/index.js +5 -0
  322. package/dist/slack/monitor.js +1029 -0
  323. package/dist/slack/probe.js +47 -0
  324. package/dist/slack/send.js +131 -0
  325. package/dist/slack/token.js +10 -0
  326. package/dist/telegram/bot.js +394 -0
  327. package/dist/telegram/download.js +34 -0
  328. package/dist/telegram/index.js +4 -0
  329. package/dist/telegram/monitor.js +47 -0
  330. package/dist/telegram/probe.js +63 -0
  331. package/dist/telegram/proxy.js +9 -0
  332. package/dist/telegram/send.js +138 -0
  333. package/dist/telegram/token.js +30 -0
  334. package/dist/telegram/webhook-set.js +12 -0
  335. package/dist/telegram/webhook.js +56 -0
  336. package/dist/tui/commands.js +74 -0
  337. package/dist/tui/components/assistant-message.js +16 -0
  338. package/dist/tui/components/chat-log.js +92 -0
  339. package/dist/tui/components/custom-editor.js +53 -0
  340. package/dist/tui/components/selectors.js +8 -0
  341. package/dist/tui/components/tool-execution.js +111 -0
  342. package/dist/tui/components/user-message.js +17 -0
  343. package/dist/tui/gateway-chat.js +140 -0
  344. package/dist/tui/layout.js +41 -0
  345. package/dist/tui/message-list.js +57 -0
  346. package/dist/tui/theme/theme.js +80 -0
  347. package/dist/tui/theme.js +25 -0
  348. package/dist/tui/tui.js +708 -0
  349. package/dist/utils.js +133 -0
  350. package/dist/version.js +18 -0
  351. package/dist/web/active-listener.js +7 -0
  352. package/dist/web/auto-reply.js +1203 -0
  353. package/dist/web/inbound.js +481 -0
  354. package/dist/web/login-qr.js +204 -0
  355. package/dist/web/login.js +59 -0
  356. package/dist/web/media.js +148 -0
  357. package/dist/web/outbound.js +67 -0
  358. package/dist/web/qr-image.js +97 -0
  359. package/dist/web/reconnect.js +60 -0
  360. package/dist/web/reply-heartbeat-wake.js +61 -0
  361. package/dist/web/session.js +346 -0
  362. package/dist/wizard/clack-prompter.js +56 -0
  363. package/dist/wizard/onboarding.js +452 -0
  364. package/dist/wizard/prompts.js +6 -0
  365. package/dist/wizard/session.js +203 -0
  366. package/docs/AGENTS.default.md +116 -0
  367. package/docs/CNAME +1 -0
  368. package/docs/RELEASING.md +64 -0
  369. package/docs/_config.yml +51 -0
  370. package/docs/_layouts/default.html +145 -0
  371. package/docs/agent-send.md +21 -0
  372. package/docs/agent.md +104 -0
  373. package/docs/android/connect.md +131 -0
  374. package/docs/architecture.md +89 -0
  375. package/docs/assets/markdown.css +130 -0
  376. package/docs/assets/pixel-lobster.svg +60 -0
  377. package/docs/assets/terminal.css +497 -0
  378. package/docs/assets/theme.js +55 -0
  379. package/docs/audio.md +50 -0
  380. package/docs/background-process.md +74 -0
  381. package/docs/bash.md +32 -0
  382. package/docs/bonjour.md +159 -0
  383. package/docs/browser.md +289 -0
  384. package/docs/camera.md +152 -0
  385. package/docs/clawd.md +199 -0
  386. package/docs/clawdbot-mac.md +104 -0
  387. package/docs/configuration.md +1177 -0
  388. package/docs/control-api.md +49 -0
  389. package/docs/control-ui.md +83 -0
  390. package/docs/cron.md +374 -0
  391. package/docs/dashboard.md +17 -0
  392. package/docs/device-models.md +46 -0
  393. package/docs/discord.md +293 -0
  394. package/docs/discovery.md +112 -0
  395. package/docs/docker.md +251 -0
  396. package/docs/docs.json +86 -0
  397. package/docs/doctor.md +47 -0
  398. package/docs/elevated.md +31 -0
  399. package/docs/faq.md +640 -0
  400. package/docs/gateway/pairing.md +109 -0
  401. package/docs/gateway-lock.md +28 -0
  402. package/docs/gateway.md +174 -0
  403. package/docs/gmail-pubsub.md +191 -0
  404. package/docs/grammy.md +27 -0
  405. package/docs/group-messages.md +71 -0
  406. package/docs/groups.md +78 -0
  407. package/docs/health.md +28 -0
  408. package/docs/heartbeat.md +64 -0
  409. package/docs/images.md +52 -0
  410. package/docs/imessage.md +63 -0
  411. package/docs/index.md +182 -0
  412. package/docs/ios/connect.md +177 -0
  413. package/docs/ios/spec.md +236 -0
  414. package/docs/location-command.md +95 -0
  415. package/docs/logging.md +99 -0
  416. package/docs/lore.md +131 -0
  417. package/docs/mac/bun.md +133 -0
  418. package/docs/mac/canvas.md +161 -0
  419. package/docs/mac/child-process.md +72 -0
  420. package/docs/mac/dev-setup.md +81 -0
  421. package/docs/mac/health.md +28 -0
  422. package/docs/mac/icon.md +26 -0
  423. package/docs/mac/logging.md +51 -0
  424. package/docs/mac/menu-bar.md +69 -0
  425. package/docs/mac/peekaboo.md +170 -0
  426. package/docs/mac/permissions.md +40 -0
  427. package/docs/mac/release.md +76 -0
  428. package/docs/mac/remote.md +57 -0
  429. package/docs/mac/signing.md +41 -0
  430. package/docs/mac/skills.md +27 -0
  431. package/docs/mac/voice-overlay.md +52 -0
  432. package/docs/mac/voicewake.md +56 -0
  433. package/docs/mac/webchat.md +27 -0
  434. package/docs/mac/xpc.md +40 -0
  435. package/docs/models.md +90 -0
  436. package/docs/nix.md +49 -0
  437. package/docs/nodes.md +157 -0
  438. package/docs/onboarding-config-protocol.md +29 -0
  439. package/docs/onboarding.md +185 -0
  440. package/docs/presence.md +133 -0
  441. package/docs/queue.md +78 -0
  442. package/docs/refactor/browser-control-simplification.md +58 -0
  443. package/docs/refactor/canvas-a2ui.md +93 -0
  444. package/docs/refactor/cli-unification.md +64 -0
  445. package/docs/refactor/gateway-client.md +31 -0
  446. package/docs/refactor/gateway.md +99 -0
  447. package/docs/refactor/new-arch.md +171 -0
  448. package/docs/refactor/tui.md +26 -0
  449. package/docs/refactor/web-gateway-troubleshooting.md +37 -0
  450. package/docs/refactor/webagent-session.md +46 -0
  451. package/docs/remote-gateway-readme.md +148 -0
  452. package/docs/remote.md +66 -0
  453. package/docs/research/memory.md +227 -0
  454. package/docs/rpc.md +35 -0
  455. package/docs/security.md +168 -0
  456. package/docs/session-tool.md +119 -0
  457. package/docs/session.md +84 -0
  458. package/docs/sessions.md +8 -0
  459. package/docs/setup.md +118 -0
  460. package/docs/signal.md +113 -0
  461. package/docs/skills-config.md +58 -0
  462. package/docs/skills.md +149 -0
  463. package/docs/slack.md +158 -0
  464. package/docs/surface.md +20 -0
  465. package/docs/tailscale.md +71 -0
  466. package/docs/talk.md +79 -0
  467. package/docs/telegram.md +90 -0
  468. package/docs/templates/AGENTS.md +126 -0
  469. package/docs/templates/BOOTSTRAP.md +53 -0
  470. package/docs/templates/IDENTITY.md +17 -0
  471. package/docs/templates/SOUL.md +41 -0
  472. package/docs/templates/TOOLS.md +41 -0
  473. package/docs/templates/USER.md +22 -0
  474. package/docs/test.md +35 -0
  475. package/docs/thinking.md +46 -0
  476. package/docs/tools.md +248 -0
  477. package/docs/troubleshooting.md +227 -0
  478. package/docs/tui.md +69 -0
  479. package/docs/typebox.md +42 -0
  480. package/docs/voicewake.md +61 -0
  481. package/docs/web.md +115 -0
  482. package/docs/webchat.md +34 -0
  483. package/docs/webhook.md +132 -0
  484. package/docs/whatsapp-clawd.jpg +0 -0
  485. package/docs/whatsapp.md +142 -0
  486. package/docs/wizard.md +158 -0
  487. package/package.json +186 -0
  488. package/skills/apple-notes/SKILL.md +50 -0
  489. package/skills/apple-reminders/SKILL.md +67 -0
  490. package/skills/bear-notes/SKILL.md +79 -0
  491. package/skills/bird/SKILL.md +25 -0
  492. package/skills/blogwatcher/SKILL.md +46 -0
  493. package/skills/blucli/SKILL.md +27 -0
  494. package/skills/brave-search/SKILL.md +30 -0
  495. package/skills/brave-search/scripts/content.mjs +53 -0
  496. package/skills/brave-search/scripts/search.mjs +79 -0
  497. package/skills/camsnap/SKILL.md +25 -0
  498. package/skills/clawdhub/SKILL.md +53 -0
  499. package/skills/coding-agent/SKILL.md +275 -0
  500. package/skills/discord/SKILL.md +369 -0
  501. package/skills/eightctl/SKILL.md +29 -0
  502. package/skills/food-order/SKILL.md +41 -0
  503. package/skills/gemini/SKILL.md +23 -0
  504. package/skills/gifgrep/SKILL.md +47 -0
  505. package/skills/github/SKILL.md +47 -0
  506. package/skills/gog/SKILL.md +36 -0
  507. package/skills/goplaces/SKILL.md +30 -0
  508. package/skills/imsg/SKILL.md +25 -0
  509. package/skills/local-places/SERVER_README.md +101 -0
  510. package/skills/local-places/SKILL.md +91 -0
  511. package/skills/local-places/pyproject.toml +27 -0
  512. package/skills/local-places/src/local_places/__init__.py +2 -0
  513. package/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  514. package/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  515. package/skills/local-places/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  516. package/skills/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  517. package/skills/local-places/src/local_places/google_places.py +314 -0
  518. package/skills/local-places/src/local_places/main.py +65 -0
  519. package/skills/local-places/src/local_places/schemas.py +107 -0
  520. package/skills/mcporter/SKILL.md +38 -0
  521. package/skills/nano-banana-pro/SKILL.md +29 -0
  522. package/skills/nano-banana-pro/scripts/generate_image.py +167 -0
  523. package/skills/nano-pdf/SKILL.md +20 -0
  524. package/skills/notion/SKILL.md +156 -0
  525. package/skills/obsidian/SKILL.md +55 -0
  526. package/skills/openai-image-gen/SKILL.md +31 -0
  527. package/skills/openai-image-gen/scripts/gen.py +173 -0
  528. package/skills/openai-whisper/SKILL.md +19 -0
  529. package/skills/openai-whisper-api/SKILL.md +43 -0
  530. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  531. package/skills/openhue/SKILL.md +30 -0
  532. package/skills/oracle/SKILL.md +105 -0
  533. package/skills/ordercli/SKILL.md +47 -0
  534. package/skills/peekaboo/SKILL.md +153 -0
  535. package/skills/qmd/SKILL.md +26 -0
  536. package/skills/sag/SKILL.md +62 -0
  537. package/skills/slack/SKILL.md +143 -0
  538. package/skills/songsee/SKILL.md +29 -0
  539. package/skills/sonoscli/SKILL.md +26 -0
  540. package/skills/spotify-player/SKILL.md +34 -0
  541. package/skills/summarize/SKILL.md +49 -0
  542. package/skills/things-mac/SKILL.md +61 -0
  543. package/skills/tmux/SKILL.md +121 -0
  544. package/skills/tmux/scripts/find-sessions.sh +112 -0
  545. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  546. package/skills/trello/SKILL.md +84 -0
  547. package/skills/video-frames/SKILL.md +29 -0
  548. package/skills/video-frames/scripts/frame.sh +81 -0
  549. package/skills/wacli/SKILL.md +42 -0
  550. package/skills/weather/SKILL.md +49 -0
@@ -0,0 +1,216 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import os from "node:os";
3
+ const entries = new Map();
4
+ const TTL_MS = 5 * 60 * 1000; // 5 minutes
5
+ const MAX_ENTRIES = 200;
6
+ function normalizePresenceKey(key) {
7
+ if (!key)
8
+ return undefined;
9
+ const trimmed = key.trim();
10
+ if (!trimmed)
11
+ return undefined;
12
+ return trimmed.toLowerCase();
13
+ }
14
+ function resolvePrimaryIPv4() {
15
+ const nets = os.networkInterfaces();
16
+ const prefer = ["en0", "eth0"];
17
+ const pick = (names) => {
18
+ for (const name of names) {
19
+ const list = nets[name];
20
+ const entry = list?.find((n) => n.family === "IPv4" && !n.internal);
21
+ if (entry?.address)
22
+ return entry.address;
23
+ }
24
+ for (const list of Object.values(nets)) {
25
+ const entry = list?.find((n) => n.family === "IPv4" && !n.internal);
26
+ if (entry?.address)
27
+ return entry.address;
28
+ }
29
+ return undefined;
30
+ };
31
+ return pick(prefer) ?? os.hostname();
32
+ }
33
+ function initSelfPresence() {
34
+ const host = os.hostname();
35
+ const ip = resolvePrimaryIPv4() ?? undefined;
36
+ const version = process.env.CLAWDBOT_VERSION ??
37
+ process.env.npm_package_version ??
38
+ "unknown";
39
+ const modelIdentifier = (() => {
40
+ const p = os.platform();
41
+ if (p === "darwin") {
42
+ const res = spawnSync("sysctl", ["-n", "hw.model"], {
43
+ encoding: "utf-8",
44
+ });
45
+ const out = typeof res.stdout === "string" ? res.stdout.trim() : "";
46
+ return out.length > 0 ? out : undefined;
47
+ }
48
+ return os.arch();
49
+ })();
50
+ const macOSVersion = () => {
51
+ const res = spawnSync("sw_vers", ["-productVersion"], {
52
+ encoding: "utf-8",
53
+ });
54
+ const out = typeof res.stdout === "string" ? res.stdout.trim() : "";
55
+ return out.length > 0 ? out : os.release();
56
+ };
57
+ const platform = (() => {
58
+ const p = os.platform();
59
+ const rel = os.release();
60
+ if (p === "darwin")
61
+ return `macos ${macOSVersion()}`;
62
+ if (p === "win32")
63
+ return `windows ${rel}`;
64
+ return `${p} ${rel}`;
65
+ })();
66
+ const deviceFamily = (() => {
67
+ const p = os.platform();
68
+ if (p === "darwin")
69
+ return "Mac";
70
+ if (p === "win32")
71
+ return "Windows";
72
+ if (p === "linux")
73
+ return "Linux";
74
+ return p;
75
+ })();
76
+ const text = `Gateway: ${host}${ip ? ` (${ip})` : ""} · app ${version} · mode gateway · reason self`;
77
+ const selfEntry = {
78
+ host,
79
+ ip,
80
+ version,
81
+ platform,
82
+ deviceFamily,
83
+ modelIdentifier,
84
+ mode: "gateway",
85
+ reason: "self",
86
+ text,
87
+ ts: Date.now(),
88
+ };
89
+ const key = host.toLowerCase();
90
+ entries.set(key, selfEntry);
91
+ }
92
+ function ensureSelfPresence() {
93
+ // If the map was somehow cleared (e.g., hot reload or a new worker spawn that
94
+ // skipped module evaluation), re-seed with a local entry so UIs always show
95
+ // at least the current gateway.
96
+ if (entries.size === 0) {
97
+ initSelfPresence();
98
+ }
99
+ }
100
+ function touchSelfPresence() {
101
+ const host = os.hostname();
102
+ const key = host.toLowerCase();
103
+ const existing = entries.get(key);
104
+ if (existing) {
105
+ entries.set(key, { ...existing, ts: Date.now() });
106
+ }
107
+ else {
108
+ initSelfPresence();
109
+ }
110
+ }
111
+ initSelfPresence();
112
+ function parsePresence(text) {
113
+ const trimmed = text.trim();
114
+ const pattern = /Node:\s*([^ (]+)\s*\(([^)]+)\)\s*·\s*app\s*([^·]+?)\s*·\s*last input\s*([0-9]+)s ago\s*·\s*mode\s*([^·]+?)\s*·\s*reason\s*(.+)$/i;
115
+ const match = trimmed.match(pattern);
116
+ if (!match) {
117
+ return { text: trimmed, ts: Date.now() };
118
+ }
119
+ const [, host, ip, version, lastInputStr, mode, reasonRaw] = match;
120
+ const lastInputSeconds = Number.parseInt(lastInputStr, 10);
121
+ const reason = reasonRaw.trim();
122
+ return {
123
+ host: host.trim(),
124
+ ip: ip.trim(),
125
+ version: version.trim(),
126
+ lastInputSeconds: Number.isFinite(lastInputSeconds)
127
+ ? lastInputSeconds
128
+ : undefined,
129
+ mode: mode.trim(),
130
+ reason,
131
+ text: trimmed,
132
+ ts: Date.now(),
133
+ };
134
+ }
135
+ export function updateSystemPresence(payload) {
136
+ ensureSelfPresence();
137
+ const parsed = parsePresence(payload.text);
138
+ const key = normalizePresenceKey(payload.instanceId) ||
139
+ normalizePresenceKey(parsed.instanceId) ||
140
+ normalizePresenceKey(parsed.host) ||
141
+ parsed.ip ||
142
+ parsed.text.slice(0, 64) ||
143
+ os.hostname().toLowerCase();
144
+ const hadExisting = entries.has(key);
145
+ const existing = entries.get(key) ?? {};
146
+ const merged = {
147
+ ...existing,
148
+ ...parsed,
149
+ host: payload.host ?? parsed.host ?? existing.host,
150
+ ip: payload.ip ?? parsed.ip ?? existing.ip,
151
+ version: payload.version ?? parsed.version ?? existing.version,
152
+ platform: payload.platform ?? existing.platform,
153
+ deviceFamily: payload.deviceFamily ?? existing.deviceFamily,
154
+ modelIdentifier: payload.modelIdentifier ?? existing.modelIdentifier,
155
+ mode: payload.mode ?? parsed.mode ?? existing.mode,
156
+ lastInputSeconds: payload.lastInputSeconds ??
157
+ parsed.lastInputSeconds ??
158
+ existing.lastInputSeconds,
159
+ reason: payload.reason ?? parsed.reason ?? existing.reason,
160
+ instanceId: payload.instanceId ?? parsed.instanceId ?? existing.instanceId,
161
+ text: payload.text || parsed.text || existing.text,
162
+ ts: Date.now(),
163
+ };
164
+ entries.set(key, merged);
165
+ const trackKeys = ["host", "ip", "version", "mode", "reason"];
166
+ const changes = {};
167
+ const changedKeys = [];
168
+ for (const k of trackKeys) {
169
+ const prev = existing[k];
170
+ const next = merged[k];
171
+ if (prev !== next) {
172
+ changes[k] = next;
173
+ changedKeys.push(k);
174
+ }
175
+ }
176
+ return {
177
+ key,
178
+ previous: hadExisting ? existing : undefined,
179
+ next: merged,
180
+ changes,
181
+ changedKeys,
182
+ };
183
+ }
184
+ export function upsertPresence(key, presence) {
185
+ ensureSelfPresence();
186
+ const normalizedKey = normalizePresenceKey(key) ?? os.hostname().toLowerCase();
187
+ const existing = entries.get(normalizedKey) ?? {};
188
+ const merged = {
189
+ ...existing,
190
+ ...presence,
191
+ ts: Date.now(),
192
+ text: presence.text ||
193
+ existing.text ||
194
+ `Node: ${presence.host ?? existing.host ?? "unknown"} · mode ${presence.mode ?? existing.mode ?? "unknown"}`,
195
+ };
196
+ entries.set(normalizedKey, merged);
197
+ }
198
+ export function listSystemPresence() {
199
+ ensureSelfPresence();
200
+ // prune expired
201
+ const now = Date.now();
202
+ for (const [k, v] of entries) {
203
+ if (now - v.ts > TTL_MS)
204
+ entries.delete(k);
205
+ }
206
+ // enforce max size (LRU by ts)
207
+ if (entries.size > MAX_ENTRIES) {
208
+ const sorted = [...entries.entries()].sort((a, b) => a[1].ts - b[1].ts);
209
+ const toDrop = entries.size - MAX_ENTRIES;
210
+ for (let i = 0; i < toDrop; i++) {
211
+ entries.delete(sorted[i][0]);
212
+ }
213
+ }
214
+ touchSelfPresence();
215
+ return [...entries.values()].sort((a, b) => b.ts - a.ts);
216
+ }
@@ -0,0 +1,46 @@
1
+ import os from "node:os";
2
+ function isTailnetIPv4(address) {
3
+ const parts = address.split(".");
4
+ if (parts.length !== 4)
5
+ return false;
6
+ const octets = parts.map((p) => Number.parseInt(p, 10));
7
+ if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255))
8
+ return false;
9
+ // Tailscale IPv4 range: 100.64.0.0/10
10
+ // https://tailscale.com/kb/1015/100.x-addresses
11
+ const [a, b] = octets;
12
+ return a === 100 && b >= 64 && b <= 127;
13
+ }
14
+ function isTailnetIPv6(address) {
15
+ // Tailscale IPv6 ULA prefix: fd7a:115c:a1e0::/48
16
+ // (stable across tailnets; nodes get per-device suffixes)
17
+ const normalized = address.trim().toLowerCase();
18
+ return normalized.startsWith("fd7a:115c:a1e0:");
19
+ }
20
+ export function listTailnetAddresses() {
21
+ const ipv4 = [];
22
+ const ipv6 = [];
23
+ const ifaces = os.networkInterfaces();
24
+ for (const entries of Object.values(ifaces)) {
25
+ if (!entries)
26
+ continue;
27
+ for (const e of entries) {
28
+ if (!e || e.internal)
29
+ continue;
30
+ const address = e.address?.trim();
31
+ if (!address)
32
+ continue;
33
+ if (isTailnetIPv4(address))
34
+ ipv4.push(address);
35
+ if (isTailnetIPv6(address))
36
+ ipv6.push(address);
37
+ }
38
+ }
39
+ return { ipv4: [...new Set(ipv4)], ipv6: [...new Set(ipv6)] };
40
+ }
41
+ export function pickPrimaryTailnetIPv4() {
42
+ return listTailnetAddresses().ipv4[0];
43
+ }
44
+ export function pickPrimaryTailnetIPv6() {
45
+ return listTailnetAddresses().ipv6[0];
46
+ }
@@ -0,0 +1,149 @@
1
+ import { existsSync } from "node:fs";
2
+ import chalk from "chalk";
3
+ import { promptYesNo } from "../cli/prompt.js";
4
+ import { danger, info, logVerbose, shouldLogVerbose, warn, } from "../globals.js";
5
+ import { runExec } from "../process/exec.js";
6
+ import { defaultRuntime } from "../runtime.js";
7
+ import { ensureBinary } from "./binaries.js";
8
+ export async function getTailnetHostname(exec = runExec) {
9
+ // Derive tailnet hostname (or IP fallback) from tailscale status JSON.
10
+ const candidates = [
11
+ "tailscale",
12
+ "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
13
+ ];
14
+ let lastError;
15
+ for (const candidate of candidates) {
16
+ if (candidate.startsWith("/") && !existsSync(candidate))
17
+ continue;
18
+ try {
19
+ const { stdout } = await exec(candidate, ["status", "--json"]);
20
+ const parsed = stdout
21
+ ? JSON.parse(stdout)
22
+ : {};
23
+ const self = typeof parsed.Self === "object" && parsed.Self !== null
24
+ ? parsed.Self
25
+ : undefined;
26
+ const dns = typeof self?.DNSName === "string"
27
+ ? self.DNSName
28
+ : undefined;
29
+ const ips = Array.isArray(self?.TailscaleIPs)
30
+ ? self.TailscaleIPs
31
+ : [];
32
+ if (dns && dns.length > 0)
33
+ return dns.replace(/\.$/, "");
34
+ if (ips.length > 0)
35
+ return ips[0];
36
+ throw new Error("Could not determine Tailscale DNS or IP");
37
+ }
38
+ catch (err) {
39
+ lastError = err;
40
+ }
41
+ }
42
+ throw lastError ?? new Error("Could not determine Tailscale DNS or IP");
43
+ }
44
+ export async function ensureGoInstalled(exec = runExec, prompt = promptYesNo, runtime = defaultRuntime) {
45
+ // Ensure Go toolchain is present; offer Homebrew install if missing.
46
+ const hasGo = await exec("go", ["version"]).then(() => true, () => false);
47
+ if (hasGo)
48
+ return;
49
+ const install = await prompt("Go is not installed. Install via Homebrew (brew install go)?", true);
50
+ if (!install) {
51
+ runtime.error("Go is required to build tailscaled from source. Aborting.");
52
+ runtime.exit(1);
53
+ }
54
+ logVerbose("Installing Go via Homebrew…");
55
+ await exec("brew", ["install", "go"]);
56
+ }
57
+ export async function ensureTailscaledInstalled(exec = runExec, prompt = promptYesNo, runtime = defaultRuntime) {
58
+ // Ensure tailscaled binary exists; install via Homebrew tailscale if missing.
59
+ const hasTailscaled = await exec("tailscaled", ["--version"]).then(() => true, () => false);
60
+ if (hasTailscaled)
61
+ return;
62
+ const install = await prompt("tailscaled not found. Install via Homebrew (tailscale package)?", true);
63
+ if (!install) {
64
+ runtime.error("tailscaled is required for user-space funnel. Aborting.");
65
+ runtime.exit(1);
66
+ }
67
+ logVerbose("Installing tailscaled via Homebrew…");
68
+ await exec("brew", ["install", "tailscale"]);
69
+ }
70
+ export async function ensureFunnel(port, exec = runExec, runtime = defaultRuntime, prompt = promptYesNo) {
71
+ // Ensure Funnel is enabled and publish the webhook port.
72
+ try {
73
+ const statusOut = (await exec("tailscale", ["funnel", "status", "--json"])).stdout.trim();
74
+ const parsed = statusOut
75
+ ? JSON.parse(statusOut)
76
+ : {};
77
+ if (!parsed || Object.keys(parsed).length === 0) {
78
+ runtime.error(danger("Tailscale Funnel is not enabled on this tailnet/device."));
79
+ runtime.error(info("Enable in admin console: https://login.tailscale.com/admin (see https://tailscale.com/kb/1223/funnel)"));
80
+ runtime.error(info("macOS user-space tailscaled docs: https://github.com/tailscale/tailscale/wiki/Tailscaled-on-macOS"));
81
+ const proceed = await prompt("Attempt local setup with user-space tailscaled?", true);
82
+ if (!proceed)
83
+ runtime.exit(1);
84
+ await ensureBinary("brew", exec, runtime);
85
+ await ensureGoInstalled(exec, prompt, runtime);
86
+ await ensureTailscaledInstalled(exec, prompt, runtime);
87
+ }
88
+ logVerbose(`Enabling funnel on port ${port}…`);
89
+ const { stdout } = await exec("tailscale", ["funnel", "--yes", "--bg", `${port}`], {
90
+ maxBuffer: 200_000,
91
+ timeoutMs: 15_000,
92
+ });
93
+ if (stdout.trim())
94
+ console.log(stdout.trim());
95
+ }
96
+ catch (err) {
97
+ const errOutput = err;
98
+ const stdout = typeof errOutput.stdout === "string" ? errOutput.stdout : "";
99
+ const stderr = typeof errOutput.stderr === "string" ? errOutput.stderr : "";
100
+ if (stdout.includes("Funnel is not enabled")) {
101
+ console.error(danger("Funnel is not enabled on this tailnet/device."));
102
+ const linkMatch = stdout.match(/https?:\/\/\S+/);
103
+ if (linkMatch) {
104
+ console.error(info(`Enable it here: ${linkMatch[0]}`));
105
+ }
106
+ else {
107
+ console.error(info("Enable in admin console: https://login.tailscale.com/admin (see https://tailscale.com/kb/1223/funnel)"));
108
+ }
109
+ }
110
+ if (stderr.includes("client version") ||
111
+ stdout.includes("client version")) {
112
+ console.error(warn("Tailscale client/server version mismatch detected; try updating tailscale/tailscaled."));
113
+ }
114
+ runtime.error("Failed to enable Tailscale Funnel. Is it allowed on your tailnet?");
115
+ runtime.error(info("Tip: Funnel is optional for CLAWDBOT. You can keep running the web gateway without it: `pnpm clawdbot gateway`"));
116
+ if (shouldLogVerbose()) {
117
+ if (stdout.trim())
118
+ runtime.error(chalk.gray(`stdout: ${stdout.trim()}`));
119
+ if (stderr.trim())
120
+ runtime.error(chalk.gray(`stderr: ${stderr.trim()}`));
121
+ runtime.error(err);
122
+ }
123
+ runtime.exit(1);
124
+ }
125
+ }
126
+ export async function enableTailscaleServe(port, exec = runExec) {
127
+ await exec("tailscale", ["serve", "--bg", "--yes", `${port}`], {
128
+ maxBuffer: 200_000,
129
+ timeoutMs: 15_000,
130
+ });
131
+ }
132
+ export async function disableTailscaleServe(exec = runExec) {
133
+ await exec("tailscale", ["serve", "reset"], {
134
+ maxBuffer: 200_000,
135
+ timeoutMs: 15_000,
136
+ });
137
+ }
138
+ export async function enableTailscaleFunnel(port, exec = runExec) {
139
+ await exec("tailscale", ["funnel", "--bg", "--yes", `${port}`], {
140
+ maxBuffer: 200_000,
141
+ timeoutMs: 15_000,
142
+ });
143
+ }
144
+ export async function disableTailscaleFunnel(exec = runExec) {
145
+ await exec("tailscale", ["funnel", "reset"], {
146
+ maxBuffer: 200_000,
147
+ timeoutMs: 15_000,
148
+ });
149
+ }
@@ -0,0 +1,77 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ const DEFAULT_TRIGGERS = ["clawd", "claude", "computer"];
6
+ function defaultBaseDir() {
7
+ return path.join(os.homedir(), ".clawdbot");
8
+ }
9
+ function resolvePath(baseDir) {
10
+ const root = baseDir ?? defaultBaseDir();
11
+ return path.join(root, "settings", "voicewake.json");
12
+ }
13
+ function sanitizeTriggers(triggers) {
14
+ const cleaned = (triggers ?? [])
15
+ .map((w) => (typeof w === "string" ? w.trim() : ""))
16
+ .filter((w) => w.length > 0);
17
+ return cleaned.length > 0 ? cleaned : DEFAULT_TRIGGERS;
18
+ }
19
+ async function readJSON(filePath) {
20
+ try {
21
+ const raw = await fs.readFile(filePath, "utf8");
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ async function writeJSONAtomic(filePath, value) {
29
+ const dir = path.dirname(filePath);
30
+ await fs.mkdir(dir, { recursive: true });
31
+ const tmp = `${filePath}.${randomUUID()}.tmp`;
32
+ await fs.writeFile(tmp, JSON.stringify(value, null, 2), "utf8");
33
+ await fs.rename(tmp, filePath);
34
+ }
35
+ let lock = Promise.resolve();
36
+ async function withLock(fn) {
37
+ const prev = lock;
38
+ let release;
39
+ lock = new Promise((resolve) => {
40
+ release = resolve;
41
+ });
42
+ await prev;
43
+ try {
44
+ return await fn();
45
+ }
46
+ finally {
47
+ release?.();
48
+ }
49
+ }
50
+ export function defaultVoiceWakeTriggers() {
51
+ return [...DEFAULT_TRIGGERS];
52
+ }
53
+ export async function loadVoiceWakeConfig(baseDir) {
54
+ const filePath = resolvePath(baseDir);
55
+ const existing = await readJSON(filePath);
56
+ if (!existing) {
57
+ return { triggers: defaultVoiceWakeTriggers(), updatedAtMs: 0 };
58
+ }
59
+ return {
60
+ triggers: sanitizeTriggers(existing.triggers),
61
+ updatedAtMs: typeof existing.updatedAtMs === "number" && existing.updatedAtMs > 0
62
+ ? existing.updatedAtMs
63
+ : 0,
64
+ };
65
+ }
66
+ export async function setVoiceWakeTriggers(triggers, baseDir) {
67
+ const sanitized = sanitizeTriggers(triggers);
68
+ const filePath = resolvePath(baseDir);
69
+ return await withLock(async () => {
70
+ const next = {
71
+ triggers: sanitized,
72
+ updatedAtMs: Date.now(),
73
+ };
74
+ await writeJSONAtomic(filePath, next);
75
+ return next;
76
+ });
77
+ }
@@ -0,0 +1,123 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { CONFIG_DIR, ensureDir } from "../utils.js";
5
+ export const WIDE_AREA_DISCOVERY_DOMAIN = "clawdbot.internal.";
6
+ export const WIDE_AREA_ZONE_FILENAME = "clawdbot.internal.db";
7
+ export function getWideAreaZonePath() {
8
+ return path.join(CONFIG_DIR, "dns", WIDE_AREA_ZONE_FILENAME);
9
+ }
10
+ function dnsLabel(raw, fallback) {
11
+ const normalized = raw
12
+ .trim()
13
+ .toLowerCase()
14
+ .replace(/[^a-z0-9-]+/g, "-")
15
+ .replace(/^-+/, "")
16
+ .replace(/-+$/, "");
17
+ const out = normalized.length > 0 ? normalized : fallback;
18
+ return out.length <= 63 ? out : out.slice(0, 63);
19
+ }
20
+ function txtQuote(value) {
21
+ const escaped = value
22
+ .replaceAll("\\", "\\\\")
23
+ .replaceAll('"', '\\"')
24
+ .replaceAll("\n", "\\n");
25
+ return `"${escaped}"`;
26
+ }
27
+ function formatYyyyMmDd(date) {
28
+ const y = date.getUTCFullYear();
29
+ const m = String(date.getUTCMonth() + 1).padStart(2, "0");
30
+ const d = String(date.getUTCDate()).padStart(2, "0");
31
+ return `${y}${m}${d}`;
32
+ }
33
+ function nextSerial(existingSerial, now) {
34
+ const today = formatYyyyMmDd(now);
35
+ const base = Number.parseInt(`${today}01`, 10);
36
+ if (!existingSerial || !Number.isFinite(existingSerial))
37
+ return base;
38
+ const existing = String(existingSerial);
39
+ if (existing.startsWith(today))
40
+ return existingSerial + 1;
41
+ return base;
42
+ }
43
+ function extractSerial(zoneText) {
44
+ const match = zoneText.match(/^\s*@\s+IN\s+SOA\s+\S+\s+\S+\s+(\d+)\s+/m);
45
+ if (!match)
46
+ return null;
47
+ const parsed = Number.parseInt(match[1], 10);
48
+ return Number.isFinite(parsed) ? parsed : null;
49
+ }
50
+ function extractContentHash(zoneText) {
51
+ const match = zoneText.match(/^\s*;\s*clawdbot-content-hash:\s*(\S+)\s*$/m);
52
+ return match?.[1] ?? null;
53
+ }
54
+ function computeContentHash(body) {
55
+ // Cheap stable hash; avoids importing crypto (and keeps deterministic across runtimes).
56
+ let h = 2166136261;
57
+ for (let i = 0; i < body.length; i++) {
58
+ h ^= body.charCodeAt(i);
59
+ h = Math.imul(h, 16777619);
60
+ }
61
+ return (h >>> 0).toString(16).padStart(8, "0");
62
+ }
63
+ function renderZone(opts) {
64
+ const hostname = os.hostname().split(".")[0] ?? "clawdbot";
65
+ const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdbot");
66
+ const instanceLabel = dnsLabel(opts.instanceLabel ?? `${hostname}-bridge`, "clawdbot-bridge");
67
+ const txt = [
68
+ `displayName=${opts.displayName.trim() || hostname}`,
69
+ `transport=bridge`,
70
+ `bridgePort=${opts.bridgePort}`,
71
+ ];
72
+ if (opts.tailnetDns?.trim()) {
73
+ txt.push(`tailnetDns=${opts.tailnetDns.trim()}`);
74
+ }
75
+ const records = [];
76
+ records.push(`$ORIGIN ${WIDE_AREA_DISCOVERY_DOMAIN}`);
77
+ records.push(`$TTL 60`);
78
+ const soaLine = `@ IN SOA ns1 hostmaster ${opts.serial} 7200 3600 1209600 60`;
79
+ records.push(soaLine);
80
+ records.push(`@ IN NS ns1`);
81
+ records.push(`ns1 IN A ${opts.tailnetIPv4}`);
82
+ records.push(`${hostLabel} IN A ${opts.tailnetIPv4}`);
83
+ if (opts.tailnetIPv6) {
84
+ records.push(`${hostLabel} IN AAAA ${opts.tailnetIPv6}`);
85
+ }
86
+ records.push(`_clawdbot-bridge._tcp IN PTR ${instanceLabel}._clawdbot-bridge._tcp`);
87
+ records.push(`${instanceLabel}._clawdbot-bridge._tcp IN SRV 0 0 ${opts.bridgePort} ${hostLabel}`);
88
+ records.push(`${instanceLabel}._clawdbot-bridge._tcp IN TXT ${txt.map(txtQuote).join(" ")}`);
89
+ const contentBody = `${records.join("\n")}\n`;
90
+ const hashBody = `${records
91
+ .map((line) => line === soaLine
92
+ ? `@ IN SOA ns1 hostmaster SERIAL 7200 3600 1209600 60`
93
+ : line)
94
+ .join("\n")}\n`;
95
+ const contentHash = computeContentHash(hashBody);
96
+ return `; clawdbot-content-hash: ${contentHash}\n${contentBody}`;
97
+ }
98
+ export function renderWideAreaBridgeZoneText(opts) {
99
+ return renderZone(opts);
100
+ }
101
+ export async function writeWideAreaBridgeZone(opts) {
102
+ const zonePath = getWideAreaZonePath();
103
+ await ensureDir(path.dirname(zonePath));
104
+ const existing = (() => {
105
+ try {
106
+ return fs.readFileSync(zonePath, "utf-8");
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ })();
112
+ const nextNoSerial = renderWideAreaBridgeZoneText({ ...opts, serial: 0 });
113
+ const nextHash = extractContentHash(nextNoSerial);
114
+ const existingHash = existing ? extractContentHash(existing) : null;
115
+ if (existing && nextHash && existingHash === nextHash) {
116
+ return { zonePath, changed: false };
117
+ }
118
+ const existingSerial = existing ? extractSerial(existing) : null;
119
+ const serial = nextSerial(existingSerial, new Date());
120
+ const next = renderWideAreaBridgeZoneText({ ...opts, serial });
121
+ fs.writeFileSync(zonePath, next, "utf-8");
122
+ return { zonePath, changed: true };
123
+ }
@@ -0,0 +1,13 @@
1
+ import { Buffer } from "node:buffer";
2
+ export function rawDataToString(data, encoding = "utf8") {
3
+ if (typeof data === "string")
4
+ return data;
5
+ if (Buffer.isBuffer(data))
6
+ return data.toString(encoding);
7
+ if (Array.isArray(data))
8
+ return Buffer.concat(data).toString(encoding);
9
+ if (data instanceof ArrayBuffer) {
10
+ return Buffer.from(data).toString(encoding);
11
+ }
12
+ return Buffer.from(String(data)).toString(encoding);
13
+ }
package/dist/logger.js ADDED
@@ -0,0 +1,52 @@
1
+ import { danger, info, logVerboseConsole, success, warn } from "./globals.js";
2
+ import { createSubsystemLogger, getLogger } from "./logging.js";
3
+ import { defaultRuntime } from "./runtime.js";
4
+ const subsystemPrefixRe = /^([a-z][a-z0-9-]{1,20}):\s+(.*)$/i;
5
+ function splitSubsystem(message) {
6
+ const match = message.match(subsystemPrefixRe);
7
+ if (!match)
8
+ return null;
9
+ const [, subsystem, rest] = match;
10
+ return { subsystem, rest };
11
+ }
12
+ export function logInfo(message, runtime = defaultRuntime) {
13
+ const parsed = runtime === defaultRuntime ? splitSubsystem(message) : null;
14
+ if (parsed) {
15
+ createSubsystemLogger(parsed.subsystem).info(parsed.rest);
16
+ return;
17
+ }
18
+ runtime.log(info(message));
19
+ getLogger().info(message);
20
+ }
21
+ export function logWarn(message, runtime = defaultRuntime) {
22
+ const parsed = runtime === defaultRuntime ? splitSubsystem(message) : null;
23
+ if (parsed) {
24
+ createSubsystemLogger(parsed.subsystem).warn(parsed.rest);
25
+ return;
26
+ }
27
+ runtime.log(warn(message));
28
+ getLogger().warn(message);
29
+ }
30
+ export function logSuccess(message, runtime = defaultRuntime) {
31
+ const parsed = runtime === defaultRuntime ? splitSubsystem(message) : null;
32
+ if (parsed) {
33
+ createSubsystemLogger(parsed.subsystem).info(parsed.rest);
34
+ return;
35
+ }
36
+ runtime.log(success(message));
37
+ getLogger().info(message);
38
+ }
39
+ export function logError(message, runtime = defaultRuntime) {
40
+ const parsed = runtime === defaultRuntime ? splitSubsystem(message) : null;
41
+ if (parsed) {
42
+ createSubsystemLogger(parsed.subsystem).error(parsed.rest);
43
+ return;
44
+ }
45
+ runtime.error(danger(message));
46
+ getLogger().error(message);
47
+ }
48
+ export function logDebug(message) {
49
+ // Always emit to file logger (level-filtered); console only when verbose.
50
+ getLogger().debug(message);
51
+ logVerboseConsole(message);
52
+ }