@openparachute/agent 0.1.2 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (608) hide show
  1. package/.parachute/module.json +124 -8
  2. package/LICENSE +2 -16
  3. package/README.md +118 -166
  4. package/package.json +35 -42
  5. package/scripts/spawn-agent.ts +371 -0
  6. package/src/_parked/interactive-spawn.test.ts +324 -0
  7. package/src/_parked/interactive-spawn.ts +701 -0
  8. package/src/agent-defs.test.ts +1504 -0
  9. package/src/agent-defs.ts +1702 -0
  10. package/src/agent-mcp-config.test.ts +115 -0
  11. package/src/agent-mcp-config.ts +115 -0
  12. package/src/agents.test.ts +360 -0
  13. package/src/agents.ts +379 -0
  14. package/src/auth.test.ts +46 -0
  15. package/src/auth.ts +140 -0
  16. package/src/backends/attached-queue.test.ts +376 -0
  17. package/src/backends/attached-queue.ts +372 -0
  18. package/src/backends/programmatic.test.ts +1715 -0
  19. package/src/backends/programmatic.ts +927 -0
  20. package/src/backends/registry.test.ts +1494 -0
  21. package/src/backends/registry.ts +1202 -0
  22. package/src/backends/stream-json.test.ts +570 -0
  23. package/src/backends/stream-json.ts +392 -0
  24. package/src/backends/types.ts +223 -0
  25. package/src/bridge.ts +417 -0
  26. package/src/channel-backend-wiring.test.ts +237 -0
  27. package/src/credentials.test.ts +274 -0
  28. package/src/credentials.ts +380 -0
  29. package/src/cron.test.ts +342 -0
  30. package/src/cron.ts +380 -0
  31. package/src/daemon-agent-def-api.test.ts +166 -0
  32. package/src/daemon-agent-defs-api.test.ts +953 -0
  33. package/src/daemon-agent-env-api.test.ts +338 -0
  34. package/src/daemon-attached-queue-store.test.ts +65 -0
  35. package/src/daemon-config-api.test.ts +962 -0
  36. package/src/daemon-jobs-api.test.ts +271 -0
  37. package/src/daemon-vault-chat.test.ts +250 -0
  38. package/src/daemon.test.ts +746 -0
  39. package/src/daemon.ts +3314 -0
  40. package/src/def-vaults.test.ts +136 -0
  41. package/src/def-vaults.ts +165 -0
  42. package/src/delivery-state.test.ts +110 -0
  43. package/src/delivery-state.ts +154 -0
  44. package/src/effective-env.test.ts +114 -0
  45. package/src/effective-env.ts +184 -0
  46. package/src/env-compat.ts +39 -0
  47. package/src/grants.test.ts +638 -0
  48. package/src/grants.ts +675 -0
  49. package/src/hub-jwt.test.ts +161 -0
  50. package/src/hub-jwt.ts +182 -0
  51. package/src/jobs.test.ts +245 -0
  52. package/src/jobs.ts +266 -0
  53. package/src/mcp-http.test.ts +265 -0
  54. package/src/mcp-http.ts +771 -0
  55. package/src/mint-token.test.ts +152 -0
  56. package/src/mint-token.ts +139 -0
  57. package/src/module-manifest.test.ts +158 -0
  58. package/src/oauth-discovery.ts +134 -0
  59. package/src/programmatic-wiring.test.ts +838 -0
  60. package/src/registry.test.ts +227 -0
  61. package/src/registry.ts +228 -0
  62. package/src/resolve-port.test.ts +64 -0
  63. package/src/routing.test.ts +184 -0
  64. package/src/routing.ts +76 -0
  65. package/src/runner.test.ts +506 -0
  66. package/src/runner.ts +255 -0
  67. package/src/sandbox/config.test.ts +150 -0
  68. package/src/sandbox/config.ts +102 -0
  69. package/src/sandbox/egress.test.ts +113 -0
  70. package/src/sandbox/egress.ts +123 -0
  71. package/src/sandbox/index.ts +180 -0
  72. package/src/sandbox/live-seatbelt.test.ts +277 -0
  73. package/src/sandbox/mounts.test.ts +154 -0
  74. package/src/sandbox/mounts.ts +133 -0
  75. package/src/sandbox/sandbox.test.ts +168 -0
  76. package/src/sandbox/types.ts +382 -0
  77. package/src/services-manifest.test.ts +106 -0
  78. package/src/services-manifest.ts +95 -0
  79. package/src/spa-serve.test.ts +116 -0
  80. package/src/spa-serve.ts +116 -0
  81. package/src/spawn-agent-cli.test.ts +172 -0
  82. package/src/spawn-agent.test.ts +1218 -0
  83. package/src/spawn-agent.ts +569 -0
  84. package/src/spawn-deps.test.ts +54 -0
  85. package/src/spawn-deps.ts +166 -0
  86. package/src/telegram/api.ts +153 -0
  87. package/src/terminal-assets.test.ts +50 -0
  88. package/src/terminal-assets.ts +79 -0
  89. package/src/terminal-ui.ts +305 -0
  90. package/src/terminal.test.ts +530 -0
  91. package/src/terminal.ts +458 -0
  92. package/src/transport.ts +270 -0
  93. package/src/transports/http-ui.test.ts +455 -0
  94. package/src/transports/http-ui.ts +201 -0
  95. package/src/transports/telegram.test.ts +174 -0
  96. package/src/transports/telegram.ts +426 -0
  97. package/src/transports/vault.test.ts +2011 -0
  98. package/src/transports/vault.ts +1790 -0
  99. package/src/ui-kit.test.ts +178 -0
  100. package/src/ui-kit.ts +402 -0
  101. package/tsconfig.json +8 -14
  102. package/web/ui/dist/assets/index-C-iWdFFV.css +1 -0
  103. package/web/ui/dist/assets/index-VFETBk0a.js +60 -0
  104. package/web/ui/dist/index.html +15 -0
  105. package/web/ui/tsconfig.json +2 -1
  106. package/.claude/scheduled_tasks.lock +0 -1
  107. package/.claude/settings.json +0 -5
  108. package/.claude/skills/add-atomic-chat-tool/SKILL.md +0 -243
  109. package/.claude/skills/add-atomic-chat-tool/atomic-chat-mcp-stdio.ts +0 -229
  110. package/.claude/skills/add-codex/SKILL.md +0 -161
  111. package/.claude/skills/add-dashboard/SKILL.md +0 -138
  112. package/.claude/skills/add-dashboard/resources/dashboard-pusher.ts +0 -495
  113. package/.claude/skills/add-emacs/SKILL.md +0 -296
  114. package/.claude/skills/add-gcal-tool/SKILL.md +0 -210
  115. package/.claude/skills/add-gchat/REMOVE.md +0 -6
  116. package/.claude/skills/add-gchat/SKILL.md +0 -92
  117. package/.claude/skills/add-gchat/VERIFY.md +0 -3
  118. package/.claude/skills/add-github/REMOVE.md +0 -6
  119. package/.claude/skills/add-github/SKILL.md +0 -148
  120. package/.claude/skills/add-github/VERIFY.md +0 -3
  121. package/.claude/skills/add-gmail-tool/SKILL.md +0 -229
  122. package/.claude/skills/add-imessage/REMOVE.md +0 -6
  123. package/.claude/skills/add-imessage/SKILL.md +0 -113
  124. package/.claude/skills/add-imessage/VERIFY.md +0 -3
  125. package/.claude/skills/add-karpathy-llm-wiki/SKILL.md +0 -110
  126. package/.claude/skills/add-karpathy-llm-wiki/llm-wiki.md +0 -75
  127. package/.claude/skills/add-linear/REMOVE.md +0 -6
  128. package/.claude/skills/add-linear/SKILL.md +0 -168
  129. package/.claude/skills/add-linear/VERIFY.md +0 -3
  130. package/.claude/skills/add-macos-statusbar/SKILL.md +0 -133
  131. package/.claude/skills/add-macos-statusbar/add/src/statusbar.swift +0 -147
  132. package/.claude/skills/add-matrix/REMOVE.md +0 -6
  133. package/.claude/skills/add-matrix/SKILL.md +0 -148
  134. package/.claude/skills/add-matrix/VERIFY.md +0 -3
  135. package/.claude/skills/add-ollama-provider/SKILL.md +0 -179
  136. package/.claude/skills/add-ollama-tool/SKILL.md +0 -193
  137. package/.claude/skills/add-opencode/SKILL.md +0 -229
  138. package/.claude/skills/add-parallel/SKILL.md +0 -290
  139. package/.claude/skills/add-resend/REMOVE.md +0 -6
  140. package/.claude/skills/add-resend/SKILL.md +0 -93
  141. package/.claude/skills/add-resend/VERIFY.md +0 -3
  142. package/.claude/skills/add-signal/REMOVE.md +0 -13
  143. package/.claude/skills/add-signal/SKILL.md +0 -318
  144. package/.claude/skills/add-signal/VERIFY.md +0 -5
  145. package/.claude/skills/add-slack/REMOVE.md +0 -6
  146. package/.claude/skills/add-slack/SKILL.md +0 -112
  147. package/.claude/skills/add-slack/VERIFY.md +0 -3
  148. package/.claude/skills/add-teams/REMOVE.md +0 -6
  149. package/.claude/skills/add-teams/SKILL.md +0 -207
  150. package/.claude/skills/add-teams/VERIFY.md +0 -3
  151. package/.claude/skills/add-vercel/SKILL.md +0 -147
  152. package/.claude/skills/add-vercel/container-skills/vercel-cli/SKILL.md +0 -103
  153. package/.claude/skills/add-webex/REMOVE.md +0 -6
  154. package/.claude/skills/add-webex/SKILL.md +0 -88
  155. package/.claude/skills/add-webex/VERIFY.md +0 -3
  156. package/.claude/skills/add-wechat/REMOVE.md +0 -49
  157. package/.claude/skills/add-wechat/SKILL.md +0 -170
  158. package/.claude/skills/add-wechat/scripts/wire-dm.ts +0 -172
  159. package/.claude/skills/add-whatsapp/SKILL.md +0 -264
  160. package/.claude/skills/add-whatsapp-cloud/REMOVE.md +0 -6
  161. package/.claude/skills/add-whatsapp-cloud/SKILL.md +0 -95
  162. package/.claude/skills/add-whatsapp-cloud/VERIFY.md +0 -3
  163. package/.claude/skills/claw/SKILL.md +0 -131
  164. package/.claude/skills/claw/scripts/claw +0 -374
  165. package/.claude/skills/convert-to-apple-container/SKILL.md +0 -212
  166. package/.claude/skills/customize/SKILL.md +0 -110
  167. package/.claude/skills/debug/SKILL.md +0 -349
  168. package/.claude/skills/get-qodo-rules/SKILL.md +0 -122
  169. package/.claude/skills/get-qodo-rules/references/output-format.md +0 -41
  170. package/.claude/skills/get-qodo-rules/references/pagination.md +0 -33
  171. package/.claude/skills/get-qodo-rules/references/repository-scope.md +0 -26
  172. package/.claude/skills/init-first-agent/SKILL.md +0 -120
  173. package/.claude/skills/init-onecli/SKILL.md +0 -270
  174. package/.claude/skills/manage-channels/SKILL.md +0 -87
  175. package/.claude/skills/manage-mounts/SKILL.md +0 -47
  176. package/.claude/skills/migrate-from-openclaw/MIGRATE_CRONS.md +0 -100
  177. package/.claude/skills/migrate-from-openclaw/SKILL.md +0 -447
  178. package/.claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts +0 -734
  179. package/.claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts +0 -476
  180. package/.claude/skills/migrate-nanoclaw/SKILL.md +0 -484
  181. package/.claude/skills/migrate-nanoclaw/diagnostics.md +0 -51
  182. package/.claude/skills/qodo-pr-resolver/SKILL.md +0 -326
  183. package/.claude/skills/qodo-pr-resolver/resources/providers.md +0 -329
  184. package/.claude/skills/update-nanoclaw/SKILL.md +0 -243
  185. package/.claude/skills/update-nanoclaw/diagnostics.md +0 -48
  186. package/.claude/skills/update-skills/SKILL.md +0 -130
  187. package/.claude/skills/use-native-credential-proxy/SKILL.md +0 -167
  188. package/.claude/skills/x-integration/SKILL.md +0 -417
  189. package/.claude/skills/x-integration/agent.ts +0 -243
  190. package/.claude/skills/x-integration/host.ts +0 -155
  191. package/.claude/skills/x-integration/lib/browser.ts +0 -148
  192. package/.claude/skills/x-integration/lib/config.ts +0 -62
  193. package/.claude/skills/x-integration/scripts/like.ts +0 -56
  194. package/.claude/skills/x-integration/scripts/post.ts +0 -66
  195. package/.claude/skills/x-integration/scripts/quote.ts +0 -80
  196. package/.claude/skills/x-integration/scripts/reply.ts +0 -74
  197. package/.claude/skills/x-integration/scripts/retweet.ts +0 -62
  198. package/.claude/skills/x-integration/scripts/setup.ts +0 -87
  199. package/.github/CODEOWNERS +0 -10
  200. package/.github/PULL_REQUEST_TEMPLATE.md +0 -18
  201. package/.github/workflows/bump-version.yml +0 -35
  202. package/.github/workflows/ci.yml +0 -39
  203. package/.github/workflows/label-pr.yml +0 -40
  204. package/.github/workflows/update-tokens.yml +0 -43
  205. package/.husky/pre-commit +0 -1
  206. package/.mcp.json +0 -3
  207. package/.nvmrc +0 -1
  208. package/.prettierrc +0 -4
  209. package/CHANGELOG.md +0 -263
  210. package/CLAUDE.md +0 -307
  211. package/CODE_OF_CONDUCT.md +0 -128
  212. package/CONTRIBUTING.md +0 -159
  213. package/CONTRIBUTORS.md +0 -26
  214. package/LICENSE-NANOCLAW-MIT +0 -21
  215. package/README_ja.md +0 -194
  216. package/README_zh.md +0 -194
  217. package/assets/nanoclaw-favicon.png +0 -0
  218. package/assets/nanoclaw-icon.png +0 -0
  219. package/assets/nanoclaw-logo-dark.png +0 -0
  220. package/assets/nanoclaw-logo.png +0 -0
  221. package/assets/nanoclaw-profile.jpeg +0 -0
  222. package/assets/nanoclaw-sales.png +0 -0
  223. package/assets/social-preview.jpg +0 -0
  224. package/config-examples/mount-allowlist.json +0 -25
  225. package/container/.dockerignore +0 -2
  226. package/container/CLAUDE.md +0 -21
  227. package/container/Dockerfile +0 -121
  228. package/container/agent-runner/bun.lock +0 -243
  229. package/container/agent-runner/package.json +0 -22
  230. package/container/agent-runner/scripts/sdk-signal-probe.ts +0 -169
  231. package/container/agent-runner/src/config.ts +0 -55
  232. package/container/agent-runner/src/db/connection.ts +0 -267
  233. package/container/agent-runner/src/db/index.ts +0 -20
  234. package/container/agent-runner/src/db/messages-in.ts +0 -138
  235. package/container/agent-runner/src/db/messages-out.ts +0 -143
  236. package/container/agent-runner/src/db/session-routing.ts +0 -30
  237. package/container/agent-runner/src/db/session-state.test.ts +0 -100
  238. package/container/agent-runner/src/db/session-state.ts +0 -79
  239. package/container/agent-runner/src/destinations.ts +0 -135
  240. package/container/agent-runner/src/formatter.test.ts +0 -167
  241. package/container/agent-runner/src/formatter.ts +0 -260
  242. package/container/agent-runner/src/index.ts +0 -110
  243. package/container/agent-runner/src/integration.test.ts +0 -121
  244. package/container/agent-runner/src/mcp-tools/agents.instructions.md +0 -26
  245. package/container/agent-runner/src/mcp-tools/agents.ts +0 -66
  246. package/container/agent-runner/src/mcp-tools/core.instructions.md +0 -27
  247. package/container/agent-runner/src/mcp-tools/core.ts +0 -262
  248. package/container/agent-runner/src/mcp-tools/index.ts +0 -22
  249. package/container/agent-runner/src/mcp-tools/interactive.instructions.md +0 -22
  250. package/container/agent-runner/src/mcp-tools/interactive.ts +0 -169
  251. package/container/agent-runner/src/mcp-tools/scheduling.instructions.md +0 -40
  252. package/container/agent-runner/src/mcp-tools/scheduling.ts +0 -299
  253. package/container/agent-runner/src/mcp-tools/self-mod.instructions.md +0 -25
  254. package/container/agent-runner/src/mcp-tools/self-mod.ts +0 -120
  255. package/container/agent-runner/src/mcp-tools/server.ts +0 -54
  256. package/container/agent-runner/src/mcp-tools/types.ts +0 -6
  257. package/container/agent-runner/src/poll-loop.test.ts +0 -248
  258. package/container/agent-runner/src/poll-loop.ts +0 -437
  259. package/container/agent-runner/src/providers/claude.ts +0 -379
  260. package/container/agent-runner/src/providers/factory.test.ts +0 -19
  261. package/container/agent-runner/src/providers/factory.ts +0 -13
  262. package/container/agent-runner/src/providers/index.ts +0 -6
  263. package/container/agent-runner/src/providers/mock.ts +0 -77
  264. package/container/agent-runner/src/providers/provider-registry.ts +0 -33
  265. package/container/agent-runner/src/providers/types.ts +0 -82
  266. package/container/agent-runner/src/scheduling/task-script.ts +0 -121
  267. package/container/agent-runner/src/timezone.test.ts +0 -93
  268. package/container/agent-runner/src/timezone.ts +0 -107
  269. package/container/agent-runner/tsconfig.json +0 -14
  270. package/container/build.sh +0 -48
  271. package/container/entrypoint.sh +0 -16
  272. package/container/skills/agent-browser/SKILL.md +0 -159
  273. package/container/skills/frontend-engineer/SKILL.md +0 -157
  274. package/container/skills/self-customize/SKILL.md +0 -87
  275. package/container/skills/slack-formatting/SKILL.md +0 -94
  276. package/container/skills/vercel-cli/SKILL.md +0 -111
  277. package/container/skills/welcome/SKILL.md +0 -85
  278. package/docs/APPLE-CONTAINER-NETWORKING.md +0 -90
  279. package/docs/BRANCH-FORK-MAINTENANCE.md +0 -81
  280. package/docs/README.md +0 -25
  281. package/docs/SDK_DEEP_DIVE.md +0 -643
  282. package/docs/SECURITY.md +0 -162
  283. package/docs/agent-runner-details.md +0 -749
  284. package/docs/api-details.md +0 -365
  285. package/docs/architecture-diagram.html +0 -422
  286. package/docs/architecture-diagram.md +0 -215
  287. package/docs/architecture.md +0 -751
  288. package/docs/audit/2026-04-30-channel-endpoint-audit.md +0 -36
  289. package/docs/build-and-runtime.md +0 -80
  290. package/docs/cross-mount-stress/README.md +0 -112
  291. package/docs/cross-mount-stress/container-writer-retry.mjs +0 -55
  292. package/docs/cross-mount-stress/container-writer-slow.mjs +0 -42
  293. package/docs/cross-mount-stress/container-writer.mjs +0 -47
  294. package/docs/cross-mount-stress/host-writer-retry.mjs +0 -55
  295. package/docs/cross-mount-stress/host-writer-slow.mjs +0 -43
  296. package/docs/cross-mount-stress/host-writer.mjs +0 -47
  297. package/docs/db-central.md +0 -316
  298. package/docs/db-session.md +0 -183
  299. package/docs/db.md +0 -119
  300. package/docs/design/2026-04-29-vault-management-ui.md +0 -231
  301. package/docs/design/2026-04-30-channel-wiring-rework.md +0 -234
  302. package/docs/design/2026-05-01-channel-wiring-approvals-deep-dive.md +0 -272
  303. package/docs/design/2026-05-02-channel-policy-and-approval-routing.md +0 -250
  304. package/docs/docker-sandboxes.md +0 -359
  305. package/docs/isolation-model.md +0 -88
  306. package/docs/ollama.md +0 -79
  307. package/docs/parachute-integration.md +0 -109
  308. package/docs/post-night-rebirth-reflections.md +0 -151
  309. package/eslint.config.js +0 -32
  310. package/pnpm-workspace.yaml +0 -8
  311. package/repo-tokens/README.md +0 -113
  312. package/repo-tokens/action.yml +0 -186
  313. package/repo-tokens/badge.svg +0 -23
  314. package/repo-tokens/examples/green.svg +0 -14
  315. package/repo-tokens/examples/red.svg +0 -14
  316. package/repo-tokens/examples/yellow-green.svg +0 -14
  317. package/repo-tokens/examples/yellow.svg +0 -14
  318. package/scripts/chat.ts +0 -101
  319. package/scripts/cleanup-sessions.sh +0 -150
  320. package/scripts/init-cli-agent.ts +0 -172
  321. package/scripts/init-first-agent.ts +0 -378
  322. package/scripts/parachute.ts +0 -158
  323. package/scripts/run-migrations.ts +0 -105
  324. package/scripts/sanity-live-poll.ts +0 -95
  325. package/scripts/seed-discord.ts +0 -80
  326. package/scripts/test-v2-agent.ts +0 -106
  327. package/scripts/test-v2-channel-e2e.ts +0 -265
  328. package/scripts/test-v2-host.ts +0 -184
  329. package/src/channels/adapter.ts +0 -214
  330. package/src/channels/api-translator.test.ts +0 -306
  331. package/src/channels/api-translator.ts +0 -214
  332. package/src/channels/ask-question.ts +0 -46
  333. package/src/channels/channel-registry.test.ts +0 -421
  334. package/src/channels/channel-registry.ts +0 -313
  335. package/src/channels/chat-sdk-bridge.test.ts +0 -84
  336. package/src/channels/chat-sdk-bridge.ts +0 -652
  337. package/src/channels/cli.ts +0 -276
  338. package/src/channels/discord.ts +0 -90
  339. package/src/channels/index.ts +0 -17
  340. package/src/channels/telegram-markdown-sanitize.test.ts +0 -78
  341. package/src/channels/telegram-markdown-sanitize.ts +0 -55
  342. package/src/channels/telegram-pairing.test.ts +0 -254
  343. package/src/channels/telegram-pairing.ts +0 -339
  344. package/src/channels/telegram.ts +0 -279
  345. package/src/channels/trust-hint.test.ts +0 -48
  346. package/src/channels/trust-hint.ts +0 -75
  347. package/src/claude-md-compose.migrate.test.ts +0 -64
  348. package/src/claude-md-compose.ts +0 -205
  349. package/src/command-gate.ts +0 -63
  350. package/src/config.test.ts +0 -93
  351. package/src/config.ts +0 -128
  352. package/src/container-config.ts +0 -167
  353. package/src/container-runner.test.ts +0 -32
  354. package/src/container-runner.ts +0 -576
  355. package/src/container-runtime.test.ts +0 -269
  356. package/src/container-runtime.ts +0 -167
  357. package/src/db/_bun-sqlite-shim.ts +0 -88
  358. package/src/db/agent-activity.test.ts +0 -155
  359. package/src/db/agent-activity.ts +0 -121
  360. package/src/db/agent-groups.ts +0 -77
  361. package/src/db/connection.migrate.test.ts +0 -176
  362. package/src/db/connection.ts +0 -259
  363. package/src/db/db-v2.test.ts +0 -440
  364. package/src/db/dropped-messages.ts +0 -44
  365. package/src/db/index.ts +0 -40
  366. package/src/db/messaging-groups.ts +0 -252
  367. package/src/db/migrations/001-initial.ts +0 -112
  368. package/src/db/migrations/002-chat-sdk-state.ts +0 -36
  369. package/src/db/migrations/008-dropped-messages.ts +0 -27
  370. package/src/db/migrations/009-drop-pending-credentials.ts +0 -13
  371. package/src/db/migrations/010-engage-modes.ts +0 -103
  372. package/src/db/migrations/011-pending-sender-approvals.ts +0 -40
  373. package/src/db/migrations/012-channel-registration.ts +0 -48
  374. package/src/db/migrations/013-approval-render-metadata.ts +0 -27
  375. package/src/db/migrations/014-secrets.ts +0 -44
  376. package/src/db/migrations/015-secrets-drop-host-pattern.ts +0 -18
  377. package/src/db/migrations/016-secret-assignments.ts +0 -30
  378. package/src/db/migrations/017-agent-activity.ts +0 -40
  379. package/src/db/migrations/018-oauth-app-configs.ts +0 -34
  380. package/src/db/migrations/019-oauth-app-connections.ts +0 -48
  381. package/src/db/migrations/020-agent-app-connections.ts +0 -28
  382. package/src/db/migrations/021-pending-oauth-states.ts +0 -35
  383. package/src/db/migrations/022-app-connections-provider.ts +0 -25
  384. package/src/db/migrations/023-agent-group-secret-mode.test.ts +0 -124
  385. package/src/db/migrations/023-agent-group-secret-mode.ts +0 -65
  386. package/src/db/migrations/024-collapse-approvals.test.ts +0 -249
  387. package/src/db/migrations/024-collapse-approvals.ts +0 -182
  388. package/src/db/migrations/025-secret-mode-check.test.ts +0 -155
  389. package/src/db/migrations/025-secret-mode-check.ts +0 -49
  390. package/src/db/migrations/026-user-dms-bot-id.test.ts +0 -116
  391. package/src/db/migrations/026-user-dms-bot-id.ts +0 -54
  392. package/src/db/migrations/027-provider-credentials.ts +0 -41
  393. package/src/db/migrations/_test-helpers.ts +0 -41
  394. package/src/db/migrations/index.ts +0 -127
  395. package/src/db/migrations/module-agent-to-agent-destinations.ts +0 -84
  396. package/src/db/migrations/module-approvals-pending-approvals.ts +0 -42
  397. package/src/db/migrations/module-approvals-title-options.ts +0 -40
  398. package/src/db/schema.ts +0 -258
  399. package/src/db/session-db.test.ts +0 -93
  400. package/src/db/session-db.ts +0 -325
  401. package/src/db/sessions.ts +0 -241
  402. package/src/delivery.test.ts +0 -148
  403. package/src/delivery.ts +0 -445
  404. package/src/env.ts +0 -74
  405. package/src/group-folder.test.ts +0 -35
  406. package/src/group-folder.ts +0 -44
  407. package/src/group-init.ts +0 -92
  408. package/src/host-core.test.ts +0 -456
  409. package/src/host-sweep.test.ts +0 -146
  410. package/src/host-sweep.ts +0 -287
  411. package/src/index.ts +0 -232
  412. package/src/install-slug.ts +0 -33
  413. package/src/log.test.ts +0 -81
  414. package/src/log.ts +0 -117
  415. package/src/mcp/http.ts +0 -72
  416. package/src/mcp/server.ts +0 -92
  417. package/src/mcp/stdio.ts +0 -51
  418. package/src/mcp/tools/activity.ts +0 -88
  419. package/src/mcp/tools/agent-groups.ts +0 -183
  420. package/src/mcp/tools/approvals.ts +0 -122
  421. package/src/mcp/tools/channels.test.ts +0 -126
  422. package/src/mcp/tools/channels.ts +0 -134
  423. package/src/mcp/tools/index.ts +0 -27
  424. package/src/mcp/tools/oauth.ts +0 -48
  425. package/src/mcp/tools/secrets.ts +0 -169
  426. package/src/mcp/tools/sessions.ts +0 -135
  427. package/src/mcp/types.ts +0 -51
  428. package/src/modules/agent-to-agent/agent-route.test.ts +0 -46
  429. package/src/modules/agent-to-agent/agent-route.ts +0 -223
  430. package/src/modules/agent-to-agent/create-agent.ts +0 -127
  431. package/src/modules/agent-to-agent/db/agent-destinations.ts +0 -135
  432. package/src/modules/agent-to-agent/index.ts +0 -22
  433. package/src/modules/agent-to-agent/write-destinations.ts +0 -59
  434. package/src/modules/approvals/agent.md +0 -45
  435. package/src/modules/approvals/index.ts +0 -21
  436. package/src/modules/approvals/picks.test.ts +0 -291
  437. package/src/modules/approvals/primitive.ts +0 -279
  438. package/src/modules/approvals/project.md +0 -27
  439. package/src/modules/approvals/response-handler.ts +0 -87
  440. package/src/modules/index.ts +0 -24
  441. package/src/modules/interactive/agent.md +0 -21
  442. package/src/modules/interactive/index.ts +0 -69
  443. package/src/modules/interactive/project.md +0 -12
  444. package/src/modules/mount-security/expand-path.test.ts +0 -82
  445. package/src/modules/mount-security/index.ts +0 -459
  446. package/src/modules/mount-security/migrate.test.ts +0 -91
  447. package/src/modules/permissions/access.ts +0 -28
  448. package/src/modules/permissions/channel-approval.test.ts +0 -389
  449. package/src/modules/permissions/channel-approval.ts +0 -188
  450. package/src/modules/permissions/db/agent-group-members.ts +0 -44
  451. package/src/modules/permissions/db/pending-channel-approvals.test.ts +0 -86
  452. package/src/modules/permissions/db/pending-channel-approvals.ts +0 -66
  453. package/src/modules/permissions/db/pending-sender-approvals.ts +0 -60
  454. package/src/modules/permissions/db/user-dms.ts +0 -58
  455. package/src/modules/permissions/db/user-roles.ts +0 -85
  456. package/src/modules/permissions/db/users.ts +0 -38
  457. package/src/modules/permissions/index.ts +0 -421
  458. package/src/modules/permissions/permissions.test.ts +0 -358
  459. package/src/modules/permissions/sender-approval.test.ts +0 -641
  460. package/src/modules/permissions/sender-approval.ts +0 -165
  461. package/src/modules/permissions/user-dm.ts +0 -200
  462. package/src/modules/provider-credentials/db.ts +0 -121
  463. package/src/modules/provider-credentials/index.ts +0 -12
  464. package/src/modules/provider-credentials/spawn.test.ts +0 -206
  465. package/src/modules/provider-credentials/spawn.ts +0 -114
  466. package/src/modules/scheduling/actions.ts +0 -113
  467. package/src/modules/scheduling/db.test.ts +0 -282
  468. package/src/modules/scheduling/db.ts +0 -148
  469. package/src/modules/scheduling/index.ts +0 -34
  470. package/src/modules/scheduling/recurrence.test.ts +0 -98
  471. package/src/modules/scheduling/recurrence.ts +0 -54
  472. package/src/modules/self-mod/agent.md +0 -30
  473. package/src/modules/self-mod/apply.ts +0 -85
  474. package/src/modules/self-mod/index.ts +0 -30
  475. package/src/modules/self-mod/project.md +0 -39
  476. package/src/modules/self-mod/request.ts +0 -91
  477. package/src/modules/typing/index.ts +0 -165
  478. package/src/oauth/agent-app-connections.ts +0 -103
  479. package/src/oauth/app-configs.test.ts +0 -64
  480. package/src/oauth/app-configs.ts +0 -114
  481. package/src/oauth/app-connections.test.ts +0 -109
  482. package/src/oauth/app-connections.ts +0 -178
  483. package/src/oauth/crypto.ts +0 -56
  484. package/src/oauth/flow.ts +0 -104
  485. package/src/oauth/providers/google.test.ts +0 -38
  486. package/src/oauth/providers/google.ts +0 -46
  487. package/src/oauth/providers/index.ts +0 -48
  488. package/src/oauth/state-store.test.ts +0 -54
  489. package/src/oauth/state-store.ts +0 -93
  490. package/src/parachute/README.md +0 -27
  491. package/src/parachute/create-agent.test.ts +0 -83
  492. package/src/parachute/create-agent.ts +0 -122
  493. package/src/parachute/group-status.test.ts +0 -165
  494. package/src/parachute/group-status.ts +0 -136
  495. package/src/parachute/types.ts +0 -41
  496. package/src/parachute/vault-mcp.test.ts +0 -251
  497. package/src/parachute/vault-mcp.ts +0 -232
  498. package/src/platform-id.test.ts +0 -104
  499. package/src/platform-id.ts +0 -109
  500. package/src/providers/index.ts +0 -6
  501. package/src/providers/provider-container-registry.ts +0 -58
  502. package/src/response-registry.ts +0 -45
  503. package/src/router.ts +0 -530
  504. package/src/secrets/crypto.test.ts +0 -45
  505. package/src/secrets/crypto.ts +0 -55
  506. package/src/secrets/index.ts +0 -461
  507. package/src/secrets/master-key.ts +0 -70
  508. package/src/secrets/secrets.test.ts +0 -651
  509. package/src/session-manager.attachments.test.ts +0 -171
  510. package/src/session-manager.dup-skip.test.ts +0 -173
  511. package/src/session-manager.migrate.test.ts +0 -59
  512. package/src/session-manager.ts +0 -451
  513. package/src/startup-bootstrap.test.ts +0 -226
  514. package/src/startup-bootstrap.ts +0 -207
  515. package/src/state-sqlite.ts +0 -182
  516. package/src/timezone.test.ts +0 -64
  517. package/src/timezone.ts +0 -37
  518. package/src/types.ts +0 -233
  519. package/src/web/auth.test.ts +0 -335
  520. package/src/web/auth.ts +0 -214
  521. package/src/web/discord-validate.test.ts +0 -77
  522. package/src/web/discord-validate.ts +0 -88
  523. package/src/web/hub-discovery.test.ts +0 -98
  524. package/src/web/hub-discovery.ts +0 -69
  525. package/src/web/routes/activity.ts +0 -106
  526. package/src/web/routes/agent-provider.test.ts +0 -282
  527. package/src/web/routes/agent-provider.ts +0 -309
  528. package/src/web/routes/approvals.ts +0 -185
  529. package/src/web/routes/apps.ts +0 -434
  530. package/src/web/routes/channels-mg-detail.test.ts +0 -324
  531. package/src/web/routes/channels-mga-detail.test.ts +0 -472
  532. package/src/web/routes/channels.ts +0 -311
  533. package/src/web/routes/oauth-providers.ts +0 -42
  534. package/src/web/routes/secrets.test.ts +0 -220
  535. package/src/web/routes/secrets.ts +0 -317
  536. package/src/web/routes/sessions.ts +0 -123
  537. package/src/web/routes/settings.test.ts +0 -106
  538. package/src/web/routes/settings.ts +0 -247
  539. package/src/web/routes/setup-status.ts +0 -205
  540. package/src/web/routes/vaults.test.ts +0 -389
  541. package/src/web/routes/vaults.ts +0 -225
  542. package/src/web/server-version.test.ts +0 -16
  543. package/src/web/server.ts +0 -1024
  544. package/src/web/services-manifest.test.ts +0 -148
  545. package/src/web/services-manifest.ts +0 -66
  546. package/src/web/static-serve.test.ts +0 -255
  547. package/src/web/static-serve.ts +0 -104
  548. package/src/web/telegram-validate.test.ts +0 -116
  549. package/src/web/telegram-validate.ts +0 -107
  550. package/src/web/vault-proxy.test.ts +0 -214
  551. package/src/web/vault-proxy.ts +0 -120
  552. package/src/web/wire-channel.ts +0 -181
  553. package/src/webhook-server.ts +0 -134
  554. package/vitest.config.ts +0 -18
  555. package/web/README.md +0 -63
  556. package/web/ui/index.html +0 -13
  557. package/web/ui/package.json +0 -35
  558. package/web/ui/pnpm-lock.yaml +0 -2164
  559. package/web/ui/scripts/verify-base.mjs +0 -31
  560. package/web/ui/src/App.tsx +0 -88
  561. package/web/ui/src/components/ActivityFeed.tsx +0 -444
  562. package/web/ui/src/components/AgentGroupPicker.tsx +0 -263
  563. package/web/ui/src/components/AgentProviderCards.tsx +0 -220
  564. package/web/ui/src/components/CredentialForm.tsx +0 -214
  565. package/web/ui/src/components/ScopeGrants.tsx +0 -74
  566. package/web/ui/src/components/StatusDot.tsx +0 -43
  567. package/web/ui/src/components/VaultPicker.tsx +0 -127
  568. package/web/ui/src/components/setup/AdapterInstallStep.tsx +0 -178
  569. package/web/ui/src/components/setup/AgentGroupStep.tsx +0 -43
  570. package/web/ui/src/components/setup/ChannelPickStep.tsx +0 -74
  571. package/web/ui/src/components/setup/DoneStep.tsx +0 -49
  572. package/web/ui/src/components/setup/PrereqStep.tsx +0 -129
  573. package/web/ui/src/components/setup/TestConnectionStep.tsx +0 -108
  574. package/web/ui/src/components/setup/TestMessageStep.tsx +0 -104
  575. package/web/ui/src/components/setup/WireChannelStep.tsx +0 -166
  576. package/web/ui/src/components/setup/types.ts +0 -105
  577. package/web/ui/src/lib/api.test.ts +0 -410
  578. package/web/ui/src/lib/api.ts +0 -1248
  579. package/web/ui/src/lib/auth.test.ts +0 -352
  580. package/web/ui/src/lib/auth.ts +0 -405
  581. package/web/ui/src/lib/channel-adapters.ts +0 -136
  582. package/web/ui/src/main.tsx +0 -19
  583. package/web/ui/src/routes/ApprovalsList.tsx +0 -294
  584. package/web/ui/src/routes/Apps.tsx +0 -613
  585. package/web/ui/src/routes/ChannelWireDetail.test.tsx +0 -233
  586. package/web/ui/src/routes/ChannelWireDetail.tsx +0 -403
  587. package/web/ui/src/routes/ChannelsList.tsx +0 -158
  588. package/web/ui/src/routes/GroupDetail.test.tsx +0 -206
  589. package/web/ui/src/routes/GroupDetail.tsx +0 -880
  590. package/web/ui/src/routes/GroupList.tsx +0 -187
  591. package/web/ui/src/routes/MessagingGroupDetail.test.tsx +0 -233
  592. package/web/ui/src/routes/MessagingGroupDetail.tsx +0 -306
  593. package/web/ui/src/routes/NewGroupWizard.tsx +0 -390
  594. package/web/ui/src/routes/OAuthCallback.tsx +0 -56
  595. package/web/ui/src/routes/SecretsList.tsx +0 -942
  596. package/web/ui/src/routes/SessionsList.tsx +0 -220
  597. package/web/ui/src/routes/SettingsAgentProvider.tsx +0 -109
  598. package/web/ui/src/routes/SettingsApprovals.tsx +0 -234
  599. package/web/ui/src/routes/SetupWizard.tsx +0 -219
  600. package/web/ui/src/routes/VaultDetail.test.tsx +0 -363
  601. package/web/ui/src/routes/VaultDetail.tsx +0 -960
  602. package/web/ui/src/routes/VaultsList.tsx +0 -295
  603. package/web/ui/src/routes/WireChannelPage.tsx +0 -413
  604. package/web/ui/src/styles.css +0 -608
  605. package/web/ui/src/test/setup.ts +0 -23
  606. package/web/ui/src/vite-env.d.ts +0 -10
  607. package/web/ui/vite.config.ts +0 -34
  608. package/web/ui/vitest.config.ts +0 -25
@@ -1,165 +0,0 @@
1
- /**
2
- * Unknown-sender approval flow.
3
- *
4
- * When `messaging_groups.unknown_sender_policy = 'request_approval'` and a
5
- * non-member writes into a wired chat, the access gate drops the routing
6
- * attempt and calls `requestSenderApproval` to:
7
- *
8
- * 1. Pick an eligible approver (owner / admin of the agent group).
9
- * 2. Open / reuse a DM to that approver on a reachable channel.
10
- * 3. Deliver an Approve / Deny card.
11
- * 4. Record a pending_sender_approvals row that holds the original message
12
- * so it can be re-routed on approve.
13
- *
14
- * On approve: the handler in index.ts adds an agent_group_members row for
15
- * the sender and re-invokes routeInbound with the stored event — the second
16
- * routing attempt passes the gate because the user is now a member.
17
- *
18
- * Failure modes (logged + row NOT created, so the dedup gate lets a future
19
- * attempt try again):
20
- * - No eligible approver in user_roles — fresh install, no owner yet.
21
- * - Approver has no reachable DM (no user_dms row + channel can't
22
- * openDM) — e.g. owner hasn't registered on any channel we're wired to.
23
- * - Delivery adapter missing.
24
- *
25
- * Dedup: `pending_sender_approvals` has UNIQUE(messaging_group_id,
26
- * sender_identity). A retry / rapid second message from the same unknown
27
- * sender is silently dropped (no duplicate card sent).
28
- */
29
- import { normalizeOptions, type RawOption } from '../../channels/ask-question.js';
30
- import { getMessagingGroup } from '../../db/messaging-groups.js';
31
- import { getDeliveryAdapter } from '../../delivery.js';
32
- import { log } from '../../log.js';
33
- import { decodePlatformIdAs } from '../../platform-id.js';
34
- import type { InboundEvent } from '../../channels/adapter.js';
35
- import { appendFallbackNotice, pickApprovalDelivery, pickApprover } from '../approvals/primitive.js';
36
- import { createPendingSenderApproval, hasInFlightSenderApproval } from './db/pending-sender-approvals.js';
37
-
38
- // Three-button card per design doc PR #75 phase 4. The "always allow" branch
39
- // flips the messaging group's unknown_sender_policy to 'public' so future
40
- // strangers walk through with no gate. Shown unconditionally — even on
41
- // 'strict' MGs that wouldn't normally render this card — so the operator can
42
- // recover from a too-restrictive default with one click. The handler short-
43
- // circuits if the policy is already 'public', so the click is idempotent.
44
- const APPROVAL_OPTIONS: RawOption[] = [
45
- { label: 'Allow', selectedLabel: '✅ Allowed', value: 'approve' },
46
- { label: 'Allow & open channel', selectedLabel: '✅ Channel opened', value: 'approve_and_allow' },
47
- { label: 'Deny', selectedLabel: '❌ Denied', value: 'reject' },
48
- ];
49
-
50
- function generateId(): string {
51
- return `nsa-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
52
- }
53
-
54
- export interface RequestSenderApprovalInput {
55
- messagingGroupId: string;
56
- agentGroupId: string;
57
- senderIdentity: string; // namespaced user id (channel_type:handle)
58
- senderName: string | null;
59
- event: InboundEvent;
60
- }
61
-
62
- export async function requestSenderApproval(input: RequestSenderApprovalInput): Promise<void> {
63
- const { messagingGroupId, agentGroupId, senderIdentity, senderName, event } = input;
64
-
65
- // In-flight dedup: don't spam the admin if the same unknown sender
66
- // retries while a card is already pending.
67
- if (hasInFlightSenderApproval(messagingGroupId, senderIdentity)) {
68
- log.debug('Unknown-sender approval already in flight — dropping retry', {
69
- messagingGroupId,
70
- senderIdentity,
71
- });
72
- return;
73
- }
74
-
75
- const approvers = pickApprover(agentGroupId);
76
- if (approvers.length === 0) {
77
- log.warn('Unknown-sender approval skipped — no owner or admin configured', {
78
- messagingGroupId,
79
- agentGroupId,
80
- senderIdentity,
81
- });
82
- return;
83
- }
84
-
85
- const originMg = getMessagingGroup(messagingGroupId);
86
- const originChannelType = originMg?.channel_type ?? '';
87
- const originBotId = originMg ? decodePlatformIdAs(originMg.platform_id, 'v2').botId : null;
88
- const target = await pickApprovalDelivery(approvers, originChannelType, originBotId);
89
- if (!target) {
90
- log.warn('Unknown-sender approval skipped — no DM channel for any approver', {
91
- messagingGroupId,
92
- agentGroupId,
93
- senderIdentity,
94
- });
95
- return;
96
- }
97
-
98
- const approvalId = generateId();
99
- const senderDisplay = senderName && senderName.length > 0 ? senderName : senderIdentity;
100
- const originName = originMg?.name ?? `a ${originChannelType} channel`;
101
-
102
- const title = '👤 New sender';
103
- const question = `${senderDisplay} wants to talk to your agent in ${originName}. Allow?`;
104
- const options = normalizeOptions(APPROVAL_OPTIONS);
105
-
106
- createPendingSenderApproval({
107
- id: approvalId,
108
- messaging_group_id: messagingGroupId,
109
- agent_group_id: agentGroupId,
110
- sender_identity: senderIdentity,
111
- sender_name: senderName,
112
- original_message: JSON.stringify(event),
113
- approver_user_id: target.userId,
114
- created_at: new Date().toISOString(),
115
- title,
116
- options_json: JSON.stringify(options),
117
- });
118
-
119
- const adapter = getDeliveryAdapter();
120
- if (!adapter) {
121
- // Without a delivery adapter, the card can't be sent. Log + leave the
122
- // row in place so the admin can see it via DB or manual tooling; the
123
- // dedup gate will suppress further cards until it's cleared.
124
- log.error('Unknown-sender approval row created but no delivery adapter is wired', {
125
- approvalId,
126
- });
127
- return;
128
- }
129
-
130
- try {
131
- await adapter.deliver(
132
- target.messagingGroup.channel_type,
133
- target.messagingGroup.platform_id,
134
- null,
135
- 'chat-sdk',
136
- JSON.stringify({
137
- type: 'ask_question',
138
- questionId: approvalId,
139
- title,
140
- question: appendFallbackNotice(question, target.viaFallbackBot, originBotId),
141
- options,
142
- }),
143
- );
144
- log.info('Unknown-sender approval card delivered', {
145
- approvalId,
146
- senderIdentity,
147
- approver: target.userId,
148
- messagingGroupId,
149
- agentGroupId,
150
- });
151
- } catch (err) {
152
- log.error('Unknown-sender approval card delivery failed', {
153
- approvalId,
154
- err,
155
- });
156
- }
157
- }
158
-
159
- /**
160
- * Option value the admin clicked that means "allow" — shared with the
161
- * response handler so the two sides can't drift.
162
- */
163
- export const APPROVE_VALUE = 'approve';
164
- export const APPROVE_AND_ALLOW_VALUE = 'approve_and_allow';
165
- export const REJECT_VALUE = 'reject';
@@ -1,200 +0,0 @@
1
- /**
2
- * User DM resolution.
3
- *
4
- * Exposes one primitive: `ensureUserDm(userId, opts?)` returns (or lazily
5
- * creates) the `messaging_groups` row that the host should deliver to
6
- * when it wants to DM a given user. Everything that needs to cold-DM a
7
- * user — approvals, pairing handshakes, host notifications — goes
8
- * through this function.
9
- *
10
- * ## Two-class resolution
11
- *
12
- * Channels split cleanly into two classes based on whether the user id is
13
- * already the DM platform id:
14
- *
15
- * - **Direct-addressable** (Telegram, WhatsApp, iMessage, email, Matrix):
16
- * user handle IS the DM chat id. No adapter method needed; we just
17
- * mint a messaging_group row with `platform_id = handle`.
18
- *
19
- * - **Resolution-required** (Discord, Slack, Teams, Webex, gChat):
20
- * user id and DM channel id are different. The adapter must implement
21
- * `openDM(handle)`, which Chat SDK's `chat.openDM` handles for us via
22
- * the bridge. The returned channel id becomes the `platform_id`.
23
- *
24
- * ## Bot-aware caching (migration 026)
25
- *
26
- * The cache PK is `(user_id, channel_type, bot_id)`. Callers that know
27
- * which bot the DM should reach pass `opts.botId` and get bot-pinned
28
- * resolution: cache reads scope to that bot, cold-resolve goes through
29
- * the live adapter for `(channel, botId)` (not just the first adapter
30
- * for that channel), and the resulting cache row is written under that
31
- * bot's id.
32
- *
33
- * Callers that don't pass a bot id get the legacy "first adapter for
34
- * this channel" behavior, with cache rows under `bot_id = ''` — the
35
- * configurable channel-default slot. The settings UI lets the operator
36
- * point that slot at a specific bot's DM, and `pickApprovalDelivery`
37
- * falls through to it when an exact-bot resolve fails.
38
- *
39
- * ## Caching
40
- *
41
- * Successful resolutions are persisted in `user_dms`. The cache survives
42
- * restarts; first-time DMs on a given `(channel, bot)` pair pay one
43
- * `openDM` round trip, everyone after is a pure DB read.
44
- *
45
- * The underlying platform APIs (`POST /users/@me/channels` on Discord,
46
- * `conversations.open` on Slack, etc.) are idempotent and return the
47
- * same channel on repeated calls, so re-resolving after a cache miss is
48
- * always safe — worst case we round-trip redundantly.
49
- */
50
- import { getChannelAdapter, getChannelAdapterByBotId } from '../../channels/channel-registry.js';
51
- import { getMessagingGroup, getMessagingGroupByPlatform, createMessagingGroup } from '../../db/messaging-groups.js';
52
- import { log } from '../../log.js';
53
- import type { ChannelAdapter } from '../../channels/adapter.js';
54
- import type { MessagingGroup, User } from '../../types.js';
55
- import { getUser } from './db/users.js';
56
- import { getUserDm, upsertUserDm } from './db/user-dms.js';
57
-
58
- export interface EnsureUserDmOptions {
59
- /**
60
- * Pin the resolution to a specific bot. When set, the cache is read /
61
- * written under that exact bot id and cold-resolve uses the adapter
62
- * registered for `(channelType, botId)`. When omitted (or empty
63
- * string), the legacy "first adapter for this channel" path runs and
64
- * the cache row lands under `bot_id = ''` (the configurable
65
- * channel-default slot).
66
- */
67
- botId?: string | null;
68
- }
69
-
70
- /**
71
- * Return a messaging_group usable to DM this user, creating it lazily if
72
- * needed. Returns null when:
73
- * - the user id isn't namespaced (no `kind:handle` prefix)
74
- * - the user's channel has no adapter registered (or, when `opts.botId`
75
- * is set, no adapter is registered for that exact `(channel, bot)`)
76
- * - the channel needs openDM but its adapter doesn't implement it
77
- * - openDM throws (platform error, user blocked bot, the bot can't
78
- * initiate a DM until the user has messaged it first, etc.)
79
- *
80
- * Callers should treat null as "this user is unreachable on this
81
- * channel + bot pair." `pickApprovalDelivery` translates that into a
82
- * channel-default fallback before giving up entirely.
83
- */
84
- export async function ensureUserDm(userId: string, opts?: EnsureUserDmOptions): Promise<MessagingGroup | null> {
85
- const user = getUser(userId);
86
- if (!user) {
87
- log.warn('ensureUserDm: user not found', { userId });
88
- return null;
89
- }
90
-
91
- const { channelType, handle } = parseUserId(user);
92
- if (!channelType || !handle) {
93
- log.warn('ensureUserDm: user id not namespaced', { userId });
94
- return null;
95
- }
96
-
97
- const botId = opts?.botId ?? '';
98
-
99
- // Cache hit: existing user_dms row → load and return the messaging_group.
100
- const cached = getUserDm(userId, channelType, botId);
101
- if (cached) {
102
- const mg = getMessagingGroup(cached.messaging_group_id);
103
- if (mg) return mg;
104
- // Row points to a deleted messaging_group — fall through and re-resolve.
105
- log.warn('ensureUserDm: cached row references missing messaging_group, re-resolving', {
106
- userId,
107
- botId,
108
- messagingGroupId: cached.messaging_group_id,
109
- });
110
- }
111
-
112
- // Cache miss: pick the adapter. With a bot id we MUST use that exact
113
- // bot's adapter — falling back to "any adapter for this channel" would
114
- // re-introduce the bug Proposal C is fixing (cross-bot delivery).
115
- const adapter = botId ? getChannelAdapterByBotId(channelType, botId) : getChannelAdapter(channelType);
116
- if (!adapter) {
117
- log.warn('ensureUserDm: no adapter for channel/bot', { channelType, botId });
118
- return null;
119
- }
120
-
121
- const dmPlatformId = await resolveDmPlatformId(adapter, channelType, handle);
122
- if (!dmPlatformId) return null;
123
-
124
- // Find-or-create the underlying messaging_group. A DM we received
125
- // earlier may already have a row matching (channel_type, platform_id).
126
- const now = new Date().toISOString();
127
- let mg = getMessagingGroupByPlatform(channelType, dmPlatformId);
128
- if (!mg) {
129
- const mgId = `mg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
130
- mg = {
131
- id: mgId,
132
- channel_type: channelType,
133
- platform_id: dmPlatformId,
134
- name: user.display_name,
135
- is_group: 0,
136
- unknown_sender_policy: 'strict',
137
- created_at: now,
138
- };
139
- createMessagingGroup(mg);
140
- log.info('ensureUserDm: created DM messaging_group', {
141
- userId,
142
- channelType,
143
- botId,
144
- messagingGroupId: mgId,
145
- });
146
- }
147
-
148
- upsertUserDm({
149
- user_id: userId,
150
- channel_type: channelType,
151
- bot_id: botId,
152
- messaging_group_id: mg.id,
153
- resolved_at: now,
154
- });
155
-
156
- return mg;
157
- }
158
-
159
- /**
160
- * Call the adapter's openDM if it has one; otherwise fall through to using
161
- * the handle directly. Returns null if openDM throws (platform-side
162
- * refusal — Telegram bots can't DM first, Discord blocked-by-recipient,
163
- * etc.).
164
- */
165
- async function resolveDmPlatformId(
166
- adapter: ChannelAdapter,
167
- channelType: string,
168
- handle: string,
169
- ): Promise<string | null> {
170
- if (!adapter.openDM) {
171
- // Direct-addressable channel — handle doubles as the DM chat id.
172
- return handle;
173
- }
174
- try {
175
- return await adapter.openDM(handle);
176
- } catch (err) {
177
- log.error('ensureUserDm: adapter.openDM failed', {
178
- channelType,
179
- botId: adapter.botId ?? null,
180
- handle,
181
- err,
182
- });
183
- return null;
184
- }
185
- }
186
-
187
- function parseUserId(user: User): { channelType: string; handle: string } | { channelType: null; handle: null } {
188
- const idx = user.id.indexOf(':');
189
- if (idx < 0) return { channelType: null, handle: null };
190
- const prefix = user.id.slice(0, idx);
191
- const handle = user.id.slice(idx + 1);
192
- if (!prefix || !handle) return { channelType: null, handle: null };
193
- // Teams user IDs use a `29:` prefix, not `teams:`. When the id prefix
194
- // isn't a registered adapter, fall back to user.kind and treat the full
195
- // id as the handle.
196
- if (!getChannelAdapter(prefix) && user.kind && getChannelAdapter(user.kind)) {
197
- return { channelType: user.kind, handle: user.id };
198
- }
199
- return { channelType: prefix, handle };
200
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * `provider_credentials` row helpers.
3
- *
4
- * The PK column doubles as a sentinel slot — id `'__default__'` is the
5
- * install-wide row; Phase 2 will add real `agent_group_id` rows alongside.
6
- *
7
- * Encryption: `api_key_encrypted` is AES-GCM ciphertext (HKDF-derived
8
- * key, info `paraclaw.provider-credentials.v1`). Plaintext only crosses
9
- * this module's boundary at put/get time.
10
- *
11
- * ⚠ The `paraclaw.` prefix in the HKDF info string is a cryptographic
12
- * domain separator and is frozen across the paraclaw → parachute-agent
13
- * rename. Renaming it derives a different key and renders existing
14
- * ciphertext undecryptable. The brand sweep does not touch these bytes.
15
- */
16
- import { getDb } from '../../db/connection.js';
17
- import { decryptSecret, deriveKey, encryptSecret } from '../../secrets/crypto.js';
18
- import { loadOrCreateMasterKey } from '../../secrets/master-key.js';
19
-
20
- export const DEFAULT_SCOPE_ID = '__default__';
21
- const PROVIDER_CREDS_INFO = 'paraclaw.provider-credentials.v1';
22
-
23
- export type ProviderSource = 'claude_setup_token' | 'anthropic_api_key' | 'external_server';
24
-
25
- export interface ProviderCredentialsRow {
26
- agent_group_id: string;
27
- source: ProviderSource;
28
- api_key_encrypted: string | null;
29
- server_url: string | null;
30
- updated_at: string;
31
- }
32
-
33
- export interface ProviderCredentialsPlaintext {
34
- agent_group_id: string;
35
- source: ProviderSource;
36
- /**
37
- * Plaintext secret. For `claude_setup_token` this is the OAuth token
38
- * (`sk-ant-oat01-...`). For `anthropic_api_key` and `external_server`
39
- * it's the API key. Null when unset.
40
- */
41
- apiKey: string | null;
42
- serverUrl: string | null;
43
- updatedAt: string;
44
- }
45
-
46
- function key(): Buffer {
47
- return deriveKey(loadOrCreateMasterKey(), PROVIDER_CREDS_INFO);
48
- }
49
-
50
- export function getProviderCredentialsRow(scopeId: string = DEFAULT_SCOPE_ID): ProviderCredentialsRow | undefined {
51
- return getDb()
52
- .prepare<ProviderCredentialsRow>('SELECT * FROM provider_credentials WHERE agent_group_id = ?')
53
- .get(scopeId);
54
- }
55
-
56
- export function readProviderCredentials(scopeId: string = DEFAULT_SCOPE_ID): ProviderCredentialsPlaintext | undefined {
57
- const row = getProviderCredentialsRow(scopeId);
58
- if (!row) return undefined;
59
- const k = key();
60
- return {
61
- agent_group_id: row.agent_group_id,
62
- source: row.source,
63
- apiKey: row.api_key_encrypted ? decryptSecret(row.api_key_encrypted, k) : null,
64
- serverUrl: row.server_url,
65
- updatedAt: row.updated_at,
66
- };
67
- }
68
-
69
- export interface PutProviderCredentialsInput {
70
- // Required so a future caller can't silently overwrite the install-wide
71
- // row by forgetting the scope. Pass `DEFAULT_SCOPE_ID` explicitly when
72
- // you mean the install-wide credential.
73
- scopeId: string;
74
- source: ProviderSource;
75
- apiKey?: string | null;
76
- serverUrl?: string | null;
77
- }
78
-
79
- /**
80
- * Upsert the row for the given scope. Plaintext fields are encrypted
81
- * here. Pass `null` to clear a field; pass `undefined` to leave it
82
- * unchanged (caller-side merge — we read-modify-write).
83
- */
84
- export function putProviderCredentials(input: PutProviderCredentialsInput): void {
85
- const { scopeId } = input;
86
- const existing = getProviderCredentialsRow(scopeId);
87
- const k = key();
88
- const api_key_encrypted =
89
- input.apiKey === undefined
90
- ? (existing?.api_key_encrypted ?? null)
91
- : input.apiKey === null
92
- ? null
93
- : encryptSecret(input.apiKey, k);
94
- const server_url = input.serverUrl === undefined ? (existing?.server_url ?? null) : input.serverUrl;
95
- const updated_at = new Date().toISOString();
96
-
97
- getDb()
98
- .prepare(
99
- `INSERT INTO provider_credentials
100
- (agent_group_id, source, api_key_encrypted, server_url, updated_at)
101
- VALUES
102
- (@agent_group_id, @source, @api_key_encrypted, @server_url, @updated_at)
103
- ON CONFLICT (agent_group_id) DO UPDATE SET
104
- source = excluded.source,
105
- api_key_encrypted = excluded.api_key_encrypted,
106
- server_url = excluded.server_url,
107
- updated_at = excluded.updated_at`,
108
- )
109
- .run({
110
- agent_group_id: scopeId,
111
- source: input.source,
112
- api_key_encrypted,
113
- server_url,
114
- updated_at,
115
- });
116
- }
117
-
118
- export function deleteProviderCredentials(scopeId: string = DEFAULT_SCOPE_ID): boolean {
119
- const r = getDb().prepare('DELETE FROM provider_credentials WHERE agent_group_id = ?').run(scopeId);
120
- return r.changes > 0;
121
- }
@@ -1,12 +0,0 @@
1
- export {
2
- DEFAULT_SCOPE_ID,
3
- deleteProviderCredentials,
4
- getProviderCredentialsRow,
5
- putProviderCredentials,
6
- readProviderCredentials,
7
- type ProviderCredentialsPlaintext,
8
- type ProviderCredentialsRow,
9
- type ProviderSource,
10
- type PutProviderCredentialsInput,
11
- } from './db.js';
12
- export { getProviderCredentialsForSpawn, type ProviderSpawnEnvelope } from './spawn.js';