@useconductor/conductor 1.0.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/.claude-plugin/marketplace.json +33 -0
- package/.claude-plugin/plugin.json +23 -0
- package/.eslintrc.json +23 -0
- package/.gitattributes +6 -0
- package/.github/FUNDING.yml +15 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +91 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +63 -0
- package/.github/ISSUE_TEMPLATE/plugin_request.yml +71 -0
- package/.github/README.md +13 -0
- package/.github/workflows/README.md +22 -0
- package/.github/workflows/auto-release.yml +112 -0
- package/.github/workflows/ci.yml +49 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +36 -0
- package/.github/workflows/sync-install.yml +47 -0
- package/.mcp.json +9 -0
- package/.prettierrc.json +7 -0
- package/C.png +0 -0
- package/CHANGELOG.md +74 -0
- package/CLAUDE.md +118 -0
- package/CONTRIBUTING.md +231 -0
- package/LICENSE +201 -0
- package/README.md +179 -0
- package/SECURITY.md +47 -0
- package/commands/conductor-setup.md +11 -0
- package/commands/conductor-status.md +7 -0
- package/dist/ai/base.d.ts +44 -0
- package/dist/ai/base.d.ts.map +1 -0
- package/dist/ai/base.js +47 -0
- package/dist/ai/base.js.map +1 -0
- package/dist/ai/claude.d.ts +11 -0
- package/dist/ai/claude.d.ts.map +1 -0
- package/dist/ai/claude.js +149 -0
- package/dist/ai/claude.js.map +1 -0
- package/dist/ai/gemini.d.ts +15 -0
- package/dist/ai/gemini.d.ts.map +1 -0
- package/dist/ai/gemini.js +156 -0
- package/dist/ai/gemini.js.map +1 -0
- package/dist/ai/maestro.d.ts +22 -0
- package/dist/ai/maestro.d.ts.map +1 -0
- package/dist/ai/maestro.js +142 -0
- package/dist/ai/maestro.js.map +1 -0
- package/dist/ai/manager.d.ts +47 -0
- package/dist/ai/manager.d.ts.map +1 -0
- package/dist/ai/manager.js +450 -0
- package/dist/ai/manager.js.map +1 -0
- package/dist/ai/ollama.d.ts +16 -0
- package/dist/ai/ollama.d.ts.map +1 -0
- package/dist/ai/ollama.js +151 -0
- package/dist/ai/ollama.js.map +1 -0
- package/dist/ai/openai.d.ts +11 -0
- package/dist/ai/openai.d.ts.map +1 -0
- package/dist/ai/openai.js +132 -0
- package/dist/ai/openai.js.map +1 -0
- package/dist/ai/openrouter.d.ts +11 -0
- package/dist/ai/openrouter.d.ts.map +1 -0
- package/dist/ai/openrouter.js +139 -0
- package/dist/ai/openrouter.js.map +1 -0
- package/dist/bot/slack.d.ts +17 -0
- package/dist/bot/slack.d.ts.map +1 -0
- package/dist/bot/slack.js +144 -0
- package/dist/bot/slack.js.map +1 -0
- package/dist/bot/telegram.d.ts +19 -0
- package/dist/bot/telegram.d.ts.map +1 -0
- package/dist/bot/telegram.js +157 -0
- package/dist/bot/telegram.js.map +1 -0
- package/dist/cli/commands/ai.d.ts +4 -0
- package/dist/cli/commands/ai.d.ts.map +1 -0
- package/dist/cli/commands/ai.js +161 -0
- package/dist/cli/commands/ai.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +18 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +213 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.d.ts +15 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +281 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install.d.ts +16 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +750 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/lifecycle.d.ts +4 -0
- package/dist/cli/commands/lifecycle.d.ts.map +1 -0
- package/dist/cli/commands/lifecycle.js +84 -0
- package/dist/cli/commands/lifecycle.js.map +1 -0
- package/dist/cli/commands/marketplace.d.ts +13 -0
- package/dist/cli/commands/marketplace.d.ts.map +1 -0
- package/dist/cli/commands/marketplace.js +197 -0
- package/dist/cli/commands/marketplace.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +6 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +83 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/onboard.d.ts +10 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -0
- package/dist/cli/commands/onboard.js +207 -0
- package/dist/cli/commands/onboard.js.map +1 -0
- package/dist/cli/commands/plugin-create.d.ts +13 -0
- package/dist/cli/commands/plugin-create.d.ts.map +1 -0
- package/dist/cli/commands/plugin-create.js +122 -0
- package/dist/cli/commands/plugin-create.js.map +1 -0
- package/dist/cli/commands/plugins.d.ts +5 -0
- package/dist/cli/commands/plugins.d.ts.map +1 -0
- package/dist/cli/commands/plugins.js +30 -0
- package/dist/cli/commands/plugins.js.map +1 -0
- package/dist/cli/commands/release.d.ts +13 -0
- package/dist/cli/commands/release.d.ts.map +1 -0
- package/dist/cli/commands/release.js +243 -0
- package/dist/cli/commands/release.js.map +1 -0
- package/dist/cli/commands/telegram.d.ts +3 -0
- package/dist/cli/commands/telegram.d.ts.map +1 -0
- package/dist/cli/commands/telegram.js +20 -0
- package/dist/cli/commands/telegram.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +402 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/oauth.d.ts +8 -0
- package/dist/config/oauth.d.ts.map +1 -0
- package/dist/config/oauth.js +13 -0
- package/dist/config/oauth.js.map +1 -0
- package/dist/core/audit.d.ts +91 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +233 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/circuit-breaker.d.ts +56 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -0
- package/dist/core/circuit-breaker.js +107 -0
- package/dist/core/circuit-breaker.js.map +1 -0
- package/dist/core/conductor.d.ts +44 -0
- package/dist/core/conductor.d.ts.map +1 -0
- package/dist/core/conductor.js +200 -0
- package/dist/core/conductor.js.map +1 -0
- package/dist/core/config.d.ts +66 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +86 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/database.d.ts +59 -0
- package/dist/core/database.d.ts.map +1 -0
- package/dist/core/database.js +342 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/errors.d.ts +231 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +254 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/health.d.ts +72 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +116 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/interfaces.d.ts +62 -0
- package/dist/core/interfaces.d.ts.map +1 -0
- package/dist/core/interfaces.js +8 -0
- package/dist/core/interfaces.js.map +1 -0
- package/dist/core/logger.d.ts +15 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +30 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/rbac.d.ts +132 -0
- package/dist/core/rbac.d.ts.map +1 -0
- package/dist/core/rbac.js +230 -0
- package/dist/core/rbac.js.map +1 -0
- package/dist/core/retry.d.ts +22 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +41 -0
- package/dist/core/retry.js.map +1 -0
- package/dist/core/webhooks.d.ts +92 -0
- package/dist/core/webhooks.d.ts.map +1 -0
- package/dist/core/webhooks.js +176 -0
- package/dist/core/webhooks.js.map +1 -0
- package/dist/core/zero-config.d.ts +22 -0
- package/dist/core/zero-config.d.ts.map +1 -0
- package/dist/core/zero-config.js +59 -0
- package/dist/core/zero-config.js.map +1 -0
- package/dist/dashboard/cli.d.ts +6 -0
- package/dist/dashboard/cli.d.ts.map +1 -0
- package/dist/dashboard/cli.js +42 -0
- package/dist/dashboard/cli.js.map +1 -0
- package/dist/dashboard/index.html +3426 -0
- package/dist/dashboard/server.d.ts +7 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +1427 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/mcp/server.d.ts +27 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +380 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/misc.d.ts +15 -0
- package/dist/mcp/tools/misc.d.ts.map +1 -0
- package/dist/mcp/tools/misc.js +49 -0
- package/dist/mcp/tools/misc.js.map +1 -0
- package/dist/plugins/builtin/calculator.d.ts +11 -0
- package/dist/plugins/builtin/calculator.d.ts.map +1 -0
- package/dist/plugins/builtin/calculator.js +166 -0
- package/dist/plugins/builtin/calculator.js.map +1 -0
- package/dist/plugins/builtin/colors.d.ts +15 -0
- package/dist/plugins/builtin/colors.d.ts.map +1 -0
- package/dist/plugins/builtin/colors.js +193 -0
- package/dist/plugins/builtin/colors.js.map +1 -0
- package/dist/plugins/builtin/cron.d.ts +40 -0
- package/dist/plugins/builtin/cron.d.ts.map +1 -0
- package/dist/plugins/builtin/cron.js +578 -0
- package/dist/plugins/builtin/cron.js.map +1 -0
- package/dist/plugins/builtin/crypto.d.ts +11 -0
- package/dist/plugins/builtin/crypto.d.ts.map +1 -0
- package/dist/plugins/builtin/crypto.js +83 -0
- package/dist/plugins/builtin/crypto.js.map +1 -0
- package/dist/plugins/builtin/database.d.ts +29 -0
- package/dist/plugins/builtin/database.d.ts.map +1 -0
- package/dist/plugins/builtin/database.js +230 -0
- package/dist/plugins/builtin/database.js.map +1 -0
- package/dist/plugins/builtin/docker.d.ts +12 -0
- package/dist/plugins/builtin/docker.d.ts.map +1 -0
- package/dist/plugins/builtin/docker.js +436 -0
- package/dist/plugins/builtin/docker.js.map +1 -0
- package/dist/plugins/builtin/fun.d.ts +11 -0
- package/dist/plugins/builtin/fun.d.ts.map +1 -0
- package/dist/plugins/builtin/fun.js +114 -0
- package/dist/plugins/builtin/fun.js.map +1 -0
- package/dist/plugins/builtin/gcal.d.ts +38 -0
- package/dist/plugins/builtin/gcal.d.ts.map +1 -0
- package/dist/plugins/builtin/gcal.js +280 -0
- package/dist/plugins/builtin/gcal.js.map +1 -0
- package/dist/plugins/builtin/gdrive.d.ts +26 -0
- package/dist/plugins/builtin/gdrive.d.ts.map +1 -0
- package/dist/plugins/builtin/gdrive.js +295 -0
- package/dist/plugins/builtin/gdrive.js.map +1 -0
- package/dist/plugins/builtin/github-actions.d.ts +38 -0
- package/dist/plugins/builtin/github-actions.d.ts.map +1 -0
- package/dist/plugins/builtin/github-actions.js +629 -0
- package/dist/plugins/builtin/github-actions.js.map +1 -0
- package/dist/plugins/builtin/github.d.ts +26 -0
- package/dist/plugins/builtin/github.d.ts.map +1 -0
- package/dist/plugins/builtin/github.js +800 -0
- package/dist/plugins/builtin/github.js.map +1 -0
- package/dist/plugins/builtin/gmail.d.ts +50 -0
- package/dist/plugins/builtin/gmail.d.ts.map +1 -0
- package/dist/plugins/builtin/gmail.js +445 -0
- package/dist/plugins/builtin/gmail.js.map +1 -0
- package/dist/plugins/builtin/hash.d.ts +11 -0
- package/dist/plugins/builtin/hash.d.ts.map +1 -0
- package/dist/plugins/builtin/hash.js +95 -0
- package/dist/plugins/builtin/hash.js.map +1 -0
- package/dist/plugins/builtin/homekit.d.ts +53 -0
- package/dist/plugins/builtin/homekit.d.ts.map +1 -0
- package/dist/plugins/builtin/homekit.js +341 -0
- package/dist/plugins/builtin/homekit.js.map +1 -0
- package/dist/plugins/builtin/index.d.ts +4 -0
- package/dist/plugins/builtin/index.d.ts.map +1 -0
- package/dist/plugins/builtin/index.js +96 -0
- package/dist/plugins/builtin/index.js.map +1 -0
- package/dist/plugins/builtin/jira.d.ts +50 -0
- package/dist/plugins/builtin/jira.d.ts.map +1 -0
- package/dist/plugins/builtin/jira.js +353 -0
- package/dist/plugins/builtin/jira.js.map +1 -0
- package/dist/plugins/builtin/linear.d.ts +35 -0
- package/dist/plugins/builtin/linear.d.ts.map +1 -0
- package/dist/plugins/builtin/linear.js +397 -0
- package/dist/plugins/builtin/linear.js.map +1 -0
- package/dist/plugins/builtin/lumen.d.ts +21 -0
- package/dist/plugins/builtin/lumen.d.ts.map +1 -0
- package/dist/plugins/builtin/lumen.js +404 -0
- package/dist/plugins/builtin/lumen.js.map +1 -0
- package/dist/plugins/builtin/memory.d.ts +22 -0
- package/dist/plugins/builtin/memory.d.ts.map +1 -0
- package/dist/plugins/builtin/memory.js +184 -0
- package/dist/plugins/builtin/memory.js.map +1 -0
- package/dist/plugins/builtin/n8n.d.ts +60 -0
- package/dist/plugins/builtin/n8n.d.ts.map +1 -0
- package/dist/plugins/builtin/n8n.js +519 -0
- package/dist/plugins/builtin/n8n.js.map +1 -0
- package/dist/plugins/builtin/network.d.ts +11 -0
- package/dist/plugins/builtin/network.d.ts.map +1 -0
- package/dist/plugins/builtin/network.js +88 -0
- package/dist/plugins/builtin/network.js.map +1 -0
- package/dist/plugins/builtin/notes.d.ts +47 -0
- package/dist/plugins/builtin/notes.d.ts.map +1 -0
- package/dist/plugins/builtin/notes.js +641 -0
- package/dist/plugins/builtin/notes.js.map +1 -0
- package/dist/plugins/builtin/notion.d.ts +47 -0
- package/dist/plugins/builtin/notion.d.ts.map +1 -0
- package/dist/plugins/builtin/notion.js +317 -0
- package/dist/plugins/builtin/notion.js.map +1 -0
- package/dist/plugins/builtin/shell.d.ts +12 -0
- package/dist/plugins/builtin/shell.d.ts.map +1 -0
- package/dist/plugins/builtin/shell.js +310 -0
- package/dist/plugins/builtin/shell.js.map +1 -0
- package/dist/plugins/builtin/slack.d.ts +31 -0
- package/dist/plugins/builtin/slack.d.ts.map +1 -0
- package/dist/plugins/builtin/slack.js +295 -0
- package/dist/plugins/builtin/slack.js.map +1 -0
- package/dist/plugins/builtin/spotify.d.ts +55 -0
- package/dist/plugins/builtin/spotify.d.ts.map +1 -0
- package/dist/plugins/builtin/spotify.js +623 -0
- package/dist/plugins/builtin/spotify.js.map +1 -0
- package/dist/plugins/builtin/stripe.d.ts +35 -0
- package/dist/plugins/builtin/stripe.d.ts.map +1 -0
- package/dist/plugins/builtin/stripe.js +376 -0
- package/dist/plugins/builtin/stripe.js.map +1 -0
- package/dist/plugins/builtin/system.d.ts +11 -0
- package/dist/plugins/builtin/system.d.ts.map +1 -0
- package/dist/plugins/builtin/system.js +91 -0
- package/dist/plugins/builtin/system.js.map +1 -0
- package/dist/plugins/builtin/text-tools.d.ts +11 -0
- package/dist/plugins/builtin/text-tools.d.ts.map +1 -0
- package/dist/plugins/builtin/text-tools.js +146 -0
- package/dist/plugins/builtin/text-tools.js.map +1 -0
- package/dist/plugins/builtin/timezone.d.ts +13 -0
- package/dist/plugins/builtin/timezone.d.ts.map +1 -0
- package/dist/plugins/builtin/timezone.js +164 -0
- package/dist/plugins/builtin/timezone.js.map +1 -0
- package/dist/plugins/builtin/todoist.d.ts +49 -0
- package/dist/plugins/builtin/todoist.d.ts.map +1 -0
- package/dist/plugins/builtin/todoist.js +540 -0
- package/dist/plugins/builtin/todoist.js.map +1 -0
- package/dist/plugins/builtin/translate.d.ts +11 -0
- package/dist/plugins/builtin/translate.d.ts.map +1 -0
- package/dist/plugins/builtin/translate.js +42 -0
- package/dist/plugins/builtin/translate.js.map +1 -0
- package/dist/plugins/builtin/url-tools.d.ts +11 -0
- package/dist/plugins/builtin/url-tools.d.ts.map +1 -0
- package/dist/plugins/builtin/url-tools.js +70 -0
- package/dist/plugins/builtin/url-tools.js.map +1 -0
- package/dist/plugins/builtin/vercel.d.ts +55 -0
- package/dist/plugins/builtin/vercel.d.ts.map +1 -0
- package/dist/plugins/builtin/vercel.js +514 -0
- package/dist/plugins/builtin/vercel.js.map +1 -0
- package/dist/plugins/builtin/weather.d.ts +13 -0
- package/dist/plugins/builtin/weather.d.ts.map +1 -0
- package/dist/plugins/builtin/weather.js +103 -0
- package/dist/plugins/builtin/weather.js.map +1 -0
- package/dist/plugins/builtin/x.d.ts +54 -0
- package/dist/plugins/builtin/x.d.ts.map +1 -0
- package/dist/plugins/builtin/x.js +402 -0
- package/dist/plugins/builtin/x.js.map +1 -0
- package/dist/plugins/manager.d.ts +77 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +141 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/validation.d.ts +18 -0
- package/dist/plugins/validation.d.ts.map +1 -0
- package/dist/plugins/validation.js +81 -0
- package/dist/plugins/validation.js.map +1 -0
- package/dist/security/auth.d.ts +23 -0
- package/dist/security/auth.d.ts.map +1 -0
- package/dist/security/auth.js +56 -0
- package/dist/security/auth.js.map +1 -0
- package/dist/security/keychain.d.ts +60 -0
- package/dist/security/keychain.d.ts.map +1 -0
- package/dist/security/keychain.js +213 -0
- package/dist/security/keychain.js.map +1 -0
- package/dist/utils/google-auth.d.ts +21 -0
- package/dist/utils/google-auth.d.ts.map +1 -0
- package/dist/utils/google-auth.js +135 -0
- package/dist/utils/google-auth.js.map +1 -0
- package/dist/utils/retry.d.ts +5 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +34 -0
- package/dist/utils/retry.js.map +1 -0
- package/docs/README.md +13 -0
- package/docs/api.md +210 -0
- package/docs/getting-started.md +100 -0
- package/docs/plugins.md +306 -0
- package/docs-site/.vitepress/config.ts +59 -0
- package/docs-site/README.md +12 -0
- package/docs-site/index.md +30 -0
- package/eslint.config.js +29 -0
- package/install.ps1 +334 -0
- package/install.sh +1119 -0
- package/local-install.sh +304 -0
- package/package.json +90 -0
- package/packages/README.md +11 -0
- package/packages/plugin-sdk/README.md +12 -0
- package/packages/plugin-sdk/package.json +22 -0
- package/packages/plugin-sdk/src/README.md +11 -0
- package/packages/plugin-sdk/src/index.ts +191 -0
- package/sdks/README.md +26 -0
- package/sdks/csharp/ConductorClient.cs +65 -0
- package/sdks/csharp/README.md +11 -0
- package/sdks/go/README.md +11 -0
- package/sdks/go/conductor.go +257 -0
- package/sdks/java/ConductorClient.java +27 -0
- package/sdks/java/README.md +11 -0
- package/sdks/php/README.md +11 -0
- package/sdks/php/src/Client.php +72 -0
- package/sdks/python/README.md +12 -0
- package/sdks/python/conductor/__init__.py +227 -0
- package/sdks/python/pyproject.toml +30 -0
- package/sdks/ruby/README.md +11 -0
- package/sdks/ruby/lib/conductor.rb +46 -0
- package/sdks/rust/Cargo.toml +14 -0
- package/sdks/rust/README.md +11 -0
- package/sdks/swift/README.md +11 -0
- package/sdks/swift/Sources/Conductor/ConductorClient.swift +65 -0
- package/skills/conductor-mcp/SKILL.md +38 -0
- package/src/README.md +20 -0
- package/src/ai/README.md +18 -0
- package/src/ai/base.ts +93 -0
- package/src/ai/claude.ts +162 -0
- package/src/ai/gemini.ts +188 -0
- package/src/ai/maestro.ts +168 -0
- package/src/ai/manager.ts +537 -0
- package/src/ai/ollama.ts +186 -0
- package/src/ai/openai.ts +147 -0
- package/src/ai/openrouter.ts +152 -0
- package/src/bot/README.md +12 -0
- package/src/bot/slack.ts +164 -0
- package/src/bot/telegram.ts +185 -0
- package/src/cli/README.md +24 -0
- package/src/cli/commands/README.md +20 -0
- package/src/cli/commands/ai.ts +170 -0
- package/src/cli/commands/doctor.ts +221 -0
- package/src/cli/commands/init.ts +348 -0
- package/src/cli/commands/install.ts +792 -0
- package/src/cli/commands/lifecycle.ts +95 -0
- package/src/cli/commands/marketplace.ts +253 -0
- package/src/cli/commands/mcp.ts +92 -0
- package/src/cli/commands/onboard.ts +248 -0
- package/src/cli/commands/plugin-create.ts +130 -0
- package/src/cli/commands/plugins.ts +36 -0
- package/src/cli/commands/release.ts +251 -0
- package/src/cli/commands/telegram.ts +25 -0
- package/src/cli/index.ts +450 -0
- package/src/config/README.md +11 -0
- package/src/config/oauth.ts +26 -0
- package/src/core/README.md +22 -0
- package/src/core/audit.ts +291 -0
- package/src/core/circuit-breaker.ts +129 -0
- package/src/core/conductor.ts +240 -0
- package/src/core/config.ts +149 -0
- package/src/core/database.ts +411 -0
- package/src/core/errors.ts +275 -0
- package/src/core/health.ts +159 -0
- package/src/core/interfaces.ts +75 -0
- package/src/core/logger.ts +33 -0
- package/src/core/rbac.ts +321 -0
- package/src/core/retry.ts +61 -0
- package/src/core/webhooks.ts +234 -0
- package/src/core/zero-config.ts +72 -0
- package/src/dashboard/README.md +15 -0
- package/src/dashboard/cli.ts +48 -0
- package/src/dashboard/index.html +3426 -0
- package/src/dashboard/server.ts +1544 -0
- package/src/mcp/README.md +20 -0
- package/src/mcp/server.ts +475 -0
- package/src/mcp/tools/README.md +11 -0
- package/src/mcp/tools/misc.ts +61 -0
- package/src/plugins/README.md +28 -0
- package/src/plugins/builtin/README.md +23 -0
- package/src/plugins/builtin/calculator.ts +178 -0
- package/src/plugins/builtin/colors.ts +201 -0
- package/src/plugins/builtin/cron.ts +649 -0
- package/src/plugins/builtin/crypto.ts +85 -0
- package/src/plugins/builtin/database.ts +235 -0
- package/src/plugins/builtin/docker.ts +426 -0
- package/src/plugins/builtin/fun.ts +118 -0
- package/src/plugins/builtin/gcal.ts +305 -0
- package/src/plugins/builtin/gdrive.ts +326 -0
- package/src/plugins/builtin/github-actions.ts +666 -0
- package/src/plugins/builtin/github.ts +912 -0
- package/src/plugins/builtin/gmail.ts +492 -0
- package/src/plugins/builtin/hash.ts +98 -0
- package/src/plugins/builtin/homekit.ts +389 -0
- package/src/plugins/builtin/index.ts +116 -0
- package/src/plugins/builtin/jira.ts +380 -0
- package/src/plugins/builtin/linear.ts +448 -0
- package/src/plugins/builtin/lumen.ts +497 -0
- package/src/plugins/builtin/memory.ts +200 -0
- package/src/plugins/builtin/n8n.ts +565 -0
- package/src/plugins/builtin/network.ts +92 -0
- package/src/plugins/builtin/notes.ts +689 -0
- package/src/plugins/builtin/notion.ts +348 -0
- package/src/plugins/builtin/shell.ts +334 -0
- package/src/plugins/builtin/slack.ts +327 -0
- package/src/plugins/builtin/spotify.ts +665 -0
- package/src/plugins/builtin/stripe.ts +388 -0
- package/src/plugins/builtin/system.ts +93 -0
- package/src/plugins/builtin/text-tools.ts +150 -0
- package/src/plugins/builtin/timezone.ts +173 -0
- package/src/plugins/builtin/todoist.ts +625 -0
- package/src/plugins/builtin/translate.ts +47 -0
- package/src/plugins/builtin/url-tools.ts +73 -0
- package/src/plugins/builtin/vercel.ts +546 -0
- package/src/plugins/builtin/weather.ts +112 -0
- package/src/plugins/builtin/x.ts +440 -0
- package/src/plugins/manager.ts +213 -0
- package/src/plugins/validation.ts +94 -0
- package/src/security/README.md +12 -0
- package/src/security/auth.ts +72 -0
- package/src/security/keychain.ts +226 -0
- package/src/utils/README.md +12 -0
- package/src/utils/google-auth.ts +159 -0
- package/src/utils/retry.ts +41 -0
- package/test-all.mjs +1256 -0
- package/test.mjs +633 -0
- package/tests/README.md +19 -0
- package/tests/calculator.test.ts +54 -0
- package/tests/docker.test.ts +42 -0
- package/tests/load.test.ts +129 -0
- package/tests/mcp.test.ts +14 -0
- package/tests/shell.test.ts +42 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +14 -0
package/src/core/rbac.ts
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC — Role-Based Access Control foundation for multi-user Conductor.
|
|
3
|
+
*
|
|
4
|
+
* Provides role definitions, permission checks, user management, and
|
|
5
|
+
* persistence. Designed to be plugged into the MCP server's tool routing
|
|
6
|
+
* so every tool call is authorized before execution.
|
|
7
|
+
*
|
|
8
|
+
* Default roles:
|
|
9
|
+
* admin — full access to all resources and actions
|
|
10
|
+
* editor — create / read / update / execute (no delete)
|
|
11
|
+
* viewer — read-only
|
|
12
|
+
* service_account — execute only (for automated tool calls)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ── Role ──────────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
export enum Role {
|
|
18
|
+
ADMIN = 'admin',
|
|
19
|
+
EDITOR = 'editor',
|
|
20
|
+
VIEWER = 'viewer',
|
|
21
|
+
SERVICE_ACCOUNT = 'service_account',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ── Action ────────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export enum Action {
|
|
27
|
+
CREATE = 'create',
|
|
28
|
+
READ = 'read',
|
|
29
|
+
UPDATE = 'update',
|
|
30
|
+
DELETE = 'delete',
|
|
31
|
+
EXECUTE = 'execute',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Permission ────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
export interface Permission {
|
|
37
|
+
resource: string;
|
|
38
|
+
action: Action;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── RolePermissions ───────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Maps each role to the set of (resource, action) pairs it is allowed to perform.
|
|
45
|
+
*
|
|
46
|
+
* The special resource '*' is a wildcard meaning "all resources".
|
|
47
|
+
*/
|
|
48
|
+
export type RolePermissions = Map<Role, Permission[]>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default permission assignments for built-in roles.
|
|
52
|
+
*/
|
|
53
|
+
export function defaultRolePermissions(): RolePermissions {
|
|
54
|
+
const perms = new Map<Role, Permission[]>();
|
|
55
|
+
|
|
56
|
+
perms.set(Role.ADMIN, [
|
|
57
|
+
{ resource: '*', action: Action.CREATE },
|
|
58
|
+
{ resource: '*', action: Action.READ },
|
|
59
|
+
{ resource: '*', action: Action.UPDATE },
|
|
60
|
+
{ resource: '*', action: Action.DELETE },
|
|
61
|
+
{ resource: '*', action: Action.EXECUTE },
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
perms.set(Role.EDITOR, [
|
|
65
|
+
{ resource: '*', action: Action.CREATE },
|
|
66
|
+
{ resource: '*', action: Action.READ },
|
|
67
|
+
{ resource: '*', action: Action.UPDATE },
|
|
68
|
+
{ resource: '*', action: Action.EXECUTE },
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
perms.set(Role.VIEWER, [{ resource: '*', action: Action.READ }]);
|
|
72
|
+
|
|
73
|
+
perms.set(Role.SERVICE_ACCOUNT, [
|
|
74
|
+
{ resource: '*', action: Action.EXECUTE },
|
|
75
|
+
{ resource: '*', action: Action.READ },
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
return perms;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── User ──────────────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
export interface User {
|
|
84
|
+
id: string;
|
|
85
|
+
email: string;
|
|
86
|
+
role: Role;
|
|
87
|
+
createdAt: Date;
|
|
88
|
+
lastLoginAt: Date | null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Audit log entry ───────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
export interface RBACAuditEntry {
|
|
94
|
+
timestamp: Date;
|
|
95
|
+
userId: string;
|
|
96
|
+
resource: string;
|
|
97
|
+
action: string;
|
|
98
|
+
granted: boolean;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Serialised shape ──────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
interface SerialisedUser {
|
|
104
|
+
id: string;
|
|
105
|
+
email: string;
|
|
106
|
+
role: Role;
|
|
107
|
+
createdAt: string;
|
|
108
|
+
lastLoginAt: string | null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface SerialisedState {
|
|
112
|
+
users: SerialisedUser[];
|
|
113
|
+
permissions: Record<string, { resource: string; action: Action }[]>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── RBACManager ───────────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
export class RBACManager {
|
|
119
|
+
private users: Map<string, User> = new Map();
|
|
120
|
+
private permissions: RolePermissions;
|
|
121
|
+
private auditLog: RBACAuditEntry[] = [];
|
|
122
|
+
|
|
123
|
+
constructor(permissions?: RolePermissions) {
|
|
124
|
+
this.permissions = permissions ?? defaultRolePermissions();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── User CRUD ────────────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Add a user. Throws if the user id already exists.
|
|
131
|
+
*/
|
|
132
|
+
addUser(user: User): void {
|
|
133
|
+
if (this.users.has(user.id)) {
|
|
134
|
+
throw new Error(`User already exists: ${user.id}`);
|
|
135
|
+
}
|
|
136
|
+
this.users.set(user.id, { ...user });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Remove a user by id. Returns true if the user existed and was removed.
|
|
141
|
+
*/
|
|
142
|
+
removeUser(userId: string): boolean {
|
|
143
|
+
return this.users.delete(userId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Retrieve a user by id, or undefined if not found.
|
|
148
|
+
*/
|
|
149
|
+
getUser(userId: string): User | undefined {
|
|
150
|
+
return this.users.get(userId);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Return a snapshot of all users.
|
|
155
|
+
*/
|
|
156
|
+
listUsers(): User[] {
|
|
157
|
+
return Array.from(this.users.values());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── Role management ──────────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Assign a new role to an existing user. Returns false if the user doesn't exist.
|
|
164
|
+
*/
|
|
165
|
+
assignRole(userId: string, role: Role): boolean {
|
|
166
|
+
const user = this.users.get(userId);
|
|
167
|
+
if (!user) return false;
|
|
168
|
+
user.role = role;
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Record a login timestamp for a user. Returns false if the user doesn't exist.
|
|
174
|
+
*/
|
|
175
|
+
recordLogin(userId: string): boolean {
|
|
176
|
+
const user = this.users.get(userId);
|
|
177
|
+
if (!user) return false;
|
|
178
|
+
user.lastLoginAt = new Date();
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ── Permission checks ────────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Check whether a user has permission to perform `action` on `resource`.
|
|
186
|
+
*
|
|
187
|
+
* The check consults the user's role against the RolePermissions map.
|
|
188
|
+
* Wildcard resource '*' in the permission set grants access to all resources.
|
|
189
|
+
*
|
|
190
|
+
* Every check (granted or denied) is appended to the in-memory audit log.
|
|
191
|
+
*/
|
|
192
|
+
checkPermission(userId: string, resource: string, action: string): boolean {
|
|
193
|
+
const user = this.users.get(userId);
|
|
194
|
+
if (!user) {
|
|
195
|
+
this.audit({ userId, resource, action, granted: false });
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const rolePerms = this.permissions.get(user.role);
|
|
200
|
+
if (!rolePerms || rolePerms.length === 0) {
|
|
201
|
+
this.audit({ userId, resource, action, granted: false });
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const granted = rolePerms.some((p) => (p.resource === '*' || p.resource === resource) && p.action === action);
|
|
206
|
+
|
|
207
|
+
this.audit({ userId, resource, action, granted });
|
|
208
|
+
return granted;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Check multiple permissions at once. Returns true only if ALL are granted.
|
|
213
|
+
*/
|
|
214
|
+
checkPermissions(userId: string, checks: { resource: string; action: string }[]): boolean {
|
|
215
|
+
return checks.every((c) => this.checkPermission(userId, c.resource, c.action));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── Custom permissions ───────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Add a custom permission entry for a specific role.
|
|
222
|
+
*/
|
|
223
|
+
addPermission(role: Role, permission: Permission): void {
|
|
224
|
+
const existing = this.permissions.get(role) ?? [];
|
|
225
|
+
// Avoid duplicates
|
|
226
|
+
if (!existing.some((p) => p.resource === permission.resource && p.action === permission.action)) {
|
|
227
|
+
existing.push(permission);
|
|
228
|
+
this.permissions.set(role, existing);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Remove a permission entry from a role.
|
|
234
|
+
*/
|
|
235
|
+
removePermission(role: Role, resource: string, action: Action): void {
|
|
236
|
+
const existing = this.permissions.get(role);
|
|
237
|
+
if (!existing) return;
|
|
238
|
+
const filtered = existing.filter((p) => !(p.resource === resource && p.action === action));
|
|
239
|
+
this.permissions.set(role, filtered);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get all permissions for a role.
|
|
244
|
+
*/
|
|
245
|
+
getRolePermissions(role: Role): Permission[] {
|
|
246
|
+
return [...(this.permissions.get(role) ?? [])];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ── Audit log ────────────────────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Return the in-memory audit log.
|
|
253
|
+
*/
|
|
254
|
+
getAuditLog(): RBACAuditEntry[] {
|
|
255
|
+
return [...this.auditLog];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Clear the audit log (useful for tests or after flushing to persistent storage).
|
|
260
|
+
*/
|
|
261
|
+
clearAuditLog(): void {
|
|
262
|
+
this.auditLog = [];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private audit(entry: Omit<RBACAuditEntry, 'timestamp'>): void {
|
|
266
|
+
this.auditLog.push({ ...entry, timestamp: new Date() });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ── Persistence ──────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Serialise the entire RBAC state (users + custom permissions) to a JSON string.
|
|
273
|
+
* The audit log is intentionally excluded — it should be flushed separately.
|
|
274
|
+
*/
|
|
275
|
+
serialize(): string {
|
|
276
|
+
const state: SerialisedState = {
|
|
277
|
+
users: Array.from(this.users.values()).map((u) => ({
|
|
278
|
+
id: u.id,
|
|
279
|
+
email: u.email,
|
|
280
|
+
role: u.role,
|
|
281
|
+
createdAt: u.createdAt.toISOString(),
|
|
282
|
+
lastLoginAt: u.lastLoginAt?.toISOString() ?? null,
|
|
283
|
+
})),
|
|
284
|
+
permissions: Object.fromEntries(
|
|
285
|
+
Array.from(this.permissions.entries()).map(([role, perms]) => [
|
|
286
|
+
role,
|
|
287
|
+
perms.map((p) => ({ resource: p.resource, action: p.action })),
|
|
288
|
+
]),
|
|
289
|
+
),
|
|
290
|
+
};
|
|
291
|
+
return JSON.stringify(state);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Restore RBAC state from a previously serialised JSON string.
|
|
296
|
+
* Replaces all existing users and permissions.
|
|
297
|
+
*/
|
|
298
|
+
deserialize(data: string): void {
|
|
299
|
+
const state: SerialisedState = JSON.parse(data);
|
|
300
|
+
|
|
301
|
+
this.users = new Map(
|
|
302
|
+
state.users.map((u) => [
|
|
303
|
+
u.id,
|
|
304
|
+
{
|
|
305
|
+
id: u.id,
|
|
306
|
+
email: u.email,
|
|
307
|
+
role: u.role,
|
|
308
|
+
createdAt: new Date(u.createdAt),
|
|
309
|
+
lastLoginAt: u.lastLoginAt ? new Date(u.lastLoginAt) : null,
|
|
310
|
+
},
|
|
311
|
+
]),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
this.permissions = new Map(
|
|
315
|
+
Object.entries(state.permissions).map(([roleStr, perms]) => [
|
|
316
|
+
roleStr as Role,
|
|
317
|
+
perms.map((p) => ({ resource: p.resource, action: p.action })),
|
|
318
|
+
]),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry with exponential backoff and jitter.
|
|
3
|
+
*
|
|
4
|
+
* Every tool call is automatically retried on transient failures.
|
|
5
|
+
* Backoff: baseDelay * 2^attempt + random jitter
|
|
6
|
+
*
|
|
7
|
+
* Designed for API rate limits, network blips, and temporary outages.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface RetryOptions {
|
|
11
|
+
/** Maximum number of attempts (including the first) */
|
|
12
|
+
maxAttempts: number;
|
|
13
|
+
/** Base delay in ms */
|
|
14
|
+
baseDelay: number;
|
|
15
|
+
/** Maximum delay in ms */
|
|
16
|
+
maxDelay: number;
|
|
17
|
+
/** Retry only on these error codes/messages */
|
|
18
|
+
retryableErrors?: string[];
|
|
19
|
+
/** Callback for each retry attempt */
|
|
20
|
+
onRetry?: (attempt: number, error: Error, delay: number) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const DEFAULTS: RetryOptions = {
|
|
24
|
+
maxAttempts: 3,
|
|
25
|
+
baseDelay: 1000,
|
|
26
|
+
maxDelay: 30000,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export async function withRetry<T>(fn: () => Promise<T>, options?: Partial<RetryOptions>): Promise<T> {
|
|
30
|
+
const opts = { ...DEFAULTS, ...options };
|
|
31
|
+
let lastError: Error | undefined;
|
|
32
|
+
|
|
33
|
+
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
|
|
34
|
+
try {
|
|
35
|
+
return await fn();
|
|
36
|
+
} catch (err) {
|
|
37
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
38
|
+
|
|
39
|
+
// Don't retry if error is not retryable
|
|
40
|
+
if (opts.retryableErrors && opts.retryableErrors.length > 0) {
|
|
41
|
+
if (!opts.retryableErrors.some((pattern) => lastError!.message.includes(pattern))) {
|
|
42
|
+
throw lastError;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Don't retry on last attempt
|
|
47
|
+
if (attempt === opts.maxAttempts) {
|
|
48
|
+
throw lastError;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Calculate delay with exponential backoff and jitter
|
|
52
|
+
const delay = Math.min(opts.baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000, opts.maxDelay);
|
|
53
|
+
|
|
54
|
+
opts.onRetry?.(attempt, lastError, delay);
|
|
55
|
+
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw lastError!;
|
|
61
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook System — event-driven plugin communication.
|
|
3
|
+
*
|
|
4
|
+
* Plugins can emit events. External systems can subscribe via webhooks.
|
|
5
|
+
* Events are queued, retried on failure, and logged for audit.
|
|
6
|
+
*
|
|
7
|
+
* Event types: tool_called, tool_failed, plugin_enabled, plugin_disabled,
|
|
8
|
+
* config_changed, auth_success, auth_failure, health_degraded
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs/promises';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import crypto from 'crypto';
|
|
14
|
+
|
|
15
|
+
export interface WebhookSubscription {
|
|
16
|
+
id: string;
|
|
17
|
+
url: string;
|
|
18
|
+
/** Events to receive. ['*'] for all events. */
|
|
19
|
+
events: string[];
|
|
20
|
+
/** Secret for HMAC signature verification */
|
|
21
|
+
secret: string;
|
|
22
|
+
/** Whether this subscription is active */
|
|
23
|
+
active: boolean;
|
|
24
|
+
/** Created timestamp */
|
|
25
|
+
createdAt: string;
|
|
26
|
+
/** Last successful delivery timestamp */
|
|
27
|
+
lastSuccessAt?: string;
|
|
28
|
+
/** Number of consecutive failures */
|
|
29
|
+
consecutiveFailures: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface WebhookEvent {
|
|
33
|
+
id: string;
|
|
34
|
+
type: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** The resource that triggered the event */
|
|
37
|
+
resource: string;
|
|
38
|
+
/** Event payload */
|
|
39
|
+
data: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface WebhookDelivery {
|
|
43
|
+
eventId: string;
|
|
44
|
+
subscriptionId: string;
|
|
45
|
+
url: string;
|
|
46
|
+
status: 'pending' | 'delivered' | 'failed';
|
|
47
|
+
attempts: number;
|
|
48
|
+
lastAttemptAt?: string;
|
|
49
|
+
responseCode?: number;
|
|
50
|
+
responseError?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const MAX_CONSECUTIVE_FAILURES = 10;
|
|
54
|
+
const DELIVERY_TIMEOUT = 10000;
|
|
55
|
+
|
|
56
|
+
export class WebhookManager {
|
|
57
|
+
private subscriptionsFile: string;
|
|
58
|
+
private subscriptions: Map<string, WebhookSubscription>;
|
|
59
|
+
private deliveryQueue: Array<{ event: WebhookEvent; subscription: WebhookSubscription }>;
|
|
60
|
+
private processing = false;
|
|
61
|
+
|
|
62
|
+
constructor(configDir: string) {
|
|
63
|
+
this.subscriptionsFile = path.join(configDir, 'webhooks.json');
|
|
64
|
+
this.subscriptions = new Map();
|
|
65
|
+
this.deliveryQueue = [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Load subscriptions from disk.
|
|
70
|
+
*/
|
|
71
|
+
async load(): Promise<void> {
|
|
72
|
+
try {
|
|
73
|
+
const content = await fs.readFile(this.subscriptionsFile, 'utf-8');
|
|
74
|
+
const data = JSON.parse(content) as WebhookSubscription[];
|
|
75
|
+
for (const sub of data) {
|
|
76
|
+
this.subscriptions.set(sub.id, sub);
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// No subscriptions file yet
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Save subscriptions to disk.
|
|
85
|
+
*/
|
|
86
|
+
async save(): Promise<void> {
|
|
87
|
+
const data = Array.from(this.subscriptions.values());
|
|
88
|
+
await fs.writeFile(this.subscriptionsFile, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create a new webhook subscription.
|
|
93
|
+
*/
|
|
94
|
+
async create(url: string, events: string[]): Promise<WebhookSubscription> {
|
|
95
|
+
const subscription: WebhookSubscription = {
|
|
96
|
+
id: crypto.randomUUID(),
|
|
97
|
+
url,
|
|
98
|
+
events,
|
|
99
|
+
secret: crypto.randomBytes(32).toString('hex'),
|
|
100
|
+
active: true,
|
|
101
|
+
createdAt: new Date().toISOString(),
|
|
102
|
+
consecutiveFailures: 0,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
this.subscriptions.set(subscription.id, subscription);
|
|
106
|
+
await this.save();
|
|
107
|
+
return subscription;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Delete a webhook subscription.
|
|
112
|
+
*/
|
|
113
|
+
async delete(id: string): Promise<boolean> {
|
|
114
|
+
const deleted = this.subscriptions.delete(id);
|
|
115
|
+
if (deleted) await this.save();
|
|
116
|
+
return deleted;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* List all subscriptions.
|
|
121
|
+
*/
|
|
122
|
+
list(): WebhookSubscription[] {
|
|
123
|
+
return Array.from(this.subscriptions.values());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Emit an event. Queues it for delivery to matching subscriptions.
|
|
128
|
+
*/
|
|
129
|
+
async emit(event: Omit<WebhookEvent, 'id' | 'timestamp'>): Promise<void> {
|
|
130
|
+
const fullEvent: WebhookEvent = {
|
|
131
|
+
...event,
|
|
132
|
+
id: crypto.randomUUID(),
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
for (const sub of this.subscriptions.values()) {
|
|
137
|
+
if (!sub.active) continue;
|
|
138
|
+
if (!sub.events.includes('*') && !sub.events.includes(event.type)) continue;
|
|
139
|
+
|
|
140
|
+
this.deliveryQueue.push({ event: fullEvent, subscription: sub });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Process queue asynchronously
|
|
144
|
+
if (!this.processing) {
|
|
145
|
+
this.processQueue().catch(() => {});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Process the delivery queue.
|
|
151
|
+
*/
|
|
152
|
+
private async processQueue(): Promise<void> {
|
|
153
|
+
this.processing = true;
|
|
154
|
+
|
|
155
|
+
while (this.deliveryQueue.length > 0) {
|
|
156
|
+
const item = this.deliveryQueue.shift()!;
|
|
157
|
+
await this.deliver(item.event, item.subscription);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.processing = false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Deliver an event to a subscription.
|
|
165
|
+
*/
|
|
166
|
+
private async deliver(event: WebhookEvent, subscription: WebhookSubscription): Promise<void> {
|
|
167
|
+
const payload = JSON.stringify({
|
|
168
|
+
id: event.id,
|
|
169
|
+
type: event.type,
|
|
170
|
+
timestamp: event.timestamp,
|
|
171
|
+
resource: event.resource,
|
|
172
|
+
data: event.data,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const signature = crypto.createHmac('sha256', subscription.secret).update(payload).digest('hex');
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const controller = new AbortController();
|
|
179
|
+
const timeout = setTimeout(() => controller.abort(), DELIVERY_TIMEOUT);
|
|
180
|
+
|
|
181
|
+
const response = await fetch(subscription.url, {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
headers: {
|
|
184
|
+
'Content-Type': 'application/json',
|
|
185
|
+
'X-Conductor-Signature': `sha256=${signature}`,
|
|
186
|
+
'X-Conductor-Event': event.type,
|
|
187
|
+
'X-Conductor-Delivery': event.id,
|
|
188
|
+
'User-Agent': 'Conductor-Webhook/1.0',
|
|
189
|
+
},
|
|
190
|
+
body: payload,
|
|
191
|
+
signal: controller.signal,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
clearTimeout(timeout);
|
|
195
|
+
|
|
196
|
+
if (response.ok) {
|
|
197
|
+
subscription.consecutiveFailures = 0;
|
|
198
|
+
subscription.lastSuccessAt = new Date().toISOString();
|
|
199
|
+
await this.save();
|
|
200
|
+
} else {
|
|
201
|
+
await this.recordFailure(subscription, response.status, `HTTP ${response.status}`);
|
|
202
|
+
}
|
|
203
|
+
} catch (err) {
|
|
204
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
205
|
+
await this.recordFailure(subscription, 0, message);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Record a delivery failure. Deactivate after MAX_CONSECUTIVE_FAILURES.
|
|
211
|
+
*/
|
|
212
|
+
private async recordFailure(subscription: WebhookSubscription, _status: number, _error: string): Promise<void> {
|
|
213
|
+
subscription.consecutiveFailures++;
|
|
214
|
+
|
|
215
|
+
if (subscription.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
216
|
+
subscription.active = false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
await this.save();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Generate example webhook payload for testing.
|
|
224
|
+
*/
|
|
225
|
+
static exampleEvent(type: string, resource: string): WebhookEvent {
|
|
226
|
+
return {
|
|
227
|
+
id: 'evt_example_123',
|
|
228
|
+
type,
|
|
229
|
+
timestamp: new Date().toISOString(),
|
|
230
|
+
resource,
|
|
231
|
+
data: { example: true, message: 'This is a test event' },
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-Config Mode Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* Automatically enables 20+ tools that work without any API keys.
|
|
5
|
+
* These plugins have isConfigured() returning true without setup,
|
|
6
|
+
* or have safe defaults that work for public/unauthenticated use.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Conductor } from '../core/conductor.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* List of plugins that work without any credentials
|
|
13
|
+
* (isConfigured() returns true or they have safe defaults)
|
|
14
|
+
*/
|
|
15
|
+
export const ZERO_CONFIG_PLUGINS = [
|
|
16
|
+
// Core utilities - all work without credentials
|
|
17
|
+
'calculator', // Math expressions, unit conversions
|
|
18
|
+
'colors', // Color format conversion
|
|
19
|
+
'crypto', // Cryptocurrency prices/search
|
|
20
|
+
'hash', // Hashing, encoding
|
|
21
|
+
'text-tools', // JSON formatting, word count
|
|
22
|
+
'timezone', // Timezone conversion
|
|
23
|
+
'network', // DNS lookup, IP info
|
|
24
|
+
'url-tools', // URL parsing, expansion
|
|
25
|
+
'fun', // Jokes, facts
|
|
26
|
+
'system', // System info, clipboard
|
|
27
|
+
|
|
28
|
+
// Productivity - local only or safe defaults
|
|
29
|
+
'notes', // Local markdown notes
|
|
30
|
+
'memory', // Local semantic memory
|
|
31
|
+
'cron', // Cron expression parsing
|
|
32
|
+
|
|
33
|
+
// Infrastructure - local tools
|
|
34
|
+
'shell', // Safe shell commands (whitelist)
|
|
35
|
+
'docker', // Local Docker (if installed)
|
|
36
|
+
|
|
37
|
+
// GitHub - public data works without auth
|
|
38
|
+
'github', // Public repos, user info
|
|
39
|
+
|
|
40
|
+
// Weather - uses free Open-Meteo API
|
|
41
|
+
'weather', // Weather/current forecasts
|
|
42
|
+
|
|
43
|
+
// File system tools are built into Shell plugin
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Enable zero-config plugins on first run
|
|
48
|
+
*/
|
|
49
|
+
export async function enableZeroConfigMode(conductor: Conductor): Promise<void> {
|
|
50
|
+
const config = conductor.getConfig();
|
|
51
|
+
|
|
52
|
+
// Get currently enabled plugins
|
|
53
|
+
let enabledPlugins = config.get<string[]>('plugins.enabled') ?? [];
|
|
54
|
+
|
|
55
|
+
// Enable any zero-config plugins not already enabled
|
|
56
|
+
const toEnable = ZERO_CONFIG_PLUGINS.filter((plugin) => !enabledPlugins.includes(plugin));
|
|
57
|
+
|
|
58
|
+
if (toEnable.length > 0) {
|
|
59
|
+
enabledPlugins = [...enabledPlugins, ...toEnable];
|
|
60
|
+
await config.set('plugins.enabled', enabledPlugins);
|
|
61
|
+
|
|
62
|
+
process.stderr.write(`[ZERO-CONFIG] Enabled ${toEnable.length} plugins: ${toEnable.join(', ')}\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if zero-config mode is active
|
|
68
|
+
*/
|
|
69
|
+
export function isZeroConfigMode(conductor: Conductor): boolean {
|
|
70
|
+
const enabledPlugins = conductor.getConfig().get<string[]>('plugins.enabled') ?? [];
|
|
71
|
+
return ZERO_CONFIG_PLUGINS.every((plugin) => enabledPlugins.includes(plugin));
|
|
72
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# src/dashboard
|
|
2
|
+
|
|
3
|
+
Web dashboard for Conductor — an Express server serving a single-page application.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- `server.ts` - Express server with metrics, audit, health, and webhook endpoints
|
|
8
|
+
- `index.html` - Single-page application UI
|
|
9
|
+
- `cli.ts` - Dashboard-specific CLI commands
|
|
10
|
+
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
The dashboard provides a web UI for monitoring Conductor. It consumes metrics, audit logs, health status, and webhook data from the MCP server's shared state. The Express server uses `express-rate-limit` for protection. The `postbuild` script copies `index.html` to `dist/dashboard/index.html`.
|
|
14
|
+
|
|
15
|
+
Transport: HTTP/SSE for real-time updates from the MCP server.
|