@openparachute/agent 0.1.1 → 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.
- package/.parachute/module.json +124 -8
- package/LICENSE +2 -16
- package/README.md +118 -166
- package/package.json +32 -43
- package/scripts/spawn-agent.ts +371 -0
- package/src/_parked/interactive-spawn.test.ts +324 -0
- package/src/_parked/interactive-spawn.ts +701 -0
- package/src/agent-defs.test.ts +1504 -0
- package/src/agent-defs.ts +1702 -0
- package/src/agent-mcp-config.test.ts +115 -0
- package/src/agent-mcp-config.ts +115 -0
- package/src/agents.test.ts +360 -0
- package/src/agents.ts +379 -0
- package/src/auth.test.ts +46 -0
- package/src/auth.ts +140 -0
- package/src/backends/attached-queue.test.ts +376 -0
- package/src/backends/attached-queue.ts +372 -0
- package/src/backends/programmatic.test.ts +1715 -0
- package/src/backends/programmatic.ts +927 -0
- package/src/backends/registry.test.ts +1494 -0
- package/src/backends/registry.ts +1202 -0
- package/src/backends/stream-json.test.ts +570 -0
- package/src/backends/stream-json.ts +392 -0
- package/src/backends/types.ts +223 -0
- package/src/bridge.ts +417 -0
- package/src/channel-backend-wiring.test.ts +237 -0
- package/src/credentials.test.ts +274 -0
- package/src/credentials.ts +380 -0
- package/src/cron.test.ts +342 -0
- package/src/cron.ts +380 -0
- package/src/daemon-agent-def-api.test.ts +166 -0
- package/src/daemon-agent-defs-api.test.ts +953 -0
- package/src/daemon-agent-env-api.test.ts +338 -0
- package/src/daemon-attached-queue-store.test.ts +65 -0
- package/src/daemon-config-api.test.ts +962 -0
- package/src/daemon-jobs-api.test.ts +271 -0
- package/src/daemon-vault-chat.test.ts +250 -0
- package/src/daemon.test.ts +746 -0
- package/src/daemon.ts +3314 -0
- package/src/def-vaults.test.ts +136 -0
- package/src/def-vaults.ts +165 -0
- package/src/delivery-state.test.ts +110 -0
- package/src/delivery-state.ts +154 -0
- package/src/effective-env.test.ts +114 -0
- package/src/effective-env.ts +184 -0
- package/src/env-compat.ts +39 -0
- package/src/grants.test.ts +638 -0
- package/src/grants.ts +675 -0
- package/src/hub-jwt.test.ts +161 -0
- package/src/hub-jwt.ts +182 -0
- package/src/jobs.test.ts +245 -0
- package/src/jobs.ts +266 -0
- package/src/mcp-http.test.ts +265 -0
- package/src/mcp-http.ts +771 -0
- package/src/mint-token.test.ts +152 -0
- package/src/mint-token.ts +139 -0
- package/src/module-manifest.test.ts +158 -0
- package/src/oauth-discovery.ts +134 -0
- package/src/programmatic-wiring.test.ts +838 -0
- package/src/registry.test.ts +227 -0
- package/src/registry.ts +228 -0
- package/src/resolve-port.test.ts +64 -0
- package/src/routing.test.ts +184 -0
- package/src/routing.ts +76 -0
- package/src/runner.test.ts +506 -0
- package/src/runner.ts +255 -0
- package/src/sandbox/config.test.ts +150 -0
- package/src/sandbox/config.ts +102 -0
- package/src/sandbox/egress.test.ts +113 -0
- package/src/sandbox/egress.ts +123 -0
- package/src/sandbox/index.ts +180 -0
- package/src/sandbox/live-seatbelt.test.ts +277 -0
- package/src/sandbox/mounts.test.ts +154 -0
- package/src/sandbox/mounts.ts +133 -0
- package/src/sandbox/sandbox.test.ts +168 -0
- package/src/sandbox/types.ts +382 -0
- package/src/services-manifest.test.ts +106 -0
- package/src/services-manifest.ts +95 -0
- package/src/spa-serve.test.ts +116 -0
- package/src/spa-serve.ts +116 -0
- package/src/spawn-agent-cli.test.ts +172 -0
- package/src/spawn-agent.test.ts +1218 -0
- package/src/spawn-agent.ts +569 -0
- package/src/spawn-deps.test.ts +54 -0
- package/src/spawn-deps.ts +166 -0
- package/src/telegram/api.ts +153 -0
- package/src/terminal-assets.test.ts +50 -0
- package/src/terminal-assets.ts +79 -0
- package/src/terminal-ui.ts +305 -0
- package/src/terminal.test.ts +530 -0
- package/src/terminal.ts +458 -0
- package/src/transport.ts +270 -0
- package/src/transports/http-ui.test.ts +455 -0
- package/src/transports/http-ui.ts +201 -0
- package/src/transports/telegram.test.ts +174 -0
- package/src/transports/telegram.ts +426 -0
- package/src/transports/vault.test.ts +2011 -0
- package/src/transports/vault.ts +1790 -0
- package/src/ui-kit.test.ts +178 -0
- package/src/ui-kit.ts +402 -0
- package/tsconfig.json +8 -14
- package/web/ui/tsconfig.json +2 -1
- package/.claude/scheduled_tasks.lock +0 -1
- package/.claude/settings.json +0 -5
- package/.claude/skills/add-atomic-chat-tool/SKILL.md +0 -243
- package/.claude/skills/add-atomic-chat-tool/atomic-chat-mcp-stdio.ts +0 -229
- package/.claude/skills/add-codex/SKILL.md +0 -161
- package/.claude/skills/add-dashboard/SKILL.md +0 -138
- package/.claude/skills/add-dashboard/resources/dashboard-pusher.ts +0 -495
- package/.claude/skills/add-emacs/SKILL.md +0 -296
- package/.claude/skills/add-gcal-tool/SKILL.md +0 -210
- package/.claude/skills/add-gchat/REMOVE.md +0 -6
- package/.claude/skills/add-gchat/SKILL.md +0 -92
- package/.claude/skills/add-gchat/VERIFY.md +0 -3
- package/.claude/skills/add-github/REMOVE.md +0 -6
- package/.claude/skills/add-github/SKILL.md +0 -148
- package/.claude/skills/add-github/VERIFY.md +0 -3
- package/.claude/skills/add-gmail-tool/SKILL.md +0 -229
- package/.claude/skills/add-imessage/REMOVE.md +0 -6
- package/.claude/skills/add-imessage/SKILL.md +0 -113
- package/.claude/skills/add-imessage/VERIFY.md +0 -3
- package/.claude/skills/add-karpathy-llm-wiki/SKILL.md +0 -110
- package/.claude/skills/add-karpathy-llm-wiki/llm-wiki.md +0 -75
- package/.claude/skills/add-linear/REMOVE.md +0 -6
- package/.claude/skills/add-linear/SKILL.md +0 -168
- package/.claude/skills/add-linear/VERIFY.md +0 -3
- package/.claude/skills/add-macos-statusbar/SKILL.md +0 -133
- package/.claude/skills/add-macos-statusbar/add/src/statusbar.swift +0 -147
- package/.claude/skills/add-matrix/REMOVE.md +0 -6
- package/.claude/skills/add-matrix/SKILL.md +0 -148
- package/.claude/skills/add-matrix/VERIFY.md +0 -3
- package/.claude/skills/add-ollama-provider/SKILL.md +0 -179
- package/.claude/skills/add-ollama-tool/SKILL.md +0 -193
- package/.claude/skills/add-opencode/SKILL.md +0 -229
- package/.claude/skills/add-parallel/SKILL.md +0 -290
- package/.claude/skills/add-resend/REMOVE.md +0 -6
- package/.claude/skills/add-resend/SKILL.md +0 -93
- package/.claude/skills/add-resend/VERIFY.md +0 -3
- package/.claude/skills/add-signal/REMOVE.md +0 -13
- package/.claude/skills/add-signal/SKILL.md +0 -318
- package/.claude/skills/add-signal/VERIFY.md +0 -5
- package/.claude/skills/add-slack/REMOVE.md +0 -6
- package/.claude/skills/add-slack/SKILL.md +0 -112
- package/.claude/skills/add-slack/VERIFY.md +0 -3
- package/.claude/skills/add-teams/REMOVE.md +0 -6
- package/.claude/skills/add-teams/SKILL.md +0 -207
- package/.claude/skills/add-teams/VERIFY.md +0 -3
- package/.claude/skills/add-vercel/SKILL.md +0 -147
- package/.claude/skills/add-vercel/container-skills/vercel-cli/SKILL.md +0 -103
- package/.claude/skills/add-webex/REMOVE.md +0 -6
- package/.claude/skills/add-webex/SKILL.md +0 -88
- package/.claude/skills/add-webex/VERIFY.md +0 -3
- package/.claude/skills/add-wechat/REMOVE.md +0 -49
- package/.claude/skills/add-wechat/SKILL.md +0 -170
- package/.claude/skills/add-wechat/scripts/wire-dm.ts +0 -172
- package/.claude/skills/add-whatsapp/SKILL.md +0 -264
- package/.claude/skills/add-whatsapp-cloud/REMOVE.md +0 -6
- package/.claude/skills/add-whatsapp-cloud/SKILL.md +0 -95
- package/.claude/skills/add-whatsapp-cloud/VERIFY.md +0 -3
- package/.claude/skills/claw/SKILL.md +0 -131
- package/.claude/skills/claw/scripts/claw +0 -374
- package/.claude/skills/convert-to-apple-container/SKILL.md +0 -212
- package/.claude/skills/customize/SKILL.md +0 -110
- package/.claude/skills/debug/SKILL.md +0 -349
- package/.claude/skills/get-qodo-rules/SKILL.md +0 -122
- package/.claude/skills/get-qodo-rules/references/output-format.md +0 -41
- package/.claude/skills/get-qodo-rules/references/pagination.md +0 -33
- package/.claude/skills/get-qodo-rules/references/repository-scope.md +0 -26
- package/.claude/skills/init-first-agent/SKILL.md +0 -120
- package/.claude/skills/init-onecli/SKILL.md +0 -270
- package/.claude/skills/manage-channels/SKILL.md +0 -87
- package/.claude/skills/manage-mounts/SKILL.md +0 -47
- package/.claude/skills/migrate-from-openclaw/MIGRATE_CRONS.md +0 -100
- package/.claude/skills/migrate-from-openclaw/SKILL.md +0 -447
- package/.claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts +0 -734
- package/.claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts +0 -476
- package/.claude/skills/migrate-nanoclaw/SKILL.md +0 -484
- package/.claude/skills/migrate-nanoclaw/diagnostics.md +0 -51
- package/.claude/skills/qodo-pr-resolver/SKILL.md +0 -326
- package/.claude/skills/qodo-pr-resolver/resources/providers.md +0 -329
- package/.claude/skills/update-nanoclaw/SKILL.md +0 -243
- package/.claude/skills/update-nanoclaw/diagnostics.md +0 -48
- package/.claude/skills/update-skills/SKILL.md +0 -130
- package/.claude/skills/use-native-credential-proxy/SKILL.md +0 -167
- package/.claude/skills/x-integration/SKILL.md +0 -417
- package/.claude/skills/x-integration/agent.ts +0 -243
- package/.claude/skills/x-integration/host.ts +0 -155
- package/.claude/skills/x-integration/lib/browser.ts +0 -148
- package/.claude/skills/x-integration/lib/config.ts +0 -62
- package/.claude/skills/x-integration/scripts/like.ts +0 -56
- package/.claude/skills/x-integration/scripts/post.ts +0 -66
- package/.claude/skills/x-integration/scripts/quote.ts +0 -80
- package/.claude/skills/x-integration/scripts/reply.ts +0 -74
- package/.claude/skills/x-integration/scripts/retweet.ts +0 -62
- package/.claude/skills/x-integration/scripts/setup.ts +0 -87
- package/.github/CODEOWNERS +0 -10
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -18
- package/.github/workflows/bump-version.yml +0 -35
- package/.github/workflows/ci.yml +0 -39
- package/.github/workflows/label-pr.yml +0 -40
- package/.github/workflows/update-tokens.yml +0 -43
- package/.husky/pre-commit +0 -1
- package/.mcp.json +0 -3
- package/.nvmrc +0 -1
- package/.prettierrc +0 -4
- package/CHANGELOG.md +0 -221
- package/CLAUDE.md +0 -307
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -159
- package/CONTRIBUTORS.md +0 -26
- package/LICENSE-NANOCLAW-MIT +0 -21
- package/README_ja.md +0 -194
- package/README_zh.md +0 -194
- package/assets/nanoclaw-favicon.png +0 -0
- package/assets/nanoclaw-icon.png +0 -0
- package/assets/nanoclaw-logo-dark.png +0 -0
- package/assets/nanoclaw-logo.png +0 -0
- package/assets/nanoclaw-profile.jpeg +0 -0
- package/assets/nanoclaw-sales.png +0 -0
- package/assets/social-preview.jpg +0 -0
- package/config-examples/mount-allowlist.json +0 -25
- package/container/.dockerignore +0 -2
- package/container/CLAUDE.md +0 -21
- package/container/Dockerfile +0 -121
- package/container/agent-runner/bun.lock +0 -243
- package/container/agent-runner/package.json +0 -22
- package/container/agent-runner/scripts/sdk-signal-probe.ts +0 -169
- package/container/agent-runner/src/config.ts +0 -55
- package/container/agent-runner/src/db/connection.ts +0 -267
- package/container/agent-runner/src/db/index.ts +0 -20
- package/container/agent-runner/src/db/messages-in.ts +0 -138
- package/container/agent-runner/src/db/messages-out.ts +0 -143
- package/container/agent-runner/src/db/session-routing.ts +0 -30
- package/container/agent-runner/src/db/session-state.test.ts +0 -100
- package/container/agent-runner/src/db/session-state.ts +0 -79
- package/container/agent-runner/src/destinations.ts +0 -135
- package/container/agent-runner/src/formatter.test.ts +0 -167
- package/container/agent-runner/src/formatter.ts +0 -260
- package/container/agent-runner/src/index.ts +0 -110
- package/container/agent-runner/src/integration.test.ts +0 -121
- package/container/agent-runner/src/mcp-tools/agents.instructions.md +0 -26
- package/container/agent-runner/src/mcp-tools/agents.ts +0 -66
- package/container/agent-runner/src/mcp-tools/core.instructions.md +0 -27
- package/container/agent-runner/src/mcp-tools/core.ts +0 -262
- package/container/agent-runner/src/mcp-tools/index.ts +0 -22
- package/container/agent-runner/src/mcp-tools/interactive.instructions.md +0 -22
- package/container/agent-runner/src/mcp-tools/interactive.ts +0 -169
- package/container/agent-runner/src/mcp-tools/scheduling.instructions.md +0 -40
- package/container/agent-runner/src/mcp-tools/scheduling.ts +0 -299
- package/container/agent-runner/src/mcp-tools/self-mod.instructions.md +0 -25
- package/container/agent-runner/src/mcp-tools/self-mod.ts +0 -120
- package/container/agent-runner/src/mcp-tools/server.ts +0 -54
- package/container/agent-runner/src/mcp-tools/types.ts +0 -6
- package/container/agent-runner/src/poll-loop.test.ts +0 -248
- package/container/agent-runner/src/poll-loop.ts +0 -437
- package/container/agent-runner/src/providers/claude.ts +0 -379
- package/container/agent-runner/src/providers/factory.test.ts +0 -19
- package/container/agent-runner/src/providers/factory.ts +0 -13
- package/container/agent-runner/src/providers/index.ts +0 -6
- package/container/agent-runner/src/providers/mock.ts +0 -77
- package/container/agent-runner/src/providers/provider-registry.ts +0 -33
- package/container/agent-runner/src/providers/types.ts +0 -82
- package/container/agent-runner/src/scheduling/task-script.ts +0 -121
- package/container/agent-runner/src/timezone.test.ts +0 -93
- package/container/agent-runner/src/timezone.ts +0 -107
- package/container/agent-runner/tsconfig.json +0 -14
- package/container/build.sh +0 -48
- package/container/entrypoint.sh +0 -16
- package/container/skills/agent-browser/SKILL.md +0 -159
- package/container/skills/frontend-engineer/SKILL.md +0 -157
- package/container/skills/self-customize/SKILL.md +0 -87
- package/container/skills/slack-formatting/SKILL.md +0 -94
- package/container/skills/vercel-cli/SKILL.md +0 -111
- package/container/skills/welcome/SKILL.md +0 -85
- package/docs/APPLE-CONTAINER-NETWORKING.md +0 -90
- package/docs/BRANCH-FORK-MAINTENANCE.md +0 -81
- package/docs/README.md +0 -25
- package/docs/SDK_DEEP_DIVE.md +0 -643
- package/docs/SECURITY.md +0 -162
- package/docs/agent-runner-details.md +0 -749
- package/docs/api-details.md +0 -365
- package/docs/architecture-diagram.html +0 -422
- package/docs/architecture-diagram.md +0 -215
- package/docs/architecture.md +0 -751
- package/docs/audit/2026-04-30-channel-endpoint-audit.md +0 -36
- package/docs/build-and-runtime.md +0 -80
- package/docs/cross-mount-stress/README.md +0 -112
- package/docs/cross-mount-stress/container-writer-retry.mjs +0 -55
- package/docs/cross-mount-stress/container-writer-slow.mjs +0 -42
- package/docs/cross-mount-stress/container-writer.mjs +0 -47
- package/docs/cross-mount-stress/host-writer-retry.mjs +0 -55
- package/docs/cross-mount-stress/host-writer-slow.mjs +0 -43
- package/docs/cross-mount-stress/host-writer.mjs +0 -47
- package/docs/db-central.md +0 -316
- package/docs/db-session.md +0 -183
- package/docs/db.md +0 -119
- package/docs/design/2026-04-29-vault-management-ui.md +0 -231
- package/docs/design/2026-04-30-channel-wiring-rework.md +0 -234
- package/docs/design/2026-05-01-channel-wiring-approvals-deep-dive.md +0 -272
- package/docs/design/2026-05-02-channel-policy-and-approval-routing.md +0 -250
- package/docs/docker-sandboxes.md +0 -359
- package/docs/isolation-model.md +0 -88
- package/docs/ollama.md +0 -79
- package/docs/parachute-integration.md +0 -109
- package/docs/post-night-rebirth-reflections.md +0 -151
- package/eslint.config.js +0 -32
- package/pnpm-workspace.yaml +0 -8
- package/repo-tokens/README.md +0 -113
- package/repo-tokens/action.yml +0 -186
- package/repo-tokens/badge.svg +0 -23
- package/repo-tokens/examples/green.svg +0 -14
- package/repo-tokens/examples/red.svg +0 -14
- package/repo-tokens/examples/yellow-green.svg +0 -14
- package/repo-tokens/examples/yellow.svg +0 -14
- package/scripts/chat.ts +0 -101
- package/scripts/cleanup-sessions.sh +0 -150
- package/scripts/init-cli-agent.ts +0 -171
- package/scripts/init-first-agent.ts +0 -377
- package/scripts/parachute.ts +0 -158
- package/scripts/run-migrations.ts +0 -105
- package/scripts/sanity-live-poll.ts +0 -95
- package/scripts/seed-discord.ts +0 -79
- package/scripts/test-v2-agent.ts +0 -106
- package/scripts/test-v2-channel-e2e.ts +0 -265
- package/scripts/test-v2-host.ts +0 -184
- package/src/channels/adapter.ts +0 -214
- package/src/channels/ask-question.ts +0 -46
- package/src/channels/channel-registry.test.ts +0 -421
- package/src/channels/channel-registry.ts +0 -313
- package/src/channels/chat-sdk-bridge.test.ts +0 -84
- package/src/channels/chat-sdk-bridge.ts +0 -652
- package/src/channels/cli.ts +0 -276
- package/src/channels/discord.ts +0 -90
- package/src/channels/index.ts +0 -17
- package/src/channels/telegram-markdown-sanitize.test.ts +0 -78
- package/src/channels/telegram-markdown-sanitize.ts +0 -55
- package/src/channels/telegram-pairing.test.ts +0 -254
- package/src/channels/telegram-pairing.ts +0 -339
- package/src/channels/telegram.ts +0 -279
- package/src/channels/trust-hint.test.ts +0 -48
- package/src/channels/trust-hint.ts +0 -75
- package/src/claude-md-compose.migrate.test.ts +0 -64
- package/src/claude-md-compose.ts +0 -205
- package/src/command-gate.ts +0 -63
- package/src/config.test.ts +0 -93
- package/src/config.ts +0 -108
- package/src/container-config.ts +0 -167
- package/src/container-runner.test.ts +0 -32
- package/src/container-runner.ts +0 -576
- package/src/container-runtime.test.ts +0 -169
- package/src/container-runtime.ts +0 -92
- package/src/db/_bun-sqlite-shim.ts +0 -88
- package/src/db/agent-activity.test.ts +0 -155
- package/src/db/agent-activity.ts +0 -121
- package/src/db/agent-groups.ts +0 -77
- package/src/db/connection.migrate.test.ts +0 -143
- package/src/db/connection.ts +0 -224
- package/src/db/db-v2.test.ts +0 -440
- package/src/db/dropped-messages.ts +0 -44
- package/src/db/index.ts +0 -40
- package/src/db/messaging-groups.ts +0 -252
- package/src/db/migrations/001-initial.ts +0 -112
- package/src/db/migrations/002-chat-sdk-state.ts +0 -36
- package/src/db/migrations/008-dropped-messages.ts +0 -27
- package/src/db/migrations/009-drop-pending-credentials.ts +0 -13
- package/src/db/migrations/010-engage-modes.ts +0 -103
- package/src/db/migrations/011-pending-sender-approvals.ts +0 -40
- package/src/db/migrations/012-channel-registration.ts +0 -48
- package/src/db/migrations/013-approval-render-metadata.ts +0 -27
- package/src/db/migrations/014-secrets.ts +0 -44
- package/src/db/migrations/015-secrets-drop-host-pattern.ts +0 -18
- package/src/db/migrations/016-secret-assignments.ts +0 -30
- package/src/db/migrations/017-agent-activity.ts +0 -40
- package/src/db/migrations/018-oauth-app-configs.ts +0 -34
- package/src/db/migrations/019-oauth-app-connections.ts +0 -48
- package/src/db/migrations/020-agent-app-connections.ts +0 -28
- package/src/db/migrations/021-pending-oauth-states.ts +0 -35
- package/src/db/migrations/022-app-connections-provider.ts +0 -25
- package/src/db/migrations/023-agent-group-secret-mode.test.ts +0 -124
- package/src/db/migrations/023-agent-group-secret-mode.ts +0 -65
- package/src/db/migrations/024-collapse-approvals.test.ts +0 -249
- package/src/db/migrations/024-collapse-approvals.ts +0 -182
- package/src/db/migrations/025-secret-mode-check.test.ts +0 -155
- package/src/db/migrations/025-secret-mode-check.ts +0 -49
- package/src/db/migrations/026-user-dms-bot-id.test.ts +0 -116
- package/src/db/migrations/026-user-dms-bot-id.ts +0 -54
- package/src/db/migrations/027-provider-credentials.ts +0 -41
- package/src/db/migrations/_test-helpers.ts +0 -41
- package/src/db/migrations/index.ts +0 -127
- package/src/db/migrations/module-agent-to-agent-destinations.ts +0 -84
- package/src/db/migrations/module-approvals-pending-approvals.ts +0 -42
- package/src/db/migrations/module-approvals-title-options.ts +0 -40
- package/src/db/schema.ts +0 -258
- package/src/db/session-db.test.ts +0 -93
- package/src/db/session-db.ts +0 -325
- package/src/db/sessions.ts +0 -241
- package/src/delivery.test.ts +0 -148
- package/src/delivery.ts +0 -445
- package/src/env.ts +0 -74
- package/src/group-folder.test.ts +0 -35
- package/src/group-folder.ts +0 -44
- package/src/group-init.ts +0 -92
- package/src/host-core.test.ts +0 -456
- package/src/host-sweep.test.ts +0 -146
- package/src/host-sweep.ts +0 -287
- package/src/index.ts +0 -227
- package/src/install-slug.ts +0 -33
- package/src/log.test.ts +0 -81
- package/src/log.ts +0 -117
- package/src/mcp/http.ts +0 -72
- package/src/mcp/server.ts +0 -92
- package/src/mcp/stdio.ts +0 -51
- package/src/mcp/tools/activity.ts +0 -88
- package/src/mcp/tools/agent-groups.ts +0 -183
- package/src/mcp/tools/approvals.ts +0 -122
- package/src/mcp/tools/channels.ts +0 -199
- package/src/mcp/tools/index.ts +0 -27
- package/src/mcp/tools/oauth.ts +0 -48
- package/src/mcp/tools/secrets.ts +0 -169
- package/src/mcp/tools/sessions.ts +0 -135
- package/src/mcp/types.ts +0 -51
- package/src/modules/agent-to-agent/agent-route.test.ts +0 -46
- package/src/modules/agent-to-agent/agent-route.ts +0 -223
- package/src/modules/agent-to-agent/create-agent.ts +0 -127
- package/src/modules/agent-to-agent/db/agent-destinations.ts +0 -135
- package/src/modules/agent-to-agent/index.ts +0 -22
- package/src/modules/agent-to-agent/write-destinations.ts +0 -59
- package/src/modules/approvals/agent.md +0 -45
- package/src/modules/approvals/index.ts +0 -21
- package/src/modules/approvals/picks.test.ts +0 -291
- package/src/modules/approvals/primitive.ts +0 -279
- package/src/modules/approvals/project.md +0 -27
- package/src/modules/approvals/response-handler.ts +0 -87
- package/src/modules/index.ts +0 -24
- package/src/modules/interactive/agent.md +0 -21
- package/src/modules/interactive/index.ts +0 -69
- package/src/modules/interactive/project.md +0 -12
- package/src/modules/mount-security/index.ts +0 -448
- package/src/modules/mount-security/migrate.test.ts +0 -91
- package/src/modules/permissions/access.ts +0 -28
- package/src/modules/permissions/channel-approval.test.ts +0 -389
- package/src/modules/permissions/channel-approval.ts +0 -188
- package/src/modules/permissions/db/agent-group-members.ts +0 -44
- package/src/modules/permissions/db/pending-channel-approvals.test.ts +0 -86
- package/src/modules/permissions/db/pending-channel-approvals.ts +0 -66
- package/src/modules/permissions/db/pending-sender-approvals.ts +0 -60
- package/src/modules/permissions/db/user-dms.ts +0 -58
- package/src/modules/permissions/db/user-roles.ts +0 -85
- package/src/modules/permissions/db/users.ts +0 -38
- package/src/modules/permissions/index.ts +0 -421
- package/src/modules/permissions/permissions.test.ts +0 -358
- package/src/modules/permissions/sender-approval.test.ts +0 -470
- package/src/modules/permissions/sender-approval.ts +0 -165
- package/src/modules/permissions/user-dm.ts +0 -200
- package/src/modules/provider-credentials/db.ts +0 -121
- package/src/modules/provider-credentials/index.ts +0 -12
- package/src/modules/provider-credentials/spawn.test.ts +0 -206
- package/src/modules/provider-credentials/spawn.ts +0 -114
- package/src/modules/scheduling/actions.ts +0 -113
- package/src/modules/scheduling/db.test.ts +0 -282
- package/src/modules/scheduling/db.ts +0 -148
- package/src/modules/scheduling/index.ts +0 -34
- package/src/modules/scheduling/recurrence.test.ts +0 -98
- package/src/modules/scheduling/recurrence.ts +0 -54
- package/src/modules/self-mod/agent.md +0 -30
- package/src/modules/self-mod/apply.ts +0 -85
- package/src/modules/self-mod/index.ts +0 -30
- package/src/modules/self-mod/project.md +0 -39
- package/src/modules/self-mod/request.ts +0 -91
- package/src/modules/typing/index.ts +0 -165
- package/src/oauth/agent-app-connections.ts +0 -103
- package/src/oauth/app-configs.test.ts +0 -64
- package/src/oauth/app-configs.ts +0 -114
- package/src/oauth/app-connections.test.ts +0 -109
- package/src/oauth/app-connections.ts +0 -178
- package/src/oauth/crypto.ts +0 -56
- package/src/oauth/flow.ts +0 -104
- package/src/oauth/providers/google.test.ts +0 -38
- package/src/oauth/providers/google.ts +0 -46
- package/src/oauth/providers/index.ts +0 -48
- package/src/oauth/state-store.test.ts +0 -54
- package/src/oauth/state-store.ts +0 -93
- package/src/parachute/README.md +0 -27
- package/src/parachute/create-agent.test.ts +0 -83
- package/src/parachute/create-agent.ts +0 -122
- package/src/parachute/group-status.test.ts +0 -165
- package/src/parachute/group-status.ts +0 -136
- package/src/parachute/types.ts +0 -41
- package/src/parachute/vault-mcp.test.ts +0 -251
- package/src/parachute/vault-mcp.ts +0 -232
- package/src/platform-id.test.ts +0 -104
- package/src/platform-id.ts +0 -109
- package/src/providers/index.ts +0 -6
- package/src/providers/provider-container-registry.ts +0 -58
- package/src/response-registry.ts +0 -45
- package/src/router.ts +0 -530
- package/src/secrets/crypto.test.ts +0 -45
- package/src/secrets/crypto.ts +0 -55
- package/src/secrets/index.ts +0 -355
- package/src/secrets/master-key.ts +0 -70
- package/src/secrets/secrets.test.ts +0 -354
- package/src/session-manager.migrate.test.ts +0 -59
- package/src/session-manager.ts +0 -433
- package/src/startup-bootstrap.test.ts +0 -226
- package/src/startup-bootstrap.ts +0 -207
- package/src/state-sqlite.ts +0 -182
- package/src/timezone.test.ts +0 -64
- package/src/timezone.ts +0 -37
- package/src/types.ts +0 -230
- package/src/web/auth.test.ts +0 -335
- package/src/web/auth.ts +0 -214
- package/src/web/discord-validate.test.ts +0 -77
- package/src/web/discord-validate.ts +0 -88
- package/src/web/hub-discovery.test.ts +0 -98
- package/src/web/hub-discovery.ts +0 -69
- package/src/web/routes/activity.ts +0 -106
- package/src/web/routes/agent-provider.test.ts +0 -282
- package/src/web/routes/agent-provider.ts +0 -309
- package/src/web/routes/approvals.ts +0 -185
- package/src/web/routes/apps.ts +0 -434
- package/src/web/routes/channels-mg-detail.test.ts +0 -324
- package/src/web/routes/channels-mga-detail.test.ts +0 -425
- package/src/web/routes/channels.ts +0 -489
- package/src/web/routes/oauth-providers.ts +0 -42
- package/src/web/routes/secrets.test.ts +0 -175
- package/src/web/routes/secrets.ts +0 -282
- package/src/web/routes/sessions.ts +0 -123
- package/src/web/routes/settings.test.ts +0 -106
- package/src/web/routes/settings.ts +0 -247
- package/src/web/routes/setup-status.ts +0 -205
- package/src/web/routes/vaults.test.ts +0 -389
- package/src/web/routes/vaults.ts +0 -225
- package/src/web/server-version.test.ts +0 -16
- package/src/web/server.ts +0 -1003
- package/src/web/services-manifest.test.ts +0 -120
- package/src/web/services-manifest.ts +0 -61
- package/src/web/static-serve.test.ts +0 -255
- package/src/web/static-serve.ts +0 -104
- package/src/web/telegram-validate.test.ts +0 -116
- package/src/web/telegram-validate.ts +0 -107
- package/src/web/vault-proxy.test.ts +0 -214
- package/src/web/vault-proxy.ts +0 -120
- package/src/web/wire-channel.ts +0 -181
- package/src/webhook-server.ts +0 -134
- package/vitest.config.ts +0 -18
- package/web/README.md +0 -63
- package/web/ui/index.html +0 -13
- package/web/ui/package.json +0 -35
- package/web/ui/pnpm-lock.yaml +0 -2164
- package/web/ui/scripts/verify-base.mjs +0 -31
- package/web/ui/src/App.tsx +0 -88
- package/web/ui/src/components/ActivityFeed.tsx +0 -444
- package/web/ui/src/components/AgentGroupPicker.tsx +0 -263
- package/web/ui/src/components/AgentProviderCards.tsx +0 -220
- package/web/ui/src/components/CredentialForm.tsx +0 -214
- package/web/ui/src/components/ScopeGrants.tsx +0 -74
- package/web/ui/src/components/StatusDot.tsx +0 -43
- package/web/ui/src/components/VaultPicker.tsx +0 -127
- package/web/ui/src/components/setup/AdapterInstallStep.tsx +0 -178
- package/web/ui/src/components/setup/AgentGroupStep.tsx +0 -43
- package/web/ui/src/components/setup/ChannelPickStep.tsx +0 -74
- package/web/ui/src/components/setup/DoneStep.tsx +0 -49
- package/web/ui/src/components/setup/PrereqStep.tsx +0 -129
- package/web/ui/src/components/setup/TestConnectionStep.tsx +0 -108
- package/web/ui/src/components/setup/TestMessageStep.tsx +0 -104
- package/web/ui/src/components/setup/WireChannelStep.tsx +0 -166
- package/web/ui/src/components/setup/types.ts +0 -105
- package/web/ui/src/lib/api.test.ts +0 -410
- package/web/ui/src/lib/api.ts +0 -1210
- package/web/ui/src/lib/auth.test.ts +0 -139
- package/web/ui/src/lib/auth.ts +0 -348
- package/web/ui/src/lib/channel-adapters.ts +0 -136
- package/web/ui/src/main.tsx +0 -19
- package/web/ui/src/routes/ApprovalsList.tsx +0 -294
- package/web/ui/src/routes/Apps.tsx +0 -613
- package/web/ui/src/routes/ChannelWireDetail.test.tsx +0 -233
- package/web/ui/src/routes/ChannelWireDetail.tsx +0 -403
- package/web/ui/src/routes/ChannelsList.tsx +0 -158
- package/web/ui/src/routes/GroupDetail.tsx +0 -755
- package/web/ui/src/routes/GroupList.tsx +0 -187
- package/web/ui/src/routes/MessagingGroupDetail.test.tsx +0 -233
- package/web/ui/src/routes/MessagingGroupDetail.tsx +0 -306
- package/web/ui/src/routes/NewGroupWizard.tsx +0 -390
- package/web/ui/src/routes/OAuthCallback.tsx +0 -56
- package/web/ui/src/routes/SecretsList.tsx +0 -921
- package/web/ui/src/routes/SessionsList.tsx +0 -220
- package/web/ui/src/routes/SettingsAgentProvider.tsx +0 -109
- package/web/ui/src/routes/SettingsApprovals.tsx +0 -234
- package/web/ui/src/routes/SetupWizard.tsx +0 -219
- package/web/ui/src/routes/VaultDetail.test.tsx +0 -361
- package/web/ui/src/routes/VaultDetail.tsx +0 -960
- package/web/ui/src/routes/VaultsList.tsx +0 -295
- package/web/ui/src/routes/WireChannelPage.tsx +0 -413
- package/web/ui/src/styles.css +0 -608
- package/web/ui/src/test/setup.ts +0 -23
- package/web/ui/src/vite-env.d.ts +0 -10
- package/web/ui/vite.config.ts +0 -34
- 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
|
-
}
|
package/src/modules/index.ts
DELETED
|
@@ -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.
|