@openparachute/agent 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -263
- 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 -172
- package/scripts/init-first-agent.ts +0 -378
- 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 -80
- 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/api-translator.test.ts +0 -306
- package/src/channels/api-translator.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 -128
- 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 -269
- package/src/container-runtime.ts +0 -167
- 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 -176
- package/src/db/connection.ts +0 -259
- 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 -232
- 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.test.ts +0 -126
- package/src/mcp/tools/channels.ts +0 -134
- 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/expand-path.test.ts +0 -82
- package/src/modules/mount-security/index.ts +0 -459
- 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 -641
- 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 -461
- package/src/secrets/master-key.ts +0 -70
- package/src/secrets/secrets.test.ts +0 -651
- package/src/session-manager.attachments.test.ts +0 -171
- package/src/session-manager.dup-skip.test.ts +0 -173
- package/src/session-manager.migrate.test.ts +0 -59
- package/src/session-manager.ts +0 -451
- 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 -233
- 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 -472
- package/src/web/routes/channels.ts +0 -311
- package/src/web/routes/oauth-providers.ts +0 -42
- package/src/web/routes/secrets.test.ts +0 -220
- package/src/web/routes/secrets.ts +0 -317
- 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 -1024
- package/src/web/services-manifest.test.ts +0 -148
- package/src/web/services-manifest.ts +0 -66
- 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 -1248
- package/web/ui/src/lib/auth.test.ts +0 -352
- package/web/ui/src/lib/auth.ts +0 -405
- 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.test.tsx +0 -206
- package/web/ui/src/routes/GroupDetail.tsx +0 -880
- 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 -942
- 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 -363
- 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,421 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Permissions module — sender resolution + access gate.
|
|
3
|
-
*
|
|
4
|
-
* Registers two hooks into the core router:
|
|
5
|
-
* 1. setSenderResolver — runs before agent resolution. Parses the payload,
|
|
6
|
-
* derives a namespaced user id, and upserts the `users` row on first
|
|
7
|
-
* sight. Returns null when the payload doesn't carry enough to identify
|
|
8
|
-
* a sender.
|
|
9
|
-
* 2. setAccessGate — runs after agent resolution. Enforces the
|
|
10
|
-
* unknown_sender_policy (strict/request_approval/public) and the
|
|
11
|
-
* owner/global-admin/scoped-admin/member access hierarchy. Records its
|
|
12
|
-
* own `dropped_messages` row on refusal (structural drops are recorded
|
|
13
|
-
* by core).
|
|
14
|
-
*
|
|
15
|
-
* Without this module: sender resolution is a no-op (userId=null); the
|
|
16
|
-
* access gate is not registered and core defaults to allow-all.
|
|
17
|
-
*/
|
|
18
|
-
import { recordDroppedMessage } from '../../db/dropped-messages.js';
|
|
19
|
-
import {
|
|
20
|
-
createMessagingGroupAgent,
|
|
21
|
-
getMessagingGroup,
|
|
22
|
-
setMessagingGroupDeniedAt,
|
|
23
|
-
updateMessagingGroup,
|
|
24
|
-
} from '../../db/messaging-groups.js';
|
|
25
|
-
import {
|
|
26
|
-
routeInbound,
|
|
27
|
-
setAccessGate,
|
|
28
|
-
setChannelRequestGate,
|
|
29
|
-
setSenderResolver,
|
|
30
|
-
setSenderScopeGate,
|
|
31
|
-
type AccessGateResult,
|
|
32
|
-
} from '../../router.js';
|
|
33
|
-
import type { InboundEvent } from '../../channels/adapter.js';
|
|
34
|
-
import { registerResponseHandler, type ResponsePayload } from '../../response-registry.js';
|
|
35
|
-
import { log } from '../../log.js';
|
|
36
|
-
import type { MessagingGroup, MessagingGroupAgent } from '../../types.js';
|
|
37
|
-
import { canAccessAgentGroup } from './access.js';
|
|
38
|
-
import { requestChannelApproval } from './channel-approval.js';
|
|
39
|
-
import { addMember } from './db/agent-group-members.js';
|
|
40
|
-
import { deletePendingChannelApproval, getPendingChannelApproval } from './db/pending-channel-approvals.js';
|
|
41
|
-
import { deletePendingSenderApproval, getPendingSenderApproval } from './db/pending-sender-approvals.js';
|
|
42
|
-
import { hasAdminPrivilege } from './db/user-roles.js';
|
|
43
|
-
import { getUser, upsertUser } from './db/users.js';
|
|
44
|
-
import { requestSenderApproval } from './sender-approval.js';
|
|
45
|
-
|
|
46
|
-
function extractAndUpsertUser(event: InboundEvent): string | null {
|
|
47
|
-
let content: Record<string, unknown>;
|
|
48
|
-
try {
|
|
49
|
-
content = JSON.parse(event.message.content) as Record<string, unknown>;
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// chat-sdk-bridge serializes author info as a nested `author.userId` and
|
|
55
|
-
// does NOT populate top-level `senderId`. Older adapters (v1, native) put
|
|
56
|
-
// `senderId` or `sender` directly at the top level. Check all three.
|
|
57
|
-
const senderIdField = typeof content.senderId === 'string' ? content.senderId : undefined;
|
|
58
|
-
const senderField = typeof content.sender === 'string' ? content.sender : undefined;
|
|
59
|
-
const author =
|
|
60
|
-
typeof content.author === 'object' && content.author !== null
|
|
61
|
-
? (content.author as Record<string, unknown>)
|
|
62
|
-
: undefined;
|
|
63
|
-
const authorUserId = typeof author?.userId === 'string' ? (author.userId as string) : undefined;
|
|
64
|
-
const senderName =
|
|
65
|
-
(typeof content.senderName === 'string' ? content.senderName : undefined) ??
|
|
66
|
-
(typeof author?.fullName === 'string' ? (author.fullName as string) : undefined) ??
|
|
67
|
-
(typeof author?.userName === 'string' ? (author.userName as string) : undefined);
|
|
68
|
-
|
|
69
|
-
const rawHandle = senderIdField ?? senderField ?? authorUserId;
|
|
70
|
-
if (!rawHandle) return null;
|
|
71
|
-
|
|
72
|
-
const userId = rawHandle.includes(':') ? rawHandle : `${event.channelType}:${rawHandle}`;
|
|
73
|
-
if (!getUser(userId)) {
|
|
74
|
-
upsertUser({
|
|
75
|
-
id: userId,
|
|
76
|
-
kind: event.channelType,
|
|
77
|
-
display_name: senderName ?? null,
|
|
78
|
-
created_at: new Date().toISOString(),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
return userId;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function safeParseContent(raw: string): { text?: string; sender?: string; senderId?: string } {
|
|
85
|
-
try {
|
|
86
|
-
return JSON.parse(raw);
|
|
87
|
-
} catch {
|
|
88
|
-
return { text: raw };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function handleUnknownSender(
|
|
93
|
-
mg: MessagingGroup,
|
|
94
|
-
userId: string | null,
|
|
95
|
-
agentGroupId: string,
|
|
96
|
-
accessReason: string,
|
|
97
|
-
event: InboundEvent,
|
|
98
|
-
): void {
|
|
99
|
-
const parsed = safeParseContent(event.message.content);
|
|
100
|
-
const senderName = parsed.sender ?? null;
|
|
101
|
-
const dropRecord = {
|
|
102
|
-
channel_type: event.channelType,
|
|
103
|
-
platform_id: event.platformId,
|
|
104
|
-
user_id: userId,
|
|
105
|
-
sender_name: senderName,
|
|
106
|
-
reason: `unknown_sender_${mg.unknown_sender_policy}`,
|
|
107
|
-
messaging_group_id: mg.id,
|
|
108
|
-
agent_group_id: agentGroupId,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
if (mg.unknown_sender_policy === 'strict') {
|
|
112
|
-
log.info('MESSAGE DROPPED — unknown sender (strict policy)', {
|
|
113
|
-
messagingGroupId: mg.id,
|
|
114
|
-
agentGroupId,
|
|
115
|
-
userId,
|
|
116
|
-
accessReason,
|
|
117
|
-
});
|
|
118
|
-
recordDroppedMessage(dropRecord);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (mg.unknown_sender_policy === 'request_approval') {
|
|
123
|
-
log.info('MESSAGE DROPPED — unknown sender (approval requested)', {
|
|
124
|
-
messagingGroupId: mg.id,
|
|
125
|
-
agentGroupId,
|
|
126
|
-
userId,
|
|
127
|
-
accessReason,
|
|
128
|
-
});
|
|
129
|
-
recordDroppedMessage(dropRecord);
|
|
130
|
-
// Fire-and-forget; pick-approver + delivery + row-insert are all async.
|
|
131
|
-
// If it fails it logs internally — the user's message still stays dropped
|
|
132
|
-
// either way. Requires a resolved userId (senderResolver populates users
|
|
133
|
-
// row before the gate fires); if we got here without one, there's nothing
|
|
134
|
-
// to identify for approval and we just stay in the "silent strict" branch.
|
|
135
|
-
if (userId) {
|
|
136
|
-
requestSenderApproval({
|
|
137
|
-
messagingGroupId: mg.id,
|
|
138
|
-
agentGroupId,
|
|
139
|
-
senderIdentity: userId,
|
|
140
|
-
senderName,
|
|
141
|
-
event,
|
|
142
|
-
}).catch((err) => log.error('Sender-approval flow threw', { err }));
|
|
143
|
-
}
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// 'public' should have been handled before the gate; fall through silently.
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
setSenderResolver(extractAndUpsertUser);
|
|
151
|
-
|
|
152
|
-
setAccessGate((event, userId, mg, agentGroupId): AccessGateResult => {
|
|
153
|
-
// Public channels skip the access check entirely.
|
|
154
|
-
if (mg.unknown_sender_policy === 'public') {
|
|
155
|
-
return { allowed: true };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!userId) {
|
|
159
|
-
handleUnknownSender(mg, null, agentGroupId, 'unknown_user', event);
|
|
160
|
-
return { allowed: false, reason: 'unknown_user' };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const decision = canAccessAgentGroup(userId, agentGroupId);
|
|
164
|
-
if (decision.allowed) {
|
|
165
|
-
return { allowed: true };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
handleUnknownSender(mg, userId, agentGroupId, decision.reason, event);
|
|
169
|
-
return { allowed: false, reason: decision.reason };
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Per-wiring sender-scope enforcement. Stricter than the messaging-group
|
|
174
|
-
* `unknown_sender_policy` — a wiring can require `sender_scope='known'`
|
|
175
|
-
* (explicit owner / admin / member) even on a 'public' messaging group.
|
|
176
|
-
*
|
|
177
|
-
* 'all' is a no-op; any sender passes. 'known' requires a userId that
|
|
178
|
-
* canAccessAgentGroup accepts (owner, admin, or group member).
|
|
179
|
-
*/
|
|
180
|
-
setSenderScopeGate(
|
|
181
|
-
(_event: InboundEvent, userId: string | null, _mg: MessagingGroup, agent: MessagingGroupAgent): AccessGateResult => {
|
|
182
|
-
if (agent.sender_scope === 'all') return { allowed: true };
|
|
183
|
-
if (!userId) return { allowed: false, reason: 'unknown_user_scope' };
|
|
184
|
-
const decision = canAccessAgentGroup(userId, agent.agent_group_id);
|
|
185
|
-
if (decision.allowed) return { allowed: true };
|
|
186
|
-
return { allowed: false, reason: `sender_scope_${decision.reason}` };
|
|
187
|
-
},
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Response handler for the unknown-sender approval card.
|
|
192
|
-
*
|
|
193
|
-
* Claim rule: questionId matches a row in pending_sender_approvals. If no
|
|
194
|
-
* such row, return false so the next handler (approvals module, interactive)
|
|
195
|
-
* gets a shot.
|
|
196
|
-
*
|
|
197
|
-
* Approve: add the sender to agent_group_members + re-invoke routeInbound
|
|
198
|
-
* with the stored event. The second routing attempt clears the gate because
|
|
199
|
-
* the user is now a member.
|
|
200
|
-
*
|
|
201
|
-
* Deny: delete the row (no "deny list" — a future message re-triggers a
|
|
202
|
-
* fresh card per ACTION-ITEMS item 5 "no denial persistence").
|
|
203
|
-
*/
|
|
204
|
-
async function handleSenderApprovalResponse(payload: ResponsePayload): Promise<boolean> {
|
|
205
|
-
const row = getPendingSenderApproval(payload.questionId);
|
|
206
|
-
if (!row) return false;
|
|
207
|
-
|
|
208
|
-
// payload.userId is the raw platform userId (e.g. "6037840640"); namespace it
|
|
209
|
-
// with the channel type so it matches users(id) format. Then verify the
|
|
210
|
-
// clicker is the designated approver OR has owner/admin privilege over this
|
|
211
|
-
// agent group — any other click is rejected so random users can't self-admit
|
|
212
|
-
// via stolen card forwarding.
|
|
213
|
-
const clickerId = payload.userId ? `${payload.channelType}:${payload.userId}` : null;
|
|
214
|
-
const isAuthorized =
|
|
215
|
-
clickerId !== null && (clickerId === row.approver_user_id || hasAdminPrivilege(clickerId, row.agent_group_id));
|
|
216
|
-
if (!isAuthorized) {
|
|
217
|
-
log.warn('Unknown-sender approval click rejected — unauthorized clicker', {
|
|
218
|
-
approvalId: row.id,
|
|
219
|
-
clickerId,
|
|
220
|
-
expectedApprover: row.approver_user_id,
|
|
221
|
-
});
|
|
222
|
-
return true; // claim the response so it's not unclaimed-logged, but do nothing
|
|
223
|
-
}
|
|
224
|
-
const approverId = clickerId;
|
|
225
|
-
const alsoAllow = payload.value === 'approve_and_allow';
|
|
226
|
-
const approved = payload.value === 'approve' || alsoAllow;
|
|
227
|
-
|
|
228
|
-
if (approved) {
|
|
229
|
-
addMember({
|
|
230
|
-
user_id: row.sender_identity,
|
|
231
|
-
agent_group_id: row.agent_group_id,
|
|
232
|
-
added_by: approverId,
|
|
233
|
-
added_at: new Date().toISOString(),
|
|
234
|
-
});
|
|
235
|
-
log.info('Unknown sender approved — member added', {
|
|
236
|
-
approvalId: row.id,
|
|
237
|
-
senderIdentity: row.sender_identity,
|
|
238
|
-
agentGroupId: row.agent_group_id,
|
|
239
|
-
approverId,
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
if (alsoAllow) {
|
|
243
|
-
// Snapshot the prior policy for the audit line — read before the
|
|
244
|
-
// update so the "fromPolicy" field reflects pre-flip state even if
|
|
245
|
-
// a concurrent click had already flipped it. fromPolicy=null means
|
|
246
|
-
// the MG row was deleted between approval-creation and click; the
|
|
247
|
-
// updateMessagingGroup call below silently no-ops on a missing row.
|
|
248
|
-
const mg = getMessagingGroup(row.messaging_group_id);
|
|
249
|
-
const fromPolicy = mg?.unknown_sender_policy ?? null;
|
|
250
|
-
if (fromPolicy !== 'public') {
|
|
251
|
-
updateMessagingGroup(row.messaging_group_id, { unknown_sender_policy: 'public' });
|
|
252
|
-
}
|
|
253
|
-
log.info('Unknown-sender policy flipped to public via approval card', {
|
|
254
|
-
audit: 'sender_approval_policy_flip',
|
|
255
|
-
approvalId: row.id,
|
|
256
|
-
messagingGroupId: row.messaging_group_id,
|
|
257
|
-
agentGroupId: row.agent_group_id,
|
|
258
|
-
approverId,
|
|
259
|
-
fromPolicy,
|
|
260
|
-
toPolicy: 'public',
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Clear the pending row BEFORE re-routing so the gate check on the
|
|
265
|
-
// second attempt doesn't see the in-flight row and short-circuit.
|
|
266
|
-
deletePendingSenderApproval(row.id);
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
const event = JSON.parse(row.original_message) as InboundEvent;
|
|
270
|
-
await routeInbound(event);
|
|
271
|
-
} catch (err) {
|
|
272
|
-
log.error('Failed to replay message after sender approval', { approvalId: row.id, err });
|
|
273
|
-
}
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
log.info('Unknown sender denied', {
|
|
278
|
-
approvalId: row.id,
|
|
279
|
-
senderIdentity: row.sender_identity,
|
|
280
|
-
agentGroupId: row.agent_group_id,
|
|
281
|
-
approverId,
|
|
282
|
-
});
|
|
283
|
-
deletePendingSenderApproval(row.id);
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
registerResponseHandler(handleSenderApprovalResponse);
|
|
288
|
-
|
|
289
|
-
// ── Unknown-channel registration flow ──
|
|
290
|
-
|
|
291
|
-
setChannelRequestGate(async (mg, event) => {
|
|
292
|
-
await requestChannelApproval({ messagingGroupId: mg.id, event });
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Response handler for the unknown-channel registration card.
|
|
297
|
-
*
|
|
298
|
-
* Claim rule: questionId matches a pending_channel_approvals row (keyed
|
|
299
|
-
* by messaging_group_id). If no such row, return false so downstream
|
|
300
|
-
* handlers get a shot.
|
|
301
|
-
*
|
|
302
|
-
* Approve: create the wiring with MVP defaults (mention-sticky for
|
|
303
|
-
* groups / pattern='.' for DMs; sender_scope='known';
|
|
304
|
-
* ignored_message_policy='accumulate'), add the triggering sender as a
|
|
305
|
-
* member so sender_scope doesn't immediately bounce them into a
|
|
306
|
-
* sender-approval card, then replay the original event.
|
|
307
|
-
*
|
|
308
|
-
* Deny: set `messaging_groups.denied_at = now()` so future mentions on
|
|
309
|
-
* this channel drop silently until an admin explicitly wires it.
|
|
310
|
-
*/
|
|
311
|
-
async function handleChannelApprovalResponse(payload: ResponsePayload): Promise<boolean> {
|
|
312
|
-
const row = getPendingChannelApproval(payload.questionId);
|
|
313
|
-
if (!row) return false;
|
|
314
|
-
|
|
315
|
-
// Click-auth: same pattern as sender-approval (see commit 68058cb).
|
|
316
|
-
// Raw platform userId → namespace with channelType → must match the
|
|
317
|
-
// designated approver OR have admin privilege over the target agent.
|
|
318
|
-
const clickerId = payload.userId ? `${payload.channelType}:${payload.userId}` : null;
|
|
319
|
-
const isAuthorized =
|
|
320
|
-
clickerId !== null && (clickerId === row.approver_user_id || hasAdminPrivilege(clickerId, row.agent_group_id));
|
|
321
|
-
if (!isAuthorized) {
|
|
322
|
-
log.warn('Channel registration click rejected — unauthorized clicker', {
|
|
323
|
-
messagingGroupId: row.messaging_group_id,
|
|
324
|
-
clickerId,
|
|
325
|
-
expectedApprover: row.approver_user_id,
|
|
326
|
-
});
|
|
327
|
-
return true; // claim but take no action
|
|
328
|
-
}
|
|
329
|
-
const approverId = clickerId;
|
|
330
|
-
const approved = payload.value === 'approve';
|
|
331
|
-
|
|
332
|
-
if (!approved) {
|
|
333
|
-
setMessagingGroupDeniedAt(row.messaging_group_id, new Date().toISOString());
|
|
334
|
-
deletePendingChannelApproval(row.messaging_group_id);
|
|
335
|
-
log.info('Channel registration denied', {
|
|
336
|
-
messagingGroupId: row.messaging_group_id,
|
|
337
|
-
agentGroupId: row.agent_group_id,
|
|
338
|
-
approverId,
|
|
339
|
-
});
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Rehydrate the original event to know (a) whether it was a DM or group
|
|
344
|
-
// (chooses engage_mode default), and (b) who the triggering sender was
|
|
345
|
-
// (auto-member-add so sender_scope='known' doesn't bounce the replay).
|
|
346
|
-
let event: InboundEvent;
|
|
347
|
-
try {
|
|
348
|
-
event = JSON.parse(row.original_message) as InboundEvent;
|
|
349
|
-
} catch (err) {
|
|
350
|
-
log.error('Channel registration: failed to parse stored event', {
|
|
351
|
-
messagingGroupId: row.messaging_group_id,
|
|
352
|
-
err,
|
|
353
|
-
});
|
|
354
|
-
deletePendingChannelApproval(row.messaging_group_id);
|
|
355
|
-
return true;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Decide engage_mode from the original event. DMs (`isMention=true` &
|
|
359
|
-
// not in a group) get `pattern='.'` (always respond). Group mentions
|
|
360
|
-
// get `mention-sticky` (respond now + follow the thread).
|
|
361
|
-
//
|
|
362
|
-
// We can't read `mg.is_group` reliably here because we only auto-create
|
|
363
|
-
// the mg with `is_group=0` on first sight — the adapter hasn't told us
|
|
364
|
-
// yet whether it's actually a group. Fall back to the InboundEvent's
|
|
365
|
-
// `threadId`: a non-null threadId implies a threaded platform (Slack
|
|
366
|
-
// channel thread, Discord thread), which we treat as a group.
|
|
367
|
-
const isGroup = event.threadId !== null;
|
|
368
|
-
const engageMode: MessagingGroupAgent['engage_mode'] = isGroup ? 'mention-sticky' : 'pattern';
|
|
369
|
-
const engagePattern = isGroup ? null : '.';
|
|
370
|
-
|
|
371
|
-
const mgaId = `mga-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
372
|
-
createMessagingGroupAgent({
|
|
373
|
-
id: mgaId,
|
|
374
|
-
messaging_group_id: row.messaging_group_id,
|
|
375
|
-
agent_group_id: row.agent_group_id,
|
|
376
|
-
engage_mode: engageMode,
|
|
377
|
-
engage_pattern: engagePattern,
|
|
378
|
-
sender_scope: 'known',
|
|
379
|
-
ignored_message_policy: 'accumulate',
|
|
380
|
-
session_mode: 'shared',
|
|
381
|
-
priority: 0,
|
|
382
|
-
created_at: new Date().toISOString(),
|
|
383
|
-
});
|
|
384
|
-
log.info('Channel registration approved — wiring created', {
|
|
385
|
-
messagingGroupId: row.messaging_group_id,
|
|
386
|
-
agentGroupId: row.agent_group_id,
|
|
387
|
-
mgaId,
|
|
388
|
-
engageMode,
|
|
389
|
-
approverId,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Auto-admit the triggering sender. Without this, the replay below
|
|
393
|
-
// would bounce through sender-approval (sender_scope='known' +
|
|
394
|
-
// sender-is-not-a-member).
|
|
395
|
-
const senderUserId = extractAndUpsertUser(event);
|
|
396
|
-
if (senderUserId) {
|
|
397
|
-
addMember({
|
|
398
|
-
user_id: senderUserId,
|
|
399
|
-
agent_group_id: row.agent_group_id,
|
|
400
|
-
added_by: approverId,
|
|
401
|
-
added_at: new Date().toISOString(),
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Clear the pending row BEFORE replay so the gate check on the second
|
|
406
|
-
// attempt sees a wired channel (agentCount > 0) and takes the fan-out
|
|
407
|
-
// path normally.
|
|
408
|
-
deletePendingChannelApproval(row.messaging_group_id);
|
|
409
|
-
|
|
410
|
-
try {
|
|
411
|
-
await routeInbound(event);
|
|
412
|
-
} catch (err) {
|
|
413
|
-
log.error('Failed to replay message after channel approval', {
|
|
414
|
-
messagingGroupId: row.messaging_group_id,
|
|
415
|
-
err,
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
return true;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
registerResponseHandler(handleChannelApprovalResponse);
|