@openparachute/agent 0.1.2 → 0.2.2

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