@openparachute/agent 0.1.2 → 0.2.0

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 (605) hide show
  1. package/.parachute/module.json +124 -8
  2. package/LICENSE +2 -16
  3. package/README.md +118 -166
  4. package/package.json +32 -43
  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/tsconfig.json +2 -1
  103. package/.claude/scheduled_tasks.lock +0 -1
  104. package/.claude/settings.json +0 -5
  105. package/.claude/skills/add-atomic-chat-tool/SKILL.md +0 -243
  106. package/.claude/skills/add-atomic-chat-tool/atomic-chat-mcp-stdio.ts +0 -229
  107. package/.claude/skills/add-codex/SKILL.md +0 -161
  108. package/.claude/skills/add-dashboard/SKILL.md +0 -138
  109. package/.claude/skills/add-dashboard/resources/dashboard-pusher.ts +0 -495
  110. package/.claude/skills/add-emacs/SKILL.md +0 -296
  111. package/.claude/skills/add-gcal-tool/SKILL.md +0 -210
  112. package/.claude/skills/add-gchat/REMOVE.md +0 -6
  113. package/.claude/skills/add-gchat/SKILL.md +0 -92
  114. package/.claude/skills/add-gchat/VERIFY.md +0 -3
  115. package/.claude/skills/add-github/REMOVE.md +0 -6
  116. package/.claude/skills/add-github/SKILL.md +0 -148
  117. package/.claude/skills/add-github/VERIFY.md +0 -3
  118. package/.claude/skills/add-gmail-tool/SKILL.md +0 -229
  119. package/.claude/skills/add-imessage/REMOVE.md +0 -6
  120. package/.claude/skills/add-imessage/SKILL.md +0 -113
  121. package/.claude/skills/add-imessage/VERIFY.md +0 -3
  122. package/.claude/skills/add-karpathy-llm-wiki/SKILL.md +0 -110
  123. package/.claude/skills/add-karpathy-llm-wiki/llm-wiki.md +0 -75
  124. package/.claude/skills/add-linear/REMOVE.md +0 -6
  125. package/.claude/skills/add-linear/SKILL.md +0 -168
  126. package/.claude/skills/add-linear/VERIFY.md +0 -3
  127. package/.claude/skills/add-macos-statusbar/SKILL.md +0 -133
  128. package/.claude/skills/add-macos-statusbar/add/src/statusbar.swift +0 -147
  129. package/.claude/skills/add-matrix/REMOVE.md +0 -6
  130. package/.claude/skills/add-matrix/SKILL.md +0 -148
  131. package/.claude/skills/add-matrix/VERIFY.md +0 -3
  132. package/.claude/skills/add-ollama-provider/SKILL.md +0 -179
  133. package/.claude/skills/add-ollama-tool/SKILL.md +0 -193
  134. package/.claude/skills/add-opencode/SKILL.md +0 -229
  135. package/.claude/skills/add-parallel/SKILL.md +0 -290
  136. package/.claude/skills/add-resend/REMOVE.md +0 -6
  137. package/.claude/skills/add-resend/SKILL.md +0 -93
  138. package/.claude/skills/add-resend/VERIFY.md +0 -3
  139. package/.claude/skills/add-signal/REMOVE.md +0 -13
  140. package/.claude/skills/add-signal/SKILL.md +0 -318
  141. package/.claude/skills/add-signal/VERIFY.md +0 -5
  142. package/.claude/skills/add-slack/REMOVE.md +0 -6
  143. package/.claude/skills/add-slack/SKILL.md +0 -112
  144. package/.claude/skills/add-slack/VERIFY.md +0 -3
  145. package/.claude/skills/add-teams/REMOVE.md +0 -6
  146. package/.claude/skills/add-teams/SKILL.md +0 -207
  147. package/.claude/skills/add-teams/VERIFY.md +0 -3
  148. package/.claude/skills/add-vercel/SKILL.md +0 -147
  149. package/.claude/skills/add-vercel/container-skills/vercel-cli/SKILL.md +0 -103
  150. package/.claude/skills/add-webex/REMOVE.md +0 -6
  151. package/.claude/skills/add-webex/SKILL.md +0 -88
  152. package/.claude/skills/add-webex/VERIFY.md +0 -3
  153. package/.claude/skills/add-wechat/REMOVE.md +0 -49
  154. package/.claude/skills/add-wechat/SKILL.md +0 -170
  155. package/.claude/skills/add-wechat/scripts/wire-dm.ts +0 -172
  156. package/.claude/skills/add-whatsapp/SKILL.md +0 -264
  157. package/.claude/skills/add-whatsapp-cloud/REMOVE.md +0 -6
  158. package/.claude/skills/add-whatsapp-cloud/SKILL.md +0 -95
  159. package/.claude/skills/add-whatsapp-cloud/VERIFY.md +0 -3
  160. package/.claude/skills/claw/SKILL.md +0 -131
  161. package/.claude/skills/claw/scripts/claw +0 -374
  162. package/.claude/skills/convert-to-apple-container/SKILL.md +0 -212
  163. package/.claude/skills/customize/SKILL.md +0 -110
  164. package/.claude/skills/debug/SKILL.md +0 -349
  165. package/.claude/skills/get-qodo-rules/SKILL.md +0 -122
  166. package/.claude/skills/get-qodo-rules/references/output-format.md +0 -41
  167. package/.claude/skills/get-qodo-rules/references/pagination.md +0 -33
  168. package/.claude/skills/get-qodo-rules/references/repository-scope.md +0 -26
  169. package/.claude/skills/init-first-agent/SKILL.md +0 -120
  170. package/.claude/skills/init-onecli/SKILL.md +0 -270
  171. package/.claude/skills/manage-channels/SKILL.md +0 -87
  172. package/.claude/skills/manage-mounts/SKILL.md +0 -47
  173. package/.claude/skills/migrate-from-openclaw/MIGRATE_CRONS.md +0 -100
  174. package/.claude/skills/migrate-from-openclaw/SKILL.md +0 -447
  175. package/.claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts +0 -734
  176. package/.claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts +0 -476
  177. package/.claude/skills/migrate-nanoclaw/SKILL.md +0 -484
  178. package/.claude/skills/migrate-nanoclaw/diagnostics.md +0 -51
  179. package/.claude/skills/qodo-pr-resolver/SKILL.md +0 -326
  180. package/.claude/skills/qodo-pr-resolver/resources/providers.md +0 -329
  181. package/.claude/skills/update-nanoclaw/SKILL.md +0 -243
  182. package/.claude/skills/update-nanoclaw/diagnostics.md +0 -48
  183. package/.claude/skills/update-skills/SKILL.md +0 -130
  184. package/.claude/skills/use-native-credential-proxy/SKILL.md +0 -167
  185. package/.claude/skills/x-integration/SKILL.md +0 -417
  186. package/.claude/skills/x-integration/agent.ts +0 -243
  187. package/.claude/skills/x-integration/host.ts +0 -155
  188. package/.claude/skills/x-integration/lib/browser.ts +0 -148
  189. package/.claude/skills/x-integration/lib/config.ts +0 -62
  190. package/.claude/skills/x-integration/scripts/like.ts +0 -56
  191. package/.claude/skills/x-integration/scripts/post.ts +0 -66
  192. package/.claude/skills/x-integration/scripts/quote.ts +0 -80
  193. package/.claude/skills/x-integration/scripts/reply.ts +0 -74
  194. package/.claude/skills/x-integration/scripts/retweet.ts +0 -62
  195. package/.claude/skills/x-integration/scripts/setup.ts +0 -87
  196. package/.github/CODEOWNERS +0 -10
  197. package/.github/PULL_REQUEST_TEMPLATE.md +0 -18
  198. package/.github/workflows/bump-version.yml +0 -35
  199. package/.github/workflows/ci.yml +0 -39
  200. package/.github/workflows/label-pr.yml +0 -40
  201. package/.github/workflows/update-tokens.yml +0 -43
  202. package/.husky/pre-commit +0 -1
  203. package/.mcp.json +0 -3
  204. package/.nvmrc +0 -1
  205. package/.prettierrc +0 -4
  206. package/CHANGELOG.md +0 -263
  207. package/CLAUDE.md +0 -307
  208. package/CODE_OF_CONDUCT.md +0 -128
  209. package/CONTRIBUTING.md +0 -159
  210. package/CONTRIBUTORS.md +0 -26
  211. package/LICENSE-NANOCLAW-MIT +0 -21
  212. package/README_ja.md +0 -194
  213. package/README_zh.md +0 -194
  214. package/assets/nanoclaw-favicon.png +0 -0
  215. package/assets/nanoclaw-icon.png +0 -0
  216. package/assets/nanoclaw-logo-dark.png +0 -0
  217. package/assets/nanoclaw-logo.png +0 -0
  218. package/assets/nanoclaw-profile.jpeg +0 -0
  219. package/assets/nanoclaw-sales.png +0 -0
  220. package/assets/social-preview.jpg +0 -0
  221. package/config-examples/mount-allowlist.json +0 -25
  222. package/container/.dockerignore +0 -2
  223. package/container/CLAUDE.md +0 -21
  224. package/container/Dockerfile +0 -121
  225. package/container/agent-runner/bun.lock +0 -243
  226. package/container/agent-runner/package.json +0 -22
  227. package/container/agent-runner/scripts/sdk-signal-probe.ts +0 -169
  228. package/container/agent-runner/src/config.ts +0 -55
  229. package/container/agent-runner/src/db/connection.ts +0 -267
  230. package/container/agent-runner/src/db/index.ts +0 -20
  231. package/container/agent-runner/src/db/messages-in.ts +0 -138
  232. package/container/agent-runner/src/db/messages-out.ts +0 -143
  233. package/container/agent-runner/src/db/session-routing.ts +0 -30
  234. package/container/agent-runner/src/db/session-state.test.ts +0 -100
  235. package/container/agent-runner/src/db/session-state.ts +0 -79
  236. package/container/agent-runner/src/destinations.ts +0 -135
  237. package/container/agent-runner/src/formatter.test.ts +0 -167
  238. package/container/agent-runner/src/formatter.ts +0 -260
  239. package/container/agent-runner/src/index.ts +0 -110
  240. package/container/agent-runner/src/integration.test.ts +0 -121
  241. package/container/agent-runner/src/mcp-tools/agents.instructions.md +0 -26
  242. package/container/agent-runner/src/mcp-tools/agents.ts +0 -66
  243. package/container/agent-runner/src/mcp-tools/core.instructions.md +0 -27
  244. package/container/agent-runner/src/mcp-tools/core.ts +0 -262
  245. package/container/agent-runner/src/mcp-tools/index.ts +0 -22
  246. package/container/agent-runner/src/mcp-tools/interactive.instructions.md +0 -22
  247. package/container/agent-runner/src/mcp-tools/interactive.ts +0 -169
  248. package/container/agent-runner/src/mcp-tools/scheduling.instructions.md +0 -40
  249. package/container/agent-runner/src/mcp-tools/scheduling.ts +0 -299
  250. package/container/agent-runner/src/mcp-tools/self-mod.instructions.md +0 -25
  251. package/container/agent-runner/src/mcp-tools/self-mod.ts +0 -120
  252. package/container/agent-runner/src/mcp-tools/server.ts +0 -54
  253. package/container/agent-runner/src/mcp-tools/types.ts +0 -6
  254. package/container/agent-runner/src/poll-loop.test.ts +0 -248
  255. package/container/agent-runner/src/poll-loop.ts +0 -437
  256. package/container/agent-runner/src/providers/claude.ts +0 -379
  257. package/container/agent-runner/src/providers/factory.test.ts +0 -19
  258. package/container/agent-runner/src/providers/factory.ts +0 -13
  259. package/container/agent-runner/src/providers/index.ts +0 -6
  260. package/container/agent-runner/src/providers/mock.ts +0 -77
  261. package/container/agent-runner/src/providers/provider-registry.ts +0 -33
  262. package/container/agent-runner/src/providers/types.ts +0 -82
  263. package/container/agent-runner/src/scheduling/task-script.ts +0 -121
  264. package/container/agent-runner/src/timezone.test.ts +0 -93
  265. package/container/agent-runner/src/timezone.ts +0 -107
  266. package/container/agent-runner/tsconfig.json +0 -14
  267. package/container/build.sh +0 -48
  268. package/container/entrypoint.sh +0 -16
  269. package/container/skills/agent-browser/SKILL.md +0 -159
  270. package/container/skills/frontend-engineer/SKILL.md +0 -157
  271. package/container/skills/self-customize/SKILL.md +0 -87
  272. package/container/skills/slack-formatting/SKILL.md +0 -94
  273. package/container/skills/vercel-cli/SKILL.md +0 -111
  274. package/container/skills/welcome/SKILL.md +0 -85
  275. package/docs/APPLE-CONTAINER-NETWORKING.md +0 -90
  276. package/docs/BRANCH-FORK-MAINTENANCE.md +0 -81
  277. package/docs/README.md +0 -25
  278. package/docs/SDK_DEEP_DIVE.md +0 -643
  279. package/docs/SECURITY.md +0 -162
  280. package/docs/agent-runner-details.md +0 -749
  281. package/docs/api-details.md +0 -365
  282. package/docs/architecture-diagram.html +0 -422
  283. package/docs/architecture-diagram.md +0 -215
  284. package/docs/architecture.md +0 -751
  285. package/docs/audit/2026-04-30-channel-endpoint-audit.md +0 -36
  286. package/docs/build-and-runtime.md +0 -80
  287. package/docs/cross-mount-stress/README.md +0 -112
  288. package/docs/cross-mount-stress/container-writer-retry.mjs +0 -55
  289. package/docs/cross-mount-stress/container-writer-slow.mjs +0 -42
  290. package/docs/cross-mount-stress/container-writer.mjs +0 -47
  291. package/docs/cross-mount-stress/host-writer-retry.mjs +0 -55
  292. package/docs/cross-mount-stress/host-writer-slow.mjs +0 -43
  293. package/docs/cross-mount-stress/host-writer.mjs +0 -47
  294. package/docs/db-central.md +0 -316
  295. package/docs/db-session.md +0 -183
  296. package/docs/db.md +0 -119
  297. package/docs/design/2026-04-29-vault-management-ui.md +0 -231
  298. package/docs/design/2026-04-30-channel-wiring-rework.md +0 -234
  299. package/docs/design/2026-05-01-channel-wiring-approvals-deep-dive.md +0 -272
  300. package/docs/design/2026-05-02-channel-policy-and-approval-routing.md +0 -250
  301. package/docs/docker-sandboxes.md +0 -359
  302. package/docs/isolation-model.md +0 -88
  303. package/docs/ollama.md +0 -79
  304. package/docs/parachute-integration.md +0 -109
  305. package/docs/post-night-rebirth-reflections.md +0 -151
  306. package/eslint.config.js +0 -32
  307. package/pnpm-workspace.yaml +0 -8
  308. package/repo-tokens/README.md +0 -113
  309. package/repo-tokens/action.yml +0 -186
  310. package/repo-tokens/badge.svg +0 -23
  311. package/repo-tokens/examples/green.svg +0 -14
  312. package/repo-tokens/examples/red.svg +0 -14
  313. package/repo-tokens/examples/yellow-green.svg +0 -14
  314. package/repo-tokens/examples/yellow.svg +0 -14
  315. package/scripts/chat.ts +0 -101
  316. package/scripts/cleanup-sessions.sh +0 -150
  317. package/scripts/init-cli-agent.ts +0 -172
  318. package/scripts/init-first-agent.ts +0 -378
  319. package/scripts/parachute.ts +0 -158
  320. package/scripts/run-migrations.ts +0 -105
  321. package/scripts/sanity-live-poll.ts +0 -95
  322. package/scripts/seed-discord.ts +0 -80
  323. package/scripts/test-v2-agent.ts +0 -106
  324. package/scripts/test-v2-channel-e2e.ts +0 -265
  325. package/scripts/test-v2-host.ts +0 -184
  326. package/src/channels/adapter.ts +0 -214
  327. package/src/channels/api-translator.test.ts +0 -306
  328. package/src/channels/api-translator.ts +0 -214
  329. package/src/channels/ask-question.ts +0 -46
  330. package/src/channels/channel-registry.test.ts +0 -421
  331. package/src/channels/channel-registry.ts +0 -313
  332. package/src/channels/chat-sdk-bridge.test.ts +0 -84
  333. package/src/channels/chat-sdk-bridge.ts +0 -652
  334. package/src/channels/cli.ts +0 -276
  335. package/src/channels/discord.ts +0 -90
  336. package/src/channels/index.ts +0 -17
  337. package/src/channels/telegram-markdown-sanitize.test.ts +0 -78
  338. package/src/channels/telegram-markdown-sanitize.ts +0 -55
  339. package/src/channels/telegram-pairing.test.ts +0 -254
  340. package/src/channels/telegram-pairing.ts +0 -339
  341. package/src/channels/telegram.ts +0 -279
  342. package/src/channels/trust-hint.test.ts +0 -48
  343. package/src/channels/trust-hint.ts +0 -75
  344. package/src/claude-md-compose.migrate.test.ts +0 -64
  345. package/src/claude-md-compose.ts +0 -205
  346. package/src/command-gate.ts +0 -63
  347. package/src/config.test.ts +0 -93
  348. package/src/config.ts +0 -128
  349. package/src/container-config.ts +0 -167
  350. package/src/container-runner.test.ts +0 -32
  351. package/src/container-runner.ts +0 -576
  352. package/src/container-runtime.test.ts +0 -269
  353. package/src/container-runtime.ts +0 -167
  354. package/src/db/_bun-sqlite-shim.ts +0 -88
  355. package/src/db/agent-activity.test.ts +0 -155
  356. package/src/db/agent-activity.ts +0 -121
  357. package/src/db/agent-groups.ts +0 -77
  358. package/src/db/connection.migrate.test.ts +0 -176
  359. package/src/db/connection.ts +0 -259
  360. package/src/db/db-v2.test.ts +0 -440
  361. package/src/db/dropped-messages.ts +0 -44
  362. package/src/db/index.ts +0 -40
  363. package/src/db/messaging-groups.ts +0 -252
  364. package/src/db/migrations/001-initial.ts +0 -112
  365. package/src/db/migrations/002-chat-sdk-state.ts +0 -36
  366. package/src/db/migrations/008-dropped-messages.ts +0 -27
  367. package/src/db/migrations/009-drop-pending-credentials.ts +0 -13
  368. package/src/db/migrations/010-engage-modes.ts +0 -103
  369. package/src/db/migrations/011-pending-sender-approvals.ts +0 -40
  370. package/src/db/migrations/012-channel-registration.ts +0 -48
  371. package/src/db/migrations/013-approval-render-metadata.ts +0 -27
  372. package/src/db/migrations/014-secrets.ts +0 -44
  373. package/src/db/migrations/015-secrets-drop-host-pattern.ts +0 -18
  374. package/src/db/migrations/016-secret-assignments.ts +0 -30
  375. package/src/db/migrations/017-agent-activity.ts +0 -40
  376. package/src/db/migrations/018-oauth-app-configs.ts +0 -34
  377. package/src/db/migrations/019-oauth-app-connections.ts +0 -48
  378. package/src/db/migrations/020-agent-app-connections.ts +0 -28
  379. package/src/db/migrations/021-pending-oauth-states.ts +0 -35
  380. package/src/db/migrations/022-app-connections-provider.ts +0 -25
  381. package/src/db/migrations/023-agent-group-secret-mode.test.ts +0 -124
  382. package/src/db/migrations/023-agent-group-secret-mode.ts +0 -65
  383. package/src/db/migrations/024-collapse-approvals.test.ts +0 -249
  384. package/src/db/migrations/024-collapse-approvals.ts +0 -182
  385. package/src/db/migrations/025-secret-mode-check.test.ts +0 -155
  386. package/src/db/migrations/025-secret-mode-check.ts +0 -49
  387. package/src/db/migrations/026-user-dms-bot-id.test.ts +0 -116
  388. package/src/db/migrations/026-user-dms-bot-id.ts +0 -54
  389. package/src/db/migrations/027-provider-credentials.ts +0 -41
  390. package/src/db/migrations/_test-helpers.ts +0 -41
  391. package/src/db/migrations/index.ts +0 -127
  392. package/src/db/migrations/module-agent-to-agent-destinations.ts +0 -84
  393. package/src/db/migrations/module-approvals-pending-approvals.ts +0 -42
  394. package/src/db/migrations/module-approvals-title-options.ts +0 -40
  395. package/src/db/schema.ts +0 -258
  396. package/src/db/session-db.test.ts +0 -93
  397. package/src/db/session-db.ts +0 -325
  398. package/src/db/sessions.ts +0 -241
  399. package/src/delivery.test.ts +0 -148
  400. package/src/delivery.ts +0 -445
  401. package/src/env.ts +0 -74
  402. package/src/group-folder.test.ts +0 -35
  403. package/src/group-folder.ts +0 -44
  404. package/src/group-init.ts +0 -92
  405. package/src/host-core.test.ts +0 -456
  406. package/src/host-sweep.test.ts +0 -146
  407. package/src/host-sweep.ts +0 -287
  408. package/src/index.ts +0 -232
  409. package/src/install-slug.ts +0 -33
  410. package/src/log.test.ts +0 -81
  411. package/src/log.ts +0 -117
  412. package/src/mcp/http.ts +0 -72
  413. package/src/mcp/server.ts +0 -92
  414. package/src/mcp/stdio.ts +0 -51
  415. package/src/mcp/tools/activity.ts +0 -88
  416. package/src/mcp/tools/agent-groups.ts +0 -183
  417. package/src/mcp/tools/approvals.ts +0 -122
  418. package/src/mcp/tools/channels.test.ts +0 -126
  419. package/src/mcp/tools/channels.ts +0 -134
  420. package/src/mcp/tools/index.ts +0 -27
  421. package/src/mcp/tools/oauth.ts +0 -48
  422. package/src/mcp/tools/secrets.ts +0 -169
  423. package/src/mcp/tools/sessions.ts +0 -135
  424. package/src/mcp/types.ts +0 -51
  425. package/src/modules/agent-to-agent/agent-route.test.ts +0 -46
  426. package/src/modules/agent-to-agent/agent-route.ts +0 -223
  427. package/src/modules/agent-to-agent/create-agent.ts +0 -127
  428. package/src/modules/agent-to-agent/db/agent-destinations.ts +0 -135
  429. package/src/modules/agent-to-agent/index.ts +0 -22
  430. package/src/modules/agent-to-agent/write-destinations.ts +0 -59
  431. package/src/modules/approvals/agent.md +0 -45
  432. package/src/modules/approvals/index.ts +0 -21
  433. package/src/modules/approvals/picks.test.ts +0 -291
  434. package/src/modules/approvals/primitive.ts +0 -279
  435. package/src/modules/approvals/project.md +0 -27
  436. package/src/modules/approvals/response-handler.ts +0 -87
  437. package/src/modules/index.ts +0 -24
  438. package/src/modules/interactive/agent.md +0 -21
  439. package/src/modules/interactive/index.ts +0 -69
  440. package/src/modules/interactive/project.md +0 -12
  441. package/src/modules/mount-security/expand-path.test.ts +0 -82
  442. package/src/modules/mount-security/index.ts +0 -459
  443. package/src/modules/mount-security/migrate.test.ts +0 -91
  444. package/src/modules/permissions/access.ts +0 -28
  445. package/src/modules/permissions/channel-approval.test.ts +0 -389
  446. package/src/modules/permissions/channel-approval.ts +0 -188
  447. package/src/modules/permissions/db/agent-group-members.ts +0 -44
  448. package/src/modules/permissions/db/pending-channel-approvals.test.ts +0 -86
  449. package/src/modules/permissions/db/pending-channel-approvals.ts +0 -66
  450. package/src/modules/permissions/db/pending-sender-approvals.ts +0 -60
  451. package/src/modules/permissions/db/user-dms.ts +0 -58
  452. package/src/modules/permissions/db/user-roles.ts +0 -85
  453. package/src/modules/permissions/db/users.ts +0 -38
  454. package/src/modules/permissions/index.ts +0 -421
  455. package/src/modules/permissions/permissions.test.ts +0 -358
  456. package/src/modules/permissions/sender-approval.test.ts +0 -641
  457. package/src/modules/permissions/sender-approval.ts +0 -165
  458. package/src/modules/permissions/user-dm.ts +0 -200
  459. package/src/modules/provider-credentials/db.ts +0 -121
  460. package/src/modules/provider-credentials/index.ts +0 -12
  461. package/src/modules/provider-credentials/spawn.test.ts +0 -206
  462. package/src/modules/provider-credentials/spawn.ts +0 -114
  463. package/src/modules/scheduling/actions.ts +0 -113
  464. package/src/modules/scheduling/db.test.ts +0 -282
  465. package/src/modules/scheduling/db.ts +0 -148
  466. package/src/modules/scheduling/index.ts +0 -34
  467. package/src/modules/scheduling/recurrence.test.ts +0 -98
  468. package/src/modules/scheduling/recurrence.ts +0 -54
  469. package/src/modules/self-mod/agent.md +0 -30
  470. package/src/modules/self-mod/apply.ts +0 -85
  471. package/src/modules/self-mod/index.ts +0 -30
  472. package/src/modules/self-mod/project.md +0 -39
  473. package/src/modules/self-mod/request.ts +0 -91
  474. package/src/modules/typing/index.ts +0 -165
  475. package/src/oauth/agent-app-connections.ts +0 -103
  476. package/src/oauth/app-configs.test.ts +0 -64
  477. package/src/oauth/app-configs.ts +0 -114
  478. package/src/oauth/app-connections.test.ts +0 -109
  479. package/src/oauth/app-connections.ts +0 -178
  480. package/src/oauth/crypto.ts +0 -56
  481. package/src/oauth/flow.ts +0 -104
  482. package/src/oauth/providers/google.test.ts +0 -38
  483. package/src/oauth/providers/google.ts +0 -46
  484. package/src/oauth/providers/index.ts +0 -48
  485. package/src/oauth/state-store.test.ts +0 -54
  486. package/src/oauth/state-store.ts +0 -93
  487. package/src/parachute/README.md +0 -27
  488. package/src/parachute/create-agent.test.ts +0 -83
  489. package/src/parachute/create-agent.ts +0 -122
  490. package/src/parachute/group-status.test.ts +0 -165
  491. package/src/parachute/group-status.ts +0 -136
  492. package/src/parachute/types.ts +0 -41
  493. package/src/parachute/vault-mcp.test.ts +0 -251
  494. package/src/parachute/vault-mcp.ts +0 -232
  495. package/src/platform-id.test.ts +0 -104
  496. package/src/platform-id.ts +0 -109
  497. package/src/providers/index.ts +0 -6
  498. package/src/providers/provider-container-registry.ts +0 -58
  499. package/src/response-registry.ts +0 -45
  500. package/src/router.ts +0 -530
  501. package/src/secrets/crypto.test.ts +0 -45
  502. package/src/secrets/crypto.ts +0 -55
  503. package/src/secrets/index.ts +0 -461
  504. package/src/secrets/master-key.ts +0 -70
  505. package/src/secrets/secrets.test.ts +0 -651
  506. package/src/session-manager.attachments.test.ts +0 -171
  507. package/src/session-manager.dup-skip.test.ts +0 -173
  508. package/src/session-manager.migrate.test.ts +0 -59
  509. package/src/session-manager.ts +0 -451
  510. package/src/startup-bootstrap.test.ts +0 -226
  511. package/src/startup-bootstrap.ts +0 -207
  512. package/src/state-sqlite.ts +0 -182
  513. package/src/timezone.test.ts +0 -64
  514. package/src/timezone.ts +0 -37
  515. package/src/types.ts +0 -233
  516. package/src/web/auth.test.ts +0 -335
  517. package/src/web/auth.ts +0 -214
  518. package/src/web/discord-validate.test.ts +0 -77
  519. package/src/web/discord-validate.ts +0 -88
  520. package/src/web/hub-discovery.test.ts +0 -98
  521. package/src/web/hub-discovery.ts +0 -69
  522. package/src/web/routes/activity.ts +0 -106
  523. package/src/web/routes/agent-provider.test.ts +0 -282
  524. package/src/web/routes/agent-provider.ts +0 -309
  525. package/src/web/routes/approvals.ts +0 -185
  526. package/src/web/routes/apps.ts +0 -434
  527. package/src/web/routes/channels-mg-detail.test.ts +0 -324
  528. package/src/web/routes/channels-mga-detail.test.ts +0 -472
  529. package/src/web/routes/channels.ts +0 -311
  530. package/src/web/routes/oauth-providers.ts +0 -42
  531. package/src/web/routes/secrets.test.ts +0 -220
  532. package/src/web/routes/secrets.ts +0 -317
  533. package/src/web/routes/sessions.ts +0 -123
  534. package/src/web/routes/settings.test.ts +0 -106
  535. package/src/web/routes/settings.ts +0 -247
  536. package/src/web/routes/setup-status.ts +0 -205
  537. package/src/web/routes/vaults.test.ts +0 -389
  538. package/src/web/routes/vaults.ts +0 -225
  539. package/src/web/server-version.test.ts +0 -16
  540. package/src/web/server.ts +0 -1024
  541. package/src/web/services-manifest.test.ts +0 -148
  542. package/src/web/services-manifest.ts +0 -66
  543. package/src/web/static-serve.test.ts +0 -255
  544. package/src/web/static-serve.ts +0 -104
  545. package/src/web/telegram-validate.test.ts +0 -116
  546. package/src/web/telegram-validate.ts +0 -107
  547. package/src/web/vault-proxy.test.ts +0 -214
  548. package/src/web/vault-proxy.ts +0 -120
  549. package/src/web/wire-channel.ts +0 -181
  550. package/src/webhook-server.ts +0 -134
  551. package/vitest.config.ts +0 -18
  552. package/web/README.md +0 -63
  553. package/web/ui/index.html +0 -13
  554. package/web/ui/package.json +0 -35
  555. package/web/ui/pnpm-lock.yaml +0 -2164
  556. package/web/ui/scripts/verify-base.mjs +0 -31
  557. package/web/ui/src/App.tsx +0 -88
  558. package/web/ui/src/components/ActivityFeed.tsx +0 -444
  559. package/web/ui/src/components/AgentGroupPicker.tsx +0 -263
  560. package/web/ui/src/components/AgentProviderCards.tsx +0 -220
  561. package/web/ui/src/components/CredentialForm.tsx +0 -214
  562. package/web/ui/src/components/ScopeGrants.tsx +0 -74
  563. package/web/ui/src/components/StatusDot.tsx +0 -43
  564. package/web/ui/src/components/VaultPicker.tsx +0 -127
  565. package/web/ui/src/components/setup/AdapterInstallStep.tsx +0 -178
  566. package/web/ui/src/components/setup/AgentGroupStep.tsx +0 -43
  567. package/web/ui/src/components/setup/ChannelPickStep.tsx +0 -74
  568. package/web/ui/src/components/setup/DoneStep.tsx +0 -49
  569. package/web/ui/src/components/setup/PrereqStep.tsx +0 -129
  570. package/web/ui/src/components/setup/TestConnectionStep.tsx +0 -108
  571. package/web/ui/src/components/setup/TestMessageStep.tsx +0 -104
  572. package/web/ui/src/components/setup/WireChannelStep.tsx +0 -166
  573. package/web/ui/src/components/setup/types.ts +0 -105
  574. package/web/ui/src/lib/api.test.ts +0 -410
  575. package/web/ui/src/lib/api.ts +0 -1248
  576. package/web/ui/src/lib/auth.test.ts +0 -352
  577. package/web/ui/src/lib/auth.ts +0 -405
  578. package/web/ui/src/lib/channel-adapters.ts +0 -136
  579. package/web/ui/src/main.tsx +0 -19
  580. package/web/ui/src/routes/ApprovalsList.tsx +0 -294
  581. package/web/ui/src/routes/Apps.tsx +0 -613
  582. package/web/ui/src/routes/ChannelWireDetail.test.tsx +0 -233
  583. package/web/ui/src/routes/ChannelWireDetail.tsx +0 -403
  584. package/web/ui/src/routes/ChannelsList.tsx +0 -158
  585. package/web/ui/src/routes/GroupDetail.test.tsx +0 -206
  586. package/web/ui/src/routes/GroupDetail.tsx +0 -880
  587. package/web/ui/src/routes/GroupList.tsx +0 -187
  588. package/web/ui/src/routes/MessagingGroupDetail.test.tsx +0 -233
  589. package/web/ui/src/routes/MessagingGroupDetail.tsx +0 -306
  590. package/web/ui/src/routes/NewGroupWizard.tsx +0 -390
  591. package/web/ui/src/routes/OAuthCallback.tsx +0 -56
  592. package/web/ui/src/routes/SecretsList.tsx +0 -942
  593. package/web/ui/src/routes/SessionsList.tsx +0 -220
  594. package/web/ui/src/routes/SettingsAgentProvider.tsx +0 -109
  595. package/web/ui/src/routes/SettingsApprovals.tsx +0 -234
  596. package/web/ui/src/routes/SetupWizard.tsx +0 -219
  597. package/web/ui/src/routes/VaultDetail.test.tsx +0 -363
  598. package/web/ui/src/routes/VaultDetail.tsx +0 -960
  599. package/web/ui/src/routes/VaultsList.tsx +0 -295
  600. package/web/ui/src/routes/WireChannelPage.tsx +0 -413
  601. package/web/ui/src/styles.css +0 -608
  602. package/web/ui/src/test/setup.ts +0 -23
  603. package/web/ui/src/vite-env.d.ts +0 -10
  604. package/web/ui/vite.config.ts +0 -34
  605. 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';