@desplega.ai/agent-swarm 1.113.0 → 1.115.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/README.md +2 -2
- package/dist/{actions-q4n7cz6e.js → actions-17ya5wde.js} +8 -9
- package/dist/{app-es4nzc71.js → app-4f718yk0.js} +6 -6
- package/dist/{assistant-0x8ey0vs.js → assistant-ah7csnjz.js} +19 -18
- package/dist/{boot-reembed-69agkhv6.js → boot-reembed-4jpxhb25.js} +6 -6
- package/dist/{boot-reembed-p0ny05t8.js → boot-reembed-qata34xa.js} +5 -5
- package/dist/{boot-scrub-logs-yybrkmvr.js → boot-scrub-logs-tv48nn3z.js} +4 -4
- package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-3csn5bks.js} +3 -3
- package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
- package/dist/cli-0pygq9r1.js +429 -0
- package/dist/{cli-hsetkkd3.js → cli-12vb0xg6.js} +33 -9
- package/dist/{cli-ncfgsqbd.js → cli-15y7qhzp.js} +262 -33
- package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
- package/dist/{cli-36ymmpmp.js → cli-3samkyap.js} +2 -2
- package/dist/cli-52fg7s7x.js +269 -0
- package/dist/{cli-hjhvekf4.js → cli-65ekje01.js} +11 -8
- package/dist/{cli-h3k622d0.js → cli-6aq8xhvm.js} +90 -3
- package/dist/{cli-f3qa069v.js → cli-7xje5amz.js} +1 -1
- package/dist/cli-86fdnerz.js +405 -0
- package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
- package/dist/{cli-c3frqf65.js → cli-b23axgz4.js} +3 -3
- package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
- package/dist/{cli-bnzbn8j8.js → cli-beea4a3y.js} +73 -24
- package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
- package/dist/{cli-pwc5e83c.js → cli-cchksf5q.js} +12 -7
- package/dist/{cli-30bbaveh.js → cli-cmw9rzy5.js} +2 -2
- package/dist/{cli-y6mrptcn.js → cli-cnwssmsr.js} +1 -1
- package/dist/{cli-r5g6ngtn.js → cli-dcca6j8m.js} +46 -5
- package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
- package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
- package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
- package/dist/{cli-4xyj9jtq.js → cli-hrhye2rm.js} +1062 -478
- package/dist/cli-jkhwmmgg.js +136 -0
- package/dist/{cli-y4ycrnjc.js → cli-k3y4z3h5.js} +1 -1
- package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
- package/dist/{cli-2fc97xm5.js → cli-mnbgv3w7.js} +4 -4
- package/dist/{cli-trmapn9k.js → cli-pet3aev6.js} +95 -10
- package/dist/{cli-z46pnksz.js → cli-q1rx7g0d.js} +175 -28
- package/dist/{cli-qwgtacd6.js → cli-r9f6ngrf.js} +1244 -336
- package/dist/{cli-gtkqc144.js → cli-shvaxw27.js} +13 -7
- package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
- package/dist/cli-t0vqevnm.js +393 -0
- package/dist/{cli-tbw13sx8.js → cli-tece6zgm.js} +1 -1
- package/dist/{cli-bgvskydy.js → cli-tffvrh6j.js} +1 -1
- package/dist/cli-wh91zby6.js +187222 -0
- package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
- package/dist/{cli-mq580e06.js → cli-zsrdty74.js} +18 -18
- package/dist/cli.js +32 -15
- package/dist/{codex-adapter-5cmy858w.js → codex-adapter-de3w0nch.js} +10 -10
- package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-bnw8cysk.js} +10 -10
- package/dist/{commands-z5dbwta3.js → commands-hch4e2k1.js} +4 -4
- package/dist/{db-bbgahh4z.js → db-p3h2j06x.js} +14 -4
- package/dist/{handlers-6b44317z.js → handlers-9er4zx9q.js} +17 -31
- package/dist/{hook-sbp5fmps.js → hook-4axs756z.js} +7 -7
- package/dist/{http-2xz43gz3.js → http-809fvtz2.js} +1934 -886
- package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
- package/dist/{index-nhat35em.js → index-47em3d2n.js} +14 -11
- package/dist/{index-5ghxn8s6.js → index-9fqaktjr.js} +12 -9
- package/dist/{index-0gzmqj4k.js → index-9ht8gr56.js} +13 -10
- package/dist/{index-vfedgdw6.js → index-rm85cfdx.js} +368 -40
- package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
- package/dist/{keepalive-62gfj91d.js → keepalive-3cps6e3e.js} +7 -6
- package/dist/{lead-ag0akn0v.js → lead-fkk95wgq.js} +36 -32
- package/dist/{maintenance-xxrrzk5x.js → maintenance-fweqh0yj.js} +6 -6
- package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
- package/dist/oauth-refresh-sweep-sycqtbph.js +114 -0
- package/dist/{onboard-64zyfcbs.js → onboard-cy0rkgvx.js} +2 -2
- package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
- package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
- package/dist/{otel-impl-b86qseaa.js → otel-impl-wbns8hf7.js} +1 -1
- package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-05sck1ds.js} +17 -109
- package/dist/{pricing-refresh-cgtkffpa.js → pricing-refresh-0hvazmkf.js} +6 -6
- package/dist/rbac-roles-kfesjy9y.js +28 -0
- package/dist/rbac-roles-mwcwhbxc.js +283 -0
- package/dist/{seed-pricing-1r1y1xkq.js → seed-pricing-h2kdq4cq.js} +5 -5
- package/dist/{setup-mkcgkjf7.js → setup-8506q97w.js} +2 -2
- package/dist/{worker-351sze63.js → worker-4r5c6zyb.js} +36 -32
- package/openapi.json +1327 -20
- package/package.json +3 -3
- package/src/agentmail/handlers.ts +16 -6
- package/src/agentmail/templates.ts +25 -5
- package/src/be/audit-user.ts +28 -4
- package/src/be/db-queries/oauth.ts +42 -0
- package/src/be/db.ts +314 -28
- package/src/be/identity.ts +79 -0
- package/src/be/mcp-proxy.ts +132 -0
- package/src/be/migrations/109_rbac_roles.sql +79 -0
- package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
- package/src/be/migrations/112_script_connections_graphql.sql +96 -0
- package/src/be/migrations/113_task_routing_affinity.sql +9 -0
- package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
- package/src/be/modelsdev-cache.json +135 -0
- package/src/be/oauth-credential-bindings.ts +35 -0
- package/src/be/oauth-refresh-sweep.ts +159 -0
- package/src/be/rbac-audit.ts +52 -13
- package/src/be/rbac-roles.ts +424 -0
- package/src/be/script-connections.ts +459 -40
- package/src/be/script-credential-broker.ts +29 -3
- package/src/be/scripts/typecheck.ts +51 -7
- package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
- package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
- package/src/be/users.ts +24 -0
- package/src/cli.tsx +17 -0
- package/src/github/handlers.ts +10 -9
- package/src/github/templates.ts +45 -9
- package/src/gitlab/handlers.ts +20 -8
- package/src/gitlab/templates.ts +18 -6
- package/src/heartbeat/heartbeat.ts +143 -21
- package/src/http/all-routes.ts +3 -0
- package/src/http/approval-requests.ts +12 -0
- package/src/http/config.ts +44 -10
- package/src/http/core.ts +30 -3
- package/src/http/favorites.ts +1 -5
- package/src/http/index.ts +25 -1
- package/src/http/mcp-oauth.ts +2 -0
- package/src/http/mcp-servers.ts +44 -3
- package/src/http/oauth-generic.ts +105 -0
- package/src/http/poll.ts +20 -3
- package/src/http/script-connection-proxy.ts +116 -0
- package/src/http/script-connections.ts +1657 -0
- package/src/http/scripts.ts +27 -7
- package/src/http/skills.ts +11 -0
- package/src/http/tasks.ts +27 -13
- package/src/http/x.ts +6 -2
- package/src/integrations/kapso/inbound.ts +23 -6
- package/src/jira/sync.ts +111 -17
- package/src/jira/templates.ts +10 -2
- package/src/mcp-client/http-client.ts +194 -0
- package/src/oauth/app-validation.ts +16 -0
- package/src/oauth/ensure-token.ts +69 -14
- package/src/oauth/mcp-wrapper.ts +15 -0
- package/src/oauth/wrapper.ts +48 -20
- package/src/prompts/session-templates.ts +3 -3
- package/src/providers/codex-models.ts +100 -30
- package/src/providers/modelsdev-reasoning.json +51 -0
- package/src/providers/pi-mono-mcp-client.ts +2 -133
- package/src/providers/reasoning-effort.ts +11 -5
- package/src/rbac/admission.ts +68 -0
- package/src/rbac/index.ts +2 -0
- package/src/rbac/legacy-policy.ts +12 -0
- package/src/rbac/permissions.ts +48 -0
- package/src/scheduler/scheduler.ts +9 -1
- package/src/scripts-runtime/api-client.ts +151 -19
- package/src/scripts-runtime/api-types.ts +38 -6
- package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
- package/src/scripts-runtime/credential-broker/types.ts +8 -0
- package/src/scripts-runtime/ctx.ts +11 -1
- package/src/scripts-runtime/eval-harness.ts +5 -1
- package/src/scripts-runtime/executors/types.ts +2 -1
- package/src/scripts-runtime/loader.ts +3 -1
- package/src/scripts-runtime/mcp-client.ts +87 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +6 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +19 -0
- package/src/server-user.ts +114 -59
- package/src/server.ts +12 -0
- package/src/slack/assistant.ts +14 -6
- package/src/slack/enrich.ts +17 -0
- package/src/slack/handlers.ts +8 -22
- package/src/slack/responses.ts +91 -1
- package/src/slack/thread-buffer.ts +6 -3
- package/src/slack/watcher.ts +9 -6
- package/src/tasks/worker-follow-up.ts +100 -3
- package/src/tests/agentmail-handlers.test.ts +32 -3
- package/src/tests/approval-requests.test.ts +61 -0
- package/src/tests/audit-user.test.ts +47 -1
- package/src/tests/codex-adapter.test.ts +46 -23
- package/src/tests/credential-broker.test.ts +5 -2
- package/src/tests/delete-page-tool.test.ts +197 -0
- package/src/tests/github-handlers.test.ts +28 -2
- package/src/tests/gitlab-handlers.test.ts +125 -0
- package/src/tests/heartbeat.test.ts +48 -3
- package/src/tests/identity.test.ts +117 -0
- package/src/tests/jira-sync.test.ts +99 -1
- package/src/tests/kapso-inbound.test.ts +7 -0
- package/src/tests/mcp-tools-user.test.ts +60 -6
- package/src/tests/model-control.test.ts +8 -2
- package/src/tests/oauth-credential-bindings.test.ts +490 -0
- package/src/tests/oauth-refresh-sweep.test.ts +160 -0
- package/src/tests/pool-affinity.test.ts +401 -0
- package/src/tests/prompt-template-remaining.test.ts +2 -2
- package/src/tests/rbac-admission-e2e.test.ts +386 -0
- package/src/tests/rbac-admission.test.ts +492 -0
- package/src/tests/rbac-e2e-helpers.ts +3 -0
- package/src/tests/rbac-engine.test.ts +50 -0
- package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
- package/src/tests/rbac-roles.test.ts +328 -0
- package/src/tests/reasoning-effort.test.ts +15 -2
- package/src/tests/schedule-target-type.test.ts +50 -0
- package/src/tests/scheduled-tasks.test.ts +40 -0
- package/src/tests/script-apis-mcp.test.ts +37 -13
- package/src/tests/script-connections-http.test.ts +1158 -0
- package/src/tests/script-connections-mcp.test.ts +894 -0
- package/src/tests/script-connections.test.ts +754 -6
- package/src/tests/scripts-external-api.test.ts +49 -1
- package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
- package/src/tests/scripts-runtime.test.ts +291 -0
- package/src/tests/seed-scripts.test.ts +36 -0
- package/src/tests/slack-identity-resolution.test.ts +37 -3
- package/src/tests/slack-inline-output.test.ts +65 -0
- package/src/tests/slack-thread-buffer.test.ts +28 -0
- package/src/tests/tool-annotations.test.ts +1 -0
- package/src/tests/user-token-rest-auth.test.ts +140 -1
- package/src/tests/workflow-swarm-script.test.ts +44 -0
- package/src/tests/workflow-triggers-v2.test.ts +300 -1
- package/src/tools/credential-bindings/tool.ts +277 -18
- package/src/tools/delete-page.ts +145 -0
- package/src/tools/mcp-servers/mcp-server-delete.ts +7 -4
- package/src/tools/request-human-input.ts +2 -0
- package/src/tools/resolve-user.ts +77 -27
- package/src/tools/script-apis.ts +62 -3
- package/src/tools/script-connections/tool.ts +275 -31
- package/src/tools/send-task.ts +15 -1
- package/src/tools/task-action.ts +34 -2
- package/src/tools/templates.ts +53 -1
- package/src/tools/tool-config.ts +2 -1
- package/src/tools/utils.ts +2 -0
- package/src/tools/workflows/create-workflow.ts +8 -1
- package/src/tools/workflows/update-workflow.ts +11 -2
- package/src/types.ts +90 -11
- package/src/utils/scoped-resource.ts +25 -0
- package/src/workflows/executors/human-in-the-loop.ts +1 -0
- package/src/workflows/executors/swarm-script.ts +7 -1
- package/src/workflows/triggers.ts +146 -18
- package/templates/skills/swarm-scripts/content.md +33 -8
- package/dist/cli-bgef578c.js +0 -771
- package/dist/cli-c9mtm09b.js +0 -43
- package/dist/cli-ceewqajw.js +0 -1698
- package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
- package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
- package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
- package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
- package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
- package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
- package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
- package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
- package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
|
@@ -7,20 +7,22 @@ import {
|
|
|
7
7
|
LlmRater,
|
|
8
8
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
9
9
|
sanitizeReferencesSource
|
|
10
|
-
} from "./cli-
|
|
11
|
-
import {
|
|
12
|
-
ensureToken,
|
|
13
|
-
ensureTokenOrThrow,
|
|
14
|
-
getOAuthApp,
|
|
15
|
-
getOAuthTokens,
|
|
16
|
-
upsertOAuthApp
|
|
17
|
-
} from "./cli-bgef578c.js";
|
|
10
|
+
} from "./cli-ftyf58xj.js";
|
|
18
11
|
import {
|
|
19
12
|
startPricingRefreshLoop
|
|
20
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-3samkyap.js";
|
|
21
14
|
import {
|
|
22
15
|
seedPricingFromModelsDev
|
|
23
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-tece6zgm.js";
|
|
17
|
+
import {
|
|
18
|
+
ensureRbacSeedsSynced,
|
|
19
|
+
getUserGrant
|
|
20
|
+
} from "./cli-52fg7s7x.js";
|
|
21
|
+
import {
|
|
22
|
+
can,
|
|
23
|
+
decideAdmission,
|
|
24
|
+
isRbacEnabled
|
|
25
|
+
} from "./cli-86fdnerz.js";
|
|
24
26
|
import {
|
|
25
27
|
createTrackerAgentMapping,
|
|
26
28
|
createTrackerSync,
|
|
@@ -35,7 +37,7 @@ import {
|
|
|
35
37
|
repointTrackerSyncBySwarmId,
|
|
36
38
|
updateTrackerSync,
|
|
37
39
|
updateTrackerSyncSwarmId
|
|
38
|
-
} from "./cli-
|
|
40
|
+
} from "./cli-dcca6j8m.js";
|
|
39
41
|
import {
|
|
40
42
|
ZodFirstPartyTypeKind,
|
|
41
43
|
objectType
|
|
@@ -45,35 +47,41 @@ import {
|
|
|
45
47
|
ensure,
|
|
46
48
|
require_dist,
|
|
47
49
|
runScheduleNow
|
|
48
|
-
} from "./cli-
|
|
50
|
+
} from "./cli-shvaxw27.js";
|
|
49
51
|
import {
|
|
50
52
|
TriggerSchemaError,
|
|
51
53
|
applyDefinitionPatch,
|
|
52
54
|
cancelWorkflowRun,
|
|
53
55
|
generateEdges,
|
|
54
56
|
getExecutorRegistry,
|
|
57
|
+
getOAuthBindingTokenStatus,
|
|
58
|
+
getOAuthProviderConfig,
|
|
55
59
|
retryFailedRun,
|
|
56
60
|
snapshotWorkflow,
|
|
57
61
|
startWorkflowExecution,
|
|
58
62
|
validateDefinition,
|
|
59
63
|
validateJsonSchema
|
|
60
|
-
} from "./cli-
|
|
64
|
+
} from "./cli-q1rx7g0d.js";
|
|
61
65
|
import {
|
|
62
66
|
getApiKey
|
|
63
67
|
} from "./cli-f14fvzag.js";
|
|
64
68
|
import {
|
|
65
69
|
CREDENTIAL_BINDINGS_CONFIG_KEY,
|
|
66
70
|
CredentialBindingSchema,
|
|
71
|
+
assertUrlSafe,
|
|
67
72
|
disableCredentialBinding,
|
|
68
73
|
getScript,
|
|
74
|
+
getScriptConnectionById,
|
|
69
75
|
importLegacyCredentialBindings,
|
|
70
76
|
listRelationalCredentialBindings,
|
|
71
77
|
listScriptConnections,
|
|
72
78
|
placeholderForConfigKey,
|
|
79
|
+
publicEndpointSsrfOptions,
|
|
80
|
+
refreshScriptConnection,
|
|
73
81
|
setScriptConnectionEnabled,
|
|
74
82
|
upsertCredentialBinding,
|
|
75
83
|
upsertScriptConnection
|
|
76
|
-
} from "./cli-
|
|
84
|
+
} from "./cli-r9f6ngrf.js";
|
|
77
85
|
import {
|
|
78
86
|
CANDIDATE_SET_MULTIPLIER,
|
|
79
87
|
computeScore,
|
|
@@ -85,32 +93,44 @@ import {
|
|
|
85
93
|
isGraphExpansionEnabled,
|
|
86
94
|
rerank,
|
|
87
95
|
rowToCandidate
|
|
88
|
-
} from "./cli-
|
|
96
|
+
} from "./cli-7xje5amz.js";
|
|
97
|
+
import {
|
|
98
|
+
buildAuthorizationUrl,
|
|
99
|
+
ensureToken,
|
|
100
|
+
ensureTokenOrThrow,
|
|
101
|
+
getOAuthApp,
|
|
102
|
+
getOAuthTokens,
|
|
103
|
+
upsertOAuthApp
|
|
104
|
+
} from "./cli-t0vqevnm.js";
|
|
89
105
|
import {
|
|
90
106
|
createAdditiveBuffer,
|
|
91
107
|
extractSlackMessageText,
|
|
92
108
|
parseSlackTs
|
|
93
|
-
} from "./cli-
|
|
109
|
+
} from "./cli-tffvrh6j.js";
|
|
94
110
|
import {
|
|
95
111
|
getSlackApp,
|
|
96
112
|
startSlackApp,
|
|
97
113
|
stopSlackApp
|
|
98
|
-
} from "./cli-
|
|
114
|
+
} from "./cli-pet3aev6.js";
|
|
99
115
|
import {
|
|
100
116
|
findOrCreateUserByEmail,
|
|
101
|
-
findUserByEmail,
|
|
102
117
|
findUserByExternalId,
|
|
103
118
|
findUserById,
|
|
119
|
+
findUsersByName,
|
|
104
120
|
fingerprintApiKey,
|
|
105
121
|
getUserIdentities,
|
|
106
122
|
linkIdentity,
|
|
107
123
|
recordIdentityEvent,
|
|
124
|
+
recordUnmappedIdentity,
|
|
125
|
+
renderIdentity,
|
|
126
|
+
resolveIdentity,
|
|
127
|
+
resolveIdentityByEmail,
|
|
108
128
|
resolveUserByToken,
|
|
109
129
|
unlinkIdentity
|
|
110
|
-
} from "./cli-
|
|
130
|
+
} from "./cli-6aq8xhvm.js";
|
|
111
131
|
import {
|
|
112
132
|
markdownToSlack
|
|
113
|
-
} from "./cli-
|
|
133
|
+
} from "./cli-ma04faw5.js";
|
|
114
134
|
import {
|
|
115
135
|
agentContextKey,
|
|
116
136
|
agentmailContextKey,
|
|
@@ -118,7 +138,7 @@ import {
|
|
|
118
138
|
createTaskWithSiblingAwareness,
|
|
119
139
|
githubContextKey,
|
|
120
140
|
linearContextKey
|
|
121
|
-
} from "./cli-
|
|
141
|
+
} from "./cli-k3y4z3h5.js";
|
|
122
142
|
import {
|
|
123
143
|
getAppUrl,
|
|
124
144
|
getMcpBaseUrl,
|
|
@@ -193,6 +213,7 @@ import {
|
|
|
193
213
|
deleteChannel,
|
|
194
214
|
deleteKv,
|
|
195
215
|
deleteMcpServer,
|
|
216
|
+
deletePage,
|
|
196
217
|
deletePromptTemplate,
|
|
197
218
|
deleteScheduledTask,
|
|
198
219
|
deleteService,
|
|
@@ -295,6 +316,7 @@ import {
|
|
|
295
316
|
installMcpServer,
|
|
296
317
|
installSkill,
|
|
297
318
|
interpolate,
|
|
319
|
+
isAgentEligibleForTask,
|
|
298
320
|
isReservedConfigKey,
|
|
299
321
|
isTerminalTaskStatus,
|
|
300
322
|
listKv,
|
|
@@ -347,10 +369,10 @@ import {
|
|
|
347
369
|
upsertService,
|
|
348
370
|
upsertSwarmConfig,
|
|
349
371
|
validateConfigValue
|
|
350
|
-
} from "./cli-
|
|
372
|
+
} from "./cli-15y7qhzp.js";
|
|
351
373
|
import {
|
|
352
374
|
init_zod
|
|
353
|
-
} from "./cli-
|
|
375
|
+
} from "./cli-bw80ck94.js";
|
|
354
376
|
import {
|
|
355
377
|
$ZodObject,
|
|
356
378
|
$ZodType,
|
|
@@ -387,11 +409,11 @@ import {
|
|
|
387
409
|
union,
|
|
388
410
|
unknown,
|
|
389
411
|
uuid
|
|
390
|
-
} from "./cli-
|
|
412
|
+
} from "./cli-xz9aq0rf.js";
|
|
391
413
|
import {
|
|
392
414
|
init_package,
|
|
393
415
|
package_default
|
|
394
|
-
} from "./cli-
|
|
416
|
+
} from "./cli-b23axgz4.js";
|
|
395
417
|
import {
|
|
396
418
|
init_secret_scrubber,
|
|
397
419
|
refreshSecretScrubberCache,
|
|
@@ -19613,300 +19635,6 @@ function registerGithubTaskReactions() {
|
|
|
19613
19635
|
init_zod();
|
|
19614
19636
|
init_db();
|
|
19615
19637
|
|
|
19616
|
-
// src/rbac/legacy-policy.ts
|
|
19617
|
-
var leadOnly = {
|
|
19618
|
-
name: "lead-only",
|
|
19619
|
-
denyReason: "requires lead agent",
|
|
19620
|
-
evaluate: (principal) => principal.kind === "agent" && principal.isLead
|
|
19621
|
-
};
|
|
19622
|
-
var leadOrTaskCreator = {
|
|
19623
|
-
name: "lead-or-task-creator",
|
|
19624
|
-
denyReason: "requires lead agent or task creator",
|
|
19625
|
-
evaluate: (principal, resource) => {
|
|
19626
|
-
if (principal.kind !== "agent")
|
|
19627
|
-
return false;
|
|
19628
|
-
if (principal.isLead)
|
|
19629
|
-
return true;
|
|
19630
|
-
return resource?.kind === "task" && resource.creatorAgentId != null && resource.creatorAgentId === principal.agentId;
|
|
19631
|
-
}
|
|
19632
|
-
};
|
|
19633
|
-
var leadOrResourceOwner = {
|
|
19634
|
-
name: "lead-or-resource-owner",
|
|
19635
|
-
denyReason: "requires lead agent or resource owner",
|
|
19636
|
-
evaluate: (principal, resource) => {
|
|
19637
|
-
if (principal.kind !== "agent")
|
|
19638
|
-
return false;
|
|
19639
|
-
if (principal.isLead)
|
|
19640
|
-
return true;
|
|
19641
|
-
return resource?.kind === "owned" && resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId;
|
|
19642
|
-
}
|
|
19643
|
-
};
|
|
19644
|
-
var leadOrOwnNamespace = {
|
|
19645
|
-
name: "lead-or-own-namespace",
|
|
19646
|
-
denyReason: "requires lead agent or your own task:agent: namespace",
|
|
19647
|
-
evaluate: (principal, resource) => {
|
|
19648
|
-
if (principal.kind !== "agent")
|
|
19649
|
-
return false;
|
|
19650
|
-
if (principal.isLead)
|
|
19651
|
-
return true;
|
|
19652
|
-
return principal.agentId !== "" && resource?.kind === "kv-namespace" && resource.namespace === `task:agent:${principal.agentId}`;
|
|
19653
|
-
}
|
|
19654
|
-
};
|
|
19655
|
-
var requesterOwnsTask = {
|
|
19656
|
-
name: "requester-owns-task",
|
|
19657
|
-
denyReason: "not the task requester",
|
|
19658
|
-
evaluate: (principal, resource) => {
|
|
19659
|
-
if (principal.kind !== "user")
|
|
19660
|
-
return true;
|
|
19661
|
-
return resource?.kind === "task" && resource.requestedByUserId === principal.userId;
|
|
19662
|
-
}
|
|
19663
|
-
};
|
|
19664
|
-
var memoryOwnerOrLeadSwarm = {
|
|
19665
|
-
name: "memory-owner-or-lead-swarm",
|
|
19666
|
-
denyReason: "requires memory owner, or lead agent for swarm-scoped memories",
|
|
19667
|
-
evaluate: (principal, resource) => {
|
|
19668
|
-
if (principal.kind !== "agent" || resource?.kind !== "owned")
|
|
19669
|
-
return false;
|
|
19670
|
-
if (resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId)
|
|
19671
|
-
return true;
|
|
19672
|
-
return principal.isLead && resource.scope === "swarm";
|
|
19673
|
-
}
|
|
19674
|
-
};
|
|
19675
|
-
var taskFsMutate = {
|
|
19676
|
-
name: "operator-or-user-or-lead-or-task-owner",
|
|
19677
|
-
denyReason: "requires operator, user, lead agent, task assignee, or task creator",
|
|
19678
|
-
evaluate: (principal, resource) => {
|
|
19679
|
-
if (principal.kind === "operator" || principal.kind === "user")
|
|
19680
|
-
return true;
|
|
19681
|
-
if (principal.isLead)
|
|
19682
|
-
return true;
|
|
19683
|
-
if (resource?.kind !== "task")
|
|
19684
|
-
return false;
|
|
19685
|
-
return resource.agentId != null && resource.agentId === principal.agentId || resource.creatorAgentId != null && resource.creatorAgentId === principal.agentId;
|
|
19686
|
-
}
|
|
19687
|
-
};
|
|
19688
|
-
var LEGACY_POLICY = {
|
|
19689
|
-
"user.manage": leadOnly,
|
|
19690
|
-
"agent.profile.update.any": leadOnly,
|
|
19691
|
-
"agent.context.read.any": leadOnly,
|
|
19692
|
-
"task.cancel.any": leadOrTaskCreator,
|
|
19693
|
-
"task.read.own": requesterOwnsTask,
|
|
19694
|
-
"task.cancel.own": requesterOwnsTask,
|
|
19695
|
-
"task.action.own": requesterOwnsTask,
|
|
19696
|
-
"task.fs.mutate": taskFsMutate,
|
|
19697
|
-
"memory.learning.inject": leadOnly,
|
|
19698
|
-
"memory.delete.any": memoryOwnerOrLeadSwarm,
|
|
19699
|
-
"channel.delete": leadOnly,
|
|
19700
|
-
"integration.kapso.manage": leadOnly,
|
|
19701
|
-
"integration.slack.post": leadOnly,
|
|
19702
|
-
"integration.slack.read": leadOnly,
|
|
19703
|
-
"integration.slack.thread.start": leadOnly,
|
|
19704
|
-
"integration.slack.upload": leadOnly,
|
|
19705
|
-
"integration.slack.delete": leadOnly,
|
|
19706
|
-
"integration.slack.update": leadOnly,
|
|
19707
|
-
"credential-binding.manage": leadOnly,
|
|
19708
|
-
"script-connection.manage": leadOnly,
|
|
19709
|
-
"config.credential-bindings.write": leadOnly,
|
|
19710
|
-
"config.write.any": leadOnly,
|
|
19711
|
-
"config.delete.any": leadOnly,
|
|
19712
|
-
"config.read.secrets": leadOnly,
|
|
19713
|
-
"skill.create.swarm": leadOnly,
|
|
19714
|
-
"skill.install.any": leadOnly,
|
|
19715
|
-
"skill.install.global": leadOnly,
|
|
19716
|
-
"skill.uninstall.any": leadOnly,
|
|
19717
|
-
"skill.update.any": leadOrResourceOwner,
|
|
19718
|
-
"skill.promote.swarm": leadOnly,
|
|
19719
|
-
"skill.delete.any": leadOrResourceOwner,
|
|
19720
|
-
"mcp-server.create.swarm": leadOnly,
|
|
19721
|
-
"mcp-server.install.any": leadOnly,
|
|
19722
|
-
"mcp-server.uninstall.any": leadOnly,
|
|
19723
|
-
"mcp-server.delete.any": leadOrResourceOwner,
|
|
19724
|
-
"mcp-server.update.any": leadOrResourceOwner,
|
|
19725
|
-
"kv.write.any": leadOrOwnNamespace,
|
|
19726
|
-
"script.global.write": leadOnly,
|
|
19727
|
-
"script.global.delete": leadOnly
|
|
19728
|
-
};
|
|
19729
|
-
|
|
19730
|
-
// src/rbac/can.ts
|
|
19731
|
-
var auditSink = null;
|
|
19732
|
-
function setAuditSink(fn) {
|
|
19733
|
-
auditSink = fn;
|
|
19734
|
-
}
|
|
19735
|
-
function clearAuditSink() {
|
|
19736
|
-
auditSink = null;
|
|
19737
|
-
}
|
|
19738
|
-
function can(check) {
|
|
19739
|
-
const rule = LEGACY_POLICY[check.verb];
|
|
19740
|
-
const decision = rule.evaluate(check.principal, check.resource) ? { allow: true } : { allow: false, reason: rule.denyReason, missing: check.verb };
|
|
19741
|
-
if (auditSink) {
|
|
19742
|
-
try {
|
|
19743
|
-
auditSink(check, decision);
|
|
19744
|
-
} catch {}
|
|
19745
|
-
}
|
|
19746
|
-
return decision;
|
|
19747
|
-
}
|
|
19748
|
-
// src/rbac/permissions.ts
|
|
19749
|
-
init_zod();
|
|
19750
|
-
var PERMISSIONS = {
|
|
19751
|
-
"user.manage": {
|
|
19752
|
-
description: "Create, update, or deactivate user profiles.",
|
|
19753
|
-
namespace: "user"
|
|
19754
|
-
},
|
|
19755
|
-
"agent.profile.update.any": {
|
|
19756
|
-
description: "Update another agent's profile.",
|
|
19757
|
-
namespace: "agent"
|
|
19758
|
-
},
|
|
19759
|
-
"agent.context.read.any": {
|
|
19760
|
-
description: "View or diff another agent's context history.",
|
|
19761
|
-
namespace: "agent"
|
|
19762
|
-
},
|
|
19763
|
-
"task.cancel.any": {
|
|
19764
|
-
description: "Cancel any task (beyond tasks the caller created).",
|
|
19765
|
-
namespace: "task"
|
|
19766
|
-
},
|
|
19767
|
-
"task.read.own": {
|
|
19768
|
-
description: "Read details of a task the principal requested.",
|
|
19769
|
-
namespace: "task"
|
|
19770
|
-
},
|
|
19771
|
-
"task.cancel.own": {
|
|
19772
|
-
description: "Cancel a task the principal requested.",
|
|
19773
|
-
namespace: "task"
|
|
19774
|
-
},
|
|
19775
|
-
"task.action.own": {
|
|
19776
|
-
description: "Run actions (follow-up, retry, ...) on a task the principal requested.",
|
|
19777
|
-
namespace: "task"
|
|
19778
|
-
},
|
|
19779
|
-
"task.fs.mutate": {
|
|
19780
|
-
description: "Mutate a task's filesystem artifacts and attachments.",
|
|
19781
|
-
namespace: "task"
|
|
19782
|
-
},
|
|
19783
|
-
"memory.learning.inject": {
|
|
19784
|
-
description: "Inject a learning into another agent's memory.",
|
|
19785
|
-
namespace: "memory"
|
|
19786
|
-
},
|
|
19787
|
-
"memory.delete.any": {
|
|
19788
|
-
description: "Delete a memory entry (own entries, or swarm-scoped entries as lead).",
|
|
19789
|
-
namespace: "memory"
|
|
19790
|
-
},
|
|
19791
|
-
"channel.delete": {
|
|
19792
|
-
description: "Delete a Slack channel.",
|
|
19793
|
-
namespace: "channel"
|
|
19794
|
-
},
|
|
19795
|
-
"integration.kapso.manage": {
|
|
19796
|
-
description: "Register or unregister a Kapso inbound number.",
|
|
19797
|
-
namespace: "integration"
|
|
19798
|
-
},
|
|
19799
|
-
"integration.slack.post": {
|
|
19800
|
-
description: "Post to a direct Slack channel.",
|
|
19801
|
-
namespace: "integration"
|
|
19802
|
-
},
|
|
19803
|
-
"integration.slack.read": {
|
|
19804
|
-
description: "Read a direct Slack channel.",
|
|
19805
|
-
namespace: "integration"
|
|
19806
|
-
},
|
|
19807
|
-
"integration.slack.thread.start": {
|
|
19808
|
-
description: "Start a thread in a direct Slack channel.",
|
|
19809
|
-
namespace: "integration"
|
|
19810
|
-
},
|
|
19811
|
-
"integration.slack.upload": {
|
|
19812
|
-
description: "Upload a file to a direct Slack channel.",
|
|
19813
|
-
namespace: "integration"
|
|
19814
|
-
},
|
|
19815
|
-
"integration.slack.delete": {
|
|
19816
|
-
description: "Delete a Slack message.",
|
|
19817
|
-
namespace: "integration"
|
|
19818
|
-
},
|
|
19819
|
-
"integration.slack.update": {
|
|
19820
|
-
description: "Update (edit) a Slack message.",
|
|
19821
|
-
namespace: "integration"
|
|
19822
|
-
},
|
|
19823
|
-
"credential-binding.manage": {
|
|
19824
|
-
description: "Manage script credential bindings.",
|
|
19825
|
-
namespace: "credential-binding"
|
|
19826
|
-
},
|
|
19827
|
-
"script-connection.manage": {
|
|
19828
|
-
description: "Manage script connections.",
|
|
19829
|
-
namespace: "script-connection"
|
|
19830
|
-
},
|
|
19831
|
-
"config.credential-bindings.write": {
|
|
19832
|
-
description: "Write the SCRIPT_CREDENTIAL_BINDINGS swarm-config key.",
|
|
19833
|
-
namespace: "config"
|
|
19834
|
-
},
|
|
19835
|
-
"config.write.any": {
|
|
19836
|
-
description: "Write any swarm-config key.",
|
|
19837
|
-
namespace: "config"
|
|
19838
|
-
},
|
|
19839
|
-
"config.delete.any": {
|
|
19840
|
-
description: "Delete any swarm-config entry.",
|
|
19841
|
-
namespace: "config"
|
|
19842
|
-
},
|
|
19843
|
-
"config.read.secrets": {
|
|
19844
|
-
description: "Read unmasked secret config values.",
|
|
19845
|
-
namespace: "config"
|
|
19846
|
-
},
|
|
19847
|
-
"skill.create.swarm": {
|
|
19848
|
-
description: "Create a swarm-scoped skill.",
|
|
19849
|
-
namespace: "skill"
|
|
19850
|
-
},
|
|
19851
|
-
"skill.install.any": {
|
|
19852
|
-
description: "Install a skill for another agent.",
|
|
19853
|
-
namespace: "skill"
|
|
19854
|
-
},
|
|
19855
|
-
"skill.install.global": {
|
|
19856
|
-
description: "Install a remote/global skill.",
|
|
19857
|
-
namespace: "skill"
|
|
19858
|
-
},
|
|
19859
|
-
"skill.uninstall.any": {
|
|
19860
|
-
description: "Uninstall a skill for another agent.",
|
|
19861
|
-
namespace: "skill"
|
|
19862
|
-
},
|
|
19863
|
-
"skill.update.any": {
|
|
19864
|
-
description: "Update a skill the caller does not own.",
|
|
19865
|
-
namespace: "skill"
|
|
19866
|
-
},
|
|
19867
|
-
"skill.promote.swarm": {
|
|
19868
|
-
description: "Promote a skill to swarm scope (skill-approval path).",
|
|
19869
|
-
namespace: "skill"
|
|
19870
|
-
},
|
|
19871
|
-
"skill.delete.any": {
|
|
19872
|
-
description: "Delete a skill the caller does not own.",
|
|
19873
|
-
namespace: "skill"
|
|
19874
|
-
},
|
|
19875
|
-
"mcp-server.create.swarm": {
|
|
19876
|
-
description: "Create a swarm- or global-scoped MCP server.",
|
|
19877
|
-
namespace: "mcp-server"
|
|
19878
|
-
},
|
|
19879
|
-
"mcp-server.install.any": {
|
|
19880
|
-
description: "Install an MCP server for another agent.",
|
|
19881
|
-
namespace: "mcp-server"
|
|
19882
|
-
},
|
|
19883
|
-
"mcp-server.uninstall.any": {
|
|
19884
|
-
description: "Uninstall an MCP server for another agent.",
|
|
19885
|
-
namespace: "mcp-server"
|
|
19886
|
-
},
|
|
19887
|
-
"mcp-server.delete.any": {
|
|
19888
|
-
description: "Delete an MCP server the caller does not own.",
|
|
19889
|
-
namespace: "mcp-server"
|
|
19890
|
-
},
|
|
19891
|
-
"mcp-server.update.any": {
|
|
19892
|
-
description: "Update an MCP server the caller does not own.",
|
|
19893
|
-
namespace: "mcp-server"
|
|
19894
|
-
},
|
|
19895
|
-
"kv.write.any": {
|
|
19896
|
-
description: "Write another agent's task:agent: KV namespace.",
|
|
19897
|
-
namespace: "kv"
|
|
19898
|
-
},
|
|
19899
|
-
"script.global.write": {
|
|
19900
|
-
description: "Create or update a global-scope script.",
|
|
19901
|
-
namespace: "script"
|
|
19902
|
-
},
|
|
19903
|
-
"script.global.delete": {
|
|
19904
|
-
description: "Delete a global-scope script.",
|
|
19905
|
-
namespace: "script"
|
|
19906
|
-
}
|
|
19907
|
-
};
|
|
19908
|
-
var PERMISSION_VERBS = Object.keys(PERMISSIONS);
|
|
19909
|
-
var PermissionVerbSchema = _enum(PERMISSION_VERBS);
|
|
19910
19638
|
// src/tools/task-tool-ctx.ts
|
|
19911
19639
|
function ownerCtx(info) {
|
|
19912
19640
|
return {
|
|
@@ -19973,7 +19701,7 @@ async function initOtel(serviceRole = process.env.AGENT_ROLE || "api") {
|
|
|
19973
19701
|
return;
|
|
19974
19702
|
initialized2 = true;
|
|
19975
19703
|
try {
|
|
19976
|
-
const impl = await import("./otel-impl-
|
|
19704
|
+
const impl = await import("./otel-impl-wbns8hf7.js");
|
|
19977
19705
|
await impl.boot(serviceRole);
|
|
19978
19706
|
realWithSpan = impl.withSpan;
|
|
19979
19707
|
realStartSpan = impl.startSpan;
|
|
@@ -21248,22 +20976,87 @@ var registerCreatePageTool = (server) => {
|
|
|
21248
20976
|
// src/tools/credential-bindings/tool.ts
|
|
21249
20977
|
init_zod();
|
|
21250
20978
|
init_db();
|
|
20979
|
+
|
|
20980
|
+
// src/oauth/app-validation.ts
|
|
20981
|
+
var RESERVED_OAUTH_PROVIDERS = new Set(["linear", "jira"]);
|
|
20982
|
+
function assertOAuthProviderIsNotReserved(provider) {
|
|
20983
|
+
if (!RESERVED_OAUTH_PROVIDERS.has(provider.toLowerCase()))
|
|
20984
|
+
return;
|
|
20985
|
+
throw new Error(`OAuth provider "${provider}" is reserved for dedicated tracker OAuth flows. Use the Linear/Jira tracker integration flow instead.`);
|
|
20986
|
+
}
|
|
20987
|
+
function assertOAuthAppUrlsSafe(input) {
|
|
20988
|
+
const options = publicEndpointSsrfOptions();
|
|
20989
|
+
assertUrlSafe(input.authorizeUrl, options);
|
|
20990
|
+
assertUrlSafe(input.tokenUrl, options);
|
|
20991
|
+
}
|
|
20992
|
+
|
|
20993
|
+
// src/utils/scoped-resource.ts
|
|
20994
|
+
init_zod();
|
|
20995
|
+
var scopedResourceScopeIdSchema = exports_external.string().min(1).max(255);
|
|
20996
|
+
var agentScopeIdSchema = exports_external.string().uuid();
|
|
20997
|
+
function resolveScopedResourceId(scope, scopeId, subject) {
|
|
20998
|
+
if (!scope || scope === "global")
|
|
20999
|
+
return null;
|
|
21000
|
+
if (!scopeId || scopeId.trim().length === 0) {
|
|
21001
|
+
throw new Error(`scopeId is required for ${scope} ${subject}.`);
|
|
21002
|
+
}
|
|
21003
|
+
if (scopeId.length > 255) {
|
|
21004
|
+
throw new Error(`scopeId must be at most 255 characters for ${scope} ${subject}.`);
|
|
21005
|
+
}
|
|
21006
|
+
if (scope === "agent" && !agentScopeIdSchema.safeParse(scopeId).success) {
|
|
21007
|
+
throw new Error(`scopeId must be an agent UUID for agent ${subject}.`);
|
|
21008
|
+
}
|
|
21009
|
+
return scopeId;
|
|
21010
|
+
}
|
|
21011
|
+
|
|
21012
|
+
// src/tools/credential-bindings/tool.ts
|
|
21013
|
+
var providerSchema = string().min(1).max(255).regex(/^[A-Za-z0-9_-]+$/);
|
|
21014
|
+
var tokenStatusSchema = _enum(["ok", "expiring", "missing"]);
|
|
21015
|
+
var credentialBindingToolBindingSchema = CredentialBindingSchema.and(object({
|
|
21016
|
+
id: string().optional(),
|
|
21017
|
+
source: _enum(["default", "user", "migration"]).optional(),
|
|
21018
|
+
createdAt: string().optional(),
|
|
21019
|
+
updatedAt: string().optional(),
|
|
21020
|
+
createdBy: string().nullable().optional(),
|
|
21021
|
+
updatedBy: string().nullable().optional(),
|
|
21022
|
+
tokenStatus: tokenStatusSchema.optional()
|
|
21023
|
+
}));
|
|
21251
21024
|
var credentialBindingsOutputSchema = object({
|
|
21252
21025
|
yourAgentId: string().uuid().optional(),
|
|
21253
21026
|
success: boolean(),
|
|
21254
21027
|
message: string(),
|
|
21255
|
-
|
|
21028
|
+
provider: string().optional(),
|
|
21029
|
+
authorizeUrl: string().optional(),
|
|
21030
|
+
redirectUri: string().optional(),
|
|
21031
|
+
bindings: array(credentialBindingToolBindingSchema)
|
|
21256
21032
|
});
|
|
21257
21033
|
var credentialBindingsInputSchema = object({
|
|
21258
|
-
action: _enum(["list", "upsert", "disable", "import-legacy"]).describe("List, add/update, disable,
|
|
21259
|
-
id: string().uuid().optional(),
|
|
21260
|
-
configKey: string().min(1).max(255).optional(),
|
|
21261
|
-
allowedHosts: array(string().min(1)).min(1).optional(),
|
|
21262
|
-
headerTemplate: string().min(1).optional(),
|
|
21263
|
-
queryTemplate: string().min(1).optional(),
|
|
21264
|
-
scope: _enum(["global", "agent", "repo"]).default("global").optional(),
|
|
21265
|
-
scopeId:
|
|
21034
|
+
action: _enum(["list", "upsert", "disable", "import-legacy", "oauth-app-upsert", "oauth-authorize-url"]).describe("List, add/update, disable, import legacy JSON bindings, or register/authorize OAuth apps."),
|
|
21035
|
+
id: string().uuid().optional().describe("Existing credential binding ID for update or disable."),
|
|
21036
|
+
configKey: string().min(1).max(255).optional().describe("Swarm config key whose secret value is injected through templates."),
|
|
21037
|
+
allowedHosts: array(string().min(1)).min(1).optional().describe("Allowed outbound hostnames for this binding."),
|
|
21038
|
+
headerTemplate: string().min(1).optional().describe("Header template containing the config-key placeholder."),
|
|
21039
|
+
queryTemplate: string().min(1).optional().describe("Query parameter template containing the config-key placeholder."),
|
|
21040
|
+
scope: _enum(["global", "agent", "repo"]).default("global").optional().describe("Binding visibility scope."),
|
|
21041
|
+
scopeId: scopedResourceScopeIdSchema.nullable().optional().describe("Agent UUID for agent scope or repo id (owner/name) for repo scope."),
|
|
21042
|
+
authKind: _enum(["config", "oauth"]).default("config").optional().describe("Use config for stored swarm config secrets or oauth for OAuth token resolution."),
|
|
21043
|
+
oauthProvider: providerSchema.optional().describe("OAuth provider slug required when authKind is oauth."),
|
|
21044
|
+
provider: providerSchema.optional().describe("OAuth provider slug for oauth-app-upsert and oauth-authorize-url."),
|
|
21045
|
+
clientId: string().min(1).optional().describe("OAuth client ID for oauth-app-upsert."),
|
|
21046
|
+
clientSecret: string().min(1).optional().describe("OAuth client secret for oauth-app-upsert."),
|
|
21047
|
+
authorizeUrl: string().url().optional().describe("OAuth authorization URL for oauth-app-upsert."),
|
|
21048
|
+
tokenUrl: string().url().optional().describe("OAuth token URL for oauth-app-upsert."),
|
|
21049
|
+
scopes: array(string().min(1)).optional().describe("OAuth scopes for oauth-app-upsert."),
|
|
21050
|
+
extraParams: record(string(), string()).optional().describe("Extra OAuth authorization parameters stored with the OAuth app."),
|
|
21051
|
+
tokenAuthStyle: _enum(["body", "basic"]).optional().describe("How client credentials reach the token endpoint: body params (default) or HTTP Basic auth (required by e.g. Notion)."),
|
|
21052
|
+
tokenBodyFormat: _enum(["form", "json"]).optional().describe("Token request body encoding: form-urlencoded (default) or JSON (required by e.g. Notion).")
|
|
21266
21053
|
});
|
|
21054
|
+
function genericOAuthRedirectUri(provider) {
|
|
21055
|
+
return `${getPublicMcpBaseUrl()}/api/oauth/${encodeURIComponent(provider)}/callback`;
|
|
21056
|
+
}
|
|
21057
|
+
function decorateBindings(bindings) {
|
|
21058
|
+
return bindings.map((binding) => binding.authKind === "oauth" && binding.oauthProvider ? { ...binding, tokenStatus: getOAuthBindingTokenStatus(binding.oauthProvider) } : binding);
|
|
21059
|
+
}
|
|
21267
21060
|
var registerCredentialBindingsTool = (server) => {
|
|
21268
21061
|
createToolRegistrar(server)("credential-bindings", {
|
|
21269
21062
|
title: "Credential Bindings",
|
|
@@ -21304,7 +21097,115 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21304
21097
|
}
|
|
21305
21098
|
};
|
|
21306
21099
|
}
|
|
21307
|
-
const
|
|
21100
|
+
const currentBindings = () => decorateBindings(listRelationalCredentialBindings({ includeInactive: true }));
|
|
21101
|
+
const bindings = currentBindings();
|
|
21102
|
+
if (args.action === "oauth-app-upsert") {
|
|
21103
|
+
if (!args.provider || !args.clientId || !args.clientSecret || !args.authorizeUrl || !args.tokenUrl || !args.scopes) {
|
|
21104
|
+
return {
|
|
21105
|
+
content: [
|
|
21106
|
+
{
|
|
21107
|
+
type: "text",
|
|
21108
|
+
text: "provider, clientId, clientSecret, authorizeUrl, tokenUrl, and scopes are required for oauth-app-upsert."
|
|
21109
|
+
}
|
|
21110
|
+
],
|
|
21111
|
+
structuredContent: {
|
|
21112
|
+
yourAgentId: requestInfo.agentId,
|
|
21113
|
+
success: false,
|
|
21114
|
+
message: "provider, clientId, clientSecret, authorizeUrl, tokenUrl, and scopes are required for oauth-app-upsert.",
|
|
21115
|
+
bindings
|
|
21116
|
+
}
|
|
21117
|
+
};
|
|
21118
|
+
}
|
|
21119
|
+
try {
|
|
21120
|
+
assertOAuthProviderIsNotReserved(args.provider);
|
|
21121
|
+
assertOAuthAppUrlsSafe({
|
|
21122
|
+
authorizeUrl: args.authorizeUrl,
|
|
21123
|
+
tokenUrl: args.tokenUrl
|
|
21124
|
+
});
|
|
21125
|
+
} catch (err) {
|
|
21126
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
21127
|
+
return {
|
|
21128
|
+
content: [{ type: "text", text: message }],
|
|
21129
|
+
structuredContent: {
|
|
21130
|
+
yourAgentId: requestInfo.agentId,
|
|
21131
|
+
success: false,
|
|
21132
|
+
message,
|
|
21133
|
+
bindings
|
|
21134
|
+
}
|
|
21135
|
+
};
|
|
21136
|
+
}
|
|
21137
|
+
const redirectUri = genericOAuthRedirectUri(args.provider);
|
|
21138
|
+
upsertOAuthApp(args.provider, {
|
|
21139
|
+
clientId: args.clientId,
|
|
21140
|
+
clientSecret: args.clientSecret,
|
|
21141
|
+
authorizeUrl: args.authorizeUrl,
|
|
21142
|
+
tokenUrl: args.tokenUrl,
|
|
21143
|
+
redirectUri,
|
|
21144
|
+
scopes: args.scopes.join(","),
|
|
21145
|
+
...args.extraParams || args.tokenAuthStyle || args.tokenBodyFormat ? {
|
|
21146
|
+
metadata: JSON.stringify({
|
|
21147
|
+
...args.extraParams ? { extraParams: args.extraParams } : {},
|
|
21148
|
+
...args.tokenAuthStyle ? { tokenAuthStyle: args.tokenAuthStyle } : {},
|
|
21149
|
+
...args.tokenBodyFormat ? { tokenBodyFormat: args.tokenBodyFormat } : {}
|
|
21150
|
+
})
|
|
21151
|
+
} : {}
|
|
21152
|
+
});
|
|
21153
|
+
return {
|
|
21154
|
+
content: [
|
|
21155
|
+
{
|
|
21156
|
+
type: "text",
|
|
21157
|
+
text: `OAuth app ${args.provider} saved. Redirect URI: ${redirectUri}`
|
|
21158
|
+
}
|
|
21159
|
+
],
|
|
21160
|
+
structuredContent: {
|
|
21161
|
+
yourAgentId: requestInfo.agentId,
|
|
21162
|
+
success: true,
|
|
21163
|
+
message: `OAuth app ${args.provider} saved.`,
|
|
21164
|
+
provider: args.provider,
|
|
21165
|
+
redirectUri,
|
|
21166
|
+
bindings: currentBindings()
|
|
21167
|
+
}
|
|
21168
|
+
};
|
|
21169
|
+
}
|
|
21170
|
+
if (args.action === "oauth-authorize-url") {
|
|
21171
|
+
if (!args.provider) {
|
|
21172
|
+
return {
|
|
21173
|
+
content: [{ type: "text", text: "provider is required for oauth-authorize-url." }],
|
|
21174
|
+
structuredContent: {
|
|
21175
|
+
yourAgentId: requestInfo.agentId,
|
|
21176
|
+
success: false,
|
|
21177
|
+
message: "provider is required for oauth-authorize-url.",
|
|
21178
|
+
bindings
|
|
21179
|
+
}
|
|
21180
|
+
};
|
|
21181
|
+
}
|
|
21182
|
+
const config = getOAuthProviderConfig(args.provider);
|
|
21183
|
+
if (!config) {
|
|
21184
|
+
return {
|
|
21185
|
+
content: [{ type: "text", text: `OAuth app ${args.provider} is not configured.` }],
|
|
21186
|
+
structuredContent: {
|
|
21187
|
+
yourAgentId: requestInfo.agentId,
|
|
21188
|
+
success: false,
|
|
21189
|
+
message: `OAuth app ${args.provider} is not configured.`,
|
|
21190
|
+
provider: args.provider,
|
|
21191
|
+
bindings
|
|
21192
|
+
}
|
|
21193
|
+
};
|
|
21194
|
+
}
|
|
21195
|
+
const result = await buildAuthorizationUrl(config);
|
|
21196
|
+
return {
|
|
21197
|
+
content: [{ type: "text", text: result.url }],
|
|
21198
|
+
structuredContent: {
|
|
21199
|
+
yourAgentId: requestInfo.agentId,
|
|
21200
|
+
success: true,
|
|
21201
|
+
message: `OAuth authorization URL generated for ${args.provider}.`,
|
|
21202
|
+
provider: args.provider,
|
|
21203
|
+
authorizeUrl: result.url,
|
|
21204
|
+
redirectUri: config.redirectUri,
|
|
21205
|
+
bindings
|
|
21206
|
+
}
|
|
21207
|
+
};
|
|
21208
|
+
}
|
|
21308
21209
|
if (args.action === "list") {
|
|
21309
21210
|
return {
|
|
21310
21211
|
content: [
|
|
@@ -21323,7 +21224,7 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21323
21224
|
}
|
|
21324
21225
|
if (args.action === "import-legacy") {
|
|
21325
21226
|
const imported = importLegacyCredentialBindings();
|
|
21326
|
-
const nextBindings2 =
|
|
21227
|
+
const nextBindings2 = currentBindings();
|
|
21327
21228
|
return {
|
|
21328
21229
|
content: [{ type: "text", text: `Imported ${imported} legacy credential binding(s).` }],
|
|
21329
21230
|
structuredContent: {
|
|
@@ -21347,7 +21248,7 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21347
21248
|
}
|
|
21348
21249
|
};
|
|
21349
21250
|
}
|
|
21350
|
-
const nextBindings2 =
|
|
21251
|
+
const nextBindings2 = currentBindings();
|
|
21351
21252
|
return {
|
|
21352
21253
|
content: [{ type: "text", text: `Credential binding ${disabled.configKey} disabled.` }],
|
|
21353
21254
|
structuredContent: {
|
|
@@ -21370,14 +21271,17 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21370
21271
|
};
|
|
21371
21272
|
}
|
|
21372
21273
|
const scope = args.scope ?? "global";
|
|
21373
|
-
|
|
21374
|
-
|
|
21274
|
+
let scopeId;
|
|
21275
|
+
try {
|
|
21276
|
+
scopeId = resolveScopedResourceId(scope, args.scopeId, "bindings");
|
|
21277
|
+
} catch (err) {
|
|
21278
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
21375
21279
|
return {
|
|
21376
|
-
content: [{ type: "text", text:
|
|
21280
|
+
content: [{ type: "text", text: message }],
|
|
21377
21281
|
structuredContent: {
|
|
21378
21282
|
yourAgentId: requestInfo.agentId,
|
|
21379
21283
|
success: false,
|
|
21380
|
-
message
|
|
21284
|
+
message,
|
|
21381
21285
|
bindings
|
|
21382
21286
|
}
|
|
21383
21287
|
};
|
|
@@ -21398,6 +21302,17 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21398
21302
|
}
|
|
21399
21303
|
};
|
|
21400
21304
|
}
|
|
21305
|
+
if ((args.authKind ?? "config") === "oauth" && !args.oauthProvider) {
|
|
21306
|
+
return {
|
|
21307
|
+
content: [{ type: "text", text: "oauthProvider is required for oauth bindings." }],
|
|
21308
|
+
structuredContent: {
|
|
21309
|
+
yourAgentId: requestInfo.agentId,
|
|
21310
|
+
success: false,
|
|
21311
|
+
message: "oauthProvider is required for oauth bindings.",
|
|
21312
|
+
bindings
|
|
21313
|
+
}
|
|
21314
|
+
};
|
|
21315
|
+
}
|
|
21401
21316
|
const placeholder = placeholderForConfigKey(args.configKey);
|
|
21402
21317
|
if (args.headerTemplate && !args.headerTemplate.includes(placeholder)) {
|
|
21403
21318
|
return {
|
|
@@ -21428,7 +21343,9 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21428
21343
|
queryTemplate: args.queryTemplate,
|
|
21429
21344
|
scope,
|
|
21430
21345
|
scopeId,
|
|
21431
|
-
active: true
|
|
21346
|
+
active: true,
|
|
21347
|
+
authKind: args.authKind ?? "config",
|
|
21348
|
+
oauthProvider: args.oauthProvider
|
|
21432
21349
|
});
|
|
21433
21350
|
upsertCredentialBinding({
|
|
21434
21351
|
id: args.id,
|
|
@@ -21438,9 +21355,11 @@ var registerCredentialBindingsTool = (server) => {
|
|
|
21438
21355
|
queryTemplate: nextBinding.queryTemplate,
|
|
21439
21356
|
scope: nextBinding.scope,
|
|
21440
21357
|
scopeId: nextBinding.scopeId ?? null,
|
|
21441
|
-
active: true
|
|
21358
|
+
active: true,
|
|
21359
|
+
authKind: nextBinding.authKind,
|
|
21360
|
+
oauthProvider: nextBinding.oauthProvider ?? null
|
|
21442
21361
|
});
|
|
21443
|
-
const nextBindings =
|
|
21362
|
+
const nextBindings = currentBindings();
|
|
21444
21363
|
return {
|
|
21445
21364
|
content: [{ type: "text", text: `Credential binding ${args.configKey} saved.` }],
|
|
21446
21365
|
structuredContent: {
|
|
@@ -21637,6 +21556,126 @@ var registerDeleteChannelTool = (server) => {
|
|
|
21637
21556
|
});
|
|
21638
21557
|
};
|
|
21639
21558
|
|
|
21559
|
+
// src/tools/delete-page.ts
|
|
21560
|
+
init_zod();
|
|
21561
|
+
init_db();
|
|
21562
|
+
var registerDeletePageTool = (server) => {
|
|
21563
|
+
createToolRegistrar(server)("delete-page", {
|
|
21564
|
+
title: "Delete Page",
|
|
21565
|
+
description: "Permanently delete one page by pageId, or by slug in the caller's page namespace. Only the lead or the page owner can delete a page.",
|
|
21566
|
+
annotations: { destructiveHint: true },
|
|
21567
|
+
inputSchema: object({
|
|
21568
|
+
pageId: string().min(1).optional().describe("Page ID to delete."),
|
|
21569
|
+
slug: string().min(1).optional().describe("Page slug to delete from the caller's own (agentId, slug) namespace. Alternative to pageId.")
|
|
21570
|
+
}),
|
|
21571
|
+
outputSchema: object({
|
|
21572
|
+
yourAgentId: string().optional(),
|
|
21573
|
+
success: boolean(),
|
|
21574
|
+
message: string(),
|
|
21575
|
+
deletedPage: object({
|
|
21576
|
+
id: string(),
|
|
21577
|
+
slug: string(),
|
|
21578
|
+
title: string()
|
|
21579
|
+
}).optional()
|
|
21580
|
+
})
|
|
21581
|
+
}, async ({ pageId, slug }, requestInfo, _meta) => {
|
|
21582
|
+
if (!requestInfo.agentId) {
|
|
21583
|
+
return {
|
|
21584
|
+
content: [{ type: "text", text: 'Agent ID not found. Set the "X-Agent-ID" header.' }],
|
|
21585
|
+
structuredContent: {
|
|
21586
|
+
success: false,
|
|
21587
|
+
message: 'Agent ID not found. Set the "X-Agent-ID" header.'
|
|
21588
|
+
}
|
|
21589
|
+
};
|
|
21590
|
+
}
|
|
21591
|
+
if (!pageId && !slug) {
|
|
21592
|
+
return {
|
|
21593
|
+
content: [{ type: "text", text: "Either pageId or slug must be provided." }],
|
|
21594
|
+
structuredContent: {
|
|
21595
|
+
yourAgentId: requestInfo.agentId,
|
|
21596
|
+
success: false,
|
|
21597
|
+
message: "Either pageId or slug must be provided."
|
|
21598
|
+
}
|
|
21599
|
+
};
|
|
21600
|
+
}
|
|
21601
|
+
const caller = getAgentById(requestInfo.agentId);
|
|
21602
|
+
if (!caller) {
|
|
21603
|
+
return {
|
|
21604
|
+
content: [{ type: "text", text: "Agent not found." }],
|
|
21605
|
+
structuredContent: {
|
|
21606
|
+
yourAgentId: requestInfo.agentId,
|
|
21607
|
+
success: false,
|
|
21608
|
+
message: "Agent not found."
|
|
21609
|
+
}
|
|
21610
|
+
};
|
|
21611
|
+
}
|
|
21612
|
+
const page = pageId ? getPage(pageId) : slug ? getPageBySlug(requestInfo.agentId, slug) : null;
|
|
21613
|
+
if (!page) {
|
|
21614
|
+
return {
|
|
21615
|
+
content: [{ type: "text", text: "Page not found." }],
|
|
21616
|
+
structuredContent: {
|
|
21617
|
+
yourAgentId: requestInfo.agentId,
|
|
21618
|
+
success: false,
|
|
21619
|
+
message: "Page not found."
|
|
21620
|
+
}
|
|
21621
|
+
};
|
|
21622
|
+
}
|
|
21623
|
+
const decision = can({
|
|
21624
|
+
principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead },
|
|
21625
|
+
verb: "page.delete.any",
|
|
21626
|
+
resource: { kind: "owned", ownerAgentId: page.agentId },
|
|
21627
|
+
source: "mcp"
|
|
21628
|
+
});
|
|
21629
|
+
if (!decision.allow) {
|
|
21630
|
+
return {
|
|
21631
|
+
content: [{ type: "text", text: "Only the lead or page owner can delete pages." }],
|
|
21632
|
+
structuredContent: {
|
|
21633
|
+
yourAgentId: requestInfo.agentId,
|
|
21634
|
+
success: false,
|
|
21635
|
+
message: "Only the lead or page owner can delete pages."
|
|
21636
|
+
}
|
|
21637
|
+
};
|
|
21638
|
+
}
|
|
21639
|
+
try {
|
|
21640
|
+
const deleted = deletePage(page.id);
|
|
21641
|
+
if (!deleted) {
|
|
21642
|
+
return {
|
|
21643
|
+
content: [{ type: "text", text: "Failed to delete page." }],
|
|
21644
|
+
structuredContent: {
|
|
21645
|
+
yourAgentId: requestInfo.agentId,
|
|
21646
|
+
success: false,
|
|
21647
|
+
message: "Failed to delete page."
|
|
21648
|
+
}
|
|
21649
|
+
};
|
|
21650
|
+
}
|
|
21651
|
+
const deletedPage = {
|
|
21652
|
+
id: page.id,
|
|
21653
|
+
slug: page.slug,
|
|
21654
|
+
title: page.title
|
|
21655
|
+
};
|
|
21656
|
+
return {
|
|
21657
|
+
content: [{ type: "text", text: `Deleted page "${page.title}".` }],
|
|
21658
|
+
structuredContent: {
|
|
21659
|
+
yourAgentId: requestInfo.agentId,
|
|
21660
|
+
success: true,
|
|
21661
|
+
message: `Deleted page "${page.title}".`,
|
|
21662
|
+
deletedPage
|
|
21663
|
+
}
|
|
21664
|
+
};
|
|
21665
|
+
} catch (error) {
|
|
21666
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
21667
|
+
return {
|
|
21668
|
+
content: [{ type: "text", text: `Failed to delete page: ${message}` }],
|
|
21669
|
+
structuredContent: {
|
|
21670
|
+
yourAgentId: requestInfo.agentId,
|
|
21671
|
+
success: false,
|
|
21672
|
+
message: `Failed to delete page: ${message}`
|
|
21673
|
+
}
|
|
21674
|
+
};
|
|
21675
|
+
}
|
|
21676
|
+
});
|
|
21677
|
+
};
|
|
21678
|
+
|
|
21640
21679
|
// src/tools/get-metrics.ts
|
|
21641
21680
|
init_zod();
|
|
21642
21681
|
init_db();
|
|
@@ -23095,18 +23134,19 @@ var registerMcpServerDeleteTool = (server) => {
|
|
|
23095
23134
|
}
|
|
23096
23135
|
};
|
|
23097
23136
|
}
|
|
23098
|
-
const
|
|
23137
|
+
const result = deleteMcpServer(args.id);
|
|
23138
|
+
const message = result.deleted ? `Deleted MCP server "${existing.name}" and ${result.deletedScriptConnectionCount} script connection(s).` : "Delete failed.";
|
|
23099
23139
|
return {
|
|
23100
23140
|
content: [
|
|
23101
23141
|
{
|
|
23102
23142
|
type: "text",
|
|
23103
|
-
text:
|
|
23143
|
+
text: message
|
|
23104
23144
|
}
|
|
23105
23145
|
],
|
|
23106
23146
|
structuredContent: {
|
|
23107
23147
|
yourAgentId: requestInfo.agentId,
|
|
23108
|
-
success: deleted,
|
|
23109
|
-
message
|
|
23148
|
+
success: result.deleted,
|
|
23149
|
+
message
|
|
23110
23150
|
}
|
|
23111
23151
|
};
|
|
23112
23152
|
});
|
|
@@ -26180,6 +26220,45 @@ var registerUpdateRepoTool = (server) => {
|
|
|
26180
26220
|
};
|
|
26181
26221
|
// src/tools/request-human-input.ts
|
|
26182
26222
|
init_zod();
|
|
26223
|
+
|
|
26224
|
+
// src/be/audit-user.ts
|
|
26225
|
+
init_request_auth_context();
|
|
26226
|
+
init_db();
|
|
26227
|
+
function resolveTaskAuditUserId(sourceTaskId, callerAgentId) {
|
|
26228
|
+
if (!callerAgentId)
|
|
26229
|
+
return null;
|
|
26230
|
+
let resolvedSourceTaskId = sourceTaskId;
|
|
26231
|
+
if (!resolvedSourceTaskId) {
|
|
26232
|
+
const currentTask = getAgentCurrentTask(callerAgentId);
|
|
26233
|
+
if (currentTask)
|
|
26234
|
+
resolvedSourceTaskId = currentTask.id;
|
|
26235
|
+
}
|
|
26236
|
+
if (!resolvedSourceTaskId)
|
|
26237
|
+
return null;
|
|
26238
|
+
const task = getTaskById(resolvedSourceTaskId);
|
|
26239
|
+
if (!task)
|
|
26240
|
+
return null;
|
|
26241
|
+
if (task.agentId !== callerAgentId)
|
|
26242
|
+
return null;
|
|
26243
|
+
if (task.requestedByUserId)
|
|
26244
|
+
return task.requestedByUserId;
|
|
26245
|
+
if (task.slackUserId) {
|
|
26246
|
+
const user = findUserByExternalId("slack", task.slackUserId);
|
|
26247
|
+
if (user)
|
|
26248
|
+
return user.id;
|
|
26249
|
+
}
|
|
26250
|
+
return null;
|
|
26251
|
+
}
|
|
26252
|
+
function resolveHttpAuditUserId(req, callerAgentId) {
|
|
26253
|
+
const auth = getRequestAuth(req);
|
|
26254
|
+
if (auth?.kind === "user")
|
|
26255
|
+
return auth.userId;
|
|
26256
|
+
const header = req.headers["x-source-task-id"];
|
|
26257
|
+
const sourceTaskId = Array.isArray(header) ? header[0] : header;
|
|
26258
|
+
return resolveTaskAuditUserId(sourceTaskId, callerAgentId);
|
|
26259
|
+
}
|
|
26260
|
+
|
|
26261
|
+
// src/tools/request-human-input.ts
|
|
26183
26262
|
init_db();
|
|
26184
26263
|
var QuestionSchema = object({
|
|
26185
26264
|
id: string().describe("Unique ID for the question (used as key in responses)"),
|
|
@@ -26245,7 +26324,8 @@ var registerRequestHumanInputTool = (server) => {
|
|
|
26245
26324
|
questions,
|
|
26246
26325
|
approvers: { policy: "any" },
|
|
26247
26326
|
sourceTaskId: sourceTaskId ?? undefined,
|
|
26248
|
-
timeoutSeconds
|
|
26327
|
+
timeoutSeconds,
|
|
26328
|
+
createdBy: resolveTaskAuditUserId(sourceTaskId, requestInfo.agentId) ?? undefined
|
|
26249
26329
|
});
|
|
26250
26330
|
const appUrl = getAppUrl();
|
|
26251
26331
|
const url = `${appUrl}/approval-requests/${request.id}`;
|
|
@@ -26270,67 +26350,72 @@ var registerRequestHumanInputTool = (server) => {
|
|
|
26270
26350
|
// src/tools/resolve-user.ts
|
|
26271
26351
|
init_zod();
|
|
26272
26352
|
var resolveUserInputSchema = object({
|
|
26273
|
-
kind: string().optional().describe("Identity kind — e.g. 'slack', 'linear', 'github', 'gitlab', 'jira', or a custom value. Must be paired with externalId."),
|
|
26274
|
-
externalId: string().optional().describe("Platform-specific identifier for the given kind (e.g. Slack user ID 'U08NR6QD6CS', Linear user UUID, GitHub login)."),
|
|
26353
|
+
kind: string().optional().describe("Identity kind — e.g. 'slack', 'linear', 'github', 'gitlab', 'jira', 'kapso', 'whatsapp', or a custom value. Must be paired with externalId."),
|
|
26354
|
+
externalId: string().optional().describe("Platform-specific identifier for the given kind (e.g. Slack user ID 'U08NR6QD6CS', Linear user UUID, GitHub login, Jira accountId)."),
|
|
26275
26355
|
email: string().email().optional().describe("Email address (primary or alias)."),
|
|
26276
|
-
userId: string().optional().describe("Canonical swarm user ID. Use this to reverse-look up all external identities for a known user (e.g. find their GitHub handle from a requestedByUserId).")
|
|
26277
|
-
|
|
26356
|
+
userId: string().optional().describe("Canonical swarm user ID. Use this to reverse-look up all external identities for a known user (e.g. find their GitHub handle from a requestedByUserId)."),
|
|
26357
|
+
name: string().min(2).optional().describe("Human display name to search for (exact, or first-token prefix). Convenience only — ambiguous matches return all candidates rather than picking one.")
|
|
26358
|
+
}).strict().refine((v) => v.kind !== undefined && v.externalId !== undefined || v.email !== undefined || v.userId !== undefined || v.name !== undefined, { message: "Provide either (kind + externalId), email, userId, or name" });
|
|
26359
|
+
function jsonResult(value) {
|
|
26360
|
+
return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
|
|
26361
|
+
}
|
|
26362
|
+
function profileResult(user) {
|
|
26363
|
+
return jsonResult({ ...user, externalIds: getUserIdentities(user.id) });
|
|
26364
|
+
}
|
|
26365
|
+
function unknownResult(kind, externalId) {
|
|
26366
|
+
return jsonResult({ status: "unknown", kind, externalId });
|
|
26367
|
+
}
|
|
26368
|
+
function ambiguousResult(candidates) {
|
|
26369
|
+
return jsonResult({
|
|
26370
|
+
status: "ambiguous",
|
|
26371
|
+
message: "AMBIGUOUS — do not pick by salience. Multiple users match this name; disambiguate with (kind, externalId), email, or userId.",
|
|
26372
|
+
candidates: candidates.map((u) => ({ userId: u.id, name: u.name, email: u.email }))
|
|
26373
|
+
});
|
|
26374
|
+
}
|
|
26278
26375
|
var registerResolveUserTool = (server) => {
|
|
26279
26376
|
createToolRegistrar(server)("resolve-user", {
|
|
26280
26377
|
title: "Resolve user identity",
|
|
26281
|
-
description: "
|
|
26378
|
+
description: "Provider-agnostic reverse lookup: (kind, externalId) → user, e.g. {kind: 'slack', externalId: 'U016H7XKZGS'} or {kind: 'github', externalId: 'octocat'} — the same shape for every provider, no per-provider keys. Also accepts email (primary or alias), userId (reverse lookup of all linked identities), or name (exact/prefix search). A miss returns a structured {status: 'unknown', ...} payload, never prose; an ambiguous name search returns {status: 'ambiguous', candidates: [...]}.",
|
|
26282
26379
|
annotations: { readOnlyHint: true },
|
|
26283
26380
|
inputSchema: resolveUserInputSchema
|
|
26284
|
-
}, async ({ kind, externalId, email, userId }) => {
|
|
26285
|
-
let user = null;
|
|
26381
|
+
}, async ({ kind, externalId, email, userId, name }) => {
|
|
26286
26382
|
if (kind && externalId) {
|
|
26287
|
-
|
|
26288
|
-
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
|
|
26293
|
-
|
|
26294
|
-
|
|
26295
|
-
|
|
26296
|
-
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
|
|
26300
|
-
|
|
26301
|
-
|
|
26302
|
-
|
|
26303
|
-
}
|
|
26383
|
+
const resolution = resolveIdentity(kind, externalId);
|
|
26384
|
+
if (resolution.status === "unknown")
|
|
26385
|
+
return unknownResult(kind, externalId);
|
|
26386
|
+
const user = findUserById(resolution.userId);
|
|
26387
|
+
if (!user)
|
|
26388
|
+
return unknownResult(kind, externalId);
|
|
26389
|
+
return profileResult(user);
|
|
26390
|
+
}
|
|
26391
|
+
if (email) {
|
|
26392
|
+
const resolution = resolveIdentityByEmail(email);
|
|
26393
|
+
if (resolution.status === "unknown")
|
|
26394
|
+
return unknownResult("email", email);
|
|
26395
|
+
const user = findUserById(resolution.userId);
|
|
26396
|
+
if (!user)
|
|
26397
|
+
return unknownResult("email", email);
|
|
26398
|
+
return profileResult(user);
|
|
26399
|
+
}
|
|
26400
|
+
if (userId) {
|
|
26401
|
+
const user = findUserById(userId);
|
|
26402
|
+
if (!user)
|
|
26403
|
+
return unknownResult("userId", userId);
|
|
26404
|
+
return profileResult(user);
|
|
26405
|
+
}
|
|
26406
|
+
const matches = findUsersByName(name ?? "");
|
|
26407
|
+
if (matches.length === 0)
|
|
26408
|
+
return unknownResult("name", name ?? "");
|
|
26409
|
+
const [only] = matches;
|
|
26410
|
+
if (matches.length === 1 && only)
|
|
26411
|
+
return profileResult(only);
|
|
26412
|
+
return ambiguousResult(matches);
|
|
26304
26413
|
});
|
|
26305
26414
|
};
|
|
26306
26415
|
|
|
26307
26416
|
// src/tools/schedules/create-schedule.ts
|
|
26308
26417
|
init_zod();
|
|
26309
26418
|
var import_cron_parser = __toESM(require_dist(), 1);
|
|
26310
|
-
|
|
26311
|
-
// src/be/audit-user.ts
|
|
26312
|
-
init_request_auth_context();
|
|
26313
|
-
init_db();
|
|
26314
|
-
function resolveTaskAuditUserId(sourceTaskId, callerAgentId) {
|
|
26315
|
-
if (!sourceTaskId || !callerAgentId)
|
|
26316
|
-
return null;
|
|
26317
|
-
const task = getTaskById(sourceTaskId);
|
|
26318
|
-
if (!task)
|
|
26319
|
-
return null;
|
|
26320
|
-
if (task.agentId !== callerAgentId)
|
|
26321
|
-
return null;
|
|
26322
|
-
return task.requestedByUserId ?? null;
|
|
26323
|
-
}
|
|
26324
|
-
function resolveHttpAuditUserId(req, callerAgentId) {
|
|
26325
|
-
const auth = getRequestAuth(req);
|
|
26326
|
-
if (auth?.kind === "user")
|
|
26327
|
-
return auth.userId;
|
|
26328
|
-
const header = req.headers["x-source-task-id"];
|
|
26329
|
-
const sourceTaskId = Array.isArray(header) ? header[0] : header;
|
|
26330
|
-
return resolveTaskAuditUserId(sourceTaskId, callerAgentId);
|
|
26331
|
-
}
|
|
26332
|
-
|
|
26333
|
-
// src/tools/schedules/create-schedule.ts
|
|
26334
26419
|
init_db();
|
|
26335
26420
|
init_types();
|
|
26336
26421
|
var createScheduleInputSchema = object({
|
|
@@ -27783,6 +27868,7 @@ var registerUpdateScheduleTool = (server) => {
|
|
|
27783
27868
|
};
|
|
27784
27869
|
// src/tools/script-apis.ts
|
|
27785
27870
|
init_zod();
|
|
27871
|
+
init_db();
|
|
27786
27872
|
init_secret_scrubber();
|
|
27787
27873
|
|
|
27788
27874
|
// src/tools/script-common.ts
|
|
@@ -27866,13 +27952,29 @@ function maskToken(endpoint) {
|
|
|
27866
27952
|
const { token: _drop, ...rest } = endpoint;
|
|
27867
27953
|
return { ...rest, token: endpoint.authMode === "bearer" ? "********" : null };
|
|
27868
27954
|
}
|
|
27869
|
-
function errorResult(message) {
|
|
27955
|
+
function errorResult(message, status = 400) {
|
|
27870
27956
|
return {
|
|
27871
27957
|
isError: true,
|
|
27872
27958
|
content: [{ type: "text", text: message }],
|
|
27873
|
-
structuredContent: { success: false, status
|
|
27959
|
+
structuredContent: { success: false, status, error: message }
|
|
27874
27960
|
};
|
|
27875
27961
|
}
|
|
27962
|
+
function requireScriptApiPermission(requestInfo, verb, message) {
|
|
27963
|
+
if (!requestInfo.agentId)
|
|
27964
|
+
return errorResult(SCRIPT_TRANSPORT_ERROR);
|
|
27965
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
27966
|
+
const decision = can({
|
|
27967
|
+
principal: {
|
|
27968
|
+
kind: "agent",
|
|
27969
|
+
agentId: requestInfo.agentId,
|
|
27970
|
+
isLead: agent?.isLead ?? false
|
|
27971
|
+
},
|
|
27972
|
+
verb,
|
|
27973
|
+
resource: { kind: "none" },
|
|
27974
|
+
source: "mcp"
|
|
27975
|
+
});
|
|
27976
|
+
return decision.allow ? null : errorResult(message, 403);
|
|
27977
|
+
}
|
|
27876
27978
|
var registerScriptApisTool = (server) => {
|
|
27877
27979
|
createToolRegistrar(server)("script-apis", {
|
|
27878
27980
|
title: "Script APIs",
|
|
@@ -27893,6 +27995,9 @@ var registerScriptApisTool = (server) => {
|
|
|
27893
27995
|
const raw = result.structuredContent?.data;
|
|
27894
27996
|
let endpoints = (raw?.apis ?? []).map(maskToken);
|
|
27895
27997
|
if (args.includeSecrets) {
|
|
27998
|
+
const denied = requireScriptApiPermission(requestInfo, "script.api.read.secrets", "Only lead agents can reveal script API bearer tokens.");
|
|
27999
|
+
if (denied)
|
|
28000
|
+
return denied;
|
|
27896
28001
|
endpoints = await Promise.all(endpoints.map(async (endpoint) => {
|
|
27897
28002
|
if (endpoint.authMode !== "bearer")
|
|
27898
28003
|
return endpoint;
|
|
@@ -27916,6 +28021,9 @@ var registerScriptApisTool = (server) => {
|
|
|
27916
28021
|
};
|
|
27917
28022
|
}
|
|
27918
28023
|
if (args.action === "create") {
|
|
28024
|
+
const denied = requireScriptApiPermission(requestInfo, "script.api.create", "Only lead agents can create script API endpoints.");
|
|
28025
|
+
if (denied)
|
|
28026
|
+
return denied;
|
|
27919
28027
|
const result = await proxyScriptsApi({
|
|
27920
28028
|
method: "POST",
|
|
27921
28029
|
path: `/api/scripts/${args.scriptId}/apis`,
|
|
@@ -27937,6 +28045,9 @@ var registerScriptApisTool = (server) => {
|
|
|
27937
28045
|
if (args.action === "rotate") {
|
|
27938
28046
|
if (!args.endpointId)
|
|
27939
28047
|
return errorResult("endpointId is required for rotate.");
|
|
28048
|
+
const denied = requireScriptApiPermission(requestInfo, "script.api.rotate", "Only lead agents can rotate script API bearer tokens.");
|
|
28049
|
+
if (denied)
|
|
28050
|
+
return denied;
|
|
27940
28051
|
const result = await proxyScriptsApi({
|
|
27941
28052
|
method: "POST",
|
|
27942
28053
|
path: `/api/scripts/${args.scriptId}/apis/${args.endpointId}/rotate`,
|
|
@@ -27953,6 +28064,9 @@ var registerScriptApisTool = (server) => {
|
|
|
27953
28064
|
if (args.action === "update") {
|
|
27954
28065
|
if (!args.endpointId)
|
|
27955
28066
|
return errorResult("endpointId is required for update.");
|
|
28067
|
+
const denied = requireScriptApiPermission(requestInfo, "script.api.update", "Only lead agents can update script API endpoints.");
|
|
28068
|
+
if (denied)
|
|
28069
|
+
return denied;
|
|
27956
28070
|
return proxyScriptsApi({
|
|
27957
28071
|
method: "PATCH",
|
|
27958
28072
|
path: `/api/scripts/${args.scriptId}/apis/${args.endpointId}`,
|
|
@@ -27964,6 +28078,9 @@ var registerScriptApisTool = (server) => {
|
|
|
27964
28078
|
if (args.action === "delete") {
|
|
27965
28079
|
if (!args.endpointId)
|
|
27966
28080
|
return errorResult("endpointId is required for delete.");
|
|
28081
|
+
const denied = requireScriptApiPermission(requestInfo, "script.api.delete", "Only lead agents can delete script API endpoints.");
|
|
28082
|
+
if (denied)
|
|
28083
|
+
return denied;
|
|
27967
28084
|
return proxyScriptsApi({
|
|
27968
28085
|
method: "DELETE",
|
|
27969
28086
|
path: `/api/scripts/${args.scriptId}/apis/${args.endpointId}`,
|
|
@@ -27979,20 +28096,22 @@ var registerScriptApisTool = (server) => {
|
|
|
27979
28096
|
init_zod();
|
|
27980
28097
|
init_db();
|
|
27981
28098
|
var scriptConnectionsInputSchema = object({
|
|
27982
|
-
action: _enum(["list", "upsert-openapi", "disable"]).describe("List, create/update, or disable a script connection."),
|
|
27983
|
-
id: string().uuid().optional(),
|
|
27984
|
-
slug: string().min(1).max(80).optional(),
|
|
27985
|
-
displayName: string().max(160).optional(),
|
|
27986
|
-
scope: _enum(["global", "agent", "repo"]).
|
|
27987
|
-
scopeId:
|
|
27988
|
-
|
|
27989
|
-
|
|
27990
|
-
|
|
27991
|
-
|
|
27992
|
-
|
|
27993
|
-
|
|
27994
|
-
|
|
27995
|
-
|
|
28099
|
+
action: _enum(["list", "upsert-openapi", "upsert-mcp", "upsert-graphql", "refresh", "disable"]).describe("List, create/update, refresh, or disable a script connection."),
|
|
28100
|
+
id: string().uuid().optional().describe("Existing connection ID for update, refresh, or disable."),
|
|
28101
|
+
slug: string().min(1).max(80).optional().describe("Stable script namespace slug exposed under ctx.api or ctx.mcp."),
|
|
28102
|
+
displayName: string().max(160).optional().describe("Human-readable connection name."),
|
|
28103
|
+
scope: _enum(["global", "agent", "repo"]).optional().describe("Connection visibility scope."),
|
|
28104
|
+
scopeId: scopedResourceScopeIdSchema.nullable().optional().describe("Agent UUID for agent scope or repo id (owner/name) for repo scope."),
|
|
28105
|
+
mcpServerId: string().uuid().optional().describe("Registered MCP server ID for upsert-mcp connections."),
|
|
28106
|
+
baseUrl: string().url().optional().describe("Base URL for OpenAPI or GraphQL connections."),
|
|
28107
|
+
allowedHosts: array(string().min(1)).optional().describe("Allowed outbound hostnames for credential substitution."),
|
|
28108
|
+
credentialBindingId: string().uuid().nullable().optional().describe("Existing credential binding ID to attach to the connection."),
|
|
28109
|
+
configKey: string().min(1).max(255).optional().describe("Config key used to create a credential binding when credentialBindingId is omitted."),
|
|
28110
|
+
headerTemplate: string().min(1).optional().describe("Header template containing the config-key placeholder."),
|
|
28111
|
+
queryTemplate: string().min(1).optional().describe("Query parameter template containing the config-key placeholder."),
|
|
28112
|
+
openapiSpecUrl: string().url().optional().describe("URL to fetch and store an OpenAPI spec for upsert-openapi and refresh."),
|
|
28113
|
+
openapiSpecJson: string().optional().describe("Inline OpenAPI JSON for upsert-openapi. Mutually exclusive with openapiSpecUrl."),
|
|
28114
|
+
enabled: boolean().optional().describe("Whether the connection is enabled.")
|
|
27996
28115
|
});
|
|
27997
28116
|
var scriptConnectionsOutputSchema = object({
|
|
27998
28117
|
yourAgentId: string().uuid().optional(),
|
|
@@ -28000,10 +28119,23 @@ var scriptConnectionsOutputSchema = object({
|
|
|
28000
28119
|
message: string(),
|
|
28001
28120
|
connections: array(unknown())
|
|
28002
28121
|
});
|
|
28122
|
+
function resolveConnectionScope(args, existing) {
|
|
28123
|
+
const scopeWasProvided = Object.hasOwn(args, "scope");
|
|
28124
|
+
const scopeIdWasProvided = Object.hasOwn(args, "scopeId");
|
|
28125
|
+
const scope = (scopeWasProvided ? args.scope : existing?.scope) ?? "global";
|
|
28126
|
+
const scopeIdInput = scopeIdWasProvided ? args.scopeId : existing && scope === existing.scope ? existing.scopeId : null;
|
|
28127
|
+
return {
|
|
28128
|
+
scope,
|
|
28129
|
+
scopeId: resolveScopedResourceId(scope, scopeIdInput, "connections")
|
|
28130
|
+
};
|
|
28131
|
+
}
|
|
28132
|
+
function resolveConnectionEnabled(args, existing) {
|
|
28133
|
+
return Object.hasOwn(args, "enabled") ? args.enabled !== false : existing?.enabled ?? true;
|
|
28134
|
+
}
|
|
28003
28135
|
var registerScriptConnectionsTool = (server) => {
|
|
28004
28136
|
createToolRegistrar(server)("script-connections", {
|
|
28005
28137
|
title: "Script Connections",
|
|
28006
|
-
description: "Lead-only registry management for scripts ctx.api/ctx.mcp connections.
|
|
28138
|
+
description: "Lead-only registry management for scripts ctx.api/ctx.mcp connections. Supports OpenAPI, MCP, and GraphQL script connections.",
|
|
28007
28139
|
annotations: { idempotentHint: true },
|
|
28008
28140
|
inputSchema: scriptConnectionsInputSchema,
|
|
28009
28141
|
outputSchema: scriptConnectionsOutputSchema
|
|
@@ -28041,7 +28173,7 @@ var registerScriptConnectionsTool = (server) => {
|
|
|
28041
28173
|
};
|
|
28042
28174
|
}
|
|
28043
28175
|
if (args.action === "list") {
|
|
28044
|
-
const connections2 = listScriptConnections({ includeDisabled: true });
|
|
28176
|
+
const connections2 = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28045
28177
|
return {
|
|
28046
28178
|
content: [{ type: "text", text: `Found ${connections2.length} script connection(s).` }],
|
|
28047
28179
|
structuredContent: {
|
|
@@ -28060,12 +28192,12 @@ var registerScriptConnectionsTool = (server) => {
|
|
|
28060
28192
|
yourAgentId: requestInfo.agentId,
|
|
28061
28193
|
success: false,
|
|
28062
28194
|
message: "id is required for disable.",
|
|
28063
|
-
connections: listScriptConnections({ includeDisabled: true })
|
|
28195
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28064
28196
|
}
|
|
28065
28197
|
};
|
|
28066
28198
|
}
|
|
28067
28199
|
setScriptConnectionEnabled(args.id, false);
|
|
28068
|
-
const connections2 = listScriptConnections({ includeDisabled: true });
|
|
28200
|
+
const connections2 = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28069
28201
|
return {
|
|
28070
28202
|
content: [{ type: "text", text: "Script connection disabled." }],
|
|
28071
28203
|
structuredContent: {
|
|
@@ -28076,44 +28208,191 @@ var registerScriptConnectionsTool = (server) => {
|
|
|
28076
28208
|
}
|
|
28077
28209
|
};
|
|
28078
28210
|
}
|
|
28079
|
-
if (
|
|
28211
|
+
if (args.action === "refresh") {
|
|
28212
|
+
if (!args.id) {
|
|
28213
|
+
return {
|
|
28214
|
+
content: [{ type: "text", text: "id is required for refresh." }],
|
|
28215
|
+
structuredContent: {
|
|
28216
|
+
yourAgentId: requestInfo.agentId,
|
|
28217
|
+
success: false,
|
|
28218
|
+
message: "id is required for refresh.",
|
|
28219
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28220
|
+
}
|
|
28221
|
+
};
|
|
28222
|
+
}
|
|
28223
|
+
const refreshed = await refreshScriptConnection(args.id, null, requestInfo.agentId);
|
|
28224
|
+
const connections2 = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28225
|
+
if (!refreshed) {
|
|
28226
|
+
return {
|
|
28227
|
+
content: [{ type: "text", text: "Script connection not found." }],
|
|
28228
|
+
structuredContent: {
|
|
28229
|
+
yourAgentId: requestInfo.agentId,
|
|
28230
|
+
success: false,
|
|
28231
|
+
message: "Script connection not found.",
|
|
28232
|
+
connections: connections2
|
|
28233
|
+
}
|
|
28234
|
+
};
|
|
28235
|
+
}
|
|
28236
|
+
return {
|
|
28237
|
+
content: [{ type: "text", text: `Script connection ${refreshed.slug} refreshed.` }],
|
|
28238
|
+
structuredContent: {
|
|
28239
|
+
yourAgentId: requestInfo.agentId,
|
|
28240
|
+
success: !refreshed.generationError,
|
|
28241
|
+
message: refreshed.generationError ? `Refreshed but generation failed: ${refreshed.generationError}` : `Script connection ${refreshed.slug} refreshed.`,
|
|
28242
|
+
connections: connections2
|
|
28243
|
+
}
|
|
28244
|
+
};
|
|
28245
|
+
}
|
|
28246
|
+
if (args.action === "upsert-mcp") {
|
|
28247
|
+
if (!args.slug || !args.mcpServerId) {
|
|
28248
|
+
return {
|
|
28249
|
+
content: [{ type: "text", text: "slug and mcpServerId are required." }],
|
|
28250
|
+
structuredContent: {
|
|
28251
|
+
yourAgentId: requestInfo.agentId,
|
|
28252
|
+
success: false,
|
|
28253
|
+
message: "slug and mcpServerId are required.",
|
|
28254
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28255
|
+
}
|
|
28256
|
+
};
|
|
28257
|
+
}
|
|
28258
|
+
const existing2 = args.id ? getScriptConnectionById(args.id) : null;
|
|
28259
|
+
const { scope: scope2, scopeId: scopeId2 } = resolveConnectionScope(args, existing2);
|
|
28260
|
+
const connection2 = await upsertScriptConnection({
|
|
28261
|
+
id: args.id,
|
|
28262
|
+
slug: args.slug,
|
|
28263
|
+
displayName: args.displayName,
|
|
28264
|
+
kind: "mcp",
|
|
28265
|
+
scope: scope2,
|
|
28266
|
+
scopeId: scopeId2,
|
|
28267
|
+
mcpServerId: args.mcpServerId,
|
|
28268
|
+
enabled: resolveConnectionEnabled(args, existing2),
|
|
28269
|
+
agentId: requestInfo.agentId
|
|
28270
|
+
});
|
|
28271
|
+
const connections2 = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28272
|
+
return {
|
|
28273
|
+
content: [{ type: "text", text: `Script MCP connection ${connection2.slug} saved.` }],
|
|
28274
|
+
structuredContent: {
|
|
28275
|
+
yourAgentId: requestInfo.agentId,
|
|
28276
|
+
success: !connection2.generationError,
|
|
28277
|
+
message: connection2.generationError ? `Saved but generation failed: ${connection2.generationError}` : `Script MCP connection ${connection2.slug} saved.`,
|
|
28278
|
+
connections: connections2
|
|
28279
|
+
}
|
|
28280
|
+
};
|
|
28281
|
+
}
|
|
28282
|
+
if (args.action === "upsert-graphql") {
|
|
28283
|
+
if (!args.slug || !args.baseUrl || !args.allowedHosts?.length) {
|
|
28284
|
+
return {
|
|
28285
|
+
content: [{ type: "text", text: "slug, baseUrl, and allowedHosts are required." }],
|
|
28286
|
+
structuredContent: {
|
|
28287
|
+
yourAgentId: requestInfo.agentId,
|
|
28288
|
+
success: false,
|
|
28289
|
+
message: "slug, baseUrl, and allowedHosts are required.",
|
|
28290
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28291
|
+
}
|
|
28292
|
+
};
|
|
28293
|
+
}
|
|
28294
|
+
let credentialBindingId2 = args.credentialBindingId ?? null;
|
|
28295
|
+
if (!credentialBindingId2 && args.configKey) {
|
|
28296
|
+
const placeholder = placeholderForConfigKey(args.configKey);
|
|
28297
|
+
const bindingScope = args.scope ?? "global";
|
|
28298
|
+
const binding = upsertCredentialBinding({
|
|
28299
|
+
configKey: args.configKey,
|
|
28300
|
+
allowedHosts: args.allowedHosts,
|
|
28301
|
+
headerTemplate: args.headerTemplate ?? (args.queryTemplate ? undefined : `Authorization: Bearer ${placeholder}`),
|
|
28302
|
+
queryTemplate: args.queryTemplate,
|
|
28303
|
+
scope: bindingScope,
|
|
28304
|
+
scopeId: resolveScopedResourceId(bindingScope, args.scopeId, "bindings")
|
|
28305
|
+
});
|
|
28306
|
+
credentialBindingId2 = binding.id;
|
|
28307
|
+
}
|
|
28308
|
+
const existing2 = args.id ? getScriptConnectionById(args.id) : null;
|
|
28309
|
+
const { scope: scope2, scopeId: scopeId2 } = resolveConnectionScope(args, existing2);
|
|
28310
|
+
const connection2 = await upsertScriptConnection({
|
|
28311
|
+
id: args.id,
|
|
28312
|
+
slug: args.slug,
|
|
28313
|
+
displayName: args.displayName,
|
|
28314
|
+
kind: "graphql",
|
|
28315
|
+
scope: scope2,
|
|
28316
|
+
scopeId: scopeId2,
|
|
28317
|
+
baseUrl: args.baseUrl,
|
|
28318
|
+
allowedHosts: args.allowedHosts,
|
|
28319
|
+
credentialBindingId: credentialBindingId2,
|
|
28320
|
+
enabled: resolveConnectionEnabled(args, existing2)
|
|
28321
|
+
});
|
|
28322
|
+
const connections2 = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28323
|
+
return {
|
|
28324
|
+
content: [{ type: "text", text: `Script GraphQL connection ${connection2.slug} saved.` }],
|
|
28325
|
+
structuredContent: {
|
|
28326
|
+
yourAgentId: requestInfo.agentId,
|
|
28327
|
+
success: !connection2.generationError,
|
|
28328
|
+
message: connection2.generationError ? `Saved but generation failed: ${connection2.generationError}` : `Script GraphQL connection ${connection2.slug} saved.`,
|
|
28329
|
+
connections: connections2
|
|
28330
|
+
}
|
|
28331
|
+
};
|
|
28332
|
+
}
|
|
28333
|
+
if (!args.slug || !args.baseUrl || !args.openapiSpecJson && !args.openapiSpecUrl) {
|
|
28334
|
+
return {
|
|
28335
|
+
content: [
|
|
28336
|
+
{
|
|
28337
|
+
type: "text",
|
|
28338
|
+
text: "slug, baseUrl, and either openapiSpecJson or openapiSpecUrl are required."
|
|
28339
|
+
}
|
|
28340
|
+
],
|
|
28341
|
+
structuredContent: {
|
|
28342
|
+
yourAgentId: requestInfo.agentId,
|
|
28343
|
+
success: false,
|
|
28344
|
+
message: "slug, baseUrl, and either openapiSpecJson or openapiSpecUrl are required.",
|
|
28345
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28346
|
+
}
|
|
28347
|
+
};
|
|
28348
|
+
}
|
|
28349
|
+
if (args.openapiSpecJson && args.openapiSpecUrl) {
|
|
28080
28350
|
return {
|
|
28081
|
-
content: [
|
|
28351
|
+
content: [
|
|
28352
|
+
{
|
|
28353
|
+
type: "text",
|
|
28354
|
+
text: "Provide either openapiSpecJson or openapiSpecUrl, not both."
|
|
28355
|
+
}
|
|
28356
|
+
],
|
|
28082
28357
|
structuredContent: {
|
|
28083
28358
|
yourAgentId: requestInfo.agentId,
|
|
28084
28359
|
success: false,
|
|
28085
|
-
message: "
|
|
28086
|
-
connections: listScriptConnections({ includeDisabled: true })
|
|
28360
|
+
message: "Provide either openapiSpecJson or openapiSpecUrl, not both.",
|
|
28361
|
+
connections: listScriptConnections({ includeDisabled: true, allScopes: true })
|
|
28087
28362
|
}
|
|
28088
28363
|
};
|
|
28089
28364
|
}
|
|
28090
28365
|
let credentialBindingId = args.credentialBindingId ?? null;
|
|
28091
28366
|
if (!credentialBindingId && args.configKey) {
|
|
28092
28367
|
const placeholder = placeholderForConfigKey(args.configKey);
|
|
28368
|
+
const bindingScope = args.scope ?? "global";
|
|
28093
28369
|
const binding = upsertCredentialBinding({
|
|
28094
28370
|
configKey: args.configKey,
|
|
28095
28371
|
allowedHosts: args.allowedHosts ?? [new URL(args.baseUrl).hostname],
|
|
28096
|
-
headerTemplate: args.headerTemplate ?? `Authorization: Bearer ${placeholder}
|
|
28372
|
+
headerTemplate: args.headerTemplate ?? (args.queryTemplate ? undefined : `Authorization: Bearer ${placeholder}`),
|
|
28097
28373
|
queryTemplate: args.queryTemplate,
|
|
28098
|
-
scope:
|
|
28099
|
-
scopeId: args.
|
|
28374
|
+
scope: bindingScope,
|
|
28375
|
+
scopeId: resolveScopedResourceId(bindingScope, args.scopeId, "bindings")
|
|
28100
28376
|
});
|
|
28101
28377
|
credentialBindingId = binding.id;
|
|
28102
28378
|
}
|
|
28103
|
-
const
|
|
28379
|
+
const existing = args.id ? getScriptConnectionById(args.id) : null;
|
|
28380
|
+
const { scope, scopeId } = resolveConnectionScope(args, existing);
|
|
28381
|
+
const connection = await upsertScriptConnection({
|
|
28104
28382
|
id: args.id,
|
|
28105
28383
|
slug: args.slug,
|
|
28106
28384
|
displayName: args.displayName,
|
|
28107
28385
|
kind: "openapi",
|
|
28108
|
-
scope
|
|
28109
|
-
scopeId
|
|
28386
|
+
scope,
|
|
28387
|
+
scopeId,
|
|
28110
28388
|
baseUrl: args.baseUrl,
|
|
28111
28389
|
allowedHosts: args.allowedHosts ?? [new URL(args.baseUrl).hostname],
|
|
28112
28390
|
credentialBindingId,
|
|
28391
|
+
openapiSpecUrl: args.openapiSpecUrl,
|
|
28113
28392
|
openapiSpecJson: args.openapiSpecJson,
|
|
28114
|
-
enabled: args
|
|
28393
|
+
enabled: resolveConnectionEnabled(args, existing)
|
|
28115
28394
|
});
|
|
28116
|
-
const connections = listScriptConnections({ includeDisabled: true });
|
|
28395
|
+
const connections = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
28117
28396
|
return {
|
|
28118
28397
|
content: [{ type: "text", text: `Script connection ${connection.slug} saved.` }],
|
|
28119
28398
|
structuredContent: {
|
|
@@ -28385,6 +28664,7 @@ var sendTaskInputSchema = object({
|
|
|
28385
28664
|
offerMode: boolean().default(false).describe("If true, offer the task instead of direct assign (agent must accept/reject)."),
|
|
28386
28665
|
taskType: string().max(50).optional().describe("Task type (e.g., 'bug', 'feature', 'review')."),
|
|
28387
28666
|
tags: array(string()).optional().describe("Tags for filtering (e.g., ['urgent', 'frontend'])."),
|
|
28667
|
+
requiredCapabilities: array(string()).optional().describe("Capabilities a claiming agent must have (declared via join-swarm/update-profile) to be pool-eligible for this task. Written into the created task's routingAffinity (role is left unset — only enforced when the pool auto-claim/claim-tool paths check it). Most useful when omitting agentId (unassigned pool task); a no-op for a task with an explicit agentId, which bypasses the pool gate entirely."),
|
|
28388
28668
|
priority: number().int().min(0).max(100).optional().describe("Priority 0-100 (default: 50)."),
|
|
28389
28669
|
dependsOn: array(uuid()).optional().describe("Task IDs this task depends on."),
|
|
28390
28670
|
parentTaskId: uuid().optional().describe("Parent task ID for session continuity. Child task will resume the parent's Claude session. Auto-routes to the same worker unless agentId is explicitly provided."),
|
|
@@ -28392,7 +28672,7 @@ var sendTaskInputSchema = object({
|
|
|
28392
28672
|
vcsRepo: string().optional().describe("VCS repo identifier (e.g., 'desplega-ai/agent-swarm' for GitHub or 'group/project' for GitLab). Links the task to a registered repo for workspace context."),
|
|
28393
28673
|
model: string().trim().min(1).optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent."),
|
|
28394
28674
|
modelTier: ModelTierSchema.optional().describe("Portable model tier for this task: 'smol', 'regular', 'smart', or 'ultra'. Resolved at claim/run time using the assignee's harness/provider. Legacy model shortnames map as haiku→smol, sonnet→regular, opus→smart, fable→ultra."),
|
|
28395
|
-
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for this task: 'off', 'low', 'medium', 'high', or '
|
|
28675
|
+
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for this task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. If omitted, the assignee's REASONING_EFFORT_OVERRIDE/default applies."),
|
|
28396
28676
|
allowDuplicate: boolean().default(false).describe("If true, skip duplicate detection and create the task even if a similar one exists."),
|
|
28397
28677
|
slackChannelId: string().optional().describe("Slack channel ID to post progress updates to. Use this to propagate Slack context when delegating from a Slack thread."),
|
|
28398
28678
|
slackThreadTs: string().optional().describe("Slack thread timestamp. Required with slackChannelId for thread-level updates."),
|
|
@@ -28429,6 +28709,7 @@ async function sendTaskHandler(ctx, {
|
|
|
28429
28709
|
offerMode,
|
|
28430
28710
|
taskType,
|
|
28431
28711
|
tags,
|
|
28712
|
+
requiredCapabilities,
|
|
28432
28713
|
priority,
|
|
28433
28714
|
dependsOn,
|
|
28434
28715
|
dir,
|
|
@@ -28561,7 +28842,8 @@ async function sendTaskHandler(ctx, {
|
|
|
28561
28842
|
slackChannelId,
|
|
28562
28843
|
slackThreadTs,
|
|
28563
28844
|
slackUserId,
|
|
28564
|
-
followUpConfig
|
|
28845
|
+
followUpConfig,
|
|
28846
|
+
routingAffinity: requiredCapabilities?.length ? { capabilities: requiredCapabilities } : undefined
|
|
28565
28847
|
});
|
|
28566
28848
|
transferTrackerSyncToResumeChild({
|
|
28567
28849
|
parentTaskId: effectiveParentTaskId,
|
|
@@ -32013,7 +32295,10 @@ Thread: {{thread_id}}
|
|
|
32013
32295
|
|
|
32014
32296
|
{{preview}}`,
|
|
32015
32297
|
variables: [
|
|
32016
|
-
{
|
|
32298
|
+
{
|
|
32299
|
+
name: "from",
|
|
32300
|
+
description: "Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel"
|
|
32301
|
+
},
|
|
32017
32302
|
{ name: "subject", description: "Email subject" },
|
|
32018
32303
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
32019
32304
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -32032,7 +32317,10 @@ Message: {{message_id}}
|
|
|
32032
32317
|
|
|
32033
32318
|
{{preview}}`,
|
|
32034
32319
|
variables: [
|
|
32035
|
-
{
|
|
32320
|
+
{
|
|
32321
|
+
name: "from",
|
|
32322
|
+
description: "Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel"
|
|
32323
|
+
},
|
|
32036
32324
|
{ name: "subject", description: "Email subject" },
|
|
32037
32325
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
32038
32326
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -32051,7 +32339,10 @@ Thread: {{thread_id}}
|
|
|
32051
32339
|
|
|
32052
32340
|
{{preview}}`,
|
|
32053
32341
|
variables: [
|
|
32054
|
-
{
|
|
32342
|
+
{
|
|
32343
|
+
name: "from",
|
|
32344
|
+
description: "Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel"
|
|
32345
|
+
},
|
|
32055
32346
|
{ name: "subject", description: "Email subject" },
|
|
32056
32347
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
32057
32348
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -32070,7 +32361,10 @@ Message: {{message_id}}
|
|
|
32070
32361
|
|
|
32071
32362
|
{{preview}}`,
|
|
32072
32363
|
variables: [
|
|
32073
|
-
{
|
|
32364
|
+
{
|
|
32365
|
+
name: "from",
|
|
32366
|
+
description: "Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel"
|
|
32367
|
+
},
|
|
32074
32368
|
{ name: "subject", description: "Email subject" },
|
|
32075
32369
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
32076
32370
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -32089,7 +32383,10 @@ Thread: {{thread_id}}
|
|
|
32089
32383
|
|
|
32090
32384
|
{{preview}}`,
|
|
32091
32385
|
variables: [
|
|
32092
|
-
{
|
|
32386
|
+
{
|
|
32387
|
+
name: "from",
|
|
32388
|
+
description: "Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel"
|
|
32389
|
+
},
|
|
32093
32390
|
{ name: "subject", description: "Email subject" },
|
|
32094
32391
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
32095
32392
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -32211,6 +32508,7 @@ async function handleMessageReceived(payload) {
|
|
|
32211
32508
|
const { user } = findOrCreateUserByEmail(senderEmail, { name: senderName ?? undefined }, { kind: "system", id: "webhook:agentmail" });
|
|
32212
32509
|
requestedByUserId = user.id;
|
|
32213
32510
|
}
|
|
32511
|
+
const senderDisplay = senderEmail ? renderIdentity(resolveIdentityByEmail(senderEmail)) : renderIdentity({ status: "unknown", kind: "email", externalId: "unknown" });
|
|
32214
32512
|
const preview = body.length > 500 ? `${body.substring(0, 500)}...` : body;
|
|
32215
32513
|
workflowEventBus.emit("agentmail.message.received", {
|
|
32216
32514
|
inboxId: inbox_id,
|
|
@@ -32225,7 +32523,7 @@ async function handleMessageReceived(payload) {
|
|
|
32225
32523
|
const contextKey = agentmailContextKey({ threadId: thread_id });
|
|
32226
32524
|
const siblingInFlight = ACTIVE_TASK_STATUSES.has(existingTask.status);
|
|
32227
32525
|
if (agentmailBuffer.enabled && agentmailBuffer.maybeBuffer(contextKey, siblingInFlight, {
|
|
32228
|
-
from,
|
|
32526
|
+
from: senderDisplay,
|
|
32229
32527
|
subject,
|
|
32230
32528
|
inboxId: inbox_id,
|
|
32231
32529
|
threadId: thread_id,
|
|
@@ -32239,7 +32537,7 @@ async function handleMessageReceived(payload) {
|
|
|
32239
32537
|
return { created: false };
|
|
32240
32538
|
}
|
|
32241
32539
|
const followupResult = resolveTemplate("agentmail.email.followup", {
|
|
32242
|
-
from,
|
|
32540
|
+
from: senderDisplay,
|
|
32243
32541
|
subject,
|
|
32244
32542
|
inbox_id,
|
|
32245
32543
|
thread_id,
|
|
@@ -32268,7 +32566,7 @@ async function handleMessageReceived(payload) {
|
|
|
32268
32566
|
if (agent) {
|
|
32269
32567
|
if (agent.isLead) {
|
|
32270
32568
|
const leadResult = resolveTemplate("agentmail.email.mapped_lead", {
|
|
32271
|
-
from,
|
|
32569
|
+
from: senderDisplay,
|
|
32272
32570
|
subject,
|
|
32273
32571
|
inbox_id,
|
|
32274
32572
|
thread_id,
|
|
@@ -32292,7 +32590,7 @@ async function handleMessageReceived(payload) {
|
|
|
32292
32590
|
return { created: true, taskId: task3.id };
|
|
32293
32591
|
}
|
|
32294
32592
|
const workerResult = resolveTemplate("agentmail.email.mapped_worker", {
|
|
32295
|
-
from,
|
|
32593
|
+
from: senderDisplay,
|
|
32296
32594
|
subject,
|
|
32297
32595
|
inbox_id,
|
|
32298
32596
|
thread_id,
|
|
@@ -32318,7 +32616,7 @@ async function handleMessageReceived(payload) {
|
|
|
32318
32616
|
const lead = findLeadAgent();
|
|
32319
32617
|
if (lead) {
|
|
32320
32618
|
const unmappedResult = resolveTemplate("agentmail.email.unmapped", {
|
|
32321
|
-
from,
|
|
32619
|
+
from: senderDisplay,
|
|
32322
32620
|
subject,
|
|
32323
32621
|
inbox_id,
|
|
32324
32622
|
thread_id,
|
|
@@ -32342,7 +32640,7 @@ async function handleMessageReceived(payload) {
|
|
|
32342
32640
|
return { created: true, taskId: task2.id };
|
|
32343
32641
|
}
|
|
32344
32642
|
const noAgentResult = resolveTemplate("agentmail.email.no_agent", {
|
|
32345
|
-
from,
|
|
32643
|
+
from: senderDisplay,
|
|
32346
32644
|
subject,
|
|
32347
32645
|
inbox_id,
|
|
32348
32646
|
thread_id,
|
|
@@ -32365,6 +32663,170 @@ async function handleMessageReceived(payload) {
|
|
|
32365
32663
|
}
|
|
32366
32664
|
// src/http/core.ts
|
|
32367
32665
|
init_db();
|
|
32666
|
+
|
|
32667
|
+
// src/be/rbac-audit.ts
|
|
32668
|
+
init_db();
|
|
32669
|
+
var FLUSH_INTERVAL_MS = 2000;
|
|
32670
|
+
var FLUSH_MAX_ROWS = 200;
|
|
32671
|
+
var AUDIT_GC_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
32672
|
+
var DEFAULT_RETENTION_DAYS = 30;
|
|
32673
|
+
var buffer = [];
|
|
32674
|
+
var flushTimer = null;
|
|
32675
|
+
var auditGcTimer = null;
|
|
32676
|
+
var thresholdFlushScheduled = false;
|
|
32677
|
+
function isAuditDisabled() {
|
|
32678
|
+
return process.env.RBAC_AUDIT_DISABLED === "true";
|
|
32679
|
+
}
|
|
32680
|
+
function principalIdOf(principal) {
|
|
32681
|
+
switch (principal.kind) {
|
|
32682
|
+
case "agent":
|
|
32683
|
+
return principal.agentId;
|
|
32684
|
+
case "user":
|
|
32685
|
+
return principal.userId;
|
|
32686
|
+
case "operator":
|
|
32687
|
+
return null;
|
|
32688
|
+
}
|
|
32689
|
+
}
|
|
32690
|
+
function resourceIdOf(resource) {
|
|
32691
|
+
if (!resource)
|
|
32692
|
+
return null;
|
|
32693
|
+
switch (resource.kind) {
|
|
32694
|
+
case "task":
|
|
32695
|
+
return resource.taskId;
|
|
32696
|
+
case "agent":
|
|
32697
|
+
return resource.agentId;
|
|
32698
|
+
case "kv-namespace":
|
|
32699
|
+
return resource.namespace;
|
|
32700
|
+
case "owned":
|
|
32701
|
+
return resource.ownerAgentId ?? null;
|
|
32702
|
+
case "none":
|
|
32703
|
+
return null;
|
|
32704
|
+
}
|
|
32705
|
+
}
|
|
32706
|
+
function toRow(check, decision) {
|
|
32707
|
+
return {
|
|
32708
|
+
principalType: check.principal.kind,
|
|
32709
|
+
principalId: principalIdOf(check.principal),
|
|
32710
|
+
originatorUserId: null,
|
|
32711
|
+
verb: check.verb,
|
|
32712
|
+
resourceType: check.resource?.kind ?? null,
|
|
32713
|
+
resourceId: resourceIdOf(check.resource),
|
|
32714
|
+
decision: decision.allow ? "allow" : "deny",
|
|
32715
|
+
reason: decision.allow ? null : decision.reason,
|
|
32716
|
+
source: check.source
|
|
32717
|
+
};
|
|
32718
|
+
}
|
|
32719
|
+
function enqueueRow(row) {
|
|
32720
|
+
buffer.push(row);
|
|
32721
|
+
if (buffer.length >= FLUSH_MAX_ROWS && !thresholdFlushScheduled) {
|
|
32722
|
+
thresholdFlushScheduled = true;
|
|
32723
|
+
const t = setTimeout(() => {
|
|
32724
|
+
thresholdFlushScheduled = false;
|
|
32725
|
+
flushAuditBuffer();
|
|
32726
|
+
}, 0);
|
|
32727
|
+
if (typeof t.unref === "function")
|
|
32728
|
+
t.unref();
|
|
32729
|
+
}
|
|
32730
|
+
}
|
|
32731
|
+
function enqueueAuditRow(check, decision) {
|
|
32732
|
+
if (isAuditDisabled())
|
|
32733
|
+
return;
|
|
32734
|
+
try {
|
|
32735
|
+
enqueueRow(toRow(check, decision));
|
|
32736
|
+
} catch (err) {
|
|
32737
|
+
console.warn("[rbac-audit] enqueue failed, dropping row:", err.message);
|
|
32738
|
+
}
|
|
32739
|
+
}
|
|
32740
|
+
function enqueueAdmissionRow(input) {
|
|
32741
|
+
if (isAuditDisabled())
|
|
32742
|
+
return;
|
|
32743
|
+
try {
|
|
32744
|
+
const isMcp = input.source === "mcp";
|
|
32745
|
+
const method = isMcp ? undefined : (input.method ?? "UNKNOWN").toUpperCase();
|
|
32746
|
+
enqueueRow({
|
|
32747
|
+
principalType: "user",
|
|
32748
|
+
principalId: input.userId,
|
|
32749
|
+
originatorUserId: null,
|
|
32750
|
+
verb: input.decision.verb ?? "(admission:no-verb)",
|
|
32751
|
+
resourceType: isMcp ? "mcp-tool" : "http-route",
|
|
32752
|
+
resourceId: isMcp ? input.toolName : `${method} ${input.route}`,
|
|
32753
|
+
decision: input.decision.allow ? "allow" : "deny",
|
|
32754
|
+
reason: input.decision.allow ? null : input.decision.reason,
|
|
32755
|
+
source: isMcp ? "mcp" : "http"
|
|
32756
|
+
});
|
|
32757
|
+
} catch (err) {
|
|
32758
|
+
console.warn("[rbac-audit] enqueue failed, dropping admission row:", err.message);
|
|
32759
|
+
}
|
|
32760
|
+
}
|
|
32761
|
+
function flushAuditBuffer() {
|
|
32762
|
+
if (buffer.length === 0)
|
|
32763
|
+
return;
|
|
32764
|
+
const rows = buffer;
|
|
32765
|
+
buffer = [];
|
|
32766
|
+
try {
|
|
32767
|
+
const db = getDb();
|
|
32768
|
+
const stmt = db.prepare(`INSERT INTO permission_audit
|
|
32769
|
+
(principalType, principalId, originatorUserId, verb, resourceType, resourceId, decision, reason, source)
|
|
32770
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
32771
|
+
const insertAll = db.transaction((batch) => {
|
|
32772
|
+
for (const r of batch) {
|
|
32773
|
+
stmt.run(r.principalType, r.principalId, r.originatorUserId, r.verb, r.resourceType, r.resourceId, r.decision, r.reason, r.source);
|
|
32774
|
+
}
|
|
32775
|
+
});
|
|
32776
|
+
insertAll(rows);
|
|
32777
|
+
} catch (err) {
|
|
32778
|
+
console.warn(`[rbac-audit] flush failed, dropping ${rows.length} row(s):`, err.message);
|
|
32779
|
+
}
|
|
32780
|
+
}
|
|
32781
|
+
function flushIntervalMs() {
|
|
32782
|
+
const v = Number(process.env.RBAC_AUDIT_FLUSH_MS);
|
|
32783
|
+
return Number.isFinite(v) && v > 0 ? v : FLUSH_INTERVAL_MS;
|
|
32784
|
+
}
|
|
32785
|
+
function startAuditWriter(intervalMs = flushIntervalMs()) {
|
|
32786
|
+
if (flushTimer)
|
|
32787
|
+
return;
|
|
32788
|
+
flushTimer = setInterval(() => flushAuditBuffer(), intervalMs);
|
|
32789
|
+
if (typeof flushTimer?.unref === "function")
|
|
32790
|
+
flushTimer.unref();
|
|
32791
|
+
}
|
|
32792
|
+
function stopAuditWriter() {
|
|
32793
|
+
if (flushTimer) {
|
|
32794
|
+
clearInterval(flushTimer);
|
|
32795
|
+
flushTimer = null;
|
|
32796
|
+
}
|
|
32797
|
+
}
|
|
32798
|
+
function purgeExpiredAuditRows() {
|
|
32799
|
+
try {
|
|
32800
|
+
const days = Number(process.env.RBAC_AUDIT_RETENTION_DAYS) || DEFAULT_RETENTION_DAYS;
|
|
32801
|
+
const result = getDb().prepare("DELETE FROM permission_audit WHERE ts < datetime('now', ?)").run(`-${days} days`);
|
|
32802
|
+
return result.changes;
|
|
32803
|
+
} catch (err) {
|
|
32804
|
+
console.warn("[rbac-audit] retention purge failed:", err.message);
|
|
32805
|
+
return 0;
|
|
32806
|
+
}
|
|
32807
|
+
}
|
|
32808
|
+
function startAuditGc(intervalMs = AUDIT_GC_INTERVAL_MS) {
|
|
32809
|
+
if (auditGcTimer)
|
|
32810
|
+
return;
|
|
32811
|
+
const purged = purgeExpiredAuditRows();
|
|
32812
|
+
if (purged > 0) {
|
|
32813
|
+
console.log(`[rbac-audit] Initial retention purge removed ${purged} audit row(s)`);
|
|
32814
|
+
}
|
|
32815
|
+
auditGcTimer = setInterval(() => {
|
|
32816
|
+
const n = purgeExpiredAuditRows();
|
|
32817
|
+
if (n > 0) {
|
|
32818
|
+
console.log(`[rbac-audit] Retention purge removed ${n} audit row(s)`);
|
|
32819
|
+
}
|
|
32820
|
+
}, intervalMs);
|
|
32821
|
+
if (typeof auditGcTimer?.unref === "function")
|
|
32822
|
+
auditGcTimer.unref();
|
|
32823
|
+
}
|
|
32824
|
+
function stopAuditGc() {
|
|
32825
|
+
if (auditGcTimer) {
|
|
32826
|
+
clearInterval(auditGcTimer);
|
|
32827
|
+
auditGcTimer = null;
|
|
32828
|
+
}
|
|
32829
|
+
}
|
|
32368
32830
|
// src/github/handlers.ts
|
|
32369
32831
|
init_db();
|
|
32370
32832
|
init_resolver();
|
|
@@ -32458,7 +32920,10 @@ Context:
|
|
|
32458
32920
|
{ name: "pr_number", description: "Pull request number" },
|
|
32459
32921
|
{ name: "pr_title", description: "Pull request title" },
|
|
32460
32922
|
{ name: "bot_name", description: "GitHub bot username" },
|
|
32461
|
-
{
|
|
32923
|
+
{
|
|
32924
|
+
name: "sender_login",
|
|
32925
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
32926
|
+
},
|
|
32462
32927
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32463
32928
|
{ name: "head_ref", description: "Head branch name" },
|
|
32464
32929
|
{ name: "base_ref", description: "Base branch name" },
|
|
@@ -32486,7 +32951,10 @@ Context:
|
|
|
32486
32951
|
{ name: "pr_number", description: "Pull request number" },
|
|
32487
32952
|
{ name: "pr_title", description: "Pull request title" },
|
|
32488
32953
|
{ name: "bot_name", description: "GitHub bot username" },
|
|
32489
|
-
{
|
|
32954
|
+
{
|
|
32955
|
+
name: "sender_login",
|
|
32956
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
32957
|
+
},
|
|
32490
32958
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32491
32959
|
{ name: "head_ref", description: "Head branch name" },
|
|
32492
32960
|
{ name: "base_ref", description: "Base branch name" },
|
|
@@ -32563,7 +33031,10 @@ Context:
|
|
|
32563
33031
|
variables: [
|
|
32564
33032
|
{ name: "pr_number", description: "Pull request number" },
|
|
32565
33033
|
{ name: "pr_title", description: "Pull request title" },
|
|
32566
|
-
{
|
|
33034
|
+
{
|
|
33035
|
+
name: "sender_login",
|
|
33036
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33037
|
+
},
|
|
32567
33038
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32568
33039
|
{ name: "head_ref", description: "Head branch name" },
|
|
32569
33040
|
{ name: "base_ref", description: "Base branch name" },
|
|
@@ -32591,7 +33062,10 @@ Context:
|
|
|
32591
33062
|
{ name: "pr_number", description: "Pull request number" },
|
|
32592
33063
|
{ name: "pr_title", description: "Pull request title" },
|
|
32593
33064
|
{ name: "label_name", description: "Label that was added" },
|
|
32594
|
-
{
|
|
33065
|
+
{
|
|
33066
|
+
name: "sender_login",
|
|
33067
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33068
|
+
},
|
|
32595
33069
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32596
33070
|
{ name: "head_ref", description: "Head branch name" },
|
|
32597
33071
|
{ name: "base_ref", description: "Base branch name" },
|
|
@@ -32618,7 +33092,10 @@ Context:
|
|
|
32618
33092
|
{ name: "issue_number", description: "Issue number" },
|
|
32619
33093
|
{ name: "issue_title", description: "Issue title" },
|
|
32620
33094
|
{ name: "bot_name", description: "GitHub bot username" },
|
|
32621
|
-
{
|
|
33095
|
+
{
|
|
33096
|
+
name: "sender_login",
|
|
33097
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33098
|
+
},
|
|
32622
33099
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32623
33100
|
{ name: "issue_url", description: "Issue HTML URL" },
|
|
32624
33101
|
{ name: "context", description: "Issue body or title as context" }
|
|
@@ -32641,7 +33118,10 @@ Context:
|
|
|
32641
33118
|
variables: [
|
|
32642
33119
|
{ name: "issue_number", description: "Issue number" },
|
|
32643
33120
|
{ name: "issue_title", description: "Issue title" },
|
|
32644
|
-
{
|
|
33121
|
+
{
|
|
33122
|
+
name: "sender_login",
|
|
33123
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33124
|
+
},
|
|
32645
33125
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32646
33126
|
{ name: "issue_url", description: "Issue HTML URL" },
|
|
32647
33127
|
{ name: "context", description: "Extracted mention context or issue title" }
|
|
@@ -32666,7 +33146,10 @@ Context:
|
|
|
32666
33146
|
{ name: "issue_number", description: "Issue number" },
|
|
32667
33147
|
{ name: "issue_title", description: "Issue title" },
|
|
32668
33148
|
{ name: "label_name", description: "Label that was added" },
|
|
32669
|
-
{
|
|
33149
|
+
{
|
|
33150
|
+
name: "sender_login",
|
|
33151
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33152
|
+
},
|
|
32670
33153
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32671
33154
|
{ name: "issue_url", description: "Issue HTML URL" },
|
|
32672
33155
|
{ name: "context", description: "Issue body or title as context" }
|
|
@@ -32690,7 +33173,10 @@ Comment:
|
|
|
32690
33173
|
{ name: "target_type", description: "PR or Issue" },
|
|
32691
33174
|
{ name: "target_number", description: "PR or issue number" },
|
|
32692
33175
|
{ name: "target_title", description: "PR or issue title" },
|
|
32693
|
-
{
|
|
33176
|
+
{
|
|
33177
|
+
name: "sender_login",
|
|
33178
|
+
description: "Event sender identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33179
|
+
},
|
|
32694
33180
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32695
33181
|
{ name: "comment_url", description: "Comment HTML URL" },
|
|
32696
33182
|
{ name: "context", description: "Extracted mention context from comment" },
|
|
@@ -32718,7 +33204,10 @@ URL: {{review_url}}{{review_body_section}}{{inline_comments_section}}
|
|
|
32718
33204
|
{ name: "pr_number", description: "Pull request number" },
|
|
32719
33205
|
{ name: "review_label", description: "Review state label (APPROVED, CHANGES REQUESTED, etc.)" },
|
|
32720
33206
|
{ name: "pr_title", description: "Pull request title" },
|
|
32721
|
-
{
|
|
33207
|
+
{
|
|
33208
|
+
name: "sender_login",
|
|
33209
|
+
description: "Reviewer identity — resolved canonical name (e.g. 'Luis (github:login)') or the UNKNOWN sentinel"
|
|
33210
|
+
},
|
|
32722
33211
|
{ name: "repo_full_name", description: "Repository full name (owner/repo)" },
|
|
32723
33212
|
{ name: "review_url", description: "Review HTML URL" },
|
|
32724
33213
|
{ name: "review_body_section", description: "Review overall body section or empty string" },
|
|
@@ -32915,7 +33404,7 @@ async function handlePullRequest(event) {
|
|
|
32915
33404
|
pr_number: pr.number,
|
|
32916
33405
|
pr_title: pr.title,
|
|
32917
33406
|
bot_name: GITHUB_BOT_NAME,
|
|
32918
|
-
sender_login: sender.login,
|
|
33407
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
32919
33408
|
repo_full_name: repository.full_name,
|
|
32920
33409
|
head_ref: pr.head.ref,
|
|
32921
33410
|
base_ref: pr.base.ref,
|
|
@@ -32987,7 +33476,7 @@ async function handlePullRequest(event) {
|
|
|
32987
33476
|
pr_number: pr.number,
|
|
32988
33477
|
pr_title: pr.title,
|
|
32989
33478
|
bot_name: GITHUB_BOT_NAME,
|
|
32990
|
-
sender_login: sender.login,
|
|
33479
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
32991
33480
|
repo_full_name: repository.full_name,
|
|
32992
33481
|
head_ref: pr.head.ref,
|
|
32993
33482
|
base_ref: pr.base.ref,
|
|
@@ -33055,7 +33544,7 @@ async function handlePullRequest(event) {
|
|
|
33055
33544
|
pr_number: pr.number,
|
|
33056
33545
|
pr_title: pr.title,
|
|
33057
33546
|
label_name: labelName,
|
|
33058
|
-
sender_login: sender.login,
|
|
33547
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33059
33548
|
repo_full_name: repository.full_name,
|
|
33060
33549
|
head_ref: pr.head.ref,
|
|
33061
33550
|
base_ref: pr.base.ref,
|
|
@@ -33113,7 +33602,7 @@ async function handlePullRequest(event) {
|
|
|
33113
33602
|
const result = resolveTemplate("github.pull_request.mentioned", {
|
|
33114
33603
|
pr_number: pr.number,
|
|
33115
33604
|
pr_title: pr.title,
|
|
33116
|
-
sender_login: sender.login,
|
|
33605
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33117
33606
|
repo_full_name: repository.full_name,
|
|
33118
33607
|
head_ref: pr.head.ref,
|
|
33119
33608
|
base_ref: pr.base.ref,
|
|
@@ -33163,7 +33652,7 @@ async function handleIssue(event) {
|
|
|
33163
33652
|
issue_number: issue.number,
|
|
33164
33653
|
issue_title: issue.title,
|
|
33165
33654
|
bot_name: GITHUB_BOT_NAME,
|
|
33166
|
-
sender_login: sender.login,
|
|
33655
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33167
33656
|
repo_full_name: repository.full_name,
|
|
33168
33657
|
issue_url: issue.html_url,
|
|
33169
33658
|
context: issue.body || issue.title
|
|
@@ -33229,7 +33718,7 @@ async function handleIssue(event) {
|
|
|
33229
33718
|
issue_number: issue.number,
|
|
33230
33719
|
issue_title: issue.title,
|
|
33231
33720
|
label_name: labelName,
|
|
33232
|
-
sender_login: sender.login,
|
|
33721
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33233
33722
|
repo_full_name: repository.full_name,
|
|
33234
33723
|
issue_url: issue.html_url,
|
|
33235
33724
|
context: issue.body || issue.title
|
|
@@ -33277,7 +33766,7 @@ async function handleIssue(event) {
|
|
|
33277
33766
|
const result = resolveTemplate("github.issue.mentioned", {
|
|
33278
33767
|
issue_number: issue.number,
|
|
33279
33768
|
issue_title: issue.title,
|
|
33280
|
-
sender_login: sender.login,
|
|
33769
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33281
33770
|
repo_full_name: repository.full_name,
|
|
33282
33771
|
issue_url: issue.html_url,
|
|
33283
33772
|
context
|
|
@@ -33338,7 +33827,7 @@ async function handleComment(event, eventType) {
|
|
|
33338
33827
|
target_type: targetType,
|
|
33339
33828
|
target_number: targetNumber,
|
|
33340
33829
|
target_title: targetTitle,
|
|
33341
|
-
sender_login: sender.login,
|
|
33830
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33342
33831
|
repo_full_name: repository.full_name,
|
|
33343
33832
|
comment_url: comment.html_url,
|
|
33344
33833
|
context,
|
|
@@ -33533,7 +34022,7 @@ ${review.body}` : "";
|
|
|
33533
34022
|
pr_number: pr.number,
|
|
33534
34023
|
review_label: label,
|
|
33535
34024
|
pr_title: pr.title,
|
|
33536
|
-
sender_login: sender.login,
|
|
34025
|
+
sender_login: renderIdentity(resolveIdentity("github", sender.login)),
|
|
33537
34026
|
repo_full_name: repository.full_name,
|
|
33538
34027
|
review_url: review.html_url,
|
|
33539
34028
|
review_body_section: reviewBodySection,
|
|
@@ -33906,7 +34395,10 @@ Reporter: {{reporter}}
|
|
|
33906
34395
|
{ name: "issue_key", description: "Jira issue key (e.g. ENG-123)" },
|
|
33907
34396
|
{ name: "issue_summary", description: "Issue summary / title" },
|
|
33908
34397
|
{ name: "issue_url", description: "Issue URL on the Jira site" },
|
|
33909
|
-
{
|
|
34398
|
+
{
|
|
34399
|
+
name: "reporter",
|
|
34400
|
+
description: "Reporter identity — resolved canonical name (e.g. 'Luis (jira:<accountId>)') or the UNKNOWN sentinel"
|
|
34401
|
+
},
|
|
33910
34402
|
{
|
|
33911
34403
|
name: "description_section",
|
|
33912
34404
|
description: "Description section (extracted from ADF) or empty string"
|
|
@@ -33928,7 +34420,10 @@ Comment:
|
|
|
33928
34420
|
{ name: "issue_key", description: "Jira issue key (e.g. ENG-123)" },
|
|
33929
34421
|
{ name: "issue_summary", description: "Issue summary / title" },
|
|
33930
34422
|
{ name: "issue_url", description: "Issue URL on the Jira site" },
|
|
33931
|
-
{
|
|
34423
|
+
{
|
|
34424
|
+
name: "comment_author",
|
|
34425
|
+
description: "Comment author identity — resolved canonical name (e.g. 'Luis (jira:<accountId>)') or the UNKNOWN sentinel"
|
|
34426
|
+
},
|
|
33932
34427
|
{
|
|
33933
34428
|
name: "description_section",
|
|
33934
34429
|
description: "Description section (extracted from ADF) or empty string"
|
|
@@ -33968,6 +34463,31 @@ Original issue: {{issue_key}} — {{issue_summary}}`,
|
|
|
33968
34463
|
init_db();
|
|
33969
34464
|
init_resolver();
|
|
33970
34465
|
init_types();
|
|
34466
|
+
var JIRA_WEBHOOK_ACTOR = { kind: "system", id: "webhook:jira" };
|
|
34467
|
+
function resolveJiraActor(accountId, email, name, sampleEventType, sampleContext) {
|
|
34468
|
+
if (!accountId)
|
|
34469
|
+
return;
|
|
34470
|
+
const existing = findUserByExternalId("jira", accountId);
|
|
34471
|
+
if (existing)
|
|
34472
|
+
return existing.id;
|
|
34473
|
+
const trimmedEmail = typeof email === "string" ? email.trim() : "";
|
|
34474
|
+
if (trimmedEmail !== "") {
|
|
34475
|
+
const { user } = findOrCreateUserByEmail(trimmedEmail, { name: name?.trim() || undefined }, JIRA_WEBHOOK_ACTOR);
|
|
34476
|
+
try {
|
|
34477
|
+
linkIdentity(user.id, "jira", accountId, JIRA_WEBHOOK_ACTOR);
|
|
34478
|
+
} catch (error) {
|
|
34479
|
+
console.warn(`[Jira Sync] linkIdentity('jira', ${accountId}) failed — likely a concurrent enroll`, error);
|
|
34480
|
+
}
|
|
34481
|
+
return user.id;
|
|
34482
|
+
}
|
|
34483
|
+
recordUnmappedIdentity("jira", accountId, { sampleEventType, sampleContext });
|
|
34484
|
+
return;
|
|
34485
|
+
}
|
|
34486
|
+
function renderJiraIdentity(accountId) {
|
|
34487
|
+
if (!accountId)
|
|
34488
|
+
return "(unknown user)";
|
|
34489
|
+
return renderIdentity(resolveIdentity("jira", accountId));
|
|
34490
|
+
}
|
|
33971
34491
|
var BOT_ACCOUNT_ID_SLOT = Symbol.for("agent-swarm.jira.botAccountId");
|
|
33972
34492
|
function getCachedBotAccountId() {
|
|
33973
34493
|
return globalThis[BOT_ACCOUNT_ID_SLOT] ?? null;
|
|
@@ -34065,7 +34585,8 @@ async function handleIssueEvent(event) {
|
|
|
34065
34585
|
const issueId = issue.id;
|
|
34066
34586
|
const issueKey = issue.key;
|
|
34067
34587
|
const summary = issue.fields?.summary ?? "(no summary)";
|
|
34068
|
-
const
|
|
34588
|
+
const reporterAccountId = issue.fields?.reporter?.accountId;
|
|
34589
|
+
const requestedByUserId = resolveJiraActor(reporterAccountId, issue.fields?.reporter?.emailAddress, issue.fields?.reporter?.displayName, "issue_updated", `${issueKey}: ${summary}`);
|
|
34069
34590
|
const descriptionText = extractText(issue.fields?.description);
|
|
34070
34591
|
const issueUrl = buildIssueUrl(issueKey);
|
|
34071
34592
|
const claim = createTrackerSyncIfAbsent({
|
|
@@ -34083,7 +34604,8 @@ async function handleIssueEvent(event) {
|
|
|
34083
34604
|
await createInitialJiraTask({
|
|
34084
34605
|
issueKey,
|
|
34085
34606
|
summary,
|
|
34086
|
-
|
|
34607
|
+
reporterAccountId,
|
|
34608
|
+
requestedByUserId,
|
|
34087
34609
|
descriptionText,
|
|
34088
34610
|
issueUrl,
|
|
34089
34611
|
syncRowId: claim.sync.id,
|
|
@@ -34099,7 +34621,8 @@ async function handleIssueEvent(event) {
|
|
|
34099
34621
|
await createInitialJiraTask({
|
|
34100
34622
|
issueKey,
|
|
34101
34623
|
summary,
|
|
34102
|
-
|
|
34624
|
+
reporterAccountId,
|
|
34625
|
+
requestedByUserId,
|
|
34103
34626
|
descriptionText,
|
|
34104
34627
|
issueUrl,
|
|
34105
34628
|
syncRowId: claim.sync.id,
|
|
@@ -34141,7 +34664,8 @@ async function handleCommentEvent(event) {
|
|
|
34141
34664
|
const summary = issue.fields?.summary ?? "(no summary)";
|
|
34142
34665
|
const descriptionText = extractText(issue.fields?.description);
|
|
34143
34666
|
const commentText = extractText(comment.body);
|
|
34144
|
-
const
|
|
34667
|
+
const commentAuthorAccountId = comment.author?.accountId ?? comment.updateAuthor?.accountId;
|
|
34668
|
+
const requestedByUserId = resolveJiraActor(commentAuthorAccountId, comment.author?.emailAddress ?? comment.updateAuthor?.emailAddress, comment.author?.displayName ?? comment.updateAuthor?.displayName, "comment_created", `${issueKey}: ${commentText.slice(0, 80)}`);
|
|
34145
34669
|
const issueUrl = buildIssueUrl(issueKey);
|
|
34146
34670
|
if (!existing) {
|
|
34147
34671
|
const claim = createTrackerSyncIfAbsent({
|
|
@@ -34161,7 +34685,8 @@ async function handleCommentEvent(event) {
|
|
|
34161
34685
|
summary,
|
|
34162
34686
|
descriptionText,
|
|
34163
34687
|
commentText,
|
|
34164
|
-
|
|
34688
|
+
commentAuthorAccountId,
|
|
34689
|
+
requestedByUserId,
|
|
34165
34690
|
issueUrl,
|
|
34166
34691
|
syncRowId: claim.sync.id
|
|
34167
34692
|
});
|
|
@@ -34172,7 +34697,8 @@ async function handleCommentEvent(event) {
|
|
|
34172
34697
|
summary,
|
|
34173
34698
|
issueUrl,
|
|
34174
34699
|
commentText,
|
|
34175
|
-
|
|
34700
|
+
commentAuthorAccountId,
|
|
34701
|
+
requestedByUserId,
|
|
34176
34702
|
syncRow: claim.sync
|
|
34177
34703
|
});
|
|
34178
34704
|
}
|
|
@@ -34181,7 +34707,8 @@ async function handleCommentEvent(event) {
|
|
|
34181
34707
|
summary,
|
|
34182
34708
|
issueUrl,
|
|
34183
34709
|
commentText,
|
|
34184
|
-
|
|
34710
|
+
commentAuthorAccountId,
|
|
34711
|
+
requestedByUserId,
|
|
34185
34712
|
syncRow: existing
|
|
34186
34713
|
});
|
|
34187
34714
|
}
|
|
@@ -34191,15 +34718,17 @@ async function routeCommentOnExistingSync(input) {
|
|
|
34191
34718
|
console.log(`[Jira Sync] Bot mentioned on issue ${input.issueKey} but task ${priorTask.id} still ${priorTask.status} — ignoring`);
|
|
34192
34719
|
return;
|
|
34193
34720
|
}
|
|
34721
|
+
const commentAuthorDisplay = renderJiraIdentity(input.commentAuthorAccountId);
|
|
34194
34722
|
await createInitialJiraTask({
|
|
34195
34723
|
issueKey: input.issueKey,
|
|
34196
34724
|
summary: input.summary,
|
|
34197
|
-
|
|
34725
|
+
reporterAccountId: input.commentAuthorAccountId,
|
|
34726
|
+
requestedByUserId: input.requestedByUserId,
|
|
34198
34727
|
descriptionText: "",
|
|
34199
34728
|
issueUrl: input.issueUrl,
|
|
34200
34729
|
syncRowId: input.syncRow.id,
|
|
34201
34730
|
followup: true,
|
|
34202
|
-
followupTrigger: `New comment from ${
|
|
34731
|
+
followupTrigger: `New comment from ${commentAuthorDisplay}`,
|
|
34203
34732
|
followupMessage: input.commentText
|
|
34204
34733
|
});
|
|
34205
34734
|
}
|
|
@@ -34233,7 +34762,7 @@ ${input.descriptionText}
|
|
|
34233
34762
|
issue_key: input.issueKey,
|
|
34234
34763
|
issue_summary: input.summary,
|
|
34235
34764
|
issue_url: input.issueUrl,
|
|
34236
|
-
reporter: input.
|
|
34765
|
+
reporter: renderJiraIdentity(input.reporterAccountId),
|
|
34237
34766
|
description_section: descriptionSection
|
|
34238
34767
|
};
|
|
34239
34768
|
const result = resolveTemplate(tmplName, variables);
|
|
@@ -34245,6 +34774,7 @@ ${input.descriptionText}
|
|
|
34245
34774
|
agentId: lead?.id ?? "",
|
|
34246
34775
|
source: "jira",
|
|
34247
34776
|
taskType: "jira-issue",
|
|
34777
|
+
requestedByUserId: input.requestedByUserId,
|
|
34248
34778
|
contextKey: buildJiraContextKey(input.issueKey)
|
|
34249
34779
|
});
|
|
34250
34780
|
updateTrackerSyncSwarmId(input.syncRowId, task.id);
|
|
@@ -34261,7 +34791,7 @@ ${input.descriptionText}
|
|
|
34261
34791
|
issue_key: input.issueKey,
|
|
34262
34792
|
issue_summary: input.summary,
|
|
34263
34793
|
issue_url: input.issueUrl,
|
|
34264
|
-
comment_author: input.
|
|
34794
|
+
comment_author: renderJiraIdentity(input.commentAuthorAccountId),
|
|
34265
34795
|
description_section: descriptionSection,
|
|
34266
34796
|
comment_text: input.commentText
|
|
34267
34797
|
});
|
|
@@ -34273,6 +34803,7 @@ ${input.descriptionText}
|
|
|
34273
34803
|
agentId: lead?.id ?? "",
|
|
34274
34804
|
source: "jira",
|
|
34275
34805
|
taskType: "jira-issue",
|
|
34806
|
+
requestedByUserId: input.requestedByUserId,
|
|
34276
34807
|
contextKey: buildJiraContextKey(input.issueKey)
|
|
34277
34808
|
});
|
|
34278
34809
|
updateTrackerSyncSwarmId(input.syncRowId, task.id);
|
|
@@ -34307,7 +34838,7 @@ async function notifySlack(text) {
|
|
|
34307
34838
|
return;
|
|
34308
34839
|
}
|
|
34309
34840
|
try {
|
|
34310
|
-
const { getSlackApp: getSlackApp2 } = await import("./app-
|
|
34841
|
+
const { getSlackApp: getSlackApp2 } = await import("./app-4f718yk0.js");
|
|
34311
34842
|
const app = getSlackApp2();
|
|
34312
34843
|
if (!app) {
|
|
34313
34844
|
console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
|
|
@@ -34376,7 +34907,7 @@ async function deleteJiraWebhook(webhookId) {
|
|
|
34376
34907
|
console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
|
|
34377
34908
|
}
|
|
34378
34909
|
async function overwriteWebhookIds(next) {
|
|
34379
|
-
const { getDb: getDb2 } = await import("./db-
|
|
34910
|
+
const { getDb: getDb2 } = await import("./db-p3h2j06x.js");
|
|
34380
34911
|
const db = getDb2();
|
|
34381
34912
|
const txn = db.transaction(() => {
|
|
34382
34913
|
const row = db.query("SELECT metadata FROM oauth_apps WHERE provider = 'jira'").get();
|
|
@@ -108655,10 +109186,11 @@ async function handleCore(req, res, myAgentId, apiKey) {
|
|
|
108655
109186
|
}
|
|
108656
109187
|
const pathSegments = getPathSegments(req.url || "");
|
|
108657
109188
|
const isUserMcpRoute = req.url === "/mcp-user";
|
|
109189
|
+
let auth = null;
|
|
108658
109190
|
if (isUserMcpRoute || isPublicRoute(req.method, pathSegments)) {
|
|
108659
109191
|
setRequestAuth(req, null);
|
|
108660
109192
|
} else {
|
|
108661
|
-
|
|
109193
|
+
auth = resolveHttpRequestAuth(req, apiKey);
|
|
108662
109194
|
if (!auth) {
|
|
108663
109195
|
setRequestAuth(req, null);
|
|
108664
109196
|
res.writeHead(401, { "Content-Type": "application/json" });
|
|
@@ -108667,6 +109199,28 @@ async function handleCore(req, res, myAgentId, apiKey) {
|
|
|
108667
109199
|
}
|
|
108668
109200
|
setRequestAuth(req, auth);
|
|
108669
109201
|
}
|
|
109202
|
+
if (auth?.kind === "user" && isRbacEnabled()) {
|
|
109203
|
+
const grant = getUserGrant(auth.userId);
|
|
109204
|
+
if (!grant.grantsAll) {
|
|
109205
|
+
const def = findRoute(req.method, pathSegments);
|
|
109206
|
+
const decision = decideAdmission({
|
|
109207
|
+
method: req.method ?? "",
|
|
109208
|
+
rbac: def?.rbac,
|
|
109209
|
+
routeKnown: def !== undefined,
|
|
109210
|
+
grant
|
|
109211
|
+
});
|
|
109212
|
+
enqueueAdmissionRow({
|
|
109213
|
+
userId: auth.userId,
|
|
109214
|
+
decision,
|
|
109215
|
+
method: req.method,
|
|
109216
|
+
route: def?.path ?? pathSegments.join("/")
|
|
109217
|
+
});
|
|
109218
|
+
if (!decision.allow) {
|
|
109219
|
+
jsonError(res, `Forbidden: ${decision.reason}`, 403);
|
|
109220
|
+
return true;
|
|
109221
|
+
}
|
|
109222
|
+
}
|
|
109223
|
+
}
|
|
108670
109224
|
if (req.method === "POST" && req.url === "/internal/reload-config") {
|
|
108671
109225
|
try {
|
|
108672
109226
|
const result = await reloadGlobalConfigsAndIntegrations();
|
|
@@ -109505,7 +110059,8 @@ var taskActionInputSchema = object({
|
|
|
109505
110059
|
dir: string().min(1).startsWith("/").optional().describe("Working directory (absolute path) for the agent to start in. Only used with 'create' action."),
|
|
109506
110060
|
model: string().trim().min(1).optional().describe("Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action."),
|
|
109507
110061
|
modelTier: ModelTierSchema.optional().describe("Portable model tier for the created task: 'smol', 'regular', 'smart', or 'ultra'. Resolved when a worker claims/runs the task. Only used with 'create' action."),
|
|
109508
|
-
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for the created task: 'off', 'low', 'medium', 'high', or '
|
|
110062
|
+
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for the created task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. Only used with 'create' action."),
|
|
110063
|
+
requiredCapabilities: array(string()).optional().describe("Capabilities a claiming agent must have (declared via join-swarm/update-profile) to be pool-eligible for this task. Written into the created task's routingAffinity (role is left unset). Only used with 'create' action.")
|
|
109509
110064
|
});
|
|
109510
110065
|
var taskActionOutputSchema = object({
|
|
109511
110066
|
yourAgentId: string().uuid().optional(),
|
|
@@ -109551,7 +110106,19 @@ function taskActionCallResult(result, agentId) {
|
|
|
109551
110106
|
};
|
|
109552
110107
|
}
|
|
109553
110108
|
async function taskActionHandler(ctx, input) {
|
|
109554
|
-
const {
|
|
110109
|
+
const {
|
|
110110
|
+
action,
|
|
110111
|
+
task,
|
|
110112
|
+
taskType,
|
|
110113
|
+
tags,
|
|
110114
|
+
priority,
|
|
110115
|
+
dependsOn,
|
|
110116
|
+
taskId,
|
|
110117
|
+
reason,
|
|
110118
|
+
dir,
|
|
110119
|
+
model,
|
|
110120
|
+
requiredCapabilities
|
|
110121
|
+
} = input;
|
|
109555
110122
|
const normalizedModel = splitLegacyModelAlias({ model, modelTier: input.modelTier });
|
|
109556
110123
|
if (ctx.kind === "user") {
|
|
109557
110124
|
if (action !== "to_backlog" && action !== "from_backlog") {
|
|
@@ -109631,7 +110198,8 @@ async function taskActionHandler(ctx, input) {
|
|
|
109631
110198
|
dir,
|
|
109632
110199
|
model: normalizedModel.model,
|
|
109633
110200
|
modelTier: normalizedModel.modelTier,
|
|
109634
|
-
effort: input.effort
|
|
110201
|
+
effort: input.effort,
|
|
110202
|
+
routingAffinity: requiredCapabilities?.length ? { capabilities: requiredCapabilities } : undefined
|
|
109635
110203
|
});
|
|
109636
110204
|
return {
|
|
109637
110205
|
success: true,
|
|
@@ -109668,6 +110236,13 @@ async function taskActionHandler(ctx, input) {
|
|
|
109668
110236
|
message: `Task "${taskId}" has unmet dependencies: ${blockedBy.join(", ")}. Cannot claim until dependencies are completed.`
|
|
109669
110237
|
};
|
|
109670
110238
|
}
|
|
110239
|
+
const claimingAgent = getAgentById(agentId);
|
|
110240
|
+
if (claimingAgent && !isAgentEligibleForTask(claimingAgent, existingTask)) {
|
|
110241
|
+
return {
|
|
110242
|
+
success: false,
|
|
110243
|
+
message: `Task "${taskId}" requires role "${existingTask.routingAffinity?.role ?? "(unspecified)"}"; yours is "${claimingAgent.role ?? "(unspecified)"}". Cannot claim.`
|
|
110244
|
+
};
|
|
110245
|
+
}
|
|
109671
110246
|
const claimedTask = claimTask(taskId, agentId);
|
|
109672
110247
|
if (!claimedTask) {
|
|
109673
110248
|
return {
|
|
@@ -110740,12 +111315,13 @@ var registerCreateWorkflowTool = (server) => {
|
|
|
110740
111315
|
` + "- STRUCTURED OUTPUT: For agent-task nodes, put outputSchema inside 'config' to validate the agent's raw JSON output. " + `Node-level outputSchema validates the executor's return ({taskId, taskOutput}), which is different.
|
|
110741
111316
|
` + `- Agent-task config: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }.
|
|
110742
111317
|
` + "- TRIGGER SCHEMA: Optional 'triggerSchema' is a JSON-Schema object that validates incoming trigger payloads. " + "Supported keywords: type, required, properties, enum, const, items (recursive into arrays). " + `Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored.
|
|
111318
|
+
` + "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "or { format: 'token-equality', header }. Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " + `verification: { format: 'timestamped-hmac-sha256', header: 'X-Superagent-Signature', toleranceSeconds: 300 } }.
|
|
110743
111319
|
` + "- WAIT NODE: type 'wait' pauses a workflow for a duration or until a named workflowEventBus event arrives. " + "See runbooks/workflows.md#wait-nodes for config shapes, ordering caveats, and built-in event names.",
|
|
110744
111320
|
inputSchema: exports_external.object({
|
|
110745
111321
|
name: exports_external.string().describe("Unique name for the workflow"),
|
|
110746
111322
|
description: exports_external.string().optional().describe("Description of what this workflow does"),
|
|
110747
111323
|
definition: WorkflowDefinitionSchema.describe("The workflow definition with nodes (each node has id, type, config, and optional next/retry/validation)"),
|
|
110748
|
-
triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule)"),
|
|
111324
|
+
triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
|
|
110749
111325
|
cooldown: CooldownConfigSchema.optional().describe("Optional cooldown configuration to prevent re-triggering too frequently"),
|
|
110750
111326
|
input: exports_external.record(exports_external.string(), InputValueSchema).optional().describe("Optional input values resolved at execution time (env vars like VAR_NAME, secrets secret.NAME, or literals)"),
|
|
110751
111327
|
dir: exports_external.string().min(1).startsWith("/").optional().describe("Default working directory for all agent-task nodes (absolute path, e.g. /tmp/workspace)"),
|
|
@@ -111364,13 +111940,13 @@ var registerUpdateWorkflowTool = (server) => {
|
|
|
111364
111940
|
createToolRegistrar(server)("update-workflow", {
|
|
111365
111941
|
title: "Update Workflow",
|
|
111366
111942
|
annotations: { destructiveHint: false },
|
|
111367
|
-
description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored.",
|
|
111943
|
+
description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored. " + "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "or { format: 'token-equality', header }.",
|
|
111368
111944
|
inputSchema: exports_external.object({
|
|
111369
111945
|
id: exports_external.string().uuid().describe("Workflow ID to update"),
|
|
111370
111946
|
name: exports_external.string().optional().describe("New name for the workflow"),
|
|
111371
111947
|
description: exports_external.string().optional().describe("New description"),
|
|
111372
111948
|
definition: WorkflowDefinitionSchema.optional().describe("New workflow definition"),
|
|
111373
|
-
triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations"),
|
|
111949
|
+
triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
|
|
111374
111950
|
cooldown: CooldownConfigSchema.optional().nullable().describe("New cooldown configuration (null to remove)"),
|
|
111375
111951
|
input: exports_external.record(exports_external.string(), InputValueSchema).optional().nullable().describe("New input values (null to remove)"),
|
|
111376
111952
|
dir: exports_external.string().min(1).startsWith("/").optional().nullable().describe("Default working directory for all agent-task nodes (null to remove)"),
|
|
@@ -111478,6 +112054,13 @@ function createServer() {
|
|
|
111478
112054
|
initDb(process.env.DATABASE_PATH);
|
|
111479
112055
|
seedPricingFromModelsDev();
|
|
111480
112056
|
startPricingRefreshLoop();
|
|
112057
|
+
try {
|
|
112058
|
+
ensureRbacSeedsSynced();
|
|
112059
|
+
} catch (err) {
|
|
112060
|
+
console.error("[startup] Failed to sync RBAC seed rows:", err);
|
|
112061
|
+
if (isRbacEnabled())
|
|
112062
|
+
throw err;
|
|
112063
|
+
}
|
|
111481
112064
|
registerGithubTaskReactions();
|
|
111482
112065
|
const server = new McpServer({
|
|
111483
112066
|
name: package_default.name,
|
|
@@ -111608,6 +112191,7 @@ function createServer() {
|
|
|
111608
112191
|
registerSkillPublishTool(server);
|
|
111609
112192
|
if (hasCapability("pages")) {
|
|
111610
112193
|
registerCreatePageTool(server);
|
|
112194
|
+
registerDeletePageTool(server);
|
|
111611
112195
|
}
|
|
111612
112196
|
if (hasCapability("metrics")) {
|
|
111613
112197
|
registerCreateMetricTool(server);
|
|
@@ -111768,4 +112352,4 @@ function writeSkillsToFilesystem(entries, harnessType = "all", home) {
|
|
|
111768
112352
|
return { synced, removed, errors };
|
|
111769
112353
|
}
|
|
111770
112354
|
|
|
111771
|
-
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature,
|
|
112355
|
+
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, userCtx, isPollTracingEnabled, initOtel, withSpan, startSpan, withSpanContext, withRemoteContext, injectTraceContext, recordSessionCost, createToolRegistrar, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, setCorsHeaders, parseQueryParams, getPathSegments, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, describeRequestRoute, route, assertSelectOnlyQuery, executeReadOnlyQuery, handleDbQuery, snapshotMetric, snapshotPage, assertOAuthProviderIsNotReserved, assertOAuthAppUrlsSafe, scopedResourceScopeIdSchema, resolveScopedResourceId, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, storeLinks, refreshLinks, canReadMemory, getLinksForMemory, recordRetrievals, expandCandidatesWithGraph, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveTaskAuditUserId, resolveHttpAuditUserId, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, sendTaskOutputSchema, sendTaskHandler, parseSkillContent, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, isInboxAllowed, isSenderAllowed, handleMessageReceived, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, hasCapability, getEnabledCapabilities, createServer, writeSkillsToFilesystem };
|