@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,279 +0,0 @@
1
- /**
2
- * Approvals primitive — the public API that other modules call.
3
- *
4
- * Two surfaces:
5
- * - `requestApproval()` — queue an approval request, deliver the card to
6
- * the right admin DM, record the row in `approvals` (paraclaw#11). Used
7
- * by any module that needs admin confirmation before doing something
8
- * sensitive.
9
- * - `registerApprovalHandler(action, handler)` — called at module import
10
- * time. When the admin approves a pending row with matching `action`,
11
- * the response handler dispatches into the registered callback. Optional
12
- * modules (self-mod, future module gates) register here.
13
- *
14
- * Approver picking lives here too — it used to sit in src/access.ts and got
15
- * folded in with the PR #7 re-tier. The picks functions walk user_roles
16
- * (owner, global admin, scoped admin) and resolve to a reachable DM via the
17
- * permissions module's user-dm helper.
18
- *
19
- * Tier: default module. Permissions is an optional module, so importing from
20
- * it here is technically a tier inversion — but the host bundles both with
21
- * main, and the alternative (a third "permissions-primitive" default module
22
- * exposing just user-roles/user-dms) is more churn than it's worth. Revisit
23
- * if either module becomes genuinely optional (see REFACTOR_PLAN open q #3).
24
- */
25
- import { normalizeOptions, type RawOption } from '../../channels/ask-question.js';
26
- import { getMessagingGroup } from '../../db/messaging-groups.js';
27
- import { createApproval, getSession } from '../../db/sessions.js';
28
- import { getDeliveryAdapter } from '../../delivery.js';
29
- import { wakeContainer } from '../../container-runner.js';
30
- import { log } from '../../log.js';
31
- import { decodePlatformIdAs } from '../../platform-id.js';
32
- import { writeSessionMessage } from '../../session-manager.js';
33
- import type { MessagingGroup, Session } from '../../types.js';
34
- import { getAdminsOfAgentGroup, getGlobalAdmins, getOwners } from '../permissions/db/user-roles.js';
35
- import { ensureUserDm } from '../permissions/user-dm.js';
36
-
37
- /** Two-button approval UI — the only options the primitive supports today. */
38
- const APPROVAL_OPTIONS: RawOption[] = [
39
- { label: 'Approve', selectedLabel: '✅ Approved', value: 'approve' },
40
- { label: 'Reject', selectedLabel: '❌ Rejected', value: 'reject' },
41
- ];
42
-
43
- // ── Approval handler registry ──
44
- // Modules that want to be called back when an admin approves a pending row
45
- // register here at import time, keyed by the `action` string they used in
46
- // their `requestApproval()` calls.
47
-
48
- export interface ApprovalHandlerContext {
49
- session: Session;
50
- payload: Record<string, unknown>;
51
- /** User ID of the admin who approved. Empty string if unknown. */
52
- userId: string;
53
- /** Send a system chat message to the requesting agent's session. */
54
- notify: (text: string) => void;
55
- }
56
-
57
- export type ApprovalHandler = (ctx: ApprovalHandlerContext) => Promise<void>;
58
-
59
- const approvalHandlers = new Map<string, ApprovalHandler>();
60
-
61
- export function registerApprovalHandler(action: string, handler: ApprovalHandler): void {
62
- if (approvalHandlers.has(action)) {
63
- log.warn('Approval handler re-registered (overwriting)', { action });
64
- }
65
- approvalHandlers.set(action, handler);
66
- }
67
-
68
- export function getApprovalHandler(action: string): ApprovalHandler | undefined {
69
- return approvalHandlers.get(action);
70
- }
71
-
72
- // ── Approver picking ──
73
-
74
- /**
75
- * Ordered list of user IDs eligible to approve an action for the given agent
76
- * group. Preference: admins @ that group → global admins → owners.
77
- */
78
- export function pickApprover(agentGroupId: string | null): string[] {
79
- const approvers: string[] = [];
80
- const seen = new Set<string>();
81
- const add = (id: string): void => {
82
- if (!seen.has(id)) {
83
- seen.add(id);
84
- approvers.push(id);
85
- }
86
- };
87
-
88
- if (agentGroupId) {
89
- for (const r of getAdminsOfAgentGroup(agentGroupId)) add(r.user_id);
90
- }
91
- for (const r of getGlobalAdmins()) add(r.user_id);
92
- for (const r of getOwners()) add(r.user_id);
93
-
94
- return approvers;
95
- }
96
-
97
- /**
98
- * Walk the approver list and return the first reachable
99
- * (approverId, messagingGroup, viaFallbackBot) tuple. Returns null if
100
- * nobody is reachable.
101
- *
102
- * Resolution order, when both `originChannelType` and `originBotId` are set:
103
- *
104
- * 1. Same-channel approver, exact `(channel, originBotId)` match —
105
- * best case, the card delivers via the same bot the inbound
106
- * came in on.
107
- * 2. Same-channel approver, channel-default DM (`bot_id = ''` slot
108
- * in `user_dms`, configured via `/agent/settings/approvals`) —
109
- * `viaFallbackBot: true`, so callers can name the origin bot in
110
- * the card body to avoid confusion.
111
- * 3. Cross-channel approver, channel-default DM — same-channel
112
- * delivery wasn't possible at all (no approver on this channel,
113
- * or none of them have any DM cached).
114
- * 4. None — null.
115
- *
116
- * When only `originChannelType` is provided (single-bot install,
117
- * legacy callers), step 1 collapses into step 2: the bot id is
118
- * effectively `''` and the channel-default row is the cache.
119
- *
120
- * Cold-resolve at step 1 hits the adapter registered for
121
- * `(channel, originBotId)` directly — see `ensureUserDm` — so a
122
- * cache miss for an active secondary bot triggers `openDM` on that
123
- * bot, not on whichever bot happens to be first in the registry.
124
- */
125
- export async function pickApprovalDelivery(
126
- approvers: string[],
127
- originChannelType: string,
128
- originBotId: string | null = null,
129
- ): Promise<{ userId: string; messagingGroup: MessagingGroup; viaFallbackBot: boolean } | null> {
130
- // Step 1 — same channel, exact bot match.
131
- if (originChannelType && originBotId) {
132
- for (const userId of approvers) {
133
- if (channelTypeOf(userId) !== originChannelType) continue;
134
- const mg = await ensureUserDm(userId, { botId: originBotId });
135
- if (mg) return { userId, messagingGroup: mg, viaFallbackBot: false };
136
- }
137
- }
138
- // Step 2 — same channel, channel-default DM. `viaFallbackBot` is true
139
- // only when an originBotId was requested but didn't resolve.
140
- if (originChannelType) {
141
- for (const userId of approvers) {
142
- if (channelTypeOf(userId) !== originChannelType) continue;
143
- const mg = await ensureUserDm(userId);
144
- if (mg) return { userId, messagingGroup: mg, viaFallbackBot: !!originBotId };
145
- }
146
- }
147
- // Step 3 — cross-channel any.
148
- for (const userId of approvers) {
149
- const mg = await ensureUserDm(userId);
150
- if (mg) return { userId, messagingGroup: mg, viaFallbackBot: !!originBotId };
151
- }
152
- return null;
153
- }
154
-
155
- function channelTypeOf(userId: string): string {
156
- const idx = userId.indexOf(':');
157
- return idx < 0 ? '' : userId.slice(0, idx);
158
- }
159
-
160
- // ── Request API ──
161
-
162
- /** Send a system chat to the agent's session. Used by callers and by the response handler. */
163
- export function notifyAgent(session: Session, text: string): void {
164
- writeSessionMessage(session.agent_group_id, session.id, {
165
- id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
166
- kind: 'chat',
167
- timestamp: new Date().toISOString(),
168
- platformId: session.agent_group_id,
169
- channelType: 'agent',
170
- threadId: null,
171
- content: JSON.stringify({ text, sender: 'system', senderId: 'system' }),
172
- });
173
- const fresh = getSession(session.id);
174
- if (fresh) {
175
- wakeContainer(fresh).catch((err) => log.error('Failed to wake container after notification', { err }));
176
- }
177
- }
178
-
179
- export interface RequestApprovalOptions {
180
- session: Session;
181
- agentName: string;
182
- /** Free-form action identifier. Must match the key the consumer registered via registerApprovalHandler. */
183
- action: string;
184
- /** JSON-serializable opaque payload. Carried in the approvals row body, handed to the handler on approve. */
185
- payload: Record<string, unknown>;
186
- /** Card title shown to the admin. */
187
- title: string;
188
- /** Card body shown to the admin. */
189
- question: string;
190
- }
191
-
192
- /**
193
- * Queue an approval request. Picks an approver, delivers the card to their
194
- * DM, and records the row in `approvals` (kind = action). Fire-and-forget
195
- * from the caller's perspective — the admin's response kicks off the
196
- * registered approval handler for this action via the response dispatcher.
197
- */
198
- export async function requestApproval(opts: RequestApprovalOptions): Promise<void> {
199
- const { session, action, payload, title, question, agentName } = opts;
200
-
201
- const approvers = pickApprover(session.agent_group_id);
202
- if (approvers.length === 0) {
203
- notifyAgent(session, `${action} failed: no owner or admin configured to approve.`);
204
- return;
205
- }
206
-
207
- const originMg = session.messaging_group_id ? (getMessagingGroup(session.messaging_group_id) ?? null) : null;
208
- const originChannelType = originMg?.channel_type ?? '';
209
- // The session's MG is paraclaw-managed and gets v2-shaped on creation
210
- // (or backfilled by startup-bootstrap), so slot1 of the platform_id is
211
- // the bot id. v1 rows return botId=null and we route by channel only —
212
- // same path as a single-bot install.
213
- const originBotId = originMg ? decodePlatformIdAs(originMg.platform_id, 'v2').botId : null;
214
-
215
- const target = await pickApprovalDelivery(approvers, originChannelType, originBotId);
216
- if (!target) {
217
- const hint = originBotId ? ` Ask them to DM ${originBotId} once so the bot can reach them, then retry.` : '';
218
- notifyAgent(session, `${action} failed: no DM channel found for any eligible approver.${hint}`);
219
- return;
220
- }
221
-
222
- const approvalId = `appr-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
223
- const normalizedOptions = normalizeOptions(APPROVAL_OPTIONS);
224
- createApproval({
225
- id: approvalId,
226
- kind: action,
227
- agent_group_id: session.agent_group_id,
228
- session_id: session.id,
229
- body: {
230
- title,
231
- options: normalizedOptions,
232
- request_id: approvalId,
233
- payload,
234
- platform_id: target.messagingGroup.platform_id,
235
- channel_type: target.messagingGroup.channel_type,
236
- thread_id: null,
237
- platform_message_id: null,
238
- },
239
- created_at: new Date().toISOString(),
240
- });
241
-
242
- const adapter = getDeliveryAdapter();
243
- if (adapter) {
244
- try {
245
- await adapter.deliver(
246
- target.messagingGroup.channel_type,
247
- target.messagingGroup.platform_id,
248
- null,
249
- 'chat-sdk',
250
- JSON.stringify({
251
- type: 'ask_question',
252
- questionId: approvalId,
253
- title,
254
- question: appendFallbackNotice(question, target.viaFallbackBot, originBotId),
255
- options: APPROVAL_OPTIONS,
256
- }),
257
- );
258
- } catch (err) {
259
- log.error('Failed to deliver approval card', { action, approvalId, err });
260
- notifyAgent(session, `${action} failed: could not deliver approval request to ${target.userId}.`);
261
- return;
262
- }
263
- }
264
-
265
- log.info('Approval requested', { action, approvalId, agentName, approver: target.userId });
266
- }
267
-
268
- /**
269
- * When `pickApprovalDelivery` falls back to the channel-default bot
270
- * (because the inbound bot can't DM this approver), append a one-line
271
- * notice to the card body. Surfaces the mismatch at the moment the
272
- * approver is making a decision, with a pointer to where they can
273
- * change the default if they want cards on the originating bot.
274
- */
275
- export function appendFallbackNotice(question: string, viaFallbackBot: boolean, originBotId: string | null): string {
276
- if (!viaFallbackBot) return question;
277
- const hint = originBotId ? ` (inbound bot ${originBotId})` : '';
278
- return `${question}\n\n_Routed via your default approval bot${hint}. Change in /agent/settings/approvals._`;
279
- }
@@ -1,27 +0,0 @@
1
- ## Approvals module
2
-
3
- Admin-gated approval flow for agent self-modification. Lives in `src/modules/approvals/`.
4
-
5
- ### Flow
6
-
7
- The container writes a `system`-kind outbound row with one of two actions — `install_packages`, `add_mcp_server`. The module's delivery-action handlers validate, route to the right approver's DM, and persist a `pending_approvals` row. When the admin clicks a button, the registered response handler applies the change (config update → image rebuild if needed → container kill) and notifies the agent via system chat.
8
-
9
- ### Wiring
10
-
11
- - **Delivery actions:** `install_packages`, `add_mcp_server` via `registerDeliveryAction`.
12
- - **Response handler:** claims approval cards by `pending_approvals` row lookup.
13
-
14
- ### Tables
15
-
16
- `pending_approvals` (created by `module-approvals-pending-approvals.ts`). Not dropped on uninstall — approvals in flight aren't lost on reinstall.
17
-
18
- ### Core integration
19
-
20
- The module depends on host-side infra but does not reach into core decision paths beyond the registered hooks:
21
-
22
- - `buildAgentGroupImage`, `killContainer` from container-runner (image rebuilds)
23
- - `updateContainerConfig` from container-config (apt/npm/mcp edits)
24
- - `pickApprover`, `pickApprovalDelivery` from access
25
- - `getDeliveryAdapter` in request-approval.ts
26
-
27
- No core code imports from this module. Removing it: delete `src/modules/approvals/`, remove the import from `src/modules/index.ts`. Delivery actions will log "Unknown system action"; button clicks on approval cards will log "Unclaimed response". Stale rows remain in `pending_approvals` until reinstall or manual cleanup.
@@ -1,87 +0,0 @@
1
- /**
2
- * Handle an admin's response to an approval card.
3
- *
4
- * Module-initiated actions — the module called `requestApproval()` with some
5
- * free-form `action` string and registered a handler via
6
- * `registerApprovalHandler(action, handler)`. On approve, we look up the
7
- * handler and call it; on reject, we notify the agent and move on.
8
- *
9
- * The response handler is registered via core's `registerResponseHandler`;
10
- * core iterates handlers and the first one to return `true` claims the response.
11
- */
12
- import { wakeContainer } from '../../container-runner.js';
13
- import { deleteApproval, getApproval, getSession } from '../../db/sessions.js';
14
- import type { ResponsePayload } from '../../response-registry.js';
15
- import { log } from '../../log.js';
16
- import { writeSessionMessage } from '../../session-manager.js';
17
- import type { ActionApprovalBody, Approval } from '../../types.js';
18
- import { getApprovalHandler } from './primitive.js';
19
-
20
- export async function handleApprovalsResponse(payload: ResponsePayload): Promise<boolean> {
21
- const approval = getApproval(payload.questionId);
22
- if (!approval) return false;
23
- if (approval.kind === 'question') return false;
24
-
25
- await handleRegisteredApproval(approval, payload.value, payload.userId ?? '');
26
- return true;
27
- }
28
-
29
- async function handleRegisteredApproval(approval: Approval, selectedOption: string, userId: string): Promise<void> {
30
- if (!approval.session_id) {
31
- deleteApproval(approval.id);
32
- return;
33
- }
34
- const session = getSession(approval.session_id);
35
- if (!session) {
36
- deleteApproval(approval.id);
37
- return;
38
- }
39
-
40
- const notify = (text: string): void => {
41
- writeSessionMessage(session.agent_group_id, session.id, {
42
- id: `appr-note-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
43
- kind: 'chat',
44
- timestamp: new Date().toISOString(),
45
- platformId: session.agent_group_id,
46
- channelType: 'agent',
47
- threadId: null,
48
- content: JSON.stringify({ text, sender: 'system', senderId: 'system' }),
49
- });
50
- };
51
-
52
- if (selectedOption !== 'approve') {
53
- notify(`Your ${approval.kind} request was rejected by admin.`);
54
- log.info('Approval rejected', { approvalId: approval.id, action: approval.kind, userId });
55
- deleteApproval(approval.id);
56
- await wakeContainer(session);
57
- return;
58
- }
59
-
60
- // Approved — dispatch to the module that registered for this action.
61
- const handler = getApprovalHandler(approval.kind);
62
- if (!handler) {
63
- log.warn('No approval handler registered — row dropped', {
64
- approvalId: approval.id,
65
- action: approval.kind,
66
- });
67
- notify(`Your ${approval.kind} was approved, but no handler is installed to apply it.`);
68
- deleteApproval(approval.id);
69
- await wakeContainer(session);
70
- return;
71
- }
72
-
73
- const body = approval.body as ActionApprovalBody;
74
- const payload = body.payload ?? {};
75
- try {
76
- await handler({ session, payload, userId, notify });
77
- log.info('Approval handled', { approvalId: approval.id, action: approval.kind, userId });
78
- } catch (err) {
79
- log.error('Approval handler threw', { approvalId: approval.id, action: approval.kind, err });
80
- notify(
81
- `Your ${approval.kind} was approved, but applying it failed: ${err instanceof Error ? err.message : String(err)}.`,
82
- );
83
- }
84
-
85
- deleteApproval(approval.id);
86
- await wakeContainer(session);
87
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Modules barrel.
3
- *
4
- * Each module self-registers at import time. This barrel is imported by
5
- * src/index.ts for side effects (registry registrations, typing impl setup,
6
- * etc.). Core runs with an empty barrel — the registries have inline
7
- * fallbacks and `sqlite_master` guards.
8
- *
9
- * Default modules (ship with main, direct core import):
10
- * - src/modules/typing/ → imported directly by router/delivery/container-runner
11
- * - src/modules/mount-security/ → imported directly by container-runner
12
- *
13
- * Registry-based modules (installed via /add-<name> skills, pulled from the
14
- * `modules` branch): append imports below.
15
- */
16
- // Approvals (default tier) must load before self-mod (optional) so the
17
- // registerApprovalHandler / requestApproval symbols are bound when self-mod
18
- // registers its handlers at import time.
19
- import './approvals/index.js';
20
- import './interactive/index.js';
21
- import './scheduling/index.js';
22
- import './permissions/index.js';
23
- import './agent-to-agent/index.js';
24
- import './self-mod/index.js';
@@ -1,21 +0,0 @@
1
- ## ask_user_question
2
-
3
- Use `ask_user_question` when you need the user to pick from a small set of concrete options and you can't infer a reasonable default. This is a **blocking** call — your turn pauses until the user clicks or the timeout expires.
4
-
5
- **When to use:**
6
- - Confirming a destructive action ("Delete these 3 files?")
7
- - Choosing between incompatible paths ("Keep their version or yours?")
8
- - Gathering a required parameter that must be one of a known set
9
-
10
- **When NOT to use:**
11
- - Open-ended text input — just send a regular message asking.
12
- - Yes/no confirmations where "no" is the safe default — just proceed and let the user interrupt.
13
- - Anything you can work out from context.
14
-
15
- **Arguments:**
16
- - `title` (string) — short card header, e.g. "Confirm deletion"
17
- - `question` (string) — the full question
18
- - `options` (array) — each is either a plain string or `{ label, selectedLabel?, value? }`. `selectedLabel` replaces the button text after click; `value` is what gets returned to you
19
- - `timeout` (number, seconds, default 300) — how long to wait before giving up
20
-
21
- The response is the `value` (or label if no value set) of whichever option the user chose. On timeout you get an error and should proceed with a sensible default or tell the user you timed out.
@@ -1,69 +0,0 @@
1
- /**
2
- * Interactive module — generic ask_user_question flow.
3
- *
4
- * Container-side `ask_user_question` writes a chat-sdk card to outbound.db +
5
- * polls inbound.db for a `question_response` system message. On the host side
6
- * this module handles the button-click response: look up the `approvals` row
7
- * (kind='question'), write the response into the session's inbound.db, wake
8
- * the container.
9
- *
10
- * The `createApproval` call in `deliverMessage` (delivery.ts) stays inline in
11
- * core — it's 15 lines guarded by `hasTable('approvals')`, modularizing it
12
- * adds more registry surface than it saves.
13
- */
14
- import { getDb, hasTable } from '../../db/connection.js';
15
- import { deleteApproval, getApproval, getSession } from '../../db/sessions.js';
16
- import { wakeContainer } from '../../container-runner.js';
17
- import { registerResponseHandler, type ResponsePayload } from '../../response-registry.js';
18
- import { log } from '../../log.js';
19
- import { writeSessionMessage } from '../../session-manager.js';
20
- import type { QuestionApprovalBody } from '../../types.js';
21
-
22
- async function handleInteractiveResponse(payload: ResponsePayload): Promise<boolean> {
23
- if (!hasTable(getDb(), 'approvals')) return false;
24
-
25
- const approval = getApproval(payload.questionId);
26
- if (!approval || approval.kind !== 'question') return false;
27
-
28
- if (!approval.session_id) {
29
- deleteApproval(payload.questionId);
30
- return true;
31
- }
32
- const session = getSession(approval.session_id);
33
- if (!session) {
34
- log.warn('Session not found for pending question', {
35
- questionId: payload.questionId,
36
- sessionId: approval.session_id,
37
- });
38
- deleteApproval(payload.questionId);
39
- return true; // claimed — we owned this questionId even though the session is gone
40
- }
41
-
42
- const body = approval.body as QuestionApprovalBody;
43
- writeSessionMessage(session.agent_group_id, session.id, {
44
- id: `qr-${payload.questionId}-${Date.now()}`,
45
- kind: 'system',
46
- timestamp: new Date().toISOString(),
47
- platformId: body.platform_id,
48
- channelType: body.channel_type,
49
- threadId: body.thread_id,
50
- content: JSON.stringify({
51
- type: 'question_response',
52
- questionId: payload.questionId,
53
- selectedOption: payload.value,
54
- userId: payload.userId ?? '',
55
- }),
56
- });
57
-
58
- deleteApproval(payload.questionId);
59
- log.info('Question response routed', {
60
- questionId: payload.questionId,
61
- selectedOption: payload.value,
62
- sessionId: session.id,
63
- });
64
-
65
- await wakeContainer(session);
66
- return true;
67
- }
68
-
69
- registerResponseHandler(handleInteractiveResponse);
@@ -1,12 +0,0 @@
1
- ## Interactive module
2
-
3
- Generic ask_user_question flow. Lives in `src/modules/interactive/`.
4
-
5
- The container-side MCP tool `ask_user_question` writes a chat-sdk card to outbound.db and polls inbound.db for a `question_response` system message. The host side of this is split:
6
-
7
- - **Inline in `src/delivery.ts`:** the `deliverMessage` path intercepts `content.type === 'ask_question'` messages and writes a row to the unified `approvals` table with `kind='question'`. Guarded by `hasTable(db, 'approvals')`.
8
- - **This module:** registers a `ResponseHandler` that runs when a button-click arrives via the channel adapter's `onAction`. It looks up the `approvals` row (filtered to `kind='question'`), writes a `question_response` system message into the session's inbound.db, wakes the container.
9
-
10
- The `approvals` table is created by migration 024 (paraclaw#11), which collapsed the previous `pending_questions` and `pending_approvals` tables into one. The module doesn't own the schema, just the behavior. Removing the module disables the button-click response path for questions only; admin approvals (other kinds) still flow through `src/modules/approvals/`, and cards are still delivered.
11
-
12
- `getAskQuestionRender` in `src/db/sessions.ts` resolves card render metadata for `chat-sdk-bridge.ts`. It reads from `approvals` and from the permissions module's side tables (`pending_channel_approvals`, `pending_sender_approvals`), degrading via `hasTable`. Stays in core.
@@ -1,82 +0,0 @@
1
- /**
2
- * `expandPath` resolves operator-supplied paths inside the mount-allowlist
3
- * (`~/projects` etc.) against `HOME_DIR` from src/config.ts. paraclaw#99
4
- * pulled the HOME-resolution out of this module so the precedence rule
5
- * (`process.env.HOME` → `os.homedir()`) lives in one place; these tests pin
6
- * the contract.
7
- *
8
- * `vi.resetModules()` is required because config.ts captures HOME_DIR at
9
- * module load — tests that flip env vars must re-import both config and the
10
- * mount-security module so the new HOME_DIR threads through.
11
- */
12
- import path from 'node:path';
13
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
14
-
15
- const ORIGINAL_HOME = process.env.HOME;
16
-
17
- beforeEach(() => {
18
- vi.resetModules();
19
- });
20
-
21
- afterEach(() => {
22
- if (ORIGINAL_HOME === undefined) delete process.env.HOME;
23
- else process.env.HOME = ORIGINAL_HOME;
24
- });
25
-
26
- describe('expandPath HOME resolution', () => {
27
- it("expands '~/foo' against config.HOME_DIR (default)", async () => {
28
- process.env.HOME = '/Users/test-default';
29
- const cfg = await import('../../config.js');
30
- const { expandPath } = await import('./index.js');
31
- expect(cfg.HOME_DIR).toBe('/Users/test-default');
32
- expect(expandPath('~/projects')).toBe(path.join('/Users/test-default', 'projects'));
33
- });
34
-
35
- it("expands bare '~' to config.HOME_DIR", async () => {
36
- process.env.HOME = '/Users/test-bare-tilde';
37
- const { expandPath } = await import('./index.js');
38
- expect(expandPath('~')).toBe('/Users/test-bare-tilde');
39
- });
40
-
41
- it('passes absolute paths through path.resolve unchanged', async () => {
42
- process.env.HOME = '/Users/test-abs';
43
- const { expandPath } = await import('./index.js');
44
- // Absolute paths should NOT consult HOME_DIR — they resolve as-is.
45
- expect(expandPath('/var/data/x')).toBe('/var/data/x');
46
- });
47
-
48
- it('honors HOME override at module load (sandbox-style override)', async () => {
49
- // The override path: PARACHUTE_HOME does NOT route mount-allowlist (#99
50
- // path 2 — operator-host policy is intentionally separate from runtime
51
- // state), but the bare HOME env var IS honored by config.HOME_DIR for
52
- // operators who reroute their entire shell session. Pin that flow.
53
- process.env.HOME = '/tmp/sandbox-home-99';
54
- const cfg = await import('../../config.js');
55
- const { expandPath } = await import('./index.js');
56
- expect(cfg.HOME_DIR).toBe('/tmp/sandbox-home-99');
57
- expect(expandPath('~/repos')).toBe('/tmp/sandbox-home-99/repos');
58
- // ALLOWLIST_DIR derives from HOME_DIR — it should follow.
59
- expect(cfg.ALLOWLIST_DIR).toBe('/tmp/sandbox-home-99/.config/parachute-agent');
60
- });
61
-
62
- it('does NOT route through PARACHUTE_HOME (operator-policy stays at <HOME>/.config)', async () => {
63
- // paraclaw#99 path 2 contract: PARACHUTE_HOME reroutes runtime state
64
- // (DB + master.key) but NOT operator-host policy (mount-allowlist).
65
- // Pin the split — if a future refactor accidentally collapses the two,
66
- // sandboxes would silently see different mount permissions than the
67
- // live install they share a host with.
68
- process.env.HOME = '/Users/operator';
69
- process.env.PARACHUTE_HOME = '/tmp/sandbox-home-collapse-check';
70
- try {
71
- const cfg = await import('../../config.js');
72
- expect(cfg.PARACHUTE_DIR).toBe('/tmp/sandbox-home-collapse-check');
73
- // CENTRAL_DB_DIR follows PARACHUTE_HOME — runtime state.
74
- expect(cfg.CENTRAL_DB_DIR).toBe('/tmp/sandbox-home-collapse-check/agent');
75
- // ALLOWLIST_DIR does NOT — operator-host policy.
76
- expect(cfg.ALLOWLIST_DIR).toBe('/Users/operator/.config/parachute-agent');
77
- expect(cfg.MOUNT_ALLOWLIST_PATH).toBe('/Users/operator/.config/parachute-agent/mount-allowlist.json');
78
- } finally {
79
- delete process.env.PARACHUTE_HOME;
80
- }
81
- });
82
- });