@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
package/src/types.ts
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
// ── Central DB entities ──
|
|
2
|
-
|
|
3
|
-
export type SecretMode = 'all' | 'selective';
|
|
4
|
-
|
|
5
|
-
export interface AgentGroup {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
folder: string;
|
|
9
|
-
agent_provider: string | null;
|
|
10
|
-
/**
|
|
11
|
-
* Per-group injection policy for secrets in this group's scope (its own
|
|
12
|
-
* scoped secrets + globals): `all` injects every in-scope secret;
|
|
13
|
-
* `selective` injects only those with an explicit `secret_assignments`
|
|
14
|
-
* row pointing to this group. Defaults to `selective` (migration 023).
|
|
15
|
-
*/
|
|
16
|
-
secret_mode: SecretMode;
|
|
17
|
-
created_at: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Exact wire mirror — `UnknownSenderPolicy` in `web/ui/src/lib/api.ts` MUST
|
|
22
|
-
* stay in lock-step with this union. No translator; the values cross the
|
|
23
|
-
* wire as-is. If you add or rename a value here, update the client too.
|
|
24
|
-
*/
|
|
25
|
-
export type UnknownSenderPolicy = 'strict' | 'request_approval' | 'public';
|
|
26
|
-
|
|
27
|
-
export interface MessagingGroup {
|
|
28
|
-
id: string;
|
|
29
|
-
channel_type: string;
|
|
30
|
-
platform_id: string;
|
|
31
|
-
name: string | null;
|
|
32
|
-
is_group: number; // 0 | 1
|
|
33
|
-
unknown_sender_policy: UnknownSenderPolicy;
|
|
34
|
-
/**
|
|
35
|
-
* When set, the owner explicitly denied registering this channel — the
|
|
36
|
-
* router drops silently and does not re-escalate. Cleared by any explicit
|
|
37
|
-
* wiring mutation (admin command). See migration 012.
|
|
38
|
-
*
|
|
39
|
-
* Optional on the TS type so pre-migration-012 callers that build
|
|
40
|
-
* MessagingGroup objects in code (fixtures, etc.) don't need to update;
|
|
41
|
-
* the column itself defaults to NULL in SQLite.
|
|
42
|
-
*/
|
|
43
|
-
denied_at?: string | null;
|
|
44
|
-
created_at: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// ── Identity & privilege ──
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* User = a messaging-platform identifier. Namespaced so distinct channels
|
|
51
|
-
* with numeric IDs don't collide: "phone:+1555...", "tg:123", "discord:456",
|
|
52
|
-
* "email:a@x.com". A single human with a phone AND a telegram handle has
|
|
53
|
-
* two separate users — no cross-channel linking (yet).
|
|
54
|
-
*/
|
|
55
|
-
export interface User {
|
|
56
|
-
id: string;
|
|
57
|
-
kind: string; // 'phone' | 'email' | 'discord' | 'telegram' | 'matrix' | ...
|
|
58
|
-
display_name: string | null;
|
|
59
|
-
created_at: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type UserRoleKind = 'owner' | 'admin';
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Role grant. Owner is always global. Admin is either global
|
|
66
|
-
* (agent_group_id = null) or scoped to a specific agent group.
|
|
67
|
-
* Admin @ A implicitly makes the user a member of A — we do not require
|
|
68
|
-
* a separate agent_group_members row for admins.
|
|
69
|
-
*/
|
|
70
|
-
export interface UserRole {
|
|
71
|
-
user_id: string;
|
|
72
|
-
role: UserRoleKind;
|
|
73
|
-
agent_group_id: string | null;
|
|
74
|
-
granted_by: string | null;
|
|
75
|
-
granted_at: string;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** "Known" membership in an agent group — required for unprivileged users. */
|
|
79
|
-
export interface AgentGroupMember {
|
|
80
|
-
user_id: string;
|
|
81
|
-
agent_group_id: string;
|
|
82
|
-
added_by: string | null;
|
|
83
|
-
added_at: string;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Cached DM channel for a user on a specific `(channel_type, bot_id)` pair.
|
|
88
|
-
*
|
|
89
|
-
* `bot_id = ''` (empty string) is the configurable channel-default slot —
|
|
90
|
-
* the operator points it at whichever bot they want approvals to fall
|
|
91
|
-
* back to when a `(user, channel, originBotId)` exact-bot lookup misses
|
|
92
|
-
* AND the cold-DM resolve also fails. Migration 026 added the column;
|
|
93
|
-
* pre-multi-bot installs land every row at `bot_id = ''`.
|
|
94
|
-
*/
|
|
95
|
-
export interface UserDm {
|
|
96
|
-
user_id: string;
|
|
97
|
-
channel_type: string;
|
|
98
|
-
bot_id: string;
|
|
99
|
-
messaging_group_id: string;
|
|
100
|
-
resolved_at: string;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// DB vocabulary. See dbToApi* in src/web/routes/channels.ts for wire equivalents in web/ui/src/lib/api.ts.
|
|
104
|
-
export type EngageMode = 'pattern' | 'mention' | 'mention-sticky';
|
|
105
|
-
// DB vocabulary. The DB-side `'all'` means "no sender filter"; the wire side
|
|
106
|
-
// uses `'allowlist' | 'unrestricted'` (paraclaw#94 — kept the two unions
|
|
107
|
-
// literal-disjoint so a grep-refactor can't conflate them through the
|
|
108
|
-
// translator).
|
|
109
|
-
export type SenderScope = 'all' | 'known';
|
|
110
|
-
// DB vocabulary. See dbToApi* in src/web/routes/channels.ts for wire equivalents in web/ui/src/lib/api.ts.
|
|
111
|
-
export type IgnoredMessagePolicy = 'drop' | 'accumulate';
|
|
112
|
-
|
|
113
|
-
export interface MessagingGroupAgent {
|
|
114
|
-
id: string;
|
|
115
|
-
messaging_group_id: string;
|
|
116
|
-
agent_group_id: string;
|
|
117
|
-
engage_mode: EngageMode;
|
|
118
|
-
/**
|
|
119
|
-
* Regex source string used when engage_mode='pattern'. `'.'` is the sentinel
|
|
120
|
-
* for "match every message" (the "always" flavor). Ignored for 'mention' /
|
|
121
|
-
* 'mention-sticky' modes.
|
|
122
|
-
*/
|
|
123
|
-
engage_pattern: string | null;
|
|
124
|
-
sender_scope: SenderScope;
|
|
125
|
-
ignored_message_policy: IgnoredMessagePolicy;
|
|
126
|
-
session_mode: 'shared' | 'per-thread' | 'agent-shared';
|
|
127
|
-
priority: number;
|
|
128
|
-
created_at: string;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export interface Session {
|
|
132
|
-
id: string;
|
|
133
|
-
agent_group_id: string;
|
|
134
|
-
messaging_group_id: string | null;
|
|
135
|
-
thread_id: string | null;
|
|
136
|
-
agent_provider: string | null;
|
|
137
|
-
status: 'active' | 'closed';
|
|
138
|
-
container_status: 'running' | 'idle' | 'stopped';
|
|
139
|
-
last_active: string | null;
|
|
140
|
-
created_at: string;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// ── Session DB entities ──
|
|
144
|
-
|
|
145
|
-
export type MessageInKind = 'chat' | 'chat-sdk' | 'task' | 'webhook' | 'system';
|
|
146
|
-
export type MessageInStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
147
|
-
|
|
148
|
-
export interface MessageIn {
|
|
149
|
-
id: string;
|
|
150
|
-
kind: MessageInKind;
|
|
151
|
-
timestamp: string;
|
|
152
|
-
status: MessageInStatus;
|
|
153
|
-
status_changed: string | null;
|
|
154
|
-
process_after: string | null;
|
|
155
|
-
recurrence: string | null;
|
|
156
|
-
tries: number;
|
|
157
|
-
platform_id: string | null;
|
|
158
|
-
channel_type: string | null;
|
|
159
|
-
thread_id: string | null;
|
|
160
|
-
content: string; // JSON blob
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export interface MessageOut {
|
|
164
|
-
id: string;
|
|
165
|
-
in_reply_to: string | null;
|
|
166
|
-
timestamp: string;
|
|
167
|
-
delivered: number; // 0 | 1
|
|
168
|
-
deliver_after: string | null;
|
|
169
|
-
recurrence: string | null;
|
|
170
|
-
kind: string;
|
|
171
|
-
platform_id: string | null;
|
|
172
|
-
channel_type: string | null;
|
|
173
|
-
thread_id: string | null;
|
|
174
|
-
content: string; // JSON blob
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// ── Approvals (central DB) ──
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Open-string discriminator. The host knows two well-known values
|
|
181
|
-
* (`'question'` for inline UX prompts; module-action strings like
|
|
182
|
-
* `'install_packages'` / `'add_mcp_server'` / `'credential'` for admin
|
|
183
|
-
* gating), but third-party modules can register their own action strings
|
|
184
|
-
* via `registerApprovalHandler`, so this is intentionally not a closed
|
|
185
|
-
* union.
|
|
186
|
-
*/
|
|
187
|
-
export type ApprovalKind = string;
|
|
188
|
-
export type ApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
|
|
189
|
-
|
|
190
|
-
export interface QuestionApprovalBody {
|
|
191
|
-
title: string;
|
|
192
|
-
options: import('./channels/ask-question.js').NormalizedOption[];
|
|
193
|
-
message_out_id: string;
|
|
194
|
-
platform_id: string | null;
|
|
195
|
-
channel_type: string | null;
|
|
196
|
-
thread_id: string | null;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export interface ActionApprovalBody {
|
|
200
|
-
title: string;
|
|
201
|
-
options: import('./channels/ask-question.js').NormalizedOption[];
|
|
202
|
-
request_id: string;
|
|
203
|
-
payload: Record<string, unknown>;
|
|
204
|
-
platform_id: string | null;
|
|
205
|
-
channel_type: string | null;
|
|
206
|
-
thread_id: string | null;
|
|
207
|
-
platform_message_id: string | null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export type ApprovalBody = QuestionApprovalBody | ActionApprovalBody | Record<string, unknown>;
|
|
211
|
-
|
|
212
|
-
export interface Approval {
|
|
213
|
-
id: string;
|
|
214
|
-
kind: ApprovalKind;
|
|
215
|
-
agent_group_id: string;
|
|
216
|
-
session_id: string | null;
|
|
217
|
-
body: ApprovalBody;
|
|
218
|
-
status: ApprovalStatus;
|
|
219
|
-
approver_user_id: string | null;
|
|
220
|
-
decided_at: string | null;
|
|
221
|
-
created_at: string;
|
|
222
|
-
expires_at: string | null;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// ── Agent destinations (central DB) ──
|
|
226
|
-
|
|
227
|
-
export interface AgentDestination {
|
|
228
|
-
agent_group_id: string;
|
|
229
|
-
local_name: string;
|
|
230
|
-
target_type: 'channel' | 'agent';
|
|
231
|
-
target_id: string;
|
|
232
|
-
created_at: string;
|
|
233
|
-
}
|
package/src/web/auth.test.ts
DELETED
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hub-JWT validation + scope-check tests. Mirrors vault's hub-jwt.test.ts
|
|
3
|
-
* shape but uses vitest + node:http (paraclaw's suite is vitest, not
|
|
4
|
-
* bun:test). A fake JWKS endpoint signs locally with a known RSA keypair;
|
|
5
|
-
* cases cover the spec failure modes plus paraclaw's agent-scope inheritance
|
|
6
|
-
* + vault:admin catch-all + legacy `claw:*` compat normalization.
|
|
7
|
-
*/
|
|
8
|
-
import http from 'node:http';
|
|
9
|
-
import type { AddressInfo } from 'node:net';
|
|
10
|
-
|
|
11
|
-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
12
|
-
import { exportJWK, generateKeyPair, SignJWT } from 'jose';
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
authenticate,
|
|
16
|
-
getHubOrigin,
|
|
17
|
-
hasScope,
|
|
18
|
-
HubJwtError,
|
|
19
|
-
resetJwksCache,
|
|
20
|
-
SCOPE_AGENT_ADMIN,
|
|
21
|
-
SCOPE_AGENT_READ,
|
|
22
|
-
SCOPE_AGENT_WRITE,
|
|
23
|
-
SCOPE_VAULT_ADMIN,
|
|
24
|
-
validateHubJwt,
|
|
25
|
-
} from './auth.js';
|
|
26
|
-
|
|
27
|
-
interface Keypair {
|
|
28
|
-
// jose's generateKeyPair returns CryptoKey under WebCrypto; type narrowly to
|
|
29
|
-
// avoid pulling in lib.dom.
|
|
30
|
-
privateKey: Awaited<ReturnType<typeof generateKeyPair>>['privateKey'];
|
|
31
|
-
publicJwk: { kty: string; n: string; e: string; kid: string; alg: string; use: string };
|
|
32
|
-
kid: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async function makeKeypair(kid: string): Promise<Keypair> {
|
|
36
|
-
const { privateKey, publicKey } = await generateKeyPair('RS256', { extractable: true });
|
|
37
|
-
const jwk = await exportJWK(publicKey);
|
|
38
|
-
return {
|
|
39
|
-
privateKey,
|
|
40
|
-
publicJwk: {
|
|
41
|
-
kty: 'RSA',
|
|
42
|
-
n: jwk.n!,
|
|
43
|
-
e: jwk.e!,
|
|
44
|
-
kid,
|
|
45
|
-
alg: 'RS256',
|
|
46
|
-
use: 'sig',
|
|
47
|
-
},
|
|
48
|
-
kid,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface JwksFixture {
|
|
53
|
-
origin: string;
|
|
54
|
-
stop: () => Promise<void>;
|
|
55
|
-
setKeys: (keys: Keypair[]) => void;
|
|
56
|
-
setUnreachable: (down: boolean) => void;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function startJwksFixture(): Promise<JwksFixture> {
|
|
60
|
-
return new Promise((resolve) => {
|
|
61
|
-
let keys: Keypair[] = [];
|
|
62
|
-
let down = false;
|
|
63
|
-
const server = http.createServer((req, res) => {
|
|
64
|
-
if (req.url !== '/.well-known/jwks.json') {
|
|
65
|
-
res.writeHead(404).end('not found');
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (down) {
|
|
69
|
-
res.writeHead(503).end('upstream down');
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
73
|
-
res.end(JSON.stringify({ keys: keys.map((k) => k.publicJwk) }));
|
|
74
|
-
});
|
|
75
|
-
server.listen(0, '127.0.0.1', () => {
|
|
76
|
-
const { port } = server.address() as AddressInfo;
|
|
77
|
-
resolve({
|
|
78
|
-
origin: `http://127.0.0.1:${port}`,
|
|
79
|
-
stop: () =>
|
|
80
|
-
new Promise<void>((r) => {
|
|
81
|
-
server.close(() => r());
|
|
82
|
-
}),
|
|
83
|
-
setKeys: (next) => {
|
|
84
|
-
keys = next;
|
|
85
|
-
},
|
|
86
|
-
setUnreachable: (v) => {
|
|
87
|
-
down = v;
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
interface SignOpts {
|
|
95
|
-
iss?: string;
|
|
96
|
-
aud?: string;
|
|
97
|
-
sub?: string;
|
|
98
|
-
scope?: string;
|
|
99
|
-
ttlSeconds?: number;
|
|
100
|
-
expiresAtSeconds?: number;
|
|
101
|
-
kid?: string;
|
|
102
|
-
clientId?: string;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function signJwt(kp: Keypair, opts: SignOpts): Promise<string> {
|
|
106
|
-
const iat = Math.floor(Date.now() / 1000);
|
|
107
|
-
const exp = opts.expiresAtSeconds ?? iat + (opts.ttlSeconds ?? 60);
|
|
108
|
-
return await new SignJWT({
|
|
109
|
-
scope: opts.scope ?? 'agent:read',
|
|
110
|
-
client_id: opts.clientId ?? 'test-client',
|
|
111
|
-
})
|
|
112
|
-
.setProtectedHeader({ alg: 'RS256', kid: opts.kid ?? kp.kid })
|
|
113
|
-
.setIssuer(opts.iss ?? 'http://issuer.invalid')
|
|
114
|
-
.setSubject(opts.sub ?? 'user-1')
|
|
115
|
-
.setAudience(opts.aud ?? 'hub')
|
|
116
|
-
.setIssuedAt(iat)
|
|
117
|
-
.setExpirationTime(exp)
|
|
118
|
-
.setJti('jti-1')
|
|
119
|
-
.sign(kp.privateKey);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
let fixture: JwksFixture;
|
|
123
|
-
let kp: Keypair;
|
|
124
|
-
let prevHubOrigin: string | undefined;
|
|
125
|
-
|
|
126
|
-
beforeAll(async () => {
|
|
127
|
-
fixture = await startJwksFixture();
|
|
128
|
-
kp = await makeKeypair('k1');
|
|
129
|
-
fixture.setKeys([kp]);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
afterAll(async () => {
|
|
133
|
-
await fixture.stop();
|
|
134
|
-
if (prevHubOrigin === undefined) delete process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
135
|
-
else process.env.PARACHUTE_AGENT_HUB_ORIGIN = prevHubOrigin;
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
beforeEach(() => {
|
|
139
|
-
prevHubOrigin = process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
140
|
-
process.env.PARACHUTE_AGENT_HUB_ORIGIN = fixture.origin;
|
|
141
|
-
fixture.setUnreachable(false);
|
|
142
|
-
fixture.setKeys([kp]);
|
|
143
|
-
resetJwksCache();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
afterEach(() => {
|
|
147
|
-
if (prevHubOrigin === undefined) delete process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
148
|
-
else process.env.PARACHUTE_AGENT_HUB_ORIGIN = prevHubOrigin;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('validateHubJwt', () => {
|
|
152
|
-
it('happy path — surfaces sub + scopes + clientId', async () => {
|
|
153
|
-
const token = await signJwt(kp, { iss: fixture.origin, scope: 'agent:read agent:write' });
|
|
154
|
-
const claims = await validateHubJwt(token);
|
|
155
|
-
expect(claims.sub).toBe('user-1');
|
|
156
|
-
expect(claims.scopes).toEqual(['agent:read', 'agent:write']);
|
|
157
|
-
expect(claims.clientId).toBe('test-client');
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('rejects token with wrong issuer', async () => {
|
|
161
|
-
const token = await signJwt(kp, { iss: 'http://attacker.example' });
|
|
162
|
-
await expect(validateHubJwt(token)).rejects.toBeInstanceOf(HubJwtError);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('rejects expired token', async () => {
|
|
166
|
-
const past = Math.floor(Date.now() / 1000) - 10;
|
|
167
|
-
const token = await signJwt(kp, { iss: fixture.origin, expiresAtSeconds: past });
|
|
168
|
-
await expect(validateHubJwt(token)).rejects.toBeInstanceOf(HubJwtError);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('rejects token signed by an unpublished key', async () => {
|
|
172
|
-
const otherKp = await makeKeypair('k1');
|
|
173
|
-
const token = await signJwt(otherKp, { iss: fixture.origin });
|
|
174
|
-
await expect(validateHubJwt(token)).rejects.toBeInstanceOf(HubJwtError);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('rejects when JWKS endpoint is unreachable', async () => {
|
|
178
|
-
fixture.setUnreachable(true);
|
|
179
|
-
const token = await signJwt(kp, { iss: fixture.origin });
|
|
180
|
-
await expect(validateHubJwt(token)).rejects.toBeInstanceOf(HubJwtError);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
describe('getHubOrigin', () => {
|
|
185
|
-
// The hub lifecycle (parachute-hub/src/commands/lifecycle.ts) stamps
|
|
186
|
-
// PARACHUTE_HUB_ORIGIN onto every spawned service so iss-strict JWT
|
|
187
|
-
// validation works behind tailnet proxying. PARACHUTE_AGENT_HUB_ORIGIN
|
|
188
|
-
// is the test/per-service override; legacy PARACLAW_HUB_ORIGIN is read
|
|
189
|
-
// through 0.1.x with a one-shot deprecation warning (drop in 0.2.0).
|
|
190
|
-
// Loopback fallback exists for local-dev when the hub isn't supervising
|
|
191
|
-
// the process.
|
|
192
|
-
let prevAgent: string | undefined;
|
|
193
|
-
let prevParaclaw: string | undefined;
|
|
194
|
-
let prevParachute: string | undefined;
|
|
195
|
-
|
|
196
|
-
beforeEach(() => {
|
|
197
|
-
prevAgent = process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
198
|
-
prevParaclaw = process.env.PARACLAW_HUB_ORIGIN;
|
|
199
|
-
prevParachute = process.env.PARACHUTE_HUB_ORIGIN;
|
|
200
|
-
delete process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
201
|
-
delete process.env.PARACLAW_HUB_ORIGIN;
|
|
202
|
-
delete process.env.PARACHUTE_HUB_ORIGIN;
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
afterEach(() => {
|
|
206
|
-
if (prevAgent === undefined) delete process.env.PARACHUTE_AGENT_HUB_ORIGIN;
|
|
207
|
-
else process.env.PARACHUTE_AGENT_HUB_ORIGIN = prevAgent;
|
|
208
|
-
if (prevParaclaw === undefined) delete process.env.PARACLAW_HUB_ORIGIN;
|
|
209
|
-
else process.env.PARACLAW_HUB_ORIGIN = prevParaclaw;
|
|
210
|
-
if (prevParachute === undefined) delete process.env.PARACHUTE_HUB_ORIGIN;
|
|
211
|
-
else process.env.PARACHUTE_HUB_ORIGIN = prevParachute;
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('reads PARACHUTE_HUB_ORIGIN as primary (set by hub lifecycle)', () => {
|
|
215
|
-
process.env.PARACHUTE_HUB_ORIGIN = 'https://parachute.taildf9ce2.ts.net';
|
|
216
|
-
expect(getHubOrigin()).toBe('https://parachute.taildf9ce2.ts.net');
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('PARACHUTE_AGENT_HUB_ORIGIN overrides PARACHUTE_HUB_ORIGIN', () => {
|
|
220
|
-
process.env.PARACHUTE_HUB_ORIGIN = 'https://parachute.taildf9ce2.ts.net';
|
|
221
|
-
process.env.PARACHUTE_AGENT_HUB_ORIGIN = 'http://localhost:9999';
|
|
222
|
-
expect(getHubOrigin()).toBe('http://localhost:9999');
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('falls back to legacy PARACLAW_HUB_ORIGIN through 0.1.x compat', () => {
|
|
226
|
-
process.env.PARACHUTE_HUB_ORIGIN = 'https://parachute.taildf9ce2.ts.net';
|
|
227
|
-
process.env.PARACLAW_HUB_ORIGIN = 'http://localhost:9998';
|
|
228
|
-
expect(getHubOrigin()).toBe('http://localhost:9998');
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('PARACHUTE_AGENT_HUB_ORIGIN takes precedence over legacy PARACLAW_HUB_ORIGIN', () => {
|
|
232
|
-
process.env.PARACLAW_HUB_ORIGIN = 'http://legacy.example';
|
|
233
|
-
process.env.PARACHUTE_AGENT_HUB_ORIGIN = 'http://current.example';
|
|
234
|
-
expect(getHubOrigin()).toBe('http://current.example');
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it('falls back to loopback when neither env is set', () => {
|
|
238
|
-
expect(getHubOrigin()).toBe('http://127.0.0.1:1939');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('strips trailing slash from either env', () => {
|
|
242
|
-
process.env.PARACHUTE_HUB_ORIGIN = 'https://hub.example/';
|
|
243
|
-
expect(getHubOrigin()).toBe('https://hub.example');
|
|
244
|
-
process.env.PARACHUTE_AGENT_HUB_ORIGIN = 'https://override.example/';
|
|
245
|
-
expect(getHubOrigin()).toBe('https://override.example');
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe('hasScope', () => {
|
|
250
|
-
it('exact match', () => {
|
|
251
|
-
expect(hasScope([SCOPE_AGENT_READ], SCOPE_AGENT_READ)).toBe(true);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('agent:admin ⊇ agent:write ⊇ agent:read', () => {
|
|
255
|
-
expect(hasScope([SCOPE_AGENT_ADMIN], SCOPE_AGENT_READ)).toBe(true);
|
|
256
|
-
expect(hasScope([SCOPE_AGENT_ADMIN], SCOPE_AGENT_WRITE)).toBe(true);
|
|
257
|
-
expect(hasScope([SCOPE_AGENT_WRITE], SCOPE_AGENT_READ)).toBe(true);
|
|
258
|
-
expect(hasScope([SCOPE_AGENT_READ], SCOPE_AGENT_WRITE)).toBe(false);
|
|
259
|
-
expect(hasScope([SCOPE_AGENT_WRITE], SCOPE_AGENT_ADMIN)).toBe(false);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('vault:admin (operator-token catch-all) satisfies every agent scope', () => {
|
|
263
|
-
expect(hasScope([SCOPE_VAULT_ADMIN], SCOPE_AGENT_READ)).toBe(true);
|
|
264
|
-
expect(hasScope([SCOPE_VAULT_ADMIN], SCOPE_AGENT_WRITE)).toBe(true);
|
|
265
|
-
expect(hasScope([SCOPE_VAULT_ADMIN], SCOPE_AGENT_ADMIN)).toBe(true);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('hub:admin does NOT satisfy agent scopes', () => {
|
|
269
|
-
expect(hasScope(['hub:admin'], SCOPE_AGENT_READ)).toBe(false);
|
|
270
|
-
expect(hasScope(['hub:admin'], SCOPE_AGENT_WRITE)).toBe(false);
|
|
271
|
-
expect(hasScope(['hub:admin'], SCOPE_AGENT_ADMIN)).toBe(false);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it('legacy `claw:*` grants are normalized to `agent:*` (pre-0.1.0 compat)', () => {
|
|
275
|
-
expect(hasScope(['claw:read'], SCOPE_AGENT_READ)).toBe(true);
|
|
276
|
-
expect(hasScope(['claw:write'], SCOPE_AGENT_READ)).toBe(true);
|
|
277
|
-
expect(hasScope(['claw:admin'], SCOPE_AGENT_WRITE)).toBe(true);
|
|
278
|
-
expect(hasScope(['claw:admin'], SCOPE_AGENT_ADMIN)).toBe(true);
|
|
279
|
-
expect(hasScope(['claw:read'], SCOPE_AGENT_WRITE)).toBe(false);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('empty scopes never satisfy', () => {
|
|
283
|
-
expect(hasScope([], SCOPE_AGENT_READ)).toBe(false);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
describe('authenticate', () => {
|
|
288
|
-
it('returns ok with claims for a valid Bearer + sufficient scope', async () => {
|
|
289
|
-
const token = await signJwt(kp, { iss: fixture.origin, scope: 'agent:write' });
|
|
290
|
-
const r = await authenticate(`Bearer ${token}`, SCOPE_AGENT_READ);
|
|
291
|
-
expect(r.ok).toBe(true);
|
|
292
|
-
if (r.ok) expect(r.claims.scopes).toContain('agent:write');
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('401 on missing header', async () => {
|
|
296
|
-
const r = await authenticate(undefined, SCOPE_AGENT_READ);
|
|
297
|
-
expect(r.ok).toBe(false);
|
|
298
|
-
if (!r.ok) expect(r.status).toBe(401);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('401 on malformed header (no Bearer prefix)', async () => {
|
|
302
|
-
const token = await signJwt(kp, { iss: fixture.origin });
|
|
303
|
-
const r = await authenticate(token, SCOPE_AGENT_READ);
|
|
304
|
-
expect(r.ok).toBe(false);
|
|
305
|
-
if (!r.ok) expect(r.status).toBe(401);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('401 on invalid token (wrong issuer)', async () => {
|
|
309
|
-
const token = await signJwt(kp, { iss: 'http://attacker.example' });
|
|
310
|
-
const r = await authenticate(`Bearer ${token}`, SCOPE_AGENT_READ);
|
|
311
|
-
expect(r.ok).toBe(false);
|
|
312
|
-
if (!r.ok) expect(r.status).toBe(401);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it('403 on insufficient scope — surfaces error_type + required + granted', async () => {
|
|
316
|
-
const token = await signJwt(kp, { iss: fixture.origin, scope: 'agent:read' });
|
|
317
|
-
const r = await authenticate(`Bearer ${token}`, SCOPE_AGENT_WRITE);
|
|
318
|
-
expect(r.ok).toBe(false);
|
|
319
|
-
if (!r.ok) {
|
|
320
|
-
expect(r.status).toBe(403);
|
|
321
|
-
expect(r.errorType).toBe('insufficient_scope');
|
|
322
|
-
expect(r.requiredScope).toBe(SCOPE_AGENT_WRITE);
|
|
323
|
-
expect(r.grantedScopes).toEqual(['agent:read']);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it('operator-token shape (vault:admin scope) passes any agent gate', async () => {
|
|
328
|
-
const token = await signJwt(kp, {
|
|
329
|
-
iss: fixture.origin,
|
|
330
|
-
scope: 'hub:admin vault:admin scribe:admin channel:send',
|
|
331
|
-
});
|
|
332
|
-
const r = await authenticate(`Bearer ${token}`, SCOPE_AGENT_ADMIN);
|
|
333
|
-
expect(r.ok).toBe(true);
|
|
334
|
-
});
|
|
335
|
-
});
|