@rudderhq/server 0.1.0-canary.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/LICENSE +14 -0
- package/dist/agent-auth-jwt.d.ts +14 -0
- package/dist/agent-auth-jwt.d.ts.map +1 -0
- package/dist/agent-auth-jwt.js +119 -0
- package/dist/agent-auth-jwt.js.map +1 -0
- package/dist/agent-runtimes/codex-models.d.ts +4 -0
- package/dist/agent-runtimes/codex-models.d.ts.map +1 -0
- package/dist/agent-runtimes/codex-models.js +98 -0
- package/dist/agent-runtimes/codex-models.js.map +1 -0
- package/dist/agent-runtimes/cursor-models.d.ts +13 -0
- package/dist/agent-runtimes/cursor-models.d.ts.map +1 -0
- package/dist/agent-runtimes/cursor-models.js +148 -0
- package/dist/agent-runtimes/cursor-models.js.map +1 -0
- package/dist/agent-runtimes/http/execute.d.ts +3 -0
- package/dist/agent-runtimes/http/execute.d.ts.map +1 -0
- package/dist/agent-runtimes/http/execute.js +39 -0
- package/dist/agent-runtimes/http/execute.js.map +1 -0
- package/dist/agent-runtimes/http/index.d.ts +3 -0
- package/dist/agent-runtimes/http/index.d.ts.map +1 -0
- package/dist/agent-runtimes/http/index.js +20 -0
- package/dist/agent-runtimes/http/index.js.map +1 -0
- package/dist/agent-runtimes/http/test.d.ts +3 -0
- package/dist/agent-runtimes/http/test.d.ts.map +1 -0
- package/dist/agent-runtimes/http/test.js +106 -0
- package/dist/agent-runtimes/http/test.js.map +1 -0
- package/dist/agent-runtimes/index.d.ts +4 -0
- package/dist/agent-runtimes/index.d.ts.map +1 -0
- package/dist/agent-runtimes/index.js +3 -0
- package/dist/agent-runtimes/index.js.map +1 -0
- package/dist/agent-runtimes/process/execute.d.ts +3 -0
- package/dist/agent-runtimes/process/execute.d.ts.map +1 -0
- package/dist/agent-runtimes/process/execute.js +63 -0
- package/dist/agent-runtimes/process/execute.js.map +1 -0
- package/dist/agent-runtimes/process/index.d.ts +3 -0
- package/dist/agent-runtimes/process/index.d.ts.map +1 -0
- package/dist/agent-runtimes/process/index.js +23 -0
- package/dist/agent-runtimes/process/index.js.map +1 -0
- package/dist/agent-runtimes/process/test.d.ts +3 -0
- package/dist/agent-runtimes/process/test.d.ts.map +1 -0
- package/dist/agent-runtimes/process/test.js +77 -0
- package/dist/agent-runtimes/process/test.js.map +1 -0
- package/dist/agent-runtimes/registry.d.ts +9 -0
- package/dist/agent-runtimes/registry.d.ts.map +1 -0
- package/dist/agent-runtimes/registry.js +189 -0
- package/dist/agent-runtimes/registry.js.map +1 -0
- package/dist/agent-runtimes/types.d.ts +2 -0
- package/dist/agent-runtimes/types.d.ts.map +1 -0
- package/dist/agent-runtimes/types.js +2 -0
- package/dist/agent-runtimes/types.js.map +1 -0
- package/dist/agent-runtimes/utils.d.ts +10 -0
- package/dist/agent-runtimes/utils.d.ts.map +1 -0
- package/dist/agent-runtimes/utils.js +14 -0
- package/dist/agent-runtimes/utils.js.map +1 -0
- package/dist/agent-workspace-key.d.ts +17 -0
- package/dist/agent-workspace-key.d.ts.map +1 -0
- package/dist/agent-workspace-key.js +49 -0
- package/dist/agent-workspace-key.js.map +1 -0
- package/dist/app.d.ts +14 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +19 -0
- package/dist/app.js.map +1 -0
- package/dist/attachment-types.d.ts +33 -0
- package/dist/attachment-types.d.ts.map +1 -0
- package/dist/attachment-types.js +67 -0
- package/dist/attachment-types.js.map +1 -0
- package/dist/auth/better-auth.d.ts +24 -0
- package/dist/auth/better-auth.d.ts.map +1 -0
- package/dist/auth/better-auth.js +108 -0
- package/dist/auth/better-auth.js.map +1 -0
- package/dist/board-claim.d.ts +23 -0
- package/dist/board-claim.d.ts.map +1 -0
- package/dist/board-claim.js +115 -0
- package/dist/board-claim.js.map +1 -0
- package/dist/bootstrap/create-http-app.d.ts +6 -0
- package/dist/bootstrap/create-http-app.d.ts.map +1 -0
- package/dist/bootstrap/create-http-app.js +122 -0
- package/dist/bootstrap/create-http-app.js.map +1 -0
- package/dist/bootstrap/plugin-host-runtime.d.ts +116 -0
- package/dist/bootstrap/plugin-host-runtime.d.ts.map +1 -0
- package/dist/bootstrap/plugin-host-runtime.js +121 -0
- package/dist/bootstrap/plugin-host-runtime.js.map +1 -0
- package/dist/bootstrap/register-api-routes.d.ts +5 -0
- package/dist/bootstrap/register-api-routes.d.ts.map +1 -0
- package/dist/bootstrap/register-api-routes.js +65 -0
- package/dist/bootstrap/register-api-routes.js.map +1 -0
- package/dist/bootstrap/types.d.ts +24 -0
- package/dist/bootstrap/types.d.ts.map +1 -0
- package/dist/bootstrap/types.js +2 -0
- package/dist/bootstrap/types.js.map +1 -0
- package/dist/config-file.d.ts +5 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +48 -0
- package/dist/config-file.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +233 -0
- package/dist/config.js.map +1 -0
- package/dist/dev-server-status.d.ts +29 -0
- package/dist/dev-server-status.d.ts.map +1 -0
- package/dist/dev-server-status.js +75 -0
- package/dist/dev-server-status.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +28 -0
- package/dist/errors.js.map +1 -0
- package/dist/home-paths.d.ts +50 -0
- package/dist/home-paths.d.ts.map +1 -0
- package/dist/home-paths.js +183 -0
- package/dist/home-paths.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +827 -0
- package/dist/index.js.map +1 -0
- package/dist/langfuse-transcript.d.ts +32 -0
- package/dist/langfuse-transcript.d.ts.map +1 -0
- package/dist/langfuse-transcript.js +341 -0
- package/dist/langfuse-transcript.js.map +1 -0
- package/dist/langfuse.d.ts +93 -0
- package/dist/langfuse.d.ts.map +1 -0
- package/dist/langfuse.js +412 -0
- package/dist/langfuse.js.map +1 -0
- package/dist/local-runtime.d.ts +67 -0
- package/dist/local-runtime.d.ts.map +1 -0
- package/dist/local-runtime.js +302 -0
- package/dist/local-runtime.js.map +1 -0
- package/dist/log-redaction.d.ts +11 -0
- package/dist/log-redaction.d.ts.map +1 -0
- package/dist/log-redaction.js +118 -0
- package/dist/log-redaction.js.map +1 -0
- package/dist/middleware/auth.d.ts +12 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +144 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/board-mutation-guard.d.ts +3 -0
- package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
- package/dist/middleware/board-mutation-guard.js +59 -0
- package/dist/middleware/board-mutation-guard.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +17 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +37 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/index.d.ts +4 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/logger.d.ts +4 -0
- package/dist/middleware/logger.d.ts.map +1 -0
- package/dist/middleware/logger.js +133 -0
- package/dist/middleware/logger.js.map +1 -0
- package/dist/middleware/private-hostname-guard.d.ts +11 -0
- package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
- package/dist/middleware/private-hostname-guard.js +78 -0
- package/dist/middleware/private-hostname-guard.js.map +1 -0
- package/dist/middleware/validate.d.ts +4 -0
- package/dist/middleware/validate.d.ts.map +1 -0
- package/dist/middleware/validate.js +7 -0
- package/dist/middleware/validate.js.map +1 -0
- package/dist/onboarding-assets/ceo/AGENTS.md +33 -0
- package/dist/onboarding-assets/ceo/HEARTBEAT.md +77 -0
- package/dist/onboarding-assets/ceo/SOUL.md +33 -0
- package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
- package/dist/onboarding-assets/default/AGENTS.md +9 -0
- package/dist/onboarding-assets/default/HEARTBEAT.md +36 -0
- package/dist/onboarding-assets/default/SOUL.md +23 -0
- package/dist/onboarding-assets/default/TOOLS.md +3 -0
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +31 -0
- package/dist/paths.js.map +1 -0
- package/dist/realtime/live-events-ws.d.ts +28 -0
- package/dist/realtime/live-events-ws.d.ts.map +1 -0
- package/dist/realtime/live-events-ws.js +187 -0
- package/dist/realtime/live-events-ws.js.map +1 -0
- package/dist/redaction.d.ts +4 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +63 -0
- package/dist/redaction.js.map +1 -0
- package/dist/routes/access.d.ts +57 -0
- package/dist/routes/access.d.ts.map +1 -0
- package/dist/routes/access.js +2266 -0
- package/dist/routes/access.js.map +1 -0
- package/dist/routes/activity.d.ts +3 -0
- package/dist/routes/activity.d.ts.map +1 -0
- package/dist/routes/activity.js +78 -0
- package/dist/routes/activity.js.map +1 -0
- package/dist/routes/agents.d.ts +3 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +1913 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/approvals.d.ts +3 -0
- package/dist/routes/approvals.d.ts.map +1 -0
- package/dist/routes/approvals.js +365 -0
- package/dist/routes/approvals.js.map +1 -0
- package/dist/routes/assets.d.ts +4 -0
- package/dist/routes/assets.d.ts.map +1 -0
- package/dist/routes/assets.js +309 -0
- package/dist/routes/assets.js.map +1 -0
- package/dist/routes/authz.d.ts +16 -0
- package/dist/routes/authz.d.ts.map +1 -0
- package/dist/routes/authz.js +47 -0
- package/dist/routes/authz.js.map +1 -0
- package/dist/routes/automations.d.ts +3 -0
- package/dist/routes/automations.d.ts.map +1 -0
- package/dist/routes/automations.js +277 -0
- package/dist/routes/automations.js.map +1 -0
- package/dist/routes/chats.d.ts +4 -0
- package/dist/routes/chats.d.ts.map +1 -0
- package/dist/routes/chats.js +1162 -0
- package/dist/routes/chats.js.map +1 -0
- package/dist/routes/costs.d.ts +3 -0
- package/dist/routes/costs.d.ts.map +1 -0
- package/dist/routes/costs.js +268 -0
- package/dist/routes/costs.js.map +1 -0
- package/dist/routes/dashboard.d.ts +3 -0
- package/dist/routes/dashboard.d.ts.map +1 -0
- package/dist/routes/dashboard.js +15 -0
- package/dist/routes/dashboard.js.map +1 -0
- package/dist/routes/execution-workspaces.d.ts +3 -0
- package/dist/routes/execution-workspaces.d.ts.map +1 -0
- package/dist/routes/execution-workspaces.js +165 -0
- package/dist/routes/execution-workspaces.js.map +1 -0
- package/dist/routes/goals.d.ts +3 -0
- package/dist/routes/goals.d.ts.map +1 -0
- package/dist/routes/goals.js +95 -0
- package/dist/routes/goals.js.map +1 -0
- package/dist/routes/health.d.ts +12 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +85 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +19 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +19 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/instance-settings.d.ts +6 -0
- package/dist/routes/instance-settings.d.ts.map +1 -0
- package/dist/routes/instance-settings.js +250 -0
- package/dist/routes/instance-settings.js.map +1 -0
- package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
- package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
- package/dist/routes/issues-checkout-wakeup.js +12 -0
- package/dist/routes/issues-checkout-wakeup.js.map +1 -0
- package/dist/routes/issues.d.ts +4 -0
- package/dist/routes/issues.d.ts.map +1 -0
- package/dist/routes/issues.js +1615 -0
- package/dist/routes/issues.js.map +1 -0
- package/dist/routes/llms.d.ts +3 -0
- package/dist/routes/llms.d.ts.map +1 -0
- package/dist/routes/llms.js +78 -0
- package/dist/routes/llms.js.map +1 -0
- package/dist/routes/messenger.d.ts +3 -0
- package/dist/routes/messenger.d.ts.map +1 -0
- package/dist/routes/messenger.js +108 -0
- package/dist/routes/messenger.js.map +1 -0
- package/dist/routes/org-chart-logo.d.ts +2 -0
- package/dist/routes/org-chart-logo.d.ts.map +1 -0
- package/dist/routes/org-chart-logo.js +2 -0
- package/dist/routes/org-chart-logo.js.map +1 -0
- package/dist/routes/org-chart-svg.d.ts +25 -0
- package/dist/routes/org-chart-svg.d.ts.map +1 -0
- package/dist/routes/org-chart-svg.js +652 -0
- package/dist/routes/org-chart-svg.js.map +1 -0
- package/dist/routes/organization-skills.d.ts +3 -0
- package/dist/routes/organization-skills.d.ts.map +1 -0
- package/dist/routes/organization-skills.js +253 -0
- package/dist/routes/organization-skills.js.map +1 -0
- package/dist/routes/orgs.d.ts +4 -0
- package/dist/routes/orgs.d.ts.map +1 -0
- package/dist/routes/orgs.js +575 -0
- package/dist/routes/orgs.js.map +1 -0
- package/dist/routes/plugin-ui-static.d.ts +69 -0
- package/dist/routes/plugin-ui-static.d.ts.map +1 -0
- package/dist/routes/plugin-ui-static.js +411 -0
- package/dist/routes/plugin-ui-static.js.map +1 -0
- package/dist/routes/plugins.d.ts +120 -0
- package/dist/routes/plugins.d.ts.map +1 -0
- package/dist/routes/plugins.js +1776 -0
- package/dist/routes/plugins.js.map +1 -0
- package/dist/routes/projects.d.ts +3 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +235 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/run-intelligence.d.ts +3 -0
- package/dist/routes/run-intelligence.d.ts.map +1 -0
- package/dist/routes/run-intelligence.js +58 -0
- package/dist/routes/run-intelligence.js.map +1 -0
- package/dist/routes/secrets.d.ts +3 -0
- package/dist/routes/secrets.d.ts.map +1 -0
- package/dist/routes/secrets.js +128 -0
- package/dist/routes/secrets.js.map +1 -0
- package/dist/routes/sidebar-badges.d.ts +3 -0
- package/dist/routes/sidebar-badges.d.ts.map +1 -0
- package/dist/routes/sidebar-badges.js +70 -0
- package/dist/routes/sidebar-badges.js.map +1 -0
- package/dist/secrets/external-stub-providers.d.ts +5 -0
- package/dist/secrets/external-stub-providers.d.ts.map +1 -0
- package/dist/secrets/external-stub-providers.js +21 -0
- package/dist/secrets/external-stub-providers.js.map +1 -0
- package/dist/secrets/local-encrypted-provider.d.ts +3 -0
- package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
- package/dist/secrets/local-encrypted-provider.js +116 -0
- package/dist/secrets/local-encrypted-provider.js.map +1 -0
- package/dist/secrets/provider-registry.d.ts +5 -0
- package/dist/secrets/provider-registry.d.ts.map +1 -0
- package/dist/secrets/provider-registry.js +20 -0
- package/dist/secrets/provider-registry.js.map +1 -0
- package/dist/secrets/types.d.ts +21 -0
- package/dist/secrets/types.d.ts.map +1 -0
- package/dist/secrets/types.js +2 -0
- package/dist/secrets/types.js.map +1 -0
- package/dist/services/access.d.ts +113 -0
- package/dist/services/access.d.ts.map +1 -0
- package/dist/services/access.js +247 -0
- package/dist/services/access.js.map +1 -0
- package/dist/services/activity-log.d.ts +17 -0
- package/dist/services/activity-log.d.ts.map +1 -0
- package/dist/services/activity-log.js +109 -0
- package/dist/services/activity-log.js.map +1 -0
- package/dist/services/activity.d.ts +472 -0
- package/dist/services/activity.d.ts.map +1 -0
- package/dist/services/activity.js +134 -0
- package/dist/services/activity.js.map +1 -0
- package/dist/services/agent-enabled-skills.d.ts +9 -0
- package/dist/services/agent-enabled-skills.d.ts.map +1 -0
- package/dist/services/agent-enabled-skills.js +89 -0
- package/dist/services/agent-enabled-skills.js.map +1 -0
- package/dist/services/agent-instructions.d.ts +98 -0
- package/dist/services/agent-instructions.d.ts.map +1 -0
- package/dist/services/agent-instructions.js +596 -0
- package/dist/services/agent-instructions.js.map +1 -0
- package/dist/services/agent-name-pool.d.ts +10 -0
- package/dist/services/agent-name-pool.d.ts.map +1 -0
- package/dist/services/agent-name-pool.js +230 -0
- package/dist/services/agent-name-pool.js.map +1 -0
- package/dist/services/agent-permissions.d.ts +6 -0
- package/dist/services/agent-permissions.d.ts.map +1 -0
- package/dist/services/agent-permissions.js +18 -0
- package/dist/services/agent-permissions.js.map +1 -0
- package/dist/services/agent-run-context.d.ts +142 -0
- package/dist/services/agent-run-context.d.ts.map +1 -0
- package/dist/services/agent-run-context.js +451 -0
- package/dist/services/agent-run-context.js.map +1 -0
- package/dist/services/agents.d.ts +1713 -0
- package/dist/services/agents.d.ts.map +1 -0
- package/dist/services/agents.js +750 -0
- package/dist/services/agents.js.map +1 -0
- package/dist/services/approvals.d.ts +546 -0
- package/dist/services/approvals.d.ts.map +1 -0
- package/dist/services/approvals.js +212 -0
- package/dist/services/approvals.js.map +1 -0
- package/dist/services/assets.d.ts +33 -0
- package/dist/services/assets.d.ts.map +1 -0
- package/dist/services/assets.js +17 -0
- package/dist/services/assets.js.map +1 -0
- package/dist/services/automations.d.ts +135 -0
- package/dist/services/automations.d.ts.map +1 -0
- package/dist/services/automations.js +1105 -0
- package/dist/services/automations.js.map +1 -0
- package/dist/services/board-auth.d.ts +234 -0
- package/dist/services/board-auth.d.ts.map +1 -0
- package/dist/services/board-auth.js +295 -0
- package/dist/services/board-auth.js.map +1 -0
- package/dist/services/budgets.d.ts +38 -0
- package/dist/services/budgets.d.ts.map +1 -0
- package/dist/services/budgets.js +784 -0
- package/dist/services/budgets.js.map +1 -0
- package/dist/services/chat-assistant.d.ts +62 -0
- package/dist/services/chat-assistant.d.ts.map +1 -0
- package/dist/services/chat-assistant.js +943 -0
- package/dist/services/chat-assistant.js.map +1 -0
- package/dist/services/chat-generation-locks.d.ts +3 -0
- package/dist/services/chat-generation-locks.d.ts.map +1 -0
- package/dist/services/chat-generation-locks.js +16 -0
- package/dist/services/chat-generation-locks.js.map +1 -0
- package/dist/services/chats.d.ts +723 -0
- package/dist/services/chats.d.ts.map +1 -0
- package/dist/services/chats.js +1188 -0
- package/dist/services/chats.js.map +1 -0
- package/dist/services/costs.d.ts +114 -0
- package/dist/services/costs.d.ts.map +1 -0
- package/dist/services/costs.js +326 -0
- package/dist/services/costs.js.map +1 -0
- package/dist/services/cron.d.ts +80 -0
- package/dist/services/cron.d.ts.map +1 -0
- package/dist/services/cron.js +300 -0
- package/dist/services/cron.js.map +1 -0
- package/dist/services/dashboard.d.ts +26 -0
- package/dist/services/dashboard.d.ts.map +1 -0
- package/dist/services/dashboard.js +98 -0
- package/dist/services/dashboard.js.map +1 -0
- package/dist/services/default-agent-instructions.d.ts +9 -0
- package/dist/services/default-agent-instructions.d.ts.map +1 -0
- package/dist/services/default-agent-instructions.js +20 -0
- package/dist/services/default-agent-instructions.js.map +1 -0
- package/dist/services/documents.d.ts +164 -0
- package/dist/services/documents.d.ts.map +1 -0
- package/dist/services/documents.js +382 -0
- package/dist/services/documents.js.map +1 -0
- package/dist/services/execution-workspace-policy.d.ts +20 -0
- package/dist/services/execution-workspace-policy.d.ts.map +1 -0
- package/dist/services/execution-workspace-policy.js +172 -0
- package/dist/services/execution-workspace-policy.js.map +1 -0
- package/dist/services/execution-workspaces.d.ts +19 -0
- package/dist/services/execution-workspaces.d.ts.map +1 -0
- package/dist/services/execution-workspaces.js +87 -0
- package/dist/services/execution-workspaces.js.map +1 -0
- package/dist/services/finance.d.ts +93 -0
- package/dist/services/finance.d.ts.map +1 -0
- package/dist/services/finance.js +120 -0
- package/dist/services/finance.js.map +1 -0
- package/dist/services/goals.d.ts +433 -0
- package/dist/services/goals.d.ts.map +1 -0
- package/dist/services/goals.js +54 -0
- package/dist/services/goals.js.map +1 -0
- package/dist/services/heartbeat-run-summary.d.ts +2 -0
- package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
- package/dist/services/heartbeat-run-summary.js +131 -0
- package/dist/services/heartbeat-run-summary.js.map +1 -0
- package/dist/services/heartbeat.d.ts +2 -0
- package/dist/services/heartbeat.d.ts.map +1 -0
- package/dist/services/heartbeat.js +2 -0
- package/dist/services/heartbeat.js.map +1 -0
- package/dist/services/hire-hook.d.ts +14 -0
- package/dist/services/hire-hook.d.ts.map +1 -0
- package/dist/services/hire-hook.js +85 -0
- package/dist/services/hire-hook.js.map +1 -0
- package/dist/services/index.d.ts +38 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +38 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/instance-settings.d.ts +14 -0
- package/dist/services/instance-settings.d.ts.map +1 -0
- package/dist/services/instance-settings.js +158 -0
- package/dist/services/instance-settings.js.map +1 -0
- package/dist/services/issue-approvals.d.ts +56 -0
- package/dist/services/issue-approvals.d.ts.map +1 -0
- package/dist/services/issue-approvals.js +153 -0
- package/dist/services/issue-approvals.js.map +1 -0
- package/dist/services/issue-assignment-wakeup.d.ts +32 -0
- package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
- package/dist/services/issue-assignment-wakeup.js +43 -0
- package/dist/services/issue-assignment-wakeup.js.map +1 -0
- package/dist/services/issue-goal-fallback.d.ts +15 -0
- package/dist/services/issue-goal-fallback.d.ts.map +1 -0
- package/dist/services/issue-goal-fallback.js +15 -0
- package/dist/services/issue-goal-fallback.js.map +1 -0
- package/dist/services/issues.d.ts +580 -0
- package/dist/services/issues.d.ts.map +1 -0
- package/dist/services/issues.js +1464 -0
- package/dist/services/issues.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.d.ts +23 -0
- package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.js +3795 -0
- package/dist/services/knowledge-portability/organization-portability.js.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.d.ts +105 -0
- package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.js +3172 -0
- package/dist/services/knowledge-portability/organization-skills.js.map +1 -0
- package/dist/services/live-events.d.ts +17 -0
- package/dist/services/live-events.d.ts.map +1 -0
- package/dist/services/live-events.js +33 -0
- package/dist/services/live-events.js.map +1 -0
- package/dist/services/messenger.d.ts +111 -0
- package/dist/services/messenger.d.ts.map +1 -0
- package/dist/services/messenger.js +774 -0
- package/dist/services/messenger.js.map +1 -0
- package/dist/services/native-path-picker.d.ts +18 -0
- package/dist/services/native-path-picker.d.ts.map +1 -0
- package/dist/services/native-path-picker.js +119 -0
- package/dist/services/native-path-picker.js.map +1 -0
- package/dist/services/operator-profile.d.ts +7 -0
- package/dist/services/operator-profile.d.ts.map +1 -0
- package/dist/services/operator-profile.js +66 -0
- package/dist/services/operator-profile.js.map +1 -0
- package/dist/services/organization-export-readme.d.ts +17 -0
- package/dist/services/organization-export-readme.d.ts.map +1 -0
- package/dist/services/organization-export-readme.js +148 -0
- package/dist/services/organization-export-readme.js.map +1 -0
- package/dist/services/organization-portability.d.ts +2 -0
- package/dist/services/organization-portability.d.ts.map +1 -0
- package/dist/services/organization-portability.js +2 -0
- package/dist/services/organization-portability.js.map +1 -0
- package/dist/services/organization-skills.d.ts +2 -0
- package/dist/services/organization-skills.d.ts.map +1 -0
- package/dist/services/organization-skills.js +2 -0
- package/dist/services/organization-skills.js.map +1 -0
- package/dist/services/organization-workspace-browser.d.ts +8 -0
- package/dist/services/organization-workspace-browser.d.ts.map +1 -0
- package/dist/services/organization-workspace-browser.js +229 -0
- package/dist/services/organization-workspace-browser.js.map +1 -0
- package/dist/services/organization-workspace.d.ts +5 -0
- package/dist/services/organization-workspace.d.ts.map +1 -0
- package/dist/services/organization-workspace.js +71 -0
- package/dist/services/organization-workspace.js.map +1 -0
- package/dist/services/orgs.d.ts +163 -0
- package/dist/services/orgs.d.ts.map +1 -0
- package/dist/services/orgs.js +327 -0
- package/dist/services/orgs.js.map +1 -0
- package/dist/services/plugin-capability-validator.d.ts +108 -0
- package/dist/services/plugin-capability-validator.d.ts.map +1 -0
- package/dist/services/plugin-capability-validator.js +268 -0
- package/dist/services/plugin-capability-validator.js.map +1 -0
- package/dist/services/plugin-config-validator.d.ts +26 -0
- package/dist/services/plugin-config-validator.d.ts.map +1 -0
- package/dist/services/plugin-config-validator.js +41 -0
- package/dist/services/plugin-config-validator.js.map +1 -0
- package/dist/services/plugin-dev-watcher.d.ts +30 -0
- package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
- package/dist/services/plugin-dev-watcher.js +241 -0
- package/dist/services/plugin-dev-watcher.js.map +1 -0
- package/dist/services/plugin-event-bus.d.ts +149 -0
- package/dist/services/plugin-event-bus.d.ts.map +1 -0
- package/dist/services/plugin-event-bus.js +258 -0
- package/dist/services/plugin-event-bus.js.map +1 -0
- package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
- package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
- package/dist/services/plugin-host-service-cleanup.js +37 -0
- package/dist/services/plugin-host-service-cleanup.js.map +1 -0
- package/dist/services/plugin-host-services.d.ts +13 -0
- package/dist/services/plugin-host-services.d.ts.map +1 -0
- package/dist/services/plugin-host-services.js +973 -0
- package/dist/services/plugin-host-services.js.map +1 -0
- package/dist/services/plugin-job-coordinator.d.ts +81 -0
- package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
- package/dist/services/plugin-job-coordinator.js +172 -0
- package/dist/services/plugin-job-coordinator.js.map +1 -0
- package/dist/services/plugin-job-scheduler.d.ts +163 -0
- package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
- package/dist/services/plugin-job-scheduler.js +564 -0
- package/dist/services/plugin-job-scheduler.js.map +1 -0
- package/dist/services/plugin-job-store.d.ts +208 -0
- package/dist/services/plugin-job-store.d.ts.map +1 -0
- package/dist/services/plugin-job-store.js +350 -0
- package/dist/services/plugin-job-store.js.map +1 -0
- package/dist/services/plugin-lifecycle.d.ts +203 -0
- package/dist/services/plugin-lifecycle.d.ts.map +1 -0
- package/dist/services/plugin-lifecycle.js +476 -0
- package/dist/services/plugin-lifecycle.js.map +1 -0
- package/dist/services/plugin-loader.d.ts +441 -0
- package/dist/services/plugin-loader.d.ts.map +1 -0
- package/dist/services/plugin-loader.js +1192 -0
- package/dist/services/plugin-loader.js.map +1 -0
- package/dist/services/plugin-log-retention.d.ts +20 -0
- package/dist/services/plugin-log-retention.d.ts.map +1 -0
- package/dist/services/plugin-log-retention.js +63 -0
- package/dist/services/plugin-log-retention.js.map +1 -0
- package/dist/services/plugin-manifest-validator.d.ts +79 -0
- package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
- package/dist/services/plugin-manifest-validator.js +84 -0
- package/dist/services/plugin-manifest-validator.js.map +1 -0
- package/dist/services/plugin-registry.d.ts +2542 -0
- package/dist/services/plugin-registry.d.ts.map +1 -0
- package/dist/services/plugin-registry.js +539 -0
- package/dist/services/plugin-registry.js.map +1 -0
- package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
- package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
- package/dist/services/plugin-runtime-sandbox.js +154 -0
- package/dist/services/plugin-runtime-sandbox.js.map +1 -0
- package/dist/services/plugin-secrets-handler.d.ts +81 -0
- package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
- package/dist/services/plugin-secrets-handler.js +275 -0
- package/dist/services/plugin-secrets-handler.js.map +1 -0
- package/dist/services/plugin-state-store.d.ts +92 -0
- package/dist/services/plugin-state-store.d.ts.map +1 -0
- package/dist/services/plugin-state-store.js +190 -0
- package/dist/services/plugin-state-store.js.map +1 -0
- package/dist/services/plugin-stream-bus.d.ts +29 -0
- package/dist/services/plugin-stream-bus.d.ts.map +1 -0
- package/dist/services/plugin-stream-bus.js +48 -0
- package/dist/services/plugin-stream-bus.js.map +1 -0
- package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
- package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
- package/dist/services/plugin-tool-dispatcher.js +224 -0
- package/dist/services/plugin-tool-dispatcher.js.map +1 -0
- package/dist/services/plugin-tool-registry.d.ts +192 -0
- package/dist/services/plugin-tool-registry.d.ts.map +1 -0
- package/dist/services/plugin-tool-registry.js +224 -0
- package/dist/services/plugin-tool-registry.js.map +1 -0
- package/dist/services/plugin-worker-manager.d.ts +260 -0
- package/dist/services/plugin-worker-manager.d.ts.map +1 -0
- package/dist/services/plugin-worker-manager.js +835 -0
- package/dist/services/plugin-worker-manager.js.map +1 -0
- package/dist/services/projects.d.ts +92 -0
- package/dist/services/projects.d.ts.map +1 -0
- package/dist/services/projects.js +705 -0
- package/dist/services/projects.js.map +1 -0
- package/dist/services/quota-windows.d.ts +9 -0
- package/dist/services/quota-windows.d.ts.map +1 -0
- package/dist/services/quota-windows.js +56 -0
- package/dist/services/quota-windows.js.map +1 -0
- package/dist/services/resource-catalog.d.ts +29 -0
- package/dist/services/resource-catalog.d.ts.map +1 -0
- package/dist/services/resource-catalog.js +298 -0
- package/dist/services/resource-catalog.js.map +1 -0
- package/dist/services/run-intelligence.d.ts +31 -0
- package/dist/services/run-intelligence.d.ts.map +1 -0
- package/dist/services/run-intelligence.js +315 -0
- package/dist/services/run-intelligence.js.map +1 -0
- package/dist/services/run-log-store.d.ts +36 -0
- package/dist/services/run-log-store.d.ts.map +1 -0
- package/dist/services/run-log-store.js +114 -0
- package/dist/services/run-log-store.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.d.ts +882 -0
- package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.js +4345 -0
- package/dist/services/runtime-kernel/heartbeat.js.map +1 -0
- package/dist/services/runtime-trace-metadata.d.ts +12 -0
- package/dist/services/runtime-trace-metadata.d.ts.map +1 -0
- package/dist/services/runtime-trace-metadata.js +13 -0
- package/dist/services/runtime-trace-metadata.js.map +1 -0
- package/dist/services/secrets.d.ts +511 -0
- package/dist/services/secrets.d.ts.map +1 -0
- package/dist/services/secrets.js +289 -0
- package/dist/services/secrets.js.map +1 -0
- package/dist/services/sidebar-badges.d.ts +11 -0
- package/dist/services/sidebar-badges.d.ts.map +1 -0
- package/dist/services/sidebar-badges.js +43 -0
- package/dist/services/sidebar-badges.js.map +1 -0
- package/dist/services/work-products.d.ts +14 -0
- package/dist/services/work-products.d.ts.map +1 -0
- package/dist/services/work-products.js +100 -0
- package/dist/services/work-products.js.map +1 -0
- package/dist/services/workspace-operation-log-store.d.ts +35 -0
- package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
- package/dist/services/workspace-operation-log-store.js +115 -0
- package/dist/services/workspace-operation-log-store.js.map +1 -0
- package/dist/services/workspace-operations.d.ts +46 -0
- package/dist/services/workspace-operations.d.ts.map +1 -0
- package/dist/services/workspace-operations.js +237 -0
- package/dist/services/workspace-operations.js.map +1 -0
- package/dist/services/workspace-runtime.d.ts +164 -0
- package/dist/services/workspace-runtime.d.ts.map +1 -0
- package/dist/services/workspace-runtime.js +1235 -0
- package/dist/services/workspace-runtime.js.map +1 -0
- package/dist/startup-banner.d.ts +31 -0
- package/dist/startup-banner.d.ts.map +1 -0
- package/dist/startup-banner.js +121 -0
- package/dist/startup-banner.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +29 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local-disk-provider.d.ts +3 -0
- package/dist/storage/local-disk-provider.d.ts.map +1 -0
- package/dist/storage/local-disk-provider.js +79 -0
- package/dist/storage/local-disk-provider.js.map +1 -0
- package/dist/storage/provider-registry.d.ts +4 -0
- package/dist/storage/provider-registry.d.ts.map +1 -0
- package/dist/storage/provider-registry.js +15 -0
- package/dist/storage/provider-registry.js.map +1 -0
- package/dist/storage/s3-provider.d.ts +11 -0
- package/dist/storage/s3-provider.d.ts.map +1 -0
- package/dist/storage/s3-provider.js +123 -0
- package/dist/storage/s3-provider.js.map +1 -0
- package/dist/storage/service.d.ts +3 -0
- package/dist/storage/service.d.ts.map +1 -0
- package/dist/storage/service.js +120 -0
- package/dist/storage/service.js.map +1 -0
- package/dist/storage/types.d.ts +55 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/ui-branding.d.ts +14 -0
- package/dist/ui-branding.d.ts.map +1 -0
- package/dist/ui-branding.js +201 -0
- package/dist/ui-branding.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +101 -0
- package/resources/bundled-skills/para-memory-files/SKILL.md +114 -0
- package/resources/bundled-skills/para-memory-files/references/schemas.md +35 -0
- package/resources/bundled-skills/rudder/SKILL.md +265 -0
- package/resources/bundled-skills/rudder/references/api-reference.md +253 -0
- package/resources/bundled-skills/rudder/references/cli-reference.md +67 -0
- package/resources/bundled-skills/rudder/references/organization-skills.md +155 -0
- package/resources/bundled-skills/rudder-create-agent/SKILL.md +166 -0
- package/resources/bundled-skills/rudder-create-agent/references/api-reference.md +172 -0
- package/resources/bundled-skills/rudder-create-agent/references/cli-reference.md +126 -0
- package/resources/bundled-skills/rudder-create-plugin/SKILL.md +103 -0
- package/resources/community-skills/deep-research/README.md +124 -0
- package/resources/community-skills/deep-research/SKILL.md +107 -0
- package/resources/community-skills/deep-research/reference/continuation.md +169 -0
- package/resources/community-skills/deep-research/reference/html-generation.md +103 -0
- package/resources/community-skills/deep-research/reference/methodology.md +421 -0
- package/resources/community-skills/deep-research/reference/quality-gates.md +197 -0
- package/resources/community-skills/deep-research/reference/report-assembly.md +119 -0
- package/resources/community-skills/deep-research/reference/weasyprint_guidelines.md +324 -0
- package/resources/community-skills/deep-research/requirements.txt +14 -0
- package/resources/community-skills/deep-research/scripts/citation_manager.py +177 -0
- package/resources/community-skills/deep-research/scripts/md_to_html.py +330 -0
- package/resources/community-skills/deep-research/scripts/research_engine.py +582 -0
- package/resources/community-skills/deep-research/scripts/source_evaluator.py +292 -0
- package/resources/community-skills/deep-research/scripts/validate_report.py +403 -0
- package/resources/community-skills/deep-research/scripts/verify_citations.py +426 -0
- package/resources/community-skills/deep-research/scripts/verify_html.py +220 -0
- package/resources/community-skills/deep-research/templates/mckinsey_report_template.html +443 -0
- package/resources/community-skills/deep-research/templates/report_template.md +433 -0
- package/resources/community-skills/skill-creator/SKILL.md +9 -0
- package/resources/community-skills/software-product-advisor/SKILL.md +290 -0
- package/skills/para-memory-files/SKILL.md +114 -0
- package/skills/para-memory-files/references/schemas.md +35 -0
- package/skills/rudder/SKILL.md +265 -0
- package/skills/rudder/references/api-reference.md +253 -0
- package/skills/rudder/references/cli-reference.md +67 -0
- package/skills/rudder/references/organization-skills.md +155 -0
- package/skills/rudder-create-agent/SKILL.md +166 -0
- package/skills/rudder-create-agent/references/api-reference.md +172 -0
- package/skills/rudder-create-agent/references/cli-reference.md +126 -0
- package/skills/rudder-create-plugin/SKILL.md +103 -0
- package/ui-dist/android-chrome-192x192.png +0 -0
- package/ui-dist/android-chrome-512x512.png +0 -0
- package/ui-dist/android-chrome-maskable-512x512.png +0 -0
- package/ui-dist/apple-touch-icon.png +0 -0
- package/ui-dist/assets/_basePickBy-CjUu04_e.js +1 -0
- package/ui-dist/assets/_baseUniq-C9YNlrVG.js +1 -0
- package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
- package/ui-dist/assets/arc-CSSZfktq.js +1 -0
- package/ui-dist/assets/architectureDiagram-2XIMDMQ5-Co78JKUi.js +36 -0
- package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
- package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
- package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
- package/ui-dist/assets/blockDiagram-WCTKOSBZ-2KUUIzzz.js +132 -0
- package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
- package/ui-dist/assets/c4Diagram-IC4MRINW-C6pq8tPP.js +10 -0
- package/ui-dist/assets/channel-BEODbRMk.js +1 -0
- package/ui-dist/assets/chunk-4BX2VUAB-ojCLkixe.js +1 -0
- package/ui-dist/assets/chunk-55IACEB6-MGONqzmz.js +1 -0
- package/ui-dist/assets/chunk-FMBD7UC4-CmGuLv2P.js +15 -0
- package/ui-dist/assets/chunk-JSJVCQXG-BNBefVr6.js +1 -0
- package/ui-dist/assets/chunk-KX2RTZJC-DIGBQLn5.js +1 -0
- package/ui-dist/assets/chunk-NQ4KR5QH-_KEutsaQ.js +220 -0
- package/ui-dist/assets/chunk-QZHKN3VN-B6pzyuwm.js +1 -0
- package/ui-dist/assets/chunk-WL4C6EOR-B8NDzcfm.js +189 -0
- package/ui-dist/assets/classDiagram-VBA2DB6C-CsSqaaRj.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CsSqaaRj.js +1 -0
- package/ui-dist/assets/clike-B9uivgTg.js +1 -0
- package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
- package/ui-dist/assets/clone-5oWMCI0u.js +1 -0
- package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
- package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
- package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
- package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
- package/ui-dist/assets/cose-bilkent-S5V4N54A-B1t6ulcV.js +1 -0
- package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
- package/ui-dist/assets/css-BnMrqG3P.js +1 -0
- package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
- package/ui-dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
- package/ui-dist/assets/d-pRatUO7H.js +1 -0
- package/ui-dist/assets/dagre-KLK3FWXG-DWVC5_HJ.js +4 -0
- package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/ui-dist/assets/diagram-E7M64L7V-C4ztYLox.js +24 -0
- package/ui-dist/assets/diagram-IFDJBPK2-DtWBGLnA.js +43 -0
- package/ui-dist/assets/diagram-P4PSJMXO-BiqiI4Df.js +24 -0
- package/ui-dist/assets/diff-DbItnlRl.js +1 -0
- package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
- package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
- package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
- package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
- package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
- package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
- package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
- package/ui-dist/assets/erDiagram-INFDFZHY-CUhr9rIh.js +70 -0
- package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
- package/ui-dist/assets/factor-kuTfRLto.js +1 -0
- package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
- package/ui-dist/assets/flowDiagram-PKNHOUZH-BEqBmNL-.js +162 -0
- package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
- package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
- package/ui-dist/assets/ganttDiagram-A5KZAMGK-CdeWhdno.js +292 -0
- package/ui-dist/assets/gas-Bneqetm1.js +1 -0
- package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
- package/ui-dist/assets/gitGraphDiagram-K3NZZRJ6-CgG66QFg.js +65 -0
- package/ui-dist/assets/graph-rmownl79.js +1 -0
- package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
- package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
- package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
- package/ui-dist/assets/http-DBlCnlav.js +1 -0
- package/ui-dist/assets/idl-BEugSyMb.js +1 -0
- package/ui-dist/assets/index-B1YyDqaG.js +1 -0
- package/ui-dist/assets/index-B7exNxYd.js +1 -0
- package/ui-dist/assets/index-BIuriVDl.js +1 -0
- package/ui-dist/assets/index-BT9rfwYt.js +1 -0
- package/ui-dist/assets/index-BZhmacJG.js +1 -0
- package/ui-dist/assets/index-B_ebS3U_.js +3 -0
- package/ui-dist/assets/index-BnQqZOsc.js +1 -0
- package/ui-dist/assets/index-BwPbAax6.js +1 -0
- package/ui-dist/assets/index-C5i670o5.js +1 -0
- package/ui-dist/assets/index-C9KwE7Yr.js +1 -0
- package/ui-dist/assets/index-CDId_UjP.js +1 -0
- package/ui-dist/assets/index-CI9ydSGM.js +1 -0
- package/ui-dist/assets/index-CKpm3WGI.css +1 -0
- package/ui-dist/assets/index-CMP_bzP3.js +2 -0
- package/ui-dist/assets/index-CRcHIoCW.js +1 -0
- package/ui-dist/assets/index-DZqNY-Lg.js +1 -0
- package/ui-dist/assets/index-DbDKJhW-.js +7 -0
- package/ui-dist/assets/index-Dkg6MwQ_.js +1 -0
- package/ui-dist/assets/index-Dn0iitKg.js +1 -0
- package/ui-dist/assets/index-GvHywIOA.js +1323 -0
- package/ui-dist/assets/index-WtX4Y4Fx.js +13 -0
- package/ui-dist/assets/index-iyC5PHC3.js +6 -0
- package/ui-dist/assets/index-jMlzlqoV.js +1 -0
- package/ui-dist/assets/index-pTIOLGTe.js +1 -0
- package/ui-dist/assets/infoDiagram-LFFYTUFH-CEhdbTYQ.js +2 -0
- package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
- package/ui-dist/assets/ishikawaDiagram-PHBUUO56-g9GiiXI2.js +70 -0
- package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
- package/ui-dist/assets/journeyDiagram-4ABVD52K-CheeZzlg.js +139 -0
- package/ui-dist/assets/julia-DuME0IfC.js +1 -0
- package/ui-dist/assets/kanban-definition-K7BYSVSG-BTpuAgUJ.js +89 -0
- package/ui-dist/assets/katex-B1X10hvy.js +261 -0
- package/ui-dist/assets/layout-CuBgufef.js +1 -0
- package/ui-dist/assets/linear-CnXO6wXw.js +1 -0
- package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
- package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
- package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
- package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
- package/ui-dist/assets/mermaid.core-DVaYxfh9.js +255 -0
- package/ui-dist/assets/mindmap-definition-YRQLILUH-00nAuexq.js +68 -0
- package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
- package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
- package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
- package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
- package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
- package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
- package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
- package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
- package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
- package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
- package/ui-dist/assets/pascal--L3eBynH.js +1 -0
- package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
- package/ui-dist/assets/pieDiagram-SKSYHLDU-NaOgRqIj.js +30 -0
- package/ui-dist/assets/pig-CevX1Tat.js +1 -0
- package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
- package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
- package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
- package/ui-dist/assets/pug-DeIclll2.js +1 -0
- package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
- package/ui-dist/assets/python-BuPzkPfP.js +1 -0
- package/ui-dist/assets/q-pXgVlZs6.js +1 -0
- package/ui-dist/assets/quadrantDiagram-337W2JSQ-Bnf9OCW0.js +7 -0
- package/ui-dist/assets/r-B6wPVr8A.js +1 -0
- package/ui-dist/assets/requirementDiagram-Z7DCOOCP-BiacZTTh.js +73 -0
- package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
- package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
- package/ui-dist/assets/sankeyDiagram-WA2Y5GQK-DOuD4D2Q.js +10 -0
- package/ui-dist/assets/sas-B4kiWyti.js +1 -0
- package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
- package/ui-dist/assets/sequenceDiagram-2WXFIKYE-oV3M_w-H.js +145 -0
- package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
- package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
- package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
- package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
- package/ui-dist/assets/solr-DehyRSwq.js +1 -0
- package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
- package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
- package/ui-dist/assets/sql-D0XecflT.js +1 -0
- package/ui-dist/assets/stateDiagram-RAJIS63D-CdRc2Pqb.js +1 -0
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-CIMHFJYg.js +1 -0
- package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
- package/ui-dist/assets/stylus-B533Al4x.js +1 -0
- package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
- package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
- package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
- package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
- package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
- package/ui-dist/assets/timeline-definition-YZTLITO2-BCWQDIwt.js +61 -0
- package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
- package/ui-dist/assets/treemap-KZPCXAKY-BvsIxXAi.js +162 -0
- package/ui-dist/assets/troff-wAsdV37c.js +1 -0
- package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
- package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
- package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
- package/ui-dist/assets/vb-CmGdzxic.js +1 -0
- package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
- package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
- package/ui-dist/assets/vennDiagram-LZ73GAT5-BzibHs4r.js +34 -0
- package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
- package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
- package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
- package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
- package/ui-dist/assets/xychartDiagram-JWTSCODW-CX_Xt_y-.js +7 -0
- package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
- package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
- package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
- package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
- package/ui-dist/favicon-16x16.png +0 -0
- package/ui-dist/favicon-32x32.png +0 -0
- package/ui-dist/favicon-dev-16x16.png +0 -0
- package/ui-dist/favicon-dev-32x32.png +0 -0
- package/ui-dist/favicon-dev.ico +0 -0
- package/ui-dist/favicon.ico +0 -0
- package/ui-dist/favicon.svg +1 -0
- package/ui-dist/index.html +61 -0
- package/ui-dist/rudder-logo.png +0 -0
- package/ui-dist/site.webmanifest +30 -0
- package/ui-dist/sw.js +42 -0
- package/ui-dist/worktree-favicon-16x16.png +0 -0
- package/ui-dist/worktree-favicon-32x32.png +0 -0
- package/ui-dist/worktree-favicon.ico +0 -0
- package/ui-dist/worktree-favicon.svg +1 -0
|
@@ -0,0 +1,1913 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { generateKeyPairSync, randomUUID } from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { agents as agentsTable, organizations, heartbeatRuns } from "@rudderhq/db";
|
|
5
|
+
import { and, desc, eq, inArray, not, sql } from "drizzle-orm";
|
|
6
|
+
import { agentSkillSyncSchema, createAgentKeySchema, createAgentHireSchema, createAgentSchema, deriveAgentUrlKey, isUuidLike, organizationSkillCreateSchema, resetAgentSessionSchema, testAgentRuntimeEnvironmentSchema, upsertAgentInstructionsFileSchema, updateAgentInstructionsBundleSchema, updateAgentPermissionsSchema, updateAgentInstructionsPathSchema, wakeAgentSchema, updateAgentSchema, } from "@rudderhq/shared";
|
|
7
|
+
import { validate } from "../middleware/validate.js";
|
|
8
|
+
import { agentService, agentInstructionsService, accessService, approvalService, organizationSkillService, budgetService, heartbeatService, issueApprovalService, issueService, logActivity, secretService, syncInstructionsBundleConfigFromFilePath, workspaceOperationService, } from "../services/index.js";
|
|
9
|
+
import { conflict, forbidden, notFound, unprocessable } from "../errors.js";
|
|
10
|
+
import { assertBoard, assertCompanyAccess, assertInstanceAdmin, getActorInfo } from "./authz.js";
|
|
11
|
+
import { findServerAdapter, listAgentRuntimeModels } from "../agent-runtimes/index.js";
|
|
12
|
+
import { redactEventPayload } from "../redaction.js";
|
|
13
|
+
import { redactCurrentUserValue } from "../log-redaction.js";
|
|
14
|
+
import { renderOrgChartSvg, renderOrgChartPng, ORG_CHART_STYLES } from "./org-chart-svg.js";
|
|
15
|
+
import { instanceSettingsService } from "../services/instance-settings.js";
|
|
16
|
+
import { runClaudeLogin } from "@rudderhq/agent-runtime-claude-local/server";
|
|
17
|
+
import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, DEFAULT_CODEX_LOCAL_MODEL, } from "@rudderhq/agent-runtime-codex-local";
|
|
18
|
+
import { DEFAULT_CURSOR_LOCAL_MODEL } from "@rudderhq/agent-runtime-cursor-local";
|
|
19
|
+
import { DEFAULT_GEMINI_LOCAL_MODEL } from "@rudderhq/agent-runtime-gemini-local";
|
|
20
|
+
import { ensureOpenCodeModelConfiguredAndAvailable } from "@rudderhq/agent-runtime-opencode-local/server";
|
|
21
|
+
import { loadDefaultAgentInstructionsBundle, resolveDefaultAgentInstructionsBundleRole, } from "../services/default-agent-instructions.js";
|
|
22
|
+
export function agentRoutes(db) {
|
|
23
|
+
function stripPersistedSkillSyncConfig(config) {
|
|
24
|
+
const next = { ...config };
|
|
25
|
+
delete next.rudderSkillSync;
|
|
26
|
+
delete next.paperclipSkillSync;
|
|
27
|
+
delete next.rudderRuntimeSkills;
|
|
28
|
+
delete next.paperclipRuntimeSkills;
|
|
29
|
+
return next;
|
|
30
|
+
}
|
|
31
|
+
function withRuntimeSkillEntries(config, runtimeSkillEntries, desiredSkills) {
|
|
32
|
+
return {
|
|
33
|
+
...config,
|
|
34
|
+
rudderSkillSync: { desiredSkills },
|
|
35
|
+
paperclipSkillSync: { desiredSkills },
|
|
36
|
+
rudderRuntimeSkills: runtimeSkillEntries,
|
|
37
|
+
paperclipRuntimeSkills: runtimeSkillEntries,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const DEFAULT_INSTRUCTIONS_PATH_KEYS = {
|
|
41
|
+
claude_local: "instructionsFilePath",
|
|
42
|
+
codex_local: "instructionsFilePath",
|
|
43
|
+
gemini_local: "instructionsFilePath",
|
|
44
|
+
opencode_local: "instructionsFilePath",
|
|
45
|
+
cursor: "instructionsFilePath",
|
|
46
|
+
pi_local: "instructionsFilePath",
|
|
47
|
+
};
|
|
48
|
+
const DEFAULT_MANAGED_INSTRUCTIONS_ADAPTER_TYPES = new Set(Object.keys(DEFAULT_INSTRUCTIONS_PATH_KEYS));
|
|
49
|
+
const KNOWN_INSTRUCTIONS_PATH_KEYS = new Set(["instructionsFilePath", "agentsMdPath"]);
|
|
50
|
+
const KNOWN_INSTRUCTIONS_BUNDLE_KEYS = [
|
|
51
|
+
"instructionsBundleMode",
|
|
52
|
+
"instructionsRootPath",
|
|
53
|
+
"instructionsEntryFile",
|
|
54
|
+
"instructionsFilePath",
|
|
55
|
+
"agentsMdPath",
|
|
56
|
+
];
|
|
57
|
+
const router = Router();
|
|
58
|
+
const svc = agentService(db);
|
|
59
|
+
const access = accessService(db);
|
|
60
|
+
const approvalsSvc = approvalService(db);
|
|
61
|
+
const budgets = budgetService(db);
|
|
62
|
+
const heartbeat = heartbeatService(db);
|
|
63
|
+
const issueApprovalsSvc = issueApprovalService(db);
|
|
64
|
+
const secretsSvc = secretService(db);
|
|
65
|
+
const instructions = agentInstructionsService();
|
|
66
|
+
const organizationSkills = organizationSkillService(db);
|
|
67
|
+
const workspaceOperations = workspaceOperationService(db);
|
|
68
|
+
const instanceSettings = instanceSettingsService(db);
|
|
69
|
+
const strictSecretsMode = process.env.RUDDER_SECRETS_STRICT_MODE === "true";
|
|
70
|
+
async function persistReconciledInstructionsBundle(agent, result) {
|
|
71
|
+
if (!result.changed)
|
|
72
|
+
return agent;
|
|
73
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(agent.orgId, result.agentRuntimeConfig, { strictMode: strictSecretsMode });
|
|
74
|
+
const updated = await svc.update(agent.id, { agentRuntimeConfig: normalizedAdapterConfig });
|
|
75
|
+
return updated ?? { ...agent, agentRuntimeConfig: normalizedAdapterConfig };
|
|
76
|
+
}
|
|
77
|
+
async function getCurrentUserRedactionOptions() {
|
|
78
|
+
return {
|
|
79
|
+
enabled: (await instanceSettings.getGeneral()).censorUsernameInLogs,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function canCreateAgents(agent) {
|
|
83
|
+
if (!agent.permissions || typeof agent.permissions !== "object")
|
|
84
|
+
return false;
|
|
85
|
+
return Boolean(agent.permissions.canCreateAgents);
|
|
86
|
+
}
|
|
87
|
+
async function buildAgentAccessState(agent) {
|
|
88
|
+
const membership = await access.getMembership(agent.orgId, "agent", agent.id);
|
|
89
|
+
const grants = membership
|
|
90
|
+
? await access.listPrincipalGrants(agent.orgId, "agent", agent.id)
|
|
91
|
+
: [];
|
|
92
|
+
const hasExplicitTaskAssignGrant = grants.some((grant) => grant.permissionKey === "tasks:assign");
|
|
93
|
+
if (agent.role === "ceo") {
|
|
94
|
+
return {
|
|
95
|
+
canAssignTasks: true,
|
|
96
|
+
taskAssignSource: "ceo_role",
|
|
97
|
+
membership,
|
|
98
|
+
grants,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (canCreateAgents(agent)) {
|
|
102
|
+
return {
|
|
103
|
+
canAssignTasks: true,
|
|
104
|
+
taskAssignSource: "agent_creator",
|
|
105
|
+
membership,
|
|
106
|
+
grants,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (hasExplicitTaskAssignGrant) {
|
|
110
|
+
return {
|
|
111
|
+
canAssignTasks: true,
|
|
112
|
+
taskAssignSource: "explicit_grant",
|
|
113
|
+
membership,
|
|
114
|
+
grants,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
canAssignTasks: false,
|
|
119
|
+
taskAssignSource: "none",
|
|
120
|
+
membership,
|
|
121
|
+
grants,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async function buildAgentDetail(agent, options) {
|
|
125
|
+
const [chainOfCommand, accessState] = await Promise.all([
|
|
126
|
+
svc.getChainOfCommand(agent.id),
|
|
127
|
+
buildAgentAccessState(agent),
|
|
128
|
+
]);
|
|
129
|
+
return {
|
|
130
|
+
...(options?.restricted ? redactForRestrictedAgentView(agent) : agent),
|
|
131
|
+
chainOfCommand,
|
|
132
|
+
access: accessState,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async function applyDefaultAgentTaskAssignGrant(orgId, agentId, grantedByUserId) {
|
|
136
|
+
await access.ensureMembership(orgId, "agent", agentId, "member", "active");
|
|
137
|
+
await access.setPrincipalPermission(orgId, "agent", agentId, "tasks:assign", true, grantedByUserId);
|
|
138
|
+
}
|
|
139
|
+
async function assertCanCreateAgentsForCompany(req, orgId) {
|
|
140
|
+
assertCompanyAccess(req, orgId);
|
|
141
|
+
if (req.actor.type === "board") {
|
|
142
|
+
if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
|
|
143
|
+
return null;
|
|
144
|
+
const allowed = await access.canUser(orgId, req.actor.userId, "agents:create");
|
|
145
|
+
if (!allowed) {
|
|
146
|
+
throw forbidden("Missing permission: agents:create");
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
if (!req.actor.agentId)
|
|
151
|
+
throw forbidden("Agent authentication required");
|
|
152
|
+
const actorAgent = await svc.getById(req.actor.agentId);
|
|
153
|
+
if (!actorAgent || actorAgent.orgId !== orgId) {
|
|
154
|
+
throw forbidden("Agent key cannot access another organization");
|
|
155
|
+
}
|
|
156
|
+
const allowedByGrant = await access.hasPermission(orgId, "agent", actorAgent.id, "agents:create");
|
|
157
|
+
if (!allowedByGrant && !canCreateAgents(actorAgent)) {
|
|
158
|
+
throw forbidden("Missing permission: can create agents");
|
|
159
|
+
}
|
|
160
|
+
return actorAgent;
|
|
161
|
+
}
|
|
162
|
+
async function assertCanReadConfigurations(req, orgId) {
|
|
163
|
+
return assertCanCreateAgentsForCompany(req, orgId);
|
|
164
|
+
}
|
|
165
|
+
async function actorCanReadConfigurationsForCompany(req, orgId) {
|
|
166
|
+
assertCompanyAccess(req, orgId);
|
|
167
|
+
if (req.actor.type === "board") {
|
|
168
|
+
if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
|
|
169
|
+
return true;
|
|
170
|
+
return access.canUser(orgId, req.actor.userId, "agents:create");
|
|
171
|
+
}
|
|
172
|
+
if (!req.actor.agentId)
|
|
173
|
+
return false;
|
|
174
|
+
const actorAgent = await svc.getById(req.actor.agentId);
|
|
175
|
+
if (!actorAgent || actorAgent.orgId !== orgId)
|
|
176
|
+
return false;
|
|
177
|
+
const allowedByGrant = await access.hasPermission(orgId, "agent", actorAgent.id, "agents:create");
|
|
178
|
+
return allowedByGrant || canCreateAgents(actorAgent);
|
|
179
|
+
}
|
|
180
|
+
async function assertCanUpdateAgent(req, targetAgent) {
|
|
181
|
+
assertCompanyAccess(req, targetAgent.orgId);
|
|
182
|
+
if (req.actor.type === "board")
|
|
183
|
+
return;
|
|
184
|
+
if (!req.actor.agentId)
|
|
185
|
+
throw forbidden("Agent authentication required");
|
|
186
|
+
const actorAgent = await svc.getById(req.actor.agentId);
|
|
187
|
+
if (!actorAgent || actorAgent.orgId !== targetAgent.orgId) {
|
|
188
|
+
throw forbidden("Agent key cannot access another organization");
|
|
189
|
+
}
|
|
190
|
+
if (actorAgent.id === targetAgent.id)
|
|
191
|
+
return;
|
|
192
|
+
if (actorAgent.role === "ceo")
|
|
193
|
+
return;
|
|
194
|
+
const allowedByGrant = await access.hasPermission(targetAgent.orgId, "agent", actorAgent.id, "agents:create");
|
|
195
|
+
if (allowedByGrant || canCreateAgents(actorAgent))
|
|
196
|
+
return;
|
|
197
|
+
throw forbidden("Only CEO or agent creators can modify other agents");
|
|
198
|
+
}
|
|
199
|
+
async function assertCanReadAgent(req, targetAgent) {
|
|
200
|
+
assertCompanyAccess(req, targetAgent.orgId);
|
|
201
|
+
if (req.actor.type === "board")
|
|
202
|
+
return;
|
|
203
|
+
if (!req.actor.agentId)
|
|
204
|
+
throw forbidden("Agent authentication required");
|
|
205
|
+
const actorAgent = await svc.getById(req.actor.agentId);
|
|
206
|
+
if (!actorAgent || actorAgent.orgId !== targetAgent.orgId) {
|
|
207
|
+
throw forbidden("Agent key cannot access another organization");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function resolveOrgIdForAgentReference(req) {
|
|
211
|
+
const orgIdQuery = req.query.orgId;
|
|
212
|
+
const requestedOrgId = typeof orgIdQuery === "string" && orgIdQuery.trim().length > 0
|
|
213
|
+
? orgIdQuery.trim()
|
|
214
|
+
: null;
|
|
215
|
+
if (requestedOrgId) {
|
|
216
|
+
assertCompanyAccess(req, requestedOrgId);
|
|
217
|
+
return requestedOrgId;
|
|
218
|
+
}
|
|
219
|
+
if (req.actor.type === "agent" && req.actor.orgId) {
|
|
220
|
+
return req.actor.orgId;
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
async function normalizeAgentReference(req, rawId) {
|
|
225
|
+
const raw = rawId.trim();
|
|
226
|
+
if (isUuidLike(raw))
|
|
227
|
+
return raw;
|
|
228
|
+
const orgId = await resolveOrgIdForAgentReference(req);
|
|
229
|
+
if (!orgId) {
|
|
230
|
+
throw unprocessable("Agent shortname lookup requires orgId query parameter");
|
|
231
|
+
}
|
|
232
|
+
const resolved = await svc.resolveByReference(orgId, raw);
|
|
233
|
+
if (resolved.ambiguous) {
|
|
234
|
+
throw conflict("Agent shortname is ambiguous in this organization. Use the agent ID.");
|
|
235
|
+
}
|
|
236
|
+
if (!resolved.agent) {
|
|
237
|
+
throw notFound("Agent not found");
|
|
238
|
+
}
|
|
239
|
+
return resolved.agent.id;
|
|
240
|
+
}
|
|
241
|
+
function parseSourceIssueIds(input) {
|
|
242
|
+
const values = [];
|
|
243
|
+
if (Array.isArray(input.sourceIssueIds))
|
|
244
|
+
values.push(...input.sourceIssueIds);
|
|
245
|
+
if (typeof input.sourceIssueId === "string" && input.sourceIssueId.length > 0) {
|
|
246
|
+
values.push(input.sourceIssueId);
|
|
247
|
+
}
|
|
248
|
+
return Array.from(new Set(values));
|
|
249
|
+
}
|
|
250
|
+
function asRecord(value) {
|
|
251
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
252
|
+
return null;
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
function asNonEmptyString(value) {
|
|
256
|
+
if (typeof value !== "string")
|
|
257
|
+
return null;
|
|
258
|
+
const trimmed = value.trim();
|
|
259
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
260
|
+
}
|
|
261
|
+
function preserveInstructionsBundleConfig(existingAdapterConfig, nextAdapterConfig) {
|
|
262
|
+
const nextKeys = new Set(Object.keys(nextAdapterConfig));
|
|
263
|
+
if (KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => nextKeys.has(key))) {
|
|
264
|
+
return nextAdapterConfig;
|
|
265
|
+
}
|
|
266
|
+
const merged = { ...nextAdapterConfig };
|
|
267
|
+
for (const key of KNOWN_INSTRUCTIONS_BUNDLE_KEYS) {
|
|
268
|
+
if (merged[key] === undefined && existingAdapterConfig[key] !== undefined) {
|
|
269
|
+
merged[key] = existingAdapterConfig[key];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return merged;
|
|
273
|
+
}
|
|
274
|
+
function parseBooleanLike(value) {
|
|
275
|
+
if (typeof value === "boolean")
|
|
276
|
+
return value;
|
|
277
|
+
if (typeof value === "number") {
|
|
278
|
+
if (value === 1)
|
|
279
|
+
return true;
|
|
280
|
+
if (value === 0)
|
|
281
|
+
return false;
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
if (typeof value !== "string")
|
|
285
|
+
return null;
|
|
286
|
+
const normalized = value.trim().toLowerCase();
|
|
287
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function parseNumberLike(value) {
|
|
296
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
297
|
+
return value;
|
|
298
|
+
if (typeof value !== "string")
|
|
299
|
+
return null;
|
|
300
|
+
const parsed = Number(value.trim());
|
|
301
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
302
|
+
}
|
|
303
|
+
function parseSchedulerHeartbeatPolicy(runtimeConfig) {
|
|
304
|
+
const heartbeat = asRecord(asRecord(runtimeConfig)?.heartbeat) ?? {};
|
|
305
|
+
return {
|
|
306
|
+
enabled: parseBooleanLike(heartbeat.enabled) ?? true,
|
|
307
|
+
intervalSec: Math.max(0, parseNumberLike(heartbeat.intervalSec) ?? 0),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function isHiddenSystemAgentMetadata(metadata) {
|
|
311
|
+
const parsed = asRecord(metadata);
|
|
312
|
+
return parsed?.hidden === true || parsed?.systemManaged === "rudder_copilot";
|
|
313
|
+
}
|
|
314
|
+
function generateEd25519PrivateKeyPem() {
|
|
315
|
+
const { privateKey } = generateKeyPairSync("ed25519");
|
|
316
|
+
return privateKey.export({ type: "pkcs8", format: "pem" }).toString();
|
|
317
|
+
}
|
|
318
|
+
function ensureGatewayDeviceKey(agentRuntimeType, agentRuntimeConfig) {
|
|
319
|
+
if (agentRuntimeType !== "openclaw_gateway")
|
|
320
|
+
return agentRuntimeConfig;
|
|
321
|
+
const disableDeviceAuth = parseBooleanLike(agentRuntimeConfig.disableDeviceAuth) === true;
|
|
322
|
+
if (disableDeviceAuth)
|
|
323
|
+
return agentRuntimeConfig;
|
|
324
|
+
if (asNonEmptyString(agentRuntimeConfig.devicePrivateKeyPem))
|
|
325
|
+
return agentRuntimeConfig;
|
|
326
|
+
return { ...agentRuntimeConfig, devicePrivateKeyPem: generateEd25519PrivateKeyPem() };
|
|
327
|
+
}
|
|
328
|
+
function applyCreateDefaultsByAdapterType(agentRuntimeType, agentRuntimeConfig) {
|
|
329
|
+
const next = { ...agentRuntimeConfig };
|
|
330
|
+
if (agentRuntimeType === "codex_local") {
|
|
331
|
+
if (!asNonEmptyString(next.model)) {
|
|
332
|
+
next.model = DEFAULT_CODEX_LOCAL_MODEL;
|
|
333
|
+
}
|
|
334
|
+
const hasBypassFlag = typeof next.dangerouslyBypassApprovalsAndSandbox === "boolean" ||
|
|
335
|
+
typeof next.dangerouslyBypassSandbox === "boolean";
|
|
336
|
+
if (!hasBypassFlag) {
|
|
337
|
+
next.dangerouslyBypassApprovalsAndSandbox = DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
|
|
338
|
+
}
|
|
339
|
+
return ensureGatewayDeviceKey(agentRuntimeType, next);
|
|
340
|
+
}
|
|
341
|
+
if (agentRuntimeType === "gemini_local" && !asNonEmptyString(next.model)) {
|
|
342
|
+
next.model = DEFAULT_GEMINI_LOCAL_MODEL;
|
|
343
|
+
return ensureGatewayDeviceKey(agentRuntimeType, next);
|
|
344
|
+
}
|
|
345
|
+
// OpenCode requires explicit model selection — no default
|
|
346
|
+
if (agentRuntimeType === "cursor" && !asNonEmptyString(next.model)) {
|
|
347
|
+
next.model = DEFAULT_CURSOR_LOCAL_MODEL;
|
|
348
|
+
}
|
|
349
|
+
return ensureGatewayDeviceKey(agentRuntimeType, next);
|
|
350
|
+
}
|
|
351
|
+
async function assertAdapterConfigConstraints(orgId, agentRuntimeType, agentRuntimeConfig) {
|
|
352
|
+
if (agentRuntimeType !== "opencode_local")
|
|
353
|
+
return;
|
|
354
|
+
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, agentRuntimeConfig);
|
|
355
|
+
const runtimeEnv = asRecord(runtimeConfig.env) ?? {};
|
|
356
|
+
try {
|
|
357
|
+
await ensureOpenCodeModelConfiguredAndAvailable({
|
|
358
|
+
model: runtimeConfig.model,
|
|
359
|
+
command: runtimeConfig.command,
|
|
360
|
+
cwd: runtimeConfig.cwd,
|
|
361
|
+
env: runtimeEnv,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
366
|
+
throw unprocessable(`Invalid opencode_local agentRuntimeConfig: ${reason}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function resolveInstructionsFilePath(candidatePath, agentRuntimeConfig) {
|
|
370
|
+
const trimmed = candidatePath.trim();
|
|
371
|
+
if (path.isAbsolute(trimmed))
|
|
372
|
+
return trimmed;
|
|
373
|
+
const cwd = asNonEmptyString(agentRuntimeConfig.cwd);
|
|
374
|
+
if (!cwd) {
|
|
375
|
+
throw unprocessable("Relative instructions path requires agentRuntimeConfig.cwd to be set to an absolute path");
|
|
376
|
+
}
|
|
377
|
+
if (!path.isAbsolute(cwd)) {
|
|
378
|
+
throw unprocessable("agentRuntimeConfig.cwd must be an absolute path to resolve relative instructions path");
|
|
379
|
+
}
|
|
380
|
+
return path.resolve(cwd, trimmed);
|
|
381
|
+
}
|
|
382
|
+
async function materializeDefaultInstructionsBundleForNewAgent(agent) {
|
|
383
|
+
if (!DEFAULT_MANAGED_INSTRUCTIONS_ADAPTER_TYPES.has(agent.agentRuntimeType)) {
|
|
384
|
+
return agent;
|
|
385
|
+
}
|
|
386
|
+
const agentRuntimeConfig = asRecord(agent.agentRuntimeConfig) ?? {};
|
|
387
|
+
const hasExplicitInstructionsBundle = Boolean(asNonEmptyString(agentRuntimeConfig.instructionsBundleMode))
|
|
388
|
+
|| Boolean(asNonEmptyString(agentRuntimeConfig.instructionsRootPath))
|
|
389
|
+
|| Boolean(asNonEmptyString(agentRuntimeConfig.instructionsEntryFile))
|
|
390
|
+
|| Boolean(asNonEmptyString(agentRuntimeConfig.instructionsFilePath))
|
|
391
|
+
|| Boolean(asNonEmptyString(agentRuntimeConfig.agentsMdPath));
|
|
392
|
+
if (hasExplicitInstructionsBundle) {
|
|
393
|
+
return agent;
|
|
394
|
+
}
|
|
395
|
+
const promptTemplate = typeof agentRuntimeConfig.promptTemplate === "string"
|
|
396
|
+
? agentRuntimeConfig.promptTemplate
|
|
397
|
+
: "";
|
|
398
|
+
// Always load the full default bundle, then override AGENTS.md with promptTemplate if provided
|
|
399
|
+
const defaultFiles = await loadDefaultAgentInstructionsBundle(resolveDefaultAgentInstructionsBundleRole(agent.role));
|
|
400
|
+
const files = promptTemplate.trim().length === 0
|
|
401
|
+
? defaultFiles
|
|
402
|
+
: { ...defaultFiles, "AGENTS.md": promptTemplate };
|
|
403
|
+
const materialized = await instructions.materializeManagedBundle(agent, files, { entryFile: "AGENTS.md", replaceExisting: false });
|
|
404
|
+
const nextAdapterConfig = { ...materialized.agentRuntimeConfig };
|
|
405
|
+
delete nextAdapterConfig.promptTemplate;
|
|
406
|
+
const updated = await svc.update(agent.id, { agentRuntimeConfig: nextAdapterConfig });
|
|
407
|
+
return updated ?? { ...agent, agentRuntimeConfig: nextAdapterConfig };
|
|
408
|
+
}
|
|
409
|
+
async function assertCanManageInstructionsPath(req, targetAgent) {
|
|
410
|
+
assertCompanyAccess(req, targetAgent.orgId);
|
|
411
|
+
if (req.actor.type === "board")
|
|
412
|
+
return;
|
|
413
|
+
if (!req.actor.agentId)
|
|
414
|
+
throw forbidden("Agent authentication required");
|
|
415
|
+
const actorAgent = await svc.getById(req.actor.agentId);
|
|
416
|
+
if (!actorAgent || actorAgent.orgId !== targetAgent.orgId) {
|
|
417
|
+
throw forbidden("Agent key cannot access another organization");
|
|
418
|
+
}
|
|
419
|
+
if (actorAgent.id === targetAgent.id)
|
|
420
|
+
return;
|
|
421
|
+
const chainOfCommand = await svc.getChainOfCommand(targetAgent.id);
|
|
422
|
+
if (chainOfCommand.some((manager) => manager.id === actorAgent.id))
|
|
423
|
+
return;
|
|
424
|
+
throw forbidden("Only the target agent or an ancestor manager can update instructions path");
|
|
425
|
+
}
|
|
426
|
+
function summarizeAgentUpdateDetails(patch) {
|
|
427
|
+
const changedTopLevelKeys = Object.keys(patch).sort();
|
|
428
|
+
const details = { changedTopLevelKeys };
|
|
429
|
+
const agentRuntimeConfigPatch = asRecord(patch.agentRuntimeConfig);
|
|
430
|
+
if (agentRuntimeConfigPatch) {
|
|
431
|
+
details.changedAdapterConfigKeys = Object.keys(agentRuntimeConfigPatch).sort();
|
|
432
|
+
}
|
|
433
|
+
const runtimeConfigPatch = asRecord(patch.runtimeConfig);
|
|
434
|
+
if (runtimeConfigPatch) {
|
|
435
|
+
details.changedRuntimeConfigKeys = Object.keys(runtimeConfigPatch).sort();
|
|
436
|
+
}
|
|
437
|
+
return details;
|
|
438
|
+
}
|
|
439
|
+
function buildUnsupportedSkillSnapshot(agentRuntimeType, desiredSkills = []) {
|
|
440
|
+
return {
|
|
441
|
+
agentRuntimeType,
|
|
442
|
+
supported: false,
|
|
443
|
+
mode: "unsupported",
|
|
444
|
+
desiredSkills,
|
|
445
|
+
entries: [],
|
|
446
|
+
warnings: ["This adapter does not implement skill sync yet."],
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
async function resolveDesiredSkillAssignment(orgId, agentRuntimeType, runtimeConfig, requestedDesiredSkills) {
|
|
450
|
+
return organizationSkills.resolveDesiredSkillSelectionForAgent({
|
|
451
|
+
id: null,
|
|
452
|
+
orgId,
|
|
453
|
+
agentRuntimeConfig: {},
|
|
454
|
+
agentRuntimeType,
|
|
455
|
+
}, runtimeConfig, requestedDesiredSkills);
|
|
456
|
+
}
|
|
457
|
+
async function resolveDesiredSkillAssignmentForAgent(agent, runtimeConfig, requestedDesiredSkills) {
|
|
458
|
+
if (!agent) {
|
|
459
|
+
return {
|
|
460
|
+
desiredSkills: [],
|
|
461
|
+
warnings: [],
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
return organizationSkills.resolveDesiredSkillSelectionForAgent(agent, runtimeConfig, requestedDesiredSkills);
|
|
465
|
+
}
|
|
466
|
+
async function buildAgentSkillSnapshot(agent, runtimeConfig) {
|
|
467
|
+
if (!agent) {
|
|
468
|
+
return buildUnsupportedSkillSnapshot("", []);
|
|
469
|
+
}
|
|
470
|
+
const snapshot = await organizationSkills.buildAgentSkillSnapshot(agent, runtimeConfig);
|
|
471
|
+
if (!snapshot.supported) {
|
|
472
|
+
return buildUnsupportedSkillSnapshot(agent.agentRuntimeType, snapshot.desiredSkills);
|
|
473
|
+
}
|
|
474
|
+
return snapshot;
|
|
475
|
+
}
|
|
476
|
+
function redactForRestrictedAgentView(agent) {
|
|
477
|
+
if (!agent)
|
|
478
|
+
return null;
|
|
479
|
+
return {
|
|
480
|
+
...agent,
|
|
481
|
+
agentRuntimeConfig: {},
|
|
482
|
+
runtimeConfig: {},
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function redactAgentConfiguration(agent) {
|
|
486
|
+
if (!agent)
|
|
487
|
+
return null;
|
|
488
|
+
return {
|
|
489
|
+
id: agent.id,
|
|
490
|
+
orgId: agent.orgId,
|
|
491
|
+
name: agent.name,
|
|
492
|
+
role: agent.role,
|
|
493
|
+
title: agent.title,
|
|
494
|
+
status: agent.status,
|
|
495
|
+
reportsTo: agent.reportsTo,
|
|
496
|
+
agentRuntimeType: agent.agentRuntimeType,
|
|
497
|
+
agentRuntimeConfig: redactEventPayload(agent.agentRuntimeConfig),
|
|
498
|
+
runtimeConfig: redactEventPayload(agent.runtimeConfig),
|
|
499
|
+
permissions: agent.permissions,
|
|
500
|
+
updatedAt: agent.updatedAt,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function redactRevisionSnapshot(snapshot) {
|
|
504
|
+
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
|
|
505
|
+
return {};
|
|
506
|
+
const record = snapshot;
|
|
507
|
+
return {
|
|
508
|
+
...record,
|
|
509
|
+
agentRuntimeConfig: redactEventPayload(typeof record.agentRuntimeConfig === "object" && record.agentRuntimeConfig !== null
|
|
510
|
+
? record.agentRuntimeConfig
|
|
511
|
+
: {}),
|
|
512
|
+
runtimeConfig: redactEventPayload(typeof record.runtimeConfig === "object" && record.runtimeConfig !== null
|
|
513
|
+
? record.runtimeConfig
|
|
514
|
+
: {}),
|
|
515
|
+
metadata: typeof record.metadata === "object" && record.metadata !== null
|
|
516
|
+
? redactEventPayload(record.metadata)
|
|
517
|
+
: record.metadata ?? null,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
function redactConfigRevision(revision) {
|
|
521
|
+
return {
|
|
522
|
+
...revision,
|
|
523
|
+
beforeConfig: redactRevisionSnapshot(revision.beforeConfig),
|
|
524
|
+
afterConfig: redactRevisionSnapshot(revision.afterConfig),
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function toLeanOrgNode(node) {
|
|
528
|
+
const reports = Array.isArray(node.reports)
|
|
529
|
+
? node.reports.map((report) => toLeanOrgNode(report))
|
|
530
|
+
: [];
|
|
531
|
+
return {
|
|
532
|
+
id: String(node.id),
|
|
533
|
+
name: String(node.name),
|
|
534
|
+
role: String(node.role),
|
|
535
|
+
status: String(node.status),
|
|
536
|
+
reports,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
router.param("id", async (req, _res, next, rawId) => {
|
|
540
|
+
try {
|
|
541
|
+
req.params.id = await normalizeAgentReference(req, String(rawId));
|
|
542
|
+
next();
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
next(err);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
router.get("/orgs/:orgId/adapters/:type/models", async (req, res) => {
|
|
549
|
+
const orgId = req.params.orgId;
|
|
550
|
+
assertCompanyAccess(req, orgId);
|
|
551
|
+
const type = req.params.type;
|
|
552
|
+
const models = await listAgentRuntimeModels(type);
|
|
553
|
+
res.json(models);
|
|
554
|
+
});
|
|
555
|
+
router.post("/orgs/:orgId/adapters/:type/test-environment", validate(testAgentRuntimeEnvironmentSchema), async (req, res) => {
|
|
556
|
+
const orgId = req.params.orgId;
|
|
557
|
+
const type = req.params.type;
|
|
558
|
+
await assertCanReadConfigurations(req, orgId);
|
|
559
|
+
const adapter = findServerAdapter(type);
|
|
560
|
+
if (!adapter) {
|
|
561
|
+
res.status(404).json({ error: `Unknown adapter type: ${type}` });
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const inputAdapterConfig = (req.body?.agentRuntimeConfig ?? {});
|
|
565
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(orgId, inputAdapterConfig, { strictMode: strictSecretsMode });
|
|
566
|
+
const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, normalizedAdapterConfig);
|
|
567
|
+
const result = await adapter.testEnvironment({
|
|
568
|
+
orgId,
|
|
569
|
+
agentRuntimeType: type,
|
|
570
|
+
config: runtimeAdapterConfig,
|
|
571
|
+
});
|
|
572
|
+
res.json(result);
|
|
573
|
+
});
|
|
574
|
+
router.get("/agents/:id/skills", async (req, res) => {
|
|
575
|
+
const id = req.params.id;
|
|
576
|
+
const agent = await svc.getById(id);
|
|
577
|
+
if (!agent) {
|
|
578
|
+
res.status(404).json({ error: "Agent not found" });
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
await assertCanReadAgent(req, agent);
|
|
582
|
+
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.orgId, agent.agentRuntimeConfig);
|
|
583
|
+
const snapshot = await buildAgentSkillSnapshot(agent, runtimeConfig);
|
|
584
|
+
res.json(snapshot);
|
|
585
|
+
});
|
|
586
|
+
router.get("/agents/:id/skills/analytics", async (req, res) => {
|
|
587
|
+
const id = req.params.id;
|
|
588
|
+
const agent = await svc.getById(id);
|
|
589
|
+
if (!agent) {
|
|
590
|
+
res.status(404).json({ error: "Agent not found" });
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
await assertCanReadAgent(req, agent);
|
|
594
|
+
const rawWindowDays = typeof req.query.windowDays === "string"
|
|
595
|
+
? Number.parseInt(req.query.windowDays, 10)
|
|
596
|
+
: undefined;
|
|
597
|
+
const startDate = typeof req.query.startDate === "string" && /^\d{4}-\d{2}-\d{2}$/.test(req.query.startDate)
|
|
598
|
+
? req.query.startDate
|
|
599
|
+
: undefined;
|
|
600
|
+
const endDate = typeof req.query.endDate === "string" && /^\d{4}-\d{2}-\d{2}$/.test(req.query.endDate)
|
|
601
|
+
? req.query.endDate
|
|
602
|
+
: undefined;
|
|
603
|
+
const analytics = await heartbeat.getAgentSkillAnalytics(agent.id, {
|
|
604
|
+
windowDays: Number.isFinite(rawWindowDays) ? rawWindowDays : undefined,
|
|
605
|
+
startDate,
|
|
606
|
+
endDate,
|
|
607
|
+
});
|
|
608
|
+
res.json(analytics);
|
|
609
|
+
});
|
|
610
|
+
router.post("/agents/:id/skills/private", validate(organizationSkillCreateSchema), async (req, res) => {
|
|
611
|
+
const id = req.params.id;
|
|
612
|
+
const agent = await svc.getById(id);
|
|
613
|
+
if (!agent) {
|
|
614
|
+
res.status(404).json({ error: "Agent not found" });
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
await assertCanUpdateAgent(req, agent);
|
|
618
|
+
const entry = await organizationSkills.createAgentPrivateSkill(agent.orgId, agent.id, req.body);
|
|
619
|
+
const actor = getActorInfo(req);
|
|
620
|
+
await logActivity(db, {
|
|
621
|
+
orgId: agent.orgId,
|
|
622
|
+
actorType: actor.actorType,
|
|
623
|
+
actorId: actor.actorId,
|
|
624
|
+
agentId: actor.agentId,
|
|
625
|
+
runId: actor.runId,
|
|
626
|
+
action: "agent.private_skill_created",
|
|
627
|
+
entityType: "agent",
|
|
628
|
+
entityId: agent.id,
|
|
629
|
+
details: {
|
|
630
|
+
slug: entry.key,
|
|
631
|
+
selectionKey: entry.selectionKey,
|
|
632
|
+
sourcePath: entry.sourcePath ?? null,
|
|
633
|
+
},
|
|
634
|
+
});
|
|
635
|
+
res.status(201).json(entry);
|
|
636
|
+
});
|
|
637
|
+
router.post("/agents/:id/skills/sync", validate(agentSkillSyncSchema), async (req, res) => {
|
|
638
|
+
const id = req.params.id;
|
|
639
|
+
const agent = await svc.getById(id);
|
|
640
|
+
if (!agent) {
|
|
641
|
+
res.status(404).json({ error: "Agent not found" });
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
await assertCanUpdateAgent(req, agent);
|
|
645
|
+
const requestedSkills = Array.from(new Set(req.body.desiredSkills
|
|
646
|
+
.map((value) => value.trim())
|
|
647
|
+
.filter(Boolean)));
|
|
648
|
+
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.orgId, agent.agentRuntimeConfig);
|
|
649
|
+
const { desiredSkills } = await resolveDesiredSkillAssignmentForAgent(agent, runtimeConfig, requestedSkills);
|
|
650
|
+
const actor = getActorInfo(req);
|
|
651
|
+
await organizationSkills.replaceEnabledSkillKeysForAgent(agent.orgId, agent.id, desiredSkills);
|
|
652
|
+
const sanitizedAdapterConfig = stripPersistedSkillSyncConfig(agent.agentRuntimeConfig ?? {});
|
|
653
|
+
let updatedAgent = agent;
|
|
654
|
+
if (JSON.stringify(sanitizedAdapterConfig) !== JSON.stringify(agent.agentRuntimeConfig ?? {})) {
|
|
655
|
+
updatedAgent = await svc.update(agent.id, {
|
|
656
|
+
agentRuntimeConfig: sanitizedAdapterConfig,
|
|
657
|
+
}, {
|
|
658
|
+
recordRevision: {
|
|
659
|
+
createdByAgentId: actor.agentId,
|
|
660
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
661
|
+
source: "skill-sync",
|
|
662
|
+
},
|
|
663
|
+
}) ?? agent;
|
|
664
|
+
}
|
|
665
|
+
const updated = updatedAgent;
|
|
666
|
+
const { config: updatedRuntimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(updated.orgId, updated.agentRuntimeConfig);
|
|
667
|
+
const snapshot = await buildAgentSkillSnapshot(updated, updatedRuntimeConfig);
|
|
668
|
+
await logActivity(db, {
|
|
669
|
+
orgId: updated.orgId,
|
|
670
|
+
actorType: actor.actorType,
|
|
671
|
+
actorId: actor.actorId,
|
|
672
|
+
action: "agent.skills_synced",
|
|
673
|
+
entityType: "agent",
|
|
674
|
+
entityId: updated.id,
|
|
675
|
+
agentId: actor.agentId,
|
|
676
|
+
runId: actor.runId,
|
|
677
|
+
details: {
|
|
678
|
+
agentRuntimeType: updated.agentRuntimeType,
|
|
679
|
+
desiredSkills,
|
|
680
|
+
mode: snapshot.mode,
|
|
681
|
+
supported: snapshot.supported,
|
|
682
|
+
entryCount: snapshot.entries.length,
|
|
683
|
+
warningCount: snapshot.warnings.length,
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
res.json(snapshot);
|
|
687
|
+
});
|
|
688
|
+
router.get("/orgs/:orgId/agents", async (req, res) => {
|
|
689
|
+
const orgId = req.params.orgId;
|
|
690
|
+
assertCompanyAccess(req, orgId);
|
|
691
|
+
const result = await svc.list(orgId);
|
|
692
|
+
const canReadConfigs = await actorCanReadConfigurationsForCompany(req, orgId);
|
|
693
|
+
if (canReadConfigs || req.actor.type === "board") {
|
|
694
|
+
res.json(result);
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
res.json(result.map((agent) => redactForRestrictedAgentView(agent)));
|
|
698
|
+
});
|
|
699
|
+
router.get("/orgs/:orgId/agents/name-suggestion", async (req, res) => {
|
|
700
|
+
const orgId = req.params.orgId;
|
|
701
|
+
await assertCanCreateAgentsForCompany(req, orgId);
|
|
702
|
+
const name = await svc.suggestName(orgId);
|
|
703
|
+
res.json({ name });
|
|
704
|
+
});
|
|
705
|
+
router.get("/instance/scheduler-heartbeats", async (req, res) => {
|
|
706
|
+
assertInstanceAdmin(req);
|
|
707
|
+
const rows = await db
|
|
708
|
+
.select({
|
|
709
|
+
id: agentsTable.id,
|
|
710
|
+
orgId: agentsTable.orgId,
|
|
711
|
+
agentName: agentsTable.name,
|
|
712
|
+
role: agentsTable.role,
|
|
713
|
+
title: agentsTable.title,
|
|
714
|
+
status: agentsTable.status,
|
|
715
|
+
agentRuntimeType: agentsTable.agentRuntimeType,
|
|
716
|
+
runtimeConfig: agentsTable.runtimeConfig,
|
|
717
|
+
lastHeartbeatAt: agentsTable.lastHeartbeatAt,
|
|
718
|
+
metadata: agentsTable.metadata,
|
|
719
|
+
organizationName: organizations.name,
|
|
720
|
+
organizationIssuePrefix: organizations.issuePrefix,
|
|
721
|
+
})
|
|
722
|
+
.from(agentsTable)
|
|
723
|
+
.innerJoin(organizations, eq(agentsTable.orgId, organizations.id))
|
|
724
|
+
.orderBy(organizations.name, agentsTable.name);
|
|
725
|
+
const items = rows
|
|
726
|
+
.filter((row) => !isHiddenSystemAgentMetadata(row.metadata))
|
|
727
|
+
.map((row) => {
|
|
728
|
+
const policy = parseSchedulerHeartbeatPolicy(row.runtimeConfig);
|
|
729
|
+
const statusEligible = row.status !== "paused" &&
|
|
730
|
+
row.status !== "terminated" &&
|
|
731
|
+
row.status !== "pending_approval";
|
|
732
|
+
return {
|
|
733
|
+
id: row.id,
|
|
734
|
+
orgId: row.orgId,
|
|
735
|
+
organizationName: row.organizationName,
|
|
736
|
+
organizationIssuePrefix: row.organizationIssuePrefix,
|
|
737
|
+
agentName: row.agentName,
|
|
738
|
+
agentUrlKey: deriveAgentUrlKey(row.agentName, row.id),
|
|
739
|
+
role: row.role,
|
|
740
|
+
title: row.title,
|
|
741
|
+
status: row.status,
|
|
742
|
+
agentRuntimeType: row.agentRuntimeType,
|
|
743
|
+
intervalSec: policy.intervalSec,
|
|
744
|
+
heartbeatEnabled: policy.enabled,
|
|
745
|
+
schedulerActive: statusEligible && policy.enabled && policy.intervalSec > 0,
|
|
746
|
+
lastHeartbeatAt: row.lastHeartbeatAt,
|
|
747
|
+
};
|
|
748
|
+
})
|
|
749
|
+
.filter((item) => item.status !== "paused" &&
|
|
750
|
+
item.status !== "terminated" &&
|
|
751
|
+
item.status !== "pending_approval")
|
|
752
|
+
.sort((left, right) => {
|
|
753
|
+
if (left.schedulerActive !== right.schedulerActive) {
|
|
754
|
+
return left.schedulerActive ? -1 : 1;
|
|
755
|
+
}
|
|
756
|
+
const organizationOrder = left.organizationName.localeCompare(right.organizationName);
|
|
757
|
+
if (organizationOrder !== 0)
|
|
758
|
+
return organizationOrder;
|
|
759
|
+
return left.agentName.localeCompare(right.agentName);
|
|
760
|
+
});
|
|
761
|
+
res.json(items);
|
|
762
|
+
});
|
|
763
|
+
router.get("/orgs/:orgId/org", async (req, res) => {
|
|
764
|
+
const orgId = req.params.orgId;
|
|
765
|
+
assertCompanyAccess(req, orgId);
|
|
766
|
+
const tree = await svc.orgForCompany(orgId);
|
|
767
|
+
const leanTree = tree.map((node) => toLeanOrgNode(node));
|
|
768
|
+
res.json(leanTree);
|
|
769
|
+
});
|
|
770
|
+
router.get("/orgs/:orgId/org.svg", async (req, res) => {
|
|
771
|
+
const orgId = req.params.orgId;
|
|
772
|
+
assertCompanyAccess(req, orgId);
|
|
773
|
+
const style = (ORG_CHART_STYLES.includes(req.query.style) ? req.query.style : "warmth");
|
|
774
|
+
const tree = await svc.orgForCompany(orgId);
|
|
775
|
+
const leanTree = tree.map((node) => toLeanOrgNode(node));
|
|
776
|
+
const svg = renderOrgChartSvg(leanTree, style);
|
|
777
|
+
res.setHeader("Content-Type", "image/svg+xml");
|
|
778
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
779
|
+
res.send(svg);
|
|
780
|
+
});
|
|
781
|
+
router.get("/orgs/:orgId/org.png", async (req, res) => {
|
|
782
|
+
const orgId = req.params.orgId;
|
|
783
|
+
assertCompanyAccess(req, orgId);
|
|
784
|
+
const style = (ORG_CHART_STYLES.includes(req.query.style) ? req.query.style : "warmth");
|
|
785
|
+
const tree = await svc.orgForCompany(orgId);
|
|
786
|
+
const leanTree = tree.map((node) => toLeanOrgNode(node));
|
|
787
|
+
const png = await renderOrgChartPng(leanTree, style);
|
|
788
|
+
res.setHeader("Content-Type", "image/png");
|
|
789
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
790
|
+
res.send(png);
|
|
791
|
+
});
|
|
792
|
+
router.get("/orgs/:orgId/agent-configurations", async (req, res) => {
|
|
793
|
+
const orgId = req.params.orgId;
|
|
794
|
+
await assertCanReadConfigurations(req, orgId);
|
|
795
|
+
const rows = await svc.list(orgId);
|
|
796
|
+
res.json(rows.map((row) => redactAgentConfiguration(row)));
|
|
797
|
+
});
|
|
798
|
+
router.get("/agents/me", async (req, res) => {
|
|
799
|
+
if (req.actor.type !== "agent" || !req.actor.agentId) {
|
|
800
|
+
res.status(401).json({ error: "Agent authentication required" });
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const agent = await svc.getById(req.actor.agentId);
|
|
804
|
+
if (!agent) {
|
|
805
|
+
res.status(404).json({ error: "Agent not found" });
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
res.json(await buildAgentDetail(agent));
|
|
809
|
+
});
|
|
810
|
+
router.get("/agents/me/inbox-lite", async (req, res) => {
|
|
811
|
+
if (req.actor.type !== "agent" || !req.actor.agentId || !req.actor.orgId) {
|
|
812
|
+
res.status(401).json({ error: "Agent authentication required" });
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const issuesSvc = issueService(db);
|
|
816
|
+
const rows = await issuesSvc.list(req.actor.orgId, {
|
|
817
|
+
assigneeAgentId: req.actor.agentId,
|
|
818
|
+
status: "todo,in_progress,blocked",
|
|
819
|
+
});
|
|
820
|
+
res.json(rows.map((issue) => ({
|
|
821
|
+
id: issue.id,
|
|
822
|
+
identifier: issue.identifier,
|
|
823
|
+
title: issue.title,
|
|
824
|
+
status: issue.status,
|
|
825
|
+
priority: issue.priority,
|
|
826
|
+
projectId: issue.projectId,
|
|
827
|
+
goalId: issue.goalId,
|
|
828
|
+
parentId: issue.parentId,
|
|
829
|
+
updatedAt: issue.updatedAt,
|
|
830
|
+
activeRun: issue.activeRun,
|
|
831
|
+
})));
|
|
832
|
+
});
|
|
833
|
+
router.get("/agents/:id", async (req, res) => {
|
|
834
|
+
const id = req.params.id;
|
|
835
|
+
const agent = await svc.getById(id);
|
|
836
|
+
if (!agent) {
|
|
837
|
+
res.status(404).json({ error: "Agent not found" });
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
assertCompanyAccess(req, agent.orgId);
|
|
841
|
+
if (req.actor.type === "agent" && req.actor.agentId !== id) {
|
|
842
|
+
const canRead = await actorCanReadConfigurationsForCompany(req, agent.orgId);
|
|
843
|
+
if (!canRead) {
|
|
844
|
+
res.json(await buildAgentDetail(agent, { restricted: true }));
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
res.json(await buildAgentDetail(agent));
|
|
849
|
+
});
|
|
850
|
+
router.get("/agents/:id/configuration", async (req, res) => {
|
|
851
|
+
const id = req.params.id;
|
|
852
|
+
const agent = await svc.getById(id);
|
|
853
|
+
if (!agent) {
|
|
854
|
+
res.status(404).json({ error: "Agent not found" });
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
await assertCanReadConfigurations(req, agent.orgId);
|
|
858
|
+
res.json(redactAgentConfiguration(agent));
|
|
859
|
+
});
|
|
860
|
+
router.get("/agents/:id/config-revisions", async (req, res) => {
|
|
861
|
+
const id = req.params.id;
|
|
862
|
+
const agent = await svc.getById(id);
|
|
863
|
+
if (!agent) {
|
|
864
|
+
res.status(404).json({ error: "Agent not found" });
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
await assertCanReadConfigurations(req, agent.orgId);
|
|
868
|
+
const revisions = await svc.listConfigRevisions(id);
|
|
869
|
+
res.json(revisions.map((revision) => redactConfigRevision(revision)));
|
|
870
|
+
});
|
|
871
|
+
router.get("/agents/:id/config-revisions/:revisionId", async (req, res) => {
|
|
872
|
+
const id = req.params.id;
|
|
873
|
+
const revisionId = req.params.revisionId;
|
|
874
|
+
const agent = await svc.getById(id);
|
|
875
|
+
if (!agent) {
|
|
876
|
+
res.status(404).json({ error: "Agent not found" });
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
await assertCanReadConfigurations(req, agent.orgId);
|
|
880
|
+
const revision = await svc.getConfigRevision(id, revisionId);
|
|
881
|
+
if (!revision) {
|
|
882
|
+
res.status(404).json({ error: "Revision not found" });
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
res.json(redactConfigRevision(revision));
|
|
886
|
+
});
|
|
887
|
+
router.post("/agents/:id/config-revisions/:revisionId/rollback", async (req, res) => {
|
|
888
|
+
const id = req.params.id;
|
|
889
|
+
const revisionId = req.params.revisionId;
|
|
890
|
+
const existing = await svc.getById(id);
|
|
891
|
+
if (!existing) {
|
|
892
|
+
res.status(404).json({ error: "Agent not found" });
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
await assertCanUpdateAgent(req, existing);
|
|
896
|
+
const actor = getActorInfo(req);
|
|
897
|
+
const updated = await svc.rollbackConfigRevision(id, revisionId, {
|
|
898
|
+
agentId: actor.agentId,
|
|
899
|
+
userId: actor.actorType === "user" ? actor.actorId : null,
|
|
900
|
+
});
|
|
901
|
+
if (!updated) {
|
|
902
|
+
res.status(404).json({ error: "Revision not found" });
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
await logActivity(db, {
|
|
906
|
+
orgId: updated.orgId,
|
|
907
|
+
actorType: actor.actorType,
|
|
908
|
+
actorId: actor.actorId,
|
|
909
|
+
agentId: actor.agentId,
|
|
910
|
+
runId: actor.runId,
|
|
911
|
+
action: "agent.config_rolled_back",
|
|
912
|
+
entityType: "agent",
|
|
913
|
+
entityId: updated.id,
|
|
914
|
+
details: { revisionId },
|
|
915
|
+
});
|
|
916
|
+
res.json(updated);
|
|
917
|
+
});
|
|
918
|
+
router.get("/agents/:id/runtime-state", async (req, res) => {
|
|
919
|
+
assertBoard(req);
|
|
920
|
+
const id = req.params.id;
|
|
921
|
+
const agent = await svc.getById(id);
|
|
922
|
+
if (!agent) {
|
|
923
|
+
res.status(404).json({ error: "Agent not found" });
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
assertCompanyAccess(req, agent.orgId);
|
|
927
|
+
const state = await heartbeat.getRuntimeState(id);
|
|
928
|
+
res.json(state);
|
|
929
|
+
});
|
|
930
|
+
router.get("/agents/:id/task-sessions", async (req, res) => {
|
|
931
|
+
assertBoard(req);
|
|
932
|
+
const id = req.params.id;
|
|
933
|
+
const agent = await svc.getById(id);
|
|
934
|
+
if (!agent) {
|
|
935
|
+
res.status(404).json({ error: "Agent not found" });
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
assertCompanyAccess(req, agent.orgId);
|
|
939
|
+
const sessions = await heartbeat.listTaskSessions(id);
|
|
940
|
+
res.json(sessions.map((session) => ({
|
|
941
|
+
...session,
|
|
942
|
+
sessionParamsJson: redactEventPayload(session.sessionParamsJson ?? null),
|
|
943
|
+
})));
|
|
944
|
+
});
|
|
945
|
+
router.post("/agents/:id/runtime-state/reset-session", validate(resetAgentSessionSchema), async (req, res) => {
|
|
946
|
+
assertBoard(req);
|
|
947
|
+
const id = req.params.id;
|
|
948
|
+
const agent = await svc.getById(id);
|
|
949
|
+
if (!agent) {
|
|
950
|
+
res.status(404).json({ error: "Agent not found" });
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
assertCompanyAccess(req, agent.orgId);
|
|
954
|
+
const taskKey = typeof req.body.taskKey === "string" && req.body.taskKey.trim().length > 0
|
|
955
|
+
? req.body.taskKey.trim()
|
|
956
|
+
: null;
|
|
957
|
+
const state = await heartbeat.resetRuntimeSession(id, { taskKey });
|
|
958
|
+
await logActivity(db, {
|
|
959
|
+
orgId: agent.orgId,
|
|
960
|
+
actorType: "user",
|
|
961
|
+
actorId: req.actor.userId ?? "board",
|
|
962
|
+
action: "agent.runtime_session_reset",
|
|
963
|
+
entityType: "agent",
|
|
964
|
+
entityId: id,
|
|
965
|
+
details: { taskKey: taskKey ?? null },
|
|
966
|
+
});
|
|
967
|
+
res.json(state);
|
|
968
|
+
});
|
|
969
|
+
router.post("/orgs/:orgId/agent-hires", validate(createAgentHireSchema), async (req, res) => {
|
|
970
|
+
const orgId = req.params.orgId;
|
|
971
|
+
await assertCanCreateAgentsForCompany(req, orgId);
|
|
972
|
+
const sourceIssueIds = parseSourceIssueIds(req.body);
|
|
973
|
+
const { desiredSkills: requestedDesiredSkills, sourceIssueId: _sourceIssueId, sourceIssueIds: _sourceIssueIds, ...hireInput } = req.body;
|
|
974
|
+
const requestedAdapterConfig = applyCreateDefaultsByAdapterType(hireInput.agentRuntimeType, (hireInput.agentRuntimeConfig ?? {}));
|
|
975
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(orgId, stripPersistedSkillSyncConfig(requestedAdapterConfig), { strictMode: strictSecretsMode });
|
|
976
|
+
const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, normalizedAdapterConfig);
|
|
977
|
+
const desiredSkillAssignment = await resolveDesiredSkillAssignment(orgId, hireInput.agentRuntimeType, runtimeAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
|
|
978
|
+
await assertAdapterConfigConstraints(orgId, hireInput.agentRuntimeType, normalizedAdapterConfig);
|
|
979
|
+
const normalizedHireInput = {
|
|
980
|
+
...hireInput,
|
|
981
|
+
agentRuntimeConfig: normalizedAdapterConfig,
|
|
982
|
+
};
|
|
983
|
+
const organization = await db
|
|
984
|
+
.select()
|
|
985
|
+
.from(organizations)
|
|
986
|
+
.where(eq(organizations.id, orgId))
|
|
987
|
+
.then((rows) => rows[0] ?? null);
|
|
988
|
+
if (!organization) {
|
|
989
|
+
res.status(404).json({ error: "Organization not found" });
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const requiresApproval = organization.requireBoardApprovalForNewAgents;
|
|
993
|
+
const status = requiresApproval ? "pending_approval" : "idle";
|
|
994
|
+
const createdAgent = await svc.create(orgId, {
|
|
995
|
+
...normalizedHireInput,
|
|
996
|
+
status,
|
|
997
|
+
spentMonthlyCents: 0,
|
|
998
|
+
lastHeartbeatAt: null,
|
|
999
|
+
});
|
|
1000
|
+
await organizationSkills.replaceEnabledSkillKeysForAgent(orgId, createdAgent.id, desiredSkillAssignment.desiredSkills);
|
|
1001
|
+
const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent);
|
|
1002
|
+
let approval = null;
|
|
1003
|
+
const actor = getActorInfo(req);
|
|
1004
|
+
if (requiresApproval) {
|
|
1005
|
+
const requestedAdapterType = normalizedHireInput.agentRuntimeType ?? agent.agentRuntimeType;
|
|
1006
|
+
const requestedAdapterConfig = redactEventPayload((agent.agentRuntimeConfig ?? normalizedHireInput.agentRuntimeConfig)) ?? {};
|
|
1007
|
+
const requestedRuntimeConfig = redactEventPayload((normalizedHireInput.runtimeConfig ?? agent.runtimeConfig)) ?? {};
|
|
1008
|
+
const requestedMetadata = redactEventPayload((normalizedHireInput.metadata ?? agent.metadata ?? {})) ?? {};
|
|
1009
|
+
approval = await approvalsSvc.create(orgId, {
|
|
1010
|
+
type: "hire_agent",
|
|
1011
|
+
requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
|
|
1012
|
+
requestedByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1013
|
+
status: "pending",
|
|
1014
|
+
payload: {
|
|
1015
|
+
name: agent.name,
|
|
1016
|
+
role: normalizedHireInput.role,
|
|
1017
|
+
title: normalizedHireInput.title ?? null,
|
|
1018
|
+
icon: normalizedHireInput.icon ?? null,
|
|
1019
|
+
reportsTo: normalizedHireInput.reportsTo ?? null,
|
|
1020
|
+
capabilities: normalizedHireInput.capabilities ?? null,
|
|
1021
|
+
agentRuntimeType: requestedAdapterType,
|
|
1022
|
+
agentRuntimeConfig: requestedAdapterConfig,
|
|
1023
|
+
runtimeConfig: requestedRuntimeConfig,
|
|
1024
|
+
budgetMonthlyCents: typeof normalizedHireInput.budgetMonthlyCents === "number"
|
|
1025
|
+
? normalizedHireInput.budgetMonthlyCents
|
|
1026
|
+
: agent.budgetMonthlyCents,
|
|
1027
|
+
desiredSkills: desiredSkillAssignment.desiredSkills,
|
|
1028
|
+
metadata: requestedMetadata,
|
|
1029
|
+
agentId: agent.id,
|
|
1030
|
+
requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
|
|
1031
|
+
requestedConfigurationSnapshot: {
|
|
1032
|
+
agentRuntimeType: requestedAdapterType,
|
|
1033
|
+
agentRuntimeConfig: requestedAdapterConfig,
|
|
1034
|
+
runtimeConfig: requestedRuntimeConfig,
|
|
1035
|
+
desiredSkills: desiredSkillAssignment.desiredSkills,
|
|
1036
|
+
},
|
|
1037
|
+
},
|
|
1038
|
+
decisionNote: null,
|
|
1039
|
+
decidedByUserId: null,
|
|
1040
|
+
decidedAt: null,
|
|
1041
|
+
updatedAt: new Date(),
|
|
1042
|
+
});
|
|
1043
|
+
if (sourceIssueIds.length > 0) {
|
|
1044
|
+
await issueApprovalsSvc.linkManyForApproval(approval.id, sourceIssueIds, {
|
|
1045
|
+
agentId: actor.actorType === "agent" ? actor.actorId : null,
|
|
1046
|
+
userId: actor.actorType === "user" ? actor.actorId : null,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
await logActivity(db, {
|
|
1051
|
+
orgId,
|
|
1052
|
+
actorType: actor.actorType,
|
|
1053
|
+
actorId: actor.actorId,
|
|
1054
|
+
agentId: actor.agentId,
|
|
1055
|
+
runId: actor.runId,
|
|
1056
|
+
action: "agent.hire_created",
|
|
1057
|
+
entityType: "agent",
|
|
1058
|
+
entityId: agent.id,
|
|
1059
|
+
details: {
|
|
1060
|
+
name: agent.name,
|
|
1061
|
+
role: agent.role,
|
|
1062
|
+
requiresApproval,
|
|
1063
|
+
approvalId: approval?.id ?? null,
|
|
1064
|
+
issueIds: sourceIssueIds,
|
|
1065
|
+
desiredSkills: desiredSkillAssignment.desiredSkills,
|
|
1066
|
+
},
|
|
1067
|
+
});
|
|
1068
|
+
await applyDefaultAgentTaskAssignGrant(orgId, agent.id, actor.actorType === "user" ? actor.actorId : null);
|
|
1069
|
+
if (approval) {
|
|
1070
|
+
await logActivity(db, {
|
|
1071
|
+
orgId,
|
|
1072
|
+
actorType: actor.actorType,
|
|
1073
|
+
actorId: actor.actorId,
|
|
1074
|
+
agentId: actor.agentId,
|
|
1075
|
+
runId: actor.runId,
|
|
1076
|
+
action: "approval.created",
|
|
1077
|
+
entityType: "approval",
|
|
1078
|
+
entityId: approval.id,
|
|
1079
|
+
details: { type: approval.type, linkedAgentId: agent.id },
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
res.status(201).json({ agent, approval });
|
|
1083
|
+
});
|
|
1084
|
+
router.post("/orgs/:orgId/agents", validate(createAgentSchema), async (req, res) => {
|
|
1085
|
+
const orgId = req.params.orgId;
|
|
1086
|
+
assertCompanyAccess(req, orgId);
|
|
1087
|
+
if (req.actor.type === "agent") {
|
|
1088
|
+
assertBoard(req);
|
|
1089
|
+
}
|
|
1090
|
+
const { desiredSkills: requestedDesiredSkills, ...createInput } = req.body;
|
|
1091
|
+
const requestedAdapterConfig = applyCreateDefaultsByAdapterType(createInput.agentRuntimeType, (createInput.agentRuntimeConfig ?? {}));
|
|
1092
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(orgId, stripPersistedSkillSyncConfig(requestedAdapterConfig), { strictMode: strictSecretsMode });
|
|
1093
|
+
const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, normalizedAdapterConfig);
|
|
1094
|
+
const desiredSkillAssignment = await resolveDesiredSkillAssignment(orgId, createInput.agentRuntimeType, runtimeAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
|
|
1095
|
+
await assertAdapterConfigConstraints(orgId, createInput.agentRuntimeType, normalizedAdapterConfig);
|
|
1096
|
+
const createdAgent = await svc.create(orgId, {
|
|
1097
|
+
...createInput,
|
|
1098
|
+
agentRuntimeConfig: normalizedAdapterConfig,
|
|
1099
|
+
status: "idle",
|
|
1100
|
+
spentMonthlyCents: 0,
|
|
1101
|
+
lastHeartbeatAt: null,
|
|
1102
|
+
});
|
|
1103
|
+
await organizationSkills.replaceEnabledSkillKeysForAgent(orgId, createdAgent.id, desiredSkillAssignment.desiredSkills);
|
|
1104
|
+
const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent);
|
|
1105
|
+
const actor = getActorInfo(req);
|
|
1106
|
+
await logActivity(db, {
|
|
1107
|
+
orgId,
|
|
1108
|
+
actorType: actor.actorType,
|
|
1109
|
+
actorId: actor.actorId,
|
|
1110
|
+
agentId: actor.agentId,
|
|
1111
|
+
runId: actor.runId,
|
|
1112
|
+
action: "agent.created",
|
|
1113
|
+
entityType: "agent",
|
|
1114
|
+
entityId: agent.id,
|
|
1115
|
+
details: {
|
|
1116
|
+
name: agent.name,
|
|
1117
|
+
role: agent.role,
|
|
1118
|
+
desiredSkills: desiredSkillAssignment.desiredSkills,
|
|
1119
|
+
},
|
|
1120
|
+
});
|
|
1121
|
+
await applyDefaultAgentTaskAssignGrant(orgId, agent.id, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
|
|
1122
|
+
if (agent.budgetMonthlyCents > 0) {
|
|
1123
|
+
await budgets.upsertPolicy(orgId, {
|
|
1124
|
+
scopeType: "agent",
|
|
1125
|
+
scopeId: agent.id,
|
|
1126
|
+
amount: agent.budgetMonthlyCents,
|
|
1127
|
+
windowKind: "calendar_month_utc",
|
|
1128
|
+
}, actor.actorType === "user" ? actor.actorId : null);
|
|
1129
|
+
}
|
|
1130
|
+
res.status(201).json(agent);
|
|
1131
|
+
});
|
|
1132
|
+
router.patch("/agents/:id/permissions", validate(updateAgentPermissionsSchema), async (req, res) => {
|
|
1133
|
+
const id = req.params.id;
|
|
1134
|
+
const existing = await svc.getById(id);
|
|
1135
|
+
if (!existing) {
|
|
1136
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
assertCompanyAccess(req, existing.orgId);
|
|
1140
|
+
if (req.actor.type === "agent") {
|
|
1141
|
+
const actorAgent = req.actor.agentId ? await svc.getById(req.actor.agentId) : null;
|
|
1142
|
+
if (!actorAgent || actorAgent.orgId !== existing.orgId) {
|
|
1143
|
+
res.status(403).json({ error: "Forbidden" });
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
if (actorAgent.role !== "ceo") {
|
|
1147
|
+
res.status(403).json({ error: "Only CEO can manage permissions" });
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
const agent = await svc.updatePermissions(id, req.body);
|
|
1152
|
+
if (!agent) {
|
|
1153
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
const effectiveCanAssignTasks = agent.role === "ceo" || Boolean(agent.permissions?.canCreateAgents) || req.body.canAssignTasks;
|
|
1157
|
+
await access.ensureMembership(agent.orgId, "agent", agent.id, "member", "active");
|
|
1158
|
+
await access.setPrincipalPermission(agent.orgId, "agent", agent.id, "tasks:assign", effectiveCanAssignTasks, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
|
|
1159
|
+
const actor = getActorInfo(req);
|
|
1160
|
+
await logActivity(db, {
|
|
1161
|
+
orgId: agent.orgId,
|
|
1162
|
+
actorType: actor.actorType,
|
|
1163
|
+
actorId: actor.actorId,
|
|
1164
|
+
agentId: actor.agentId,
|
|
1165
|
+
runId: actor.runId,
|
|
1166
|
+
action: "agent.permissions_updated",
|
|
1167
|
+
entityType: "agent",
|
|
1168
|
+
entityId: agent.id,
|
|
1169
|
+
details: {
|
|
1170
|
+
canCreateAgents: agent.permissions?.canCreateAgents ?? false,
|
|
1171
|
+
canAssignTasks: effectiveCanAssignTasks,
|
|
1172
|
+
},
|
|
1173
|
+
});
|
|
1174
|
+
res.json(await buildAgentDetail(agent));
|
|
1175
|
+
});
|
|
1176
|
+
router.patch("/agents/:id/instructions-path", validate(updateAgentInstructionsPathSchema), async (req, res) => {
|
|
1177
|
+
const id = req.params.id;
|
|
1178
|
+
const existing = await svc.getInternalById(id);
|
|
1179
|
+
if (!existing) {
|
|
1180
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1184
|
+
const existingAdapterConfig = asRecord(existing.agentRuntimeConfig) ?? {};
|
|
1185
|
+
const explicitKey = asNonEmptyString(req.body.agentRuntimeConfigKey);
|
|
1186
|
+
const defaultKey = DEFAULT_INSTRUCTIONS_PATH_KEYS[existing.agentRuntimeType] ?? null;
|
|
1187
|
+
const agentRuntimeConfigKey = explicitKey ?? defaultKey;
|
|
1188
|
+
if (!agentRuntimeConfigKey) {
|
|
1189
|
+
res.status(422).json({
|
|
1190
|
+
error: `No default instructions path key for adapter type '${existing.agentRuntimeType}'. Provide agentRuntimeConfigKey.`,
|
|
1191
|
+
});
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
const nextAdapterConfig = { ...existingAdapterConfig };
|
|
1195
|
+
if (req.body.path === null) {
|
|
1196
|
+
delete nextAdapterConfig[agentRuntimeConfigKey];
|
|
1197
|
+
}
|
|
1198
|
+
else {
|
|
1199
|
+
nextAdapterConfig[agentRuntimeConfigKey] = resolveInstructionsFilePath(req.body.path, existingAdapterConfig);
|
|
1200
|
+
}
|
|
1201
|
+
const syncedAdapterConfig = syncInstructionsBundleConfigFromFilePath(existing, nextAdapterConfig);
|
|
1202
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, syncedAdapterConfig, { strictMode: strictSecretsMode });
|
|
1203
|
+
const actor = getActorInfo(req);
|
|
1204
|
+
const agent = await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
|
|
1205
|
+
recordRevision: {
|
|
1206
|
+
createdByAgentId: actor.agentId,
|
|
1207
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1208
|
+
source: "instructions_path_patch",
|
|
1209
|
+
},
|
|
1210
|
+
});
|
|
1211
|
+
if (!agent) {
|
|
1212
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
const updatedAdapterConfig = asRecord(agent.agentRuntimeConfig) ?? {};
|
|
1216
|
+
const pathValue = asNonEmptyString(updatedAdapterConfig[agentRuntimeConfigKey]);
|
|
1217
|
+
await logActivity(db, {
|
|
1218
|
+
orgId: agent.orgId,
|
|
1219
|
+
actorType: actor.actorType,
|
|
1220
|
+
actorId: actor.actorId,
|
|
1221
|
+
agentId: actor.agentId,
|
|
1222
|
+
runId: actor.runId,
|
|
1223
|
+
action: "agent.instructions_path_updated",
|
|
1224
|
+
entityType: "agent",
|
|
1225
|
+
entityId: agent.id,
|
|
1226
|
+
details: {
|
|
1227
|
+
agentRuntimeConfigKey,
|
|
1228
|
+
path: pathValue,
|
|
1229
|
+
cleared: req.body.path === null,
|
|
1230
|
+
},
|
|
1231
|
+
});
|
|
1232
|
+
res.json({
|
|
1233
|
+
agentId: agent.id,
|
|
1234
|
+
agentRuntimeType: agent.agentRuntimeType,
|
|
1235
|
+
agentRuntimeConfigKey,
|
|
1236
|
+
path: pathValue,
|
|
1237
|
+
});
|
|
1238
|
+
});
|
|
1239
|
+
router.get("/agents/:id/instructions-bundle", async (req, res) => {
|
|
1240
|
+
const id = req.params.id;
|
|
1241
|
+
const existing = await svc.getInternalById(id);
|
|
1242
|
+
if (!existing) {
|
|
1243
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
await assertCanReadAgent(req, existing);
|
|
1247
|
+
const result = await instructions.reconcileBundle(existing);
|
|
1248
|
+
await persistReconciledInstructionsBundle(existing, result);
|
|
1249
|
+
res.json(result.bundle);
|
|
1250
|
+
});
|
|
1251
|
+
router.patch("/agents/:id/instructions-bundle", validate(updateAgentInstructionsBundleSchema), async (req, res) => {
|
|
1252
|
+
const id = req.params.id;
|
|
1253
|
+
const existing = await svc.getInternalById(id);
|
|
1254
|
+
if (!existing) {
|
|
1255
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1259
|
+
const actor = getActorInfo(req);
|
|
1260
|
+
const { bundle, agentRuntimeConfig } = await instructions.updateBundle(existing, req.body);
|
|
1261
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, agentRuntimeConfig, { strictMode: strictSecretsMode });
|
|
1262
|
+
await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
|
|
1263
|
+
recordRevision: {
|
|
1264
|
+
createdByAgentId: actor.agentId,
|
|
1265
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1266
|
+
source: "instructions_bundle_patch",
|
|
1267
|
+
},
|
|
1268
|
+
});
|
|
1269
|
+
await logActivity(db, {
|
|
1270
|
+
orgId: existing.orgId,
|
|
1271
|
+
actorType: actor.actorType,
|
|
1272
|
+
actorId: actor.actorId,
|
|
1273
|
+
agentId: actor.agentId,
|
|
1274
|
+
runId: actor.runId,
|
|
1275
|
+
action: "agent.instructions_bundle_updated",
|
|
1276
|
+
entityType: "agent",
|
|
1277
|
+
entityId: existing.id,
|
|
1278
|
+
details: {
|
|
1279
|
+
mode: bundle.mode,
|
|
1280
|
+
rootPath: bundle.rootPath,
|
|
1281
|
+
entryFile: bundle.entryFile,
|
|
1282
|
+
clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
|
|
1283
|
+
},
|
|
1284
|
+
});
|
|
1285
|
+
res.json(bundle);
|
|
1286
|
+
});
|
|
1287
|
+
router.get("/agents/:id/instructions-bundle/file", async (req, res) => {
|
|
1288
|
+
const id = req.params.id;
|
|
1289
|
+
const existing = await svc.getInternalById(id);
|
|
1290
|
+
if (!existing) {
|
|
1291
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
await assertCanReadAgent(req, existing);
|
|
1295
|
+
const relativePath = typeof req.query.path === "string" ? req.query.path : "";
|
|
1296
|
+
if (!relativePath.trim()) {
|
|
1297
|
+
res.status(422).json({ error: "Query parameter 'path' is required" });
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
const result = await instructions.reconcileBundle(existing);
|
|
1301
|
+
const effectiveAgent = await persistReconciledInstructionsBundle(existing, result);
|
|
1302
|
+
res.json(await instructions.readFile(effectiveAgent, relativePath));
|
|
1303
|
+
});
|
|
1304
|
+
router.put("/agents/:id/instructions-bundle/file", validate(upsertAgentInstructionsFileSchema), async (req, res) => {
|
|
1305
|
+
const id = req.params.id;
|
|
1306
|
+
const existing = await svc.getInternalById(id);
|
|
1307
|
+
if (!existing) {
|
|
1308
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1312
|
+
const actor = getActorInfo(req);
|
|
1313
|
+
const result = await instructions.writeFile(existing, req.body.path, req.body.content, {
|
|
1314
|
+
clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate,
|
|
1315
|
+
});
|
|
1316
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, result.agentRuntimeConfig, { strictMode: strictSecretsMode });
|
|
1317
|
+
await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
|
|
1318
|
+
recordRevision: {
|
|
1319
|
+
createdByAgentId: actor.agentId,
|
|
1320
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1321
|
+
source: "instructions_bundle_file_put",
|
|
1322
|
+
},
|
|
1323
|
+
});
|
|
1324
|
+
await logActivity(db, {
|
|
1325
|
+
orgId: existing.orgId,
|
|
1326
|
+
actorType: actor.actorType,
|
|
1327
|
+
actorId: actor.actorId,
|
|
1328
|
+
agentId: actor.agentId,
|
|
1329
|
+
runId: actor.runId,
|
|
1330
|
+
action: "agent.instructions_file_updated",
|
|
1331
|
+
entityType: "agent",
|
|
1332
|
+
entityId: existing.id,
|
|
1333
|
+
details: {
|
|
1334
|
+
path: result.file.path,
|
|
1335
|
+
size: result.file.size,
|
|
1336
|
+
clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
|
|
1337
|
+
},
|
|
1338
|
+
});
|
|
1339
|
+
res.json(result.file);
|
|
1340
|
+
});
|
|
1341
|
+
router.delete("/agents/:id/instructions-bundle/file", async (req, res) => {
|
|
1342
|
+
const id = req.params.id;
|
|
1343
|
+
const existing = await svc.getInternalById(id);
|
|
1344
|
+
if (!existing) {
|
|
1345
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1349
|
+
const relativePath = typeof req.query.path === "string" ? req.query.path : "";
|
|
1350
|
+
if (!relativePath.trim()) {
|
|
1351
|
+
res.status(422).json({ error: "Query parameter 'path' is required" });
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
const actor = getActorInfo(req);
|
|
1355
|
+
const result = await instructions.deleteFile(existing, relativePath);
|
|
1356
|
+
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, result.agentRuntimeConfig, { strictMode: strictSecretsMode });
|
|
1357
|
+
await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
|
|
1358
|
+
recordRevision: {
|
|
1359
|
+
createdByAgentId: actor.agentId,
|
|
1360
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1361
|
+
source: "instructions_bundle_file_delete",
|
|
1362
|
+
},
|
|
1363
|
+
});
|
|
1364
|
+
await logActivity(db, {
|
|
1365
|
+
orgId: existing.orgId,
|
|
1366
|
+
actorType: actor.actorType,
|
|
1367
|
+
actorId: actor.actorId,
|
|
1368
|
+
agentId: actor.agentId,
|
|
1369
|
+
runId: actor.runId,
|
|
1370
|
+
action: "agent.instructions_file_deleted",
|
|
1371
|
+
entityType: "agent",
|
|
1372
|
+
entityId: existing.id,
|
|
1373
|
+
details: {
|
|
1374
|
+
path: relativePath,
|
|
1375
|
+
},
|
|
1376
|
+
});
|
|
1377
|
+
res.json(result.bundle);
|
|
1378
|
+
});
|
|
1379
|
+
router.patch("/agents/:id", validate(updateAgentSchema), async (req, res) => {
|
|
1380
|
+
const id = req.params.id;
|
|
1381
|
+
const existing = await svc.getInternalById(id);
|
|
1382
|
+
if (!existing) {
|
|
1383
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
await assertCanUpdateAgent(req, existing);
|
|
1387
|
+
if (Object.prototype.hasOwnProperty.call(req.body, "permissions")) {
|
|
1388
|
+
res.status(422).json({ error: "Use /api/agents/:id/permissions for permission changes" });
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
const patchData = { ...req.body };
|
|
1392
|
+
const replaceAgentRuntimeConfig = patchData.replaceAgentRuntimeConfig === true;
|
|
1393
|
+
delete patchData.replaceAgentRuntimeConfig;
|
|
1394
|
+
if (Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig")) {
|
|
1395
|
+
const agentRuntimeConfig = asRecord(patchData.agentRuntimeConfig);
|
|
1396
|
+
if (!agentRuntimeConfig) {
|
|
1397
|
+
res.status(422).json({ error: "agentRuntimeConfig must be an object" });
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const changingInstructionsPath = Object.keys(agentRuntimeConfig).some((key) => KNOWN_INSTRUCTIONS_PATH_KEYS.has(key));
|
|
1401
|
+
if (changingInstructionsPath) {
|
|
1402
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1403
|
+
}
|
|
1404
|
+
patchData.agentRuntimeConfig = agentRuntimeConfig;
|
|
1405
|
+
}
|
|
1406
|
+
const requestedAdapterType = typeof patchData.agentRuntimeType === "string" ? patchData.agentRuntimeType : existing.agentRuntimeType;
|
|
1407
|
+
const touchesAdapterConfiguration = Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeType") ||
|
|
1408
|
+
Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig");
|
|
1409
|
+
if (touchesAdapterConfiguration) {
|
|
1410
|
+
const existingAdapterConfig = asRecord(existing.agentRuntimeConfig) ?? {};
|
|
1411
|
+
const changingAdapterType = typeof patchData.agentRuntimeType === "string" && patchData.agentRuntimeType !== existing.agentRuntimeType;
|
|
1412
|
+
const requestedAdapterConfig = Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig")
|
|
1413
|
+
? (asRecord(patchData.agentRuntimeConfig) ?? {})
|
|
1414
|
+
: null;
|
|
1415
|
+
if (requestedAdapterConfig
|
|
1416
|
+
&& replaceAgentRuntimeConfig
|
|
1417
|
+
&& KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => existingAdapterConfig[key] !== undefined && requestedAdapterConfig[key] === undefined)) {
|
|
1418
|
+
await assertCanManageInstructionsPath(req, existing);
|
|
1419
|
+
}
|
|
1420
|
+
let rawEffectiveAdapterConfig = requestedAdapterConfig ?? existingAdapterConfig;
|
|
1421
|
+
if (requestedAdapterConfig && !changingAdapterType && !replaceAgentRuntimeConfig) {
|
|
1422
|
+
rawEffectiveAdapterConfig = { ...existingAdapterConfig, ...requestedAdapterConfig };
|
|
1423
|
+
}
|
|
1424
|
+
if (changingAdapterType) {
|
|
1425
|
+
rawEffectiveAdapterConfig = preserveInstructionsBundleConfig(existingAdapterConfig, rawEffectiveAdapterConfig);
|
|
1426
|
+
}
|
|
1427
|
+
const effectiveAdapterConfig = applyCreateDefaultsByAdapterType(requestedAdapterType, rawEffectiveAdapterConfig);
|
|
1428
|
+
const normalizedEffectiveAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, effectiveAdapterConfig, { strictMode: strictSecretsMode });
|
|
1429
|
+
patchData.agentRuntimeConfig = syncInstructionsBundleConfigFromFilePath(existing, normalizedEffectiveAdapterConfig);
|
|
1430
|
+
}
|
|
1431
|
+
if (touchesAdapterConfiguration && requestedAdapterType === "opencode_local") {
|
|
1432
|
+
const effectiveAdapterConfig = asRecord(patchData.agentRuntimeConfig) ?? {};
|
|
1433
|
+
await assertAdapterConfigConstraints(existing.orgId, requestedAdapterType, effectiveAdapterConfig);
|
|
1434
|
+
}
|
|
1435
|
+
const actor = getActorInfo(req);
|
|
1436
|
+
const agent = await svc.update(id, patchData, {
|
|
1437
|
+
recordRevision: {
|
|
1438
|
+
createdByAgentId: actor.agentId,
|
|
1439
|
+
createdByUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
1440
|
+
source: "patch",
|
|
1441
|
+
},
|
|
1442
|
+
});
|
|
1443
|
+
if (!agent) {
|
|
1444
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
await logActivity(db, {
|
|
1448
|
+
orgId: agent.orgId,
|
|
1449
|
+
actorType: actor.actorType,
|
|
1450
|
+
actorId: actor.actorId,
|
|
1451
|
+
agentId: actor.agentId,
|
|
1452
|
+
runId: actor.runId,
|
|
1453
|
+
action: "agent.updated",
|
|
1454
|
+
entityType: "agent",
|
|
1455
|
+
entityId: agent.id,
|
|
1456
|
+
details: summarizeAgentUpdateDetails(patchData),
|
|
1457
|
+
});
|
|
1458
|
+
res.json(agent);
|
|
1459
|
+
});
|
|
1460
|
+
router.post("/agents/:id/pause", async (req, res) => {
|
|
1461
|
+
assertBoard(req);
|
|
1462
|
+
const id = req.params.id;
|
|
1463
|
+
const agent = await svc.pause(id);
|
|
1464
|
+
if (!agent) {
|
|
1465
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
await heartbeat.cancelActiveForAgent(id);
|
|
1469
|
+
await logActivity(db, {
|
|
1470
|
+
orgId: agent.orgId,
|
|
1471
|
+
actorType: "user",
|
|
1472
|
+
actorId: req.actor.userId ?? "board",
|
|
1473
|
+
action: "agent.paused",
|
|
1474
|
+
entityType: "agent",
|
|
1475
|
+
entityId: agent.id,
|
|
1476
|
+
});
|
|
1477
|
+
res.json(agent);
|
|
1478
|
+
});
|
|
1479
|
+
router.post("/agents/:id/resume", async (req, res) => {
|
|
1480
|
+
assertBoard(req);
|
|
1481
|
+
const id = req.params.id;
|
|
1482
|
+
const agent = await svc.resume(id);
|
|
1483
|
+
if (!agent) {
|
|
1484
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
await heartbeat.resumeDeferredWakeupsForAgent(id);
|
|
1488
|
+
await logActivity(db, {
|
|
1489
|
+
orgId: agent.orgId,
|
|
1490
|
+
actorType: "user",
|
|
1491
|
+
actorId: req.actor.userId ?? "board",
|
|
1492
|
+
action: "agent.resumed",
|
|
1493
|
+
entityType: "agent",
|
|
1494
|
+
entityId: agent.id,
|
|
1495
|
+
});
|
|
1496
|
+
res.json(agent);
|
|
1497
|
+
});
|
|
1498
|
+
router.post("/agents/:id/terminate", async (req, res) => {
|
|
1499
|
+
assertBoard(req);
|
|
1500
|
+
const id = req.params.id;
|
|
1501
|
+
const agent = await svc.terminate(id);
|
|
1502
|
+
if (!agent) {
|
|
1503
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
await heartbeat.cancelActiveForAgent(id);
|
|
1507
|
+
await logActivity(db, {
|
|
1508
|
+
orgId: agent.orgId,
|
|
1509
|
+
actorType: "user",
|
|
1510
|
+
actorId: req.actor.userId ?? "board",
|
|
1511
|
+
action: "agent.terminated",
|
|
1512
|
+
entityType: "agent",
|
|
1513
|
+
entityId: agent.id,
|
|
1514
|
+
});
|
|
1515
|
+
res.json(agent);
|
|
1516
|
+
});
|
|
1517
|
+
router.delete("/agents/:id", async (req, res) => {
|
|
1518
|
+
assertBoard(req);
|
|
1519
|
+
const id = req.params.id;
|
|
1520
|
+
const agent = await svc.remove(id);
|
|
1521
|
+
if (!agent) {
|
|
1522
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
await logActivity(db, {
|
|
1526
|
+
orgId: agent.orgId,
|
|
1527
|
+
actorType: "user",
|
|
1528
|
+
actorId: req.actor.userId ?? "board",
|
|
1529
|
+
action: "agent.deleted",
|
|
1530
|
+
entityType: "agent",
|
|
1531
|
+
entityId: agent.id,
|
|
1532
|
+
});
|
|
1533
|
+
res.json({ ok: true });
|
|
1534
|
+
});
|
|
1535
|
+
router.get("/agents/:id/keys", async (req, res) => {
|
|
1536
|
+
assertBoard(req);
|
|
1537
|
+
const id = req.params.id;
|
|
1538
|
+
const keys = await svc.listKeys(id);
|
|
1539
|
+
res.json(keys);
|
|
1540
|
+
});
|
|
1541
|
+
router.post("/agents/:id/keys", validate(createAgentKeySchema), async (req, res) => {
|
|
1542
|
+
assertBoard(req);
|
|
1543
|
+
const id = req.params.id;
|
|
1544
|
+
const key = await svc.createApiKey(id, req.body.name);
|
|
1545
|
+
const agent = await svc.getById(id);
|
|
1546
|
+
if (agent) {
|
|
1547
|
+
await logActivity(db, {
|
|
1548
|
+
orgId: agent.orgId,
|
|
1549
|
+
actorType: "user",
|
|
1550
|
+
actorId: req.actor.userId ?? "board",
|
|
1551
|
+
action: "agent.key_created",
|
|
1552
|
+
entityType: "agent",
|
|
1553
|
+
entityId: agent.id,
|
|
1554
|
+
details: { keyId: key.id, name: key.name },
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
res.status(201).json(key);
|
|
1558
|
+
});
|
|
1559
|
+
router.delete("/agents/:id/keys/:keyId", async (req, res) => {
|
|
1560
|
+
assertBoard(req);
|
|
1561
|
+
const keyId = req.params.keyId;
|
|
1562
|
+
const revoked = await svc.revokeKey(keyId);
|
|
1563
|
+
if (!revoked) {
|
|
1564
|
+
res.status(404).json({ error: "Key not found" });
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
res.json({ ok: true });
|
|
1568
|
+
});
|
|
1569
|
+
router.post("/agents/:id/wakeup", validate(wakeAgentSchema), async (req, res) => {
|
|
1570
|
+
const id = req.params.id;
|
|
1571
|
+
const agent = await svc.getById(id);
|
|
1572
|
+
if (!agent) {
|
|
1573
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
assertCompanyAccess(req, agent.orgId);
|
|
1577
|
+
if (req.actor.type === "agent" && req.actor.agentId !== id) {
|
|
1578
|
+
res.status(403).json({ error: "Agent can only invoke itself" });
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
const run = await heartbeat.wakeup(id, {
|
|
1582
|
+
source: req.body.source,
|
|
1583
|
+
triggerDetail: req.body.triggerDetail ?? "manual",
|
|
1584
|
+
reason: req.body.reason ?? null,
|
|
1585
|
+
payload: req.body.payload ?? null,
|
|
1586
|
+
idempotencyKey: req.body.idempotencyKey ?? null,
|
|
1587
|
+
requestedByActorType: req.actor.type === "agent" ? "agent" : "user",
|
|
1588
|
+
requestedByActorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
|
|
1589
|
+
contextSnapshot: {
|
|
1590
|
+
triggeredBy: req.actor.type,
|
|
1591
|
+
actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
|
|
1592
|
+
forceFreshSession: req.body.forceFreshSession === true,
|
|
1593
|
+
},
|
|
1594
|
+
});
|
|
1595
|
+
if (!run) {
|
|
1596
|
+
res.status(202).json({ status: "skipped" });
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
const actor = getActorInfo(req);
|
|
1600
|
+
await logActivity(db, {
|
|
1601
|
+
orgId: agent.orgId,
|
|
1602
|
+
actorType: actor.actorType,
|
|
1603
|
+
actorId: actor.actorId,
|
|
1604
|
+
agentId: actor.agentId,
|
|
1605
|
+
runId: actor.runId,
|
|
1606
|
+
action: "heartbeat.invoked",
|
|
1607
|
+
entityType: "heartbeat_run",
|
|
1608
|
+
entityId: run.id,
|
|
1609
|
+
details: { agentId: id },
|
|
1610
|
+
});
|
|
1611
|
+
res.status(202).json(run);
|
|
1612
|
+
});
|
|
1613
|
+
router.post("/agents/:id/heartbeat/invoke", async (req, res) => {
|
|
1614
|
+
const id = req.params.id;
|
|
1615
|
+
const agent = await svc.getById(id);
|
|
1616
|
+
if (!agent) {
|
|
1617
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
assertCompanyAccess(req, agent.orgId);
|
|
1621
|
+
if (req.actor.type === "agent" && req.actor.agentId !== id) {
|
|
1622
|
+
res.status(403).json({ error: "Agent can only invoke itself" });
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
const run = await heartbeat.invoke(id, "on_demand", {
|
|
1626
|
+
triggeredBy: req.actor.type,
|
|
1627
|
+
actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
|
|
1628
|
+
}, "manual", {
|
|
1629
|
+
actorType: req.actor.type === "agent" ? "agent" : "user",
|
|
1630
|
+
actorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
|
|
1631
|
+
});
|
|
1632
|
+
if (!run) {
|
|
1633
|
+
res.status(202).json({ status: "skipped" });
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
const actor = getActorInfo(req);
|
|
1637
|
+
await logActivity(db, {
|
|
1638
|
+
orgId: agent.orgId,
|
|
1639
|
+
actorType: actor.actorType,
|
|
1640
|
+
actorId: actor.actorId,
|
|
1641
|
+
agentId: actor.agentId,
|
|
1642
|
+
runId: actor.runId,
|
|
1643
|
+
action: "heartbeat.invoked",
|
|
1644
|
+
entityType: "heartbeat_run",
|
|
1645
|
+
entityId: run.id,
|
|
1646
|
+
details: { agentId: id },
|
|
1647
|
+
});
|
|
1648
|
+
res.status(202).json(run);
|
|
1649
|
+
});
|
|
1650
|
+
router.post("/agents/:id/claude-login", async (req, res) => {
|
|
1651
|
+
assertBoard(req);
|
|
1652
|
+
const id = req.params.id;
|
|
1653
|
+
const agent = await svc.getById(id);
|
|
1654
|
+
if (!agent) {
|
|
1655
|
+
res.status(404).json({ error: "Agent not found" });
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
assertCompanyAccess(req, agent.orgId);
|
|
1659
|
+
if (agent.agentRuntimeType !== "claude_local") {
|
|
1660
|
+
res.status(400).json({ error: "Login is only supported for claude_local agents" });
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const config = asRecord(agent.agentRuntimeConfig) ?? {};
|
|
1664
|
+
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.orgId, config);
|
|
1665
|
+
const result = await runClaudeLogin({
|
|
1666
|
+
runId: `claude-login-${randomUUID()}`,
|
|
1667
|
+
agent: {
|
|
1668
|
+
id: agent.id,
|
|
1669
|
+
orgId: agent.orgId,
|
|
1670
|
+
name: agent.name,
|
|
1671
|
+
agentRuntimeType: agent.agentRuntimeType,
|
|
1672
|
+
agentRuntimeConfig: agent.agentRuntimeConfig,
|
|
1673
|
+
},
|
|
1674
|
+
config: runtimeConfig,
|
|
1675
|
+
});
|
|
1676
|
+
res.json(result);
|
|
1677
|
+
});
|
|
1678
|
+
router.get("/orgs/:orgId/heartbeat-runs", async (req, res) => {
|
|
1679
|
+
const orgId = req.params.orgId;
|
|
1680
|
+
assertCompanyAccess(req, orgId);
|
|
1681
|
+
const agentId = req.query.agentId;
|
|
1682
|
+
const limitParam = req.query.limit;
|
|
1683
|
+
const limit = limitParam ? Math.max(1, Math.min(1000, parseInt(limitParam, 10) || 200)) : undefined;
|
|
1684
|
+
const runs = await heartbeat.list(orgId, agentId, limit);
|
|
1685
|
+
res.json(runs);
|
|
1686
|
+
});
|
|
1687
|
+
router.get("/orgs/:orgId/live-runs", async (req, res) => {
|
|
1688
|
+
const orgId = req.params.orgId;
|
|
1689
|
+
assertCompanyAccess(req, orgId);
|
|
1690
|
+
const minCountParam = req.query.minCount;
|
|
1691
|
+
const minCount = minCountParam ? Math.max(0, Math.min(20, parseInt(minCountParam, 10) || 0)) : 0;
|
|
1692
|
+
const columns = {
|
|
1693
|
+
id: heartbeatRuns.id,
|
|
1694
|
+
status: heartbeatRuns.status,
|
|
1695
|
+
invocationSource: heartbeatRuns.invocationSource,
|
|
1696
|
+
triggerDetail: heartbeatRuns.triggerDetail,
|
|
1697
|
+
startedAt: heartbeatRuns.startedAt,
|
|
1698
|
+
finishedAt: heartbeatRuns.finishedAt,
|
|
1699
|
+
createdAt: heartbeatRuns.createdAt,
|
|
1700
|
+
agentId: heartbeatRuns.agentId,
|
|
1701
|
+
agentName: agentsTable.name,
|
|
1702
|
+
agentRuntimeType: agentsTable.agentRuntimeType,
|
|
1703
|
+
issueId: sql `${heartbeatRuns.contextSnapshot} ->> 'issueId'`.as("issueId"),
|
|
1704
|
+
};
|
|
1705
|
+
const liveRuns = await db
|
|
1706
|
+
.select(columns)
|
|
1707
|
+
.from(heartbeatRuns)
|
|
1708
|
+
.innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
|
|
1709
|
+
.where(and(eq(heartbeatRuns.orgId, orgId), inArray(heartbeatRuns.status, ["queued", "running"])))
|
|
1710
|
+
.orderBy(desc(heartbeatRuns.createdAt));
|
|
1711
|
+
if (minCount > 0 && liveRuns.length < minCount) {
|
|
1712
|
+
const activeIds = liveRuns.map((r) => r.id);
|
|
1713
|
+
const recentRuns = await db
|
|
1714
|
+
.select(columns)
|
|
1715
|
+
.from(heartbeatRuns)
|
|
1716
|
+
.innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
|
|
1717
|
+
.where(and(eq(heartbeatRuns.orgId, orgId), not(inArray(heartbeatRuns.status, ["queued", "running"])), ...(activeIds.length > 0 ? [not(inArray(heartbeatRuns.id, activeIds))] : [])))
|
|
1718
|
+
.orderBy(desc(heartbeatRuns.createdAt))
|
|
1719
|
+
.limit(minCount - liveRuns.length);
|
|
1720
|
+
res.json([...liveRuns, ...recentRuns]);
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
res.json(liveRuns);
|
|
1724
|
+
});
|
|
1725
|
+
router.get("/heartbeat-runs/:runId", async (req, res) => {
|
|
1726
|
+
const runId = req.params.runId;
|
|
1727
|
+
const run = await heartbeat.getRun(runId);
|
|
1728
|
+
if (!run) {
|
|
1729
|
+
res.status(404).json({ error: "Heartbeat run not found" });
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
assertCompanyAccess(req, run.orgId);
|
|
1733
|
+
res.json(redactCurrentUserValue(run, await getCurrentUserRedactionOptions()));
|
|
1734
|
+
});
|
|
1735
|
+
router.post("/heartbeat-runs/:runId/cancel", async (req, res) => {
|
|
1736
|
+
assertBoard(req);
|
|
1737
|
+
const runId = req.params.runId;
|
|
1738
|
+
const run = await heartbeat.cancelRun(runId);
|
|
1739
|
+
if (run) {
|
|
1740
|
+
await logActivity(db, {
|
|
1741
|
+
orgId: run.orgId,
|
|
1742
|
+
actorType: "user",
|
|
1743
|
+
actorId: req.actor.userId ?? "board",
|
|
1744
|
+
action: "heartbeat.cancelled",
|
|
1745
|
+
entityType: "heartbeat_run",
|
|
1746
|
+
entityId: run.id,
|
|
1747
|
+
details: { agentId: run.agentId },
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
res.json(run);
|
|
1751
|
+
});
|
|
1752
|
+
router.post("/heartbeat-runs/:runId/retry", async (req, res) => {
|
|
1753
|
+
assertBoard(req);
|
|
1754
|
+
const runId = req.params.runId;
|
|
1755
|
+
const originalRun = await heartbeat.getRun(runId);
|
|
1756
|
+
if (!originalRun) {
|
|
1757
|
+
res.status(404).json({ error: "Heartbeat run not found" });
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
assertCompanyAccess(req, originalRun.orgId);
|
|
1761
|
+
const actor = getActorInfo(req);
|
|
1762
|
+
const run = await heartbeat.retryRun(runId, {
|
|
1763
|
+
requestedByActorType: actor.actorType,
|
|
1764
|
+
requestedByActorId: actor.actorId,
|
|
1765
|
+
});
|
|
1766
|
+
await logActivity(db, {
|
|
1767
|
+
orgId: run.orgId,
|
|
1768
|
+
actorType: actor.actorType,
|
|
1769
|
+
actorId: actor.actorId,
|
|
1770
|
+
action: "heartbeat.retried",
|
|
1771
|
+
entityType: "heartbeat_run",
|
|
1772
|
+
entityId: run.id,
|
|
1773
|
+
details: {
|
|
1774
|
+
agentId: run.agentId,
|
|
1775
|
+
originalRunId: originalRun.id,
|
|
1776
|
+
recoveryTrigger: "manual",
|
|
1777
|
+
},
|
|
1778
|
+
});
|
|
1779
|
+
res.json(redactCurrentUserValue(run, await getCurrentUserRedactionOptions()));
|
|
1780
|
+
});
|
|
1781
|
+
router.get("/heartbeat-runs/:runId/events", async (req, res) => {
|
|
1782
|
+
const runId = req.params.runId;
|
|
1783
|
+
const run = await heartbeat.getRun(runId);
|
|
1784
|
+
if (!run) {
|
|
1785
|
+
res.status(404).json({ error: "Heartbeat run not found" });
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
assertCompanyAccess(req, run.orgId);
|
|
1789
|
+
const afterSeq = Number(req.query.afterSeq ?? 0);
|
|
1790
|
+
const limit = Number(req.query.limit ?? 200);
|
|
1791
|
+
const events = await heartbeat.listEvents(runId, Number.isFinite(afterSeq) ? afterSeq : 0, Number.isFinite(limit) ? limit : 200);
|
|
1792
|
+
const currentUserRedactionOptions = await getCurrentUserRedactionOptions();
|
|
1793
|
+
const redactedEvents = events.map((event) => redactCurrentUserValue({
|
|
1794
|
+
...event,
|
|
1795
|
+
payload: redactEventPayload(event.payload),
|
|
1796
|
+
}, currentUserRedactionOptions));
|
|
1797
|
+
res.json(redactedEvents);
|
|
1798
|
+
});
|
|
1799
|
+
router.get("/heartbeat-runs/:runId/log", async (req, res) => {
|
|
1800
|
+
const runId = req.params.runId;
|
|
1801
|
+
const run = await heartbeat.getRun(runId);
|
|
1802
|
+
if (!run) {
|
|
1803
|
+
res.status(404).json({ error: "Heartbeat run not found" });
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
assertCompanyAccess(req, run.orgId);
|
|
1807
|
+
const offset = Number(req.query.offset ?? 0);
|
|
1808
|
+
const limitBytes = Number(req.query.limitBytes ?? 256000);
|
|
1809
|
+
const result = await heartbeat.readLog(runId, {
|
|
1810
|
+
offset: Number.isFinite(offset) ? offset : 0,
|
|
1811
|
+
limitBytes: Number.isFinite(limitBytes) ? limitBytes : 256000,
|
|
1812
|
+
});
|
|
1813
|
+
res.json(result);
|
|
1814
|
+
});
|
|
1815
|
+
router.get("/heartbeat-runs/:runId/workspace-operations", async (req, res) => {
|
|
1816
|
+
const runId = req.params.runId;
|
|
1817
|
+
const run = await heartbeat.getRun(runId);
|
|
1818
|
+
if (!run) {
|
|
1819
|
+
res.status(404).json({ error: "Heartbeat run not found" });
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
assertCompanyAccess(req, run.orgId);
|
|
1823
|
+
const context = asRecord(run.contextSnapshot);
|
|
1824
|
+
const executionWorkspaceId = asNonEmptyString(context?.executionWorkspaceId);
|
|
1825
|
+
const operations = await workspaceOperations.listForRun(runId, executionWorkspaceId);
|
|
1826
|
+
res.json(redactCurrentUserValue(operations, await getCurrentUserRedactionOptions()));
|
|
1827
|
+
});
|
|
1828
|
+
router.get("/workspace-operations/:operationId/log", async (req, res) => {
|
|
1829
|
+
const operationId = req.params.operationId;
|
|
1830
|
+
const operation = await workspaceOperations.getById(operationId);
|
|
1831
|
+
if (!operation) {
|
|
1832
|
+
res.status(404).json({ error: "Workspace operation not found" });
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
assertCompanyAccess(req, operation.orgId);
|
|
1836
|
+
const offset = Number(req.query.offset ?? 0);
|
|
1837
|
+
const limitBytes = Number(req.query.limitBytes ?? 256000);
|
|
1838
|
+
const result = await workspaceOperations.readLog(operationId, {
|
|
1839
|
+
offset: Number.isFinite(offset) ? offset : 0,
|
|
1840
|
+
limitBytes: Number.isFinite(limitBytes) ? limitBytes : 256000,
|
|
1841
|
+
});
|
|
1842
|
+
res.json(result);
|
|
1843
|
+
});
|
|
1844
|
+
router.get("/issues/:issueId/live-runs", async (req, res) => {
|
|
1845
|
+
const rawId = req.params.issueId;
|
|
1846
|
+
const issueSvc = issueService(db);
|
|
1847
|
+
const isIdentifier = /^[A-Z]+-\d+$/i.test(rawId);
|
|
1848
|
+
const issue = isIdentifier ? await issueSvc.getByIdentifier(rawId) : await issueSvc.getById(rawId);
|
|
1849
|
+
if (!issue) {
|
|
1850
|
+
res.status(404).json({ error: "Issue not found" });
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
assertCompanyAccess(req, issue.orgId);
|
|
1854
|
+
const liveRuns = await db
|
|
1855
|
+
.select({
|
|
1856
|
+
id: heartbeatRuns.id,
|
|
1857
|
+
status: heartbeatRuns.status,
|
|
1858
|
+
invocationSource: heartbeatRuns.invocationSource,
|
|
1859
|
+
triggerDetail: heartbeatRuns.triggerDetail,
|
|
1860
|
+
startedAt: heartbeatRuns.startedAt,
|
|
1861
|
+
finishedAt: heartbeatRuns.finishedAt,
|
|
1862
|
+
createdAt: heartbeatRuns.createdAt,
|
|
1863
|
+
agentId: heartbeatRuns.agentId,
|
|
1864
|
+
agentName: agentsTable.name,
|
|
1865
|
+
agentRuntimeType: agentsTable.agentRuntimeType,
|
|
1866
|
+
})
|
|
1867
|
+
.from(heartbeatRuns)
|
|
1868
|
+
.innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
|
|
1869
|
+
.where(and(eq(heartbeatRuns.orgId, issue.orgId), inArray(heartbeatRuns.status, ["queued", "running"]), sql `${heartbeatRuns.contextSnapshot} ->> 'issueId' = ${issue.id}`))
|
|
1870
|
+
.orderBy(desc(heartbeatRuns.createdAt));
|
|
1871
|
+
res.json(liveRuns);
|
|
1872
|
+
});
|
|
1873
|
+
router.get("/issues/:issueId/active-run", async (req, res) => {
|
|
1874
|
+
const rawId = req.params.issueId;
|
|
1875
|
+
const issueSvc = issueService(db);
|
|
1876
|
+
const isIdentifier = /^[A-Z]+-\d+$/i.test(rawId);
|
|
1877
|
+
const issue = isIdentifier ? await issueSvc.getByIdentifier(rawId) : await issueSvc.getById(rawId);
|
|
1878
|
+
if (!issue) {
|
|
1879
|
+
res.status(404).json({ error: "Issue not found" });
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
assertCompanyAccess(req, issue.orgId);
|
|
1883
|
+
let run = issue.executionRunId ? await heartbeat.getRun(issue.executionRunId) : null;
|
|
1884
|
+
if (run && run.status !== "queued" && run.status !== "running") {
|
|
1885
|
+
run = null;
|
|
1886
|
+
}
|
|
1887
|
+
if (!run && issue.assigneeAgentId && issue.status === "in_progress") {
|
|
1888
|
+
const candidateRun = await heartbeat.getActiveRunForAgent(issue.assigneeAgentId);
|
|
1889
|
+
const candidateContext = asRecord(candidateRun?.contextSnapshot);
|
|
1890
|
+
const candidateIssueId = asNonEmptyString(candidateContext?.issueId);
|
|
1891
|
+
if (candidateRun && candidateIssueId === issue.id) {
|
|
1892
|
+
run = candidateRun;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
if (!run) {
|
|
1896
|
+
res.json(null);
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
const agent = await svc.getById(run.agentId);
|
|
1900
|
+
if (!agent) {
|
|
1901
|
+
res.json(null);
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
res.json({
|
|
1905
|
+
...redactCurrentUserValue(run, await getCurrentUserRedactionOptions()),
|
|
1906
|
+
agentId: agent.id,
|
|
1907
|
+
agentName: agent.name,
|
|
1908
|
+
agentRuntimeType: agent.agentRuntimeType,
|
|
1909
|
+
});
|
|
1910
|
+
});
|
|
1911
|
+
return router;
|
|
1912
|
+
}
|
|
1913
|
+
//# sourceMappingURL=agents.js.map
|