@desplega.ai/agent-swarm 1.119.6 → 1.121.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-qe5zjcbr.js → actions-mwshtkf7.js} +6 -6
- package/dist/{anthropic-messages-qjxzsabf.js → anthropic-messages-4gn944cn.js} +29 -13
- package/dist/{app-31x7k3vj.js → app-skbty91x.js} +4 -4
- package/dist/{assistant-4crt9dve.js → assistant-tg7dhfj8.js} +13 -13
- package/dist/{azure-openai-responses-ntfd05zd.js → azure-openai-responses-79zc0wyy.js} +28 -13
- package/dist/{boot-reembed-8g69ttz4.js → boot-reembed-ntjmeyh2.js} +4 -4
- package/dist/{boot-reembed-q648j733.js → boot-reembed-q5x0xpcp.js} +5 -5
- package/dist/{boot-scrub-logs-sfmzd2hj.js → boot-scrub-logs-5gznsfbe.js} +4 -4
- package/dist/{claude-adapter-9n3nzt65.js → claude-adapter-vxvcym3r.js} +3 -3
- package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-g807894s.js} +2 -2
- package/dist/{cli-bpvgs2y6.js → cli-072t49hf.js} +2123 -1533
- package/dist/{cli-g6qz2kts.js → cli-0df2g86x.js} +336 -18
- package/dist/cli-1728qh70.js +791 -0
- package/dist/{cli-vg1jxfqz.js → cli-3b1ayz83.js} +5 -5
- package/dist/{cli-r93nz80j.js → cli-3fxqwfh3.js} +1 -1
- package/dist/{cli-w6rhc30s.js → cli-3jrdwnn9.js} +20 -5
- package/dist/{cli-pasyk3vc.js → cli-46etyprn.js} +10 -5
- package/dist/{cli-433c0f4b.js → cli-4pfweq4x.js} +8 -8
- package/dist/{cli-2r7s8jhp.js → cli-5c4327dx.js} +7 -1
- package/dist/{cli-4s84mw72.js → cli-5hpvd15x.js} +2 -2
- package/dist/{cli-branks1w.js → cli-6s3ytc5x.js} +1 -1
- package/dist/{cli-da3x3btq.js → cli-7pt9sc83.js} +2 -2
- package/dist/{cli-2gv8ygwr.js → cli-7pzae66m.js} +2 -2
- package/dist/{cli-qs7nb3zn.js → cli-8wrympd7.js} +27 -1
- package/dist/{cli-qw1ccvxm.js → cli-95rbe11h.js} +70 -51
- package/dist/{cli-6rvm3jkk.js → cli-agdrxyex.js} +1 -1
- package/dist/{cli-wr706gez.js → cli-av2s7my4.js} +167 -66
- package/dist/{cli-59jy217p.js → cli-avw9ev3x.js} +55 -21
- package/dist/{cli-fkxxh5d4.js → cli-b2mqkg1h.js} +2 -2
- package/dist/{cli-1arw00dp.js → cli-ccjwgarc.js} +12 -3
- package/dist/{cli-pscrc6tw.js → cli-ch7t5v7n.js} +5 -0
- package/dist/{cli-tghre7g6.js → cli-cw70hymf.js} +1 -0
- package/dist/{cli-n61x2aph.js → cli-dmzv0986.js} +816 -1335
- package/dist/{cli-d1reabed.js → cli-g9vva2qh.js} +2 -2
- package/dist/{cli-ner6af7m.js → cli-gdpx70nc.js} +24048 -23715
- package/dist/{cli-96feg24n.js → cli-ghq3v4c9.js} +2 -2
- package/dist/{cli-wxbnjgce.js → cli-ky8esb8t.js} +3 -3
- package/dist/{cli-gdqdkr3j.js → cli-nf7sadev.js} +2 -2
- package/dist/{cli-h6cf69x5.js → cli-p9w7kb3h.js} +1 -1
- package/dist/{cli-xeatwfbe.js → cli-ry656xem.js} +24 -17
- package/dist/{cli-q8dway4w.js → cli-s8bdcke2.js} +1 -1
- package/dist/cli-s8s499xy.js +81 -0
- package/dist/{cli-sbkwvn5e.js → cli-srjqn7fd.js} +1 -1
- package/dist/cli-tv7vekye.js +367 -0
- package/dist/{cli-gg5bd32n.js → cli-vg3zrw6h.js} +4 -4
- package/dist/{cli-vx0y68jv.js → cli-vp9r4ap4.js} +5 -4
- package/dist/{cli-mg280wsv.js → cli-we156bmz.js} +1 -1
- package/dist/{cli-86fdnerz.js → cli-wwsaj97q.js} +9 -4
- package/dist/{cli-e0y603nn.js → cli-x0e0yvnq.js} +101 -1
- package/dist/{cli-mw3xpgwb.js → cli-x4apc9t3.js} +4 -4
- package/dist/cli.js +26 -21
- package/dist/{codex-adapter-6j2b38tg.js → codex-adapter-mmy741zd.js} +8 -9
- package/dist/{codex-session-runner-vz215wgw.js → codex-session-runner-sazmx9zt.js} +8 -9
- package/dist/{commands-6xr20jbe.js → commands-cxxye5e4.js} +3 -3
- package/dist/{db-1mmvk1z4.js → db-ab1954b7.js} +5 -3
- package/dist/{google-generative-ai-n1d3xt4n.js → google-generative-ai-wwa2ked5.js} +14 -18
- package/dist/{google-vertex-mxst23gy.js → google-vertex-71xmdd7n.js} +14 -18
- package/dist/{handlers-xvrknk8w.js → handlers-fmfe2343.js} +13 -13
- package/dist/{hook-qm7he8wn.js → hook-ygnw3cvt.js} +7 -8
- package/dist/{http-hj08zq67.js → http-kactcc0z.js} +1128 -536
- package/dist/{index-688jph6a.js → index-6erq0wvk.js} +11 -11
- package/dist/{index-gze4fg2w.js → index-g86j2yt5.js} +9 -9
- package/dist/{index-etz7d8md.js → index-gmzs6a2q.js} +10 -10
- package/dist/{index-wj8dfpwh.js → index-hmp82wn0.js} +12 -12
- package/dist/{keepalive-94wn9yxw.js → keepalive-3cvt26dw.js} +18 -14
- package/dist/{lead-rvcqkp11.js → lead-ysf26cjr.js} +31 -32
- package/dist/{maintenance-qhfc4dnp.js → maintenance-9npwptbb.js} +5 -5
- package/dist/{mistral-conversations-ykcg66za.js → mistral-conversations-26ya4yah.js} +17 -13
- package/dist/{oauth-refresh-sweep-rj8wgvsw.js → oauth-refresh-sweep-0r2v76vw.js} +23 -17
- package/dist/{onboard-8bv8q1wc.js → onboard-ddb1674a.js} +2 -2
- package/dist/{openai-codex-responses-zy0907j9.js → openai-codex-responses-6rr2ye0s.js} +78 -38
- package/dist/{openai-completions-xk4p56n9.js → openai-completions-zfa9nkvt.js} +130 -33
- package/dist/{openai-responses-4gv3ca5d.js → openai-responses-9wmdks0g.js} +38 -14
- package/dist/{opencode-adapter-5bwzvbwj.js → opencode-adapter-h6rkxwrk.js} +2 -2
- package/dist/{openrouter-images-4fsrrzes.js → openrouter-images-dgq98729.js} +10 -3
- package/dist/{otel-impl-1kf6fr2m.js → otel-impl-b43bkq8e.js} +4 -4
- package/dist/{pi-messages-zb8v76wx.js → pi-messages-nzjbbz47.js} +4 -6
- package/dist/{pi-mono-adapter-9sg69kg3.js → pi-mono-adapter-ke789738.js} +2328 -1281
- package/dist/{pricing-refresh-e84tar2s.js → pricing-refresh-2rqf114z.js} +5 -5
- package/dist/{rbac-roles-atytq5ch.js → rbac-roles-5wkhc8xv.js} +5 -5
- package/dist/{rbac-roles-pg0zvnwn.js → rbac-roles-6vtafvzb.js} +4 -4
- package/dist/{seed-pricing-xd6nxq7k.js → seed-pricing-23wrb873.js} +4 -4
- package/dist/{setup-4z389yk0.js → setup-6rny4fk6.js} +2 -2
- package/dist/{worker-m61r0t7m.js → worker-yapewe14.js} +31 -32
- package/openapi.json +2671 -1811
- package/package.json +10 -5
- package/plugin/commands/swarm-chat.md +2 -0
- package/plugin/pi-skills/swarm-chat/SKILL.md +2 -0
- package/src/be/connection-bindings-blob-migration.ts +123 -0
- package/src/be/db-queries/mcp-oauth.ts +409 -247
- package/src/be/db-queries/oauth.ts +813 -131
- package/src/be/db.ts +97 -6
- package/src/be/migrations/117_unified_oauth.sql +624 -0
- package/src/be/migrations/119_agent_avatar.sql +7 -0
- package/src/be/migrations/120_task_title.sql +3 -0
- package/src/be/oauth-credential-bindings.ts +48 -14
- package/src/be/oauth-encryption-backfill.ts +84 -0
- package/src/be/oauth-refresh-sweep.ts +38 -23
- package/src/be/script-connections.ts +1130 -163
- package/src/be/script-credential-broker.ts +37 -27
- package/src/be/scripts/typecheck.ts +3 -2
- package/src/be/seed-capabilities.ts +62 -0
- package/src/be/seed-pricing.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/vendored-openapi.ts +98 -0
- package/src/commands/runner.ts +69 -6
- package/src/http/agents.ts +23 -5
- package/src/http/all-routes.ts +1 -0
- package/src/http/core.ts +8 -5
- package/src/http/index.ts +18 -5
- package/src/http/mcp-bridge.ts +5 -2
- package/src/http/mcp-oauth.ts +103 -101
- package/src/http/oauth-callback.ts +332 -0
- package/src/http/oauth-generic.ts +14 -54
- package/src/http/poll.ts +5 -1
- package/src/http/script-connections.ts +651 -170
- package/src/http/scripts.ts +4 -2
- package/src/http/sessions.ts +1 -1
- package/src/http/tasks.ts +35 -0
- package/src/http/trackers/jira.ts +22 -34
- package/src/http/trackers/linear.ts +21 -36
- package/src/http/x.ts +6 -2
- package/src/jira/app.ts +12 -6
- package/src/jira/oauth.ts +48 -48
- package/src/linear/app.ts +44 -2
- package/src/linear/oauth.ts +12 -37
- package/src/oauth/app-validation.ts +27 -9
- package/src/oauth/ensure-mcp-token.ts +1 -0
- package/src/oauth/ensure-token.ts +331 -108
- package/src/oauth/identity-capture.ts +103 -0
- package/src/oauth/keepalive.ts +14 -9
- package/src/oauth/presets.ts +242 -0
- package/src/oauth/wrapper.ts +197 -76
- package/src/prompts/base-prompt.ts +48 -4
- package/src/prompts/session-templates.ts +13 -1
- package/src/providers/claude-managed-models.ts +8 -0
- package/src/rbac/legacy-policy.ts +2 -1
- package/src/rbac/permissions.ts +7 -3
- package/src/scripts-runtime/credential-broker/broker.ts +51 -8
- package/src/scripts-runtime/credential-broker/fetch-patch.ts +30 -3
- package/src/scripts-runtime/credential-broker/index.ts +1 -1
- package/src/scripts-runtime/credential-broker/types.ts +55 -8
- package/src/scripts-runtime/egress-secrets.ts +6 -2
- package/src/scripts-runtime/eval-harness.ts +2 -2
- package/src/scripts-runtime/executors/types.ts +2 -1
- package/src/scripts-runtime/loader.ts +3 -0
- package/src/scripts-runtime/types/stdlib.d.ts +11 -0
- package/src/server.ts +230 -126
- package/src/tests/agent-avatar-resolution.test.ts +123 -0
- package/src/tests/agents-list-model-display.test.ts +10 -0
- package/src/tests/base-prompt.test.ts +72 -0
- package/src/tests/claude-managed-adapter.test.ts +6 -0
- package/src/tests/connection-embedded-auth.test.ts +709 -0
- package/src/tests/context-window.test.ts +1 -0
- package/src/tests/credential-broker.test.ts +123 -125
- package/src/tests/db-queries-oauth.test.ts +126 -1
- package/src/tests/ensure-token.test.ts +44 -2
- package/src/tests/list-endpoint-slimming.test.ts +45 -0
- package/src/tests/mcp-oauth-manual-client.test.ts +20 -1
- package/src/tests/mcp-oauth-queries.test.ts +154 -8
- package/src/tests/oauth-access-token-tool.test.ts +37 -1
- package/src/tests/oauth-callback-flow.test.ts +534 -0
- package/src/tests/oauth-credential-bindings.test.ts +50 -22
- package/src/tests/oauth-presets.test.ts +275 -0
- package/src/tests/oauth-refresh-failure.test.ts +263 -0
- package/src/tests/oauth-refresh-sweep.test.ts +83 -3
- package/src/tests/oauth-wrapper.test.ts +77 -55
- package/src/tests/prompt-template-session.test.ts +6 -5
- package/src/tests/rbac-charact-misc-tools.test.ts +60 -0
- package/src/tests/rbac-engine.test.ts +2 -1
- package/src/tests/script-connections-http.test.ts +356 -11
- package/src/tests/script-connections.test.ts +102 -0
- package/src/tests/sdk-allowlist.test.ts +4 -1
- package/src/tests/seed-capabilities.test.ts +92 -0
- package/src/tests/session-costs-model-key-normalize.test.ts +1 -0
- package/src/tests/sessions.test.ts +46 -0
- package/src/tests/spec-base-url.test.ts +266 -0
- package/src/tests/status.test.ts +3 -4
- package/src/tests/swarm-config-reserved-keys.test.ts +4 -2
- package/src/tests/task-title-route.test.ts +106 -0
- package/src/tests/tool-annotations.test.ts +6 -3
- package/src/tests/tracker-fold.test.ts +412 -0
- package/src/tests/unified-oauth-migration.test.ts +455 -0
- package/src/tests/vendored-openapi.test.ts +263 -0
- package/src/tools/credential-bindings/tool.ts +232 -77
- package/src/tools/oauth-access-token.ts +55 -6
- package/src/tools/script-connections/tool.ts +73 -53
- package/src/tools/swarm-config/set-config.ts +24 -50
- package/src/tools/update-profile.ts +15 -5
- package/src/tracker/types.ts +12 -0
- package/src/types.ts +29 -0
- package/src/utils/context-window.ts +1 -0
- package/src/workflows/executors/swarm-script.ts +6 -2
- package/vendored-openapi/README.md +22 -0
- package/vendored-openapi/github.json +7759 -0
- package/vendored-openapi/gmail.json +393 -0
- package/vendored-openapi/jira.json +3396 -0
- package/vendored-openapi/linear.json +252 -0
- package/vendored-openapi/manifest.json +128 -0
- package/vendored-openapi/slack.json +2895 -0
- package/dist/cli-0pygq9r1.js +0 -429
- package/dist/cli-8hhms4hp.js +0 -393
- package/dist/cli-z9gzq07x.js +0 -27
- package/src/scripts-runtime/credential-broker/store.ts +0 -72
- package/dist/{otel-g299k41b.js → otel-63jr5v38.js} +1 -1
|
@@ -2,15 +2,15 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { getAgentById } from "@/be/db";
|
|
4
4
|
import {
|
|
5
|
+
ConnectionAuthInputSchema,
|
|
6
|
+
connectionAuthInputFromFlat,
|
|
5
7
|
getScriptConnectionById,
|
|
6
8
|
listScriptConnections,
|
|
7
9
|
refreshScriptConnection,
|
|
8
10
|
setScriptConnectionEnabled,
|
|
9
|
-
upsertCredentialBinding,
|
|
10
11
|
upsertScriptConnection,
|
|
11
12
|
} from "@/be/script-connections";
|
|
12
13
|
import { can } from "@/rbac";
|
|
13
|
-
import { placeholderForConfigKey } from "@/scripts-runtime/credential-broker";
|
|
14
14
|
import { createToolRegistrar } from "@/tools/utils";
|
|
15
15
|
import { resolveScopedResourceId, scopedResourceScopeIdSchema } from "@/utils/scoped-resource";
|
|
16
16
|
|
|
@@ -51,24 +51,29 @@ const scriptConnectionsInputSchema = z.object({
|
|
|
51
51
|
.nullable()
|
|
52
52
|
.optional()
|
|
53
53
|
.describe("Existing credential binding ID to attach to the connection."),
|
|
54
|
+
auth: ConnectionAuthInputSchema.optional().describe(
|
|
55
|
+
"Inline connection auth. type=bearer|header|query with an inline `secret` (stored encrypted under a derived key) or a shared `configKey`; type=oauth with an `authorizationId`; type=none clears auth. Auto-manages the connection's credential binding.",
|
|
56
|
+
),
|
|
54
57
|
configKey: z
|
|
55
58
|
.string()
|
|
56
59
|
.min(1)
|
|
57
60
|
.max(255)
|
|
58
61
|
.optional()
|
|
59
|
-
.describe(
|
|
60
|
-
"Config key used to create a credential binding when credentialBindingId is omitted.",
|
|
61
|
-
),
|
|
62
|
+
.describe("Deprecated flat alias for auth: config key for a derived credential binding."),
|
|
62
63
|
headerTemplate: z
|
|
63
64
|
.string()
|
|
64
65
|
.min(1)
|
|
65
66
|
.optional()
|
|
66
|
-
.describe(
|
|
67
|
+
.describe(
|
|
68
|
+
"Deprecated flat alias for auth: header template containing the config-key placeholder.",
|
|
69
|
+
),
|
|
67
70
|
queryTemplate: z
|
|
68
71
|
.string()
|
|
69
72
|
.min(1)
|
|
70
73
|
.optional()
|
|
71
|
-
.describe(
|
|
74
|
+
.describe(
|
|
75
|
+
"Deprecated flat alias for auth: query parameter template containing the config-key placeholder.",
|
|
76
|
+
),
|
|
72
77
|
openapiSpecUrl: z
|
|
73
78
|
.string()
|
|
74
79
|
.url()
|
|
@@ -78,6 +83,12 @@ const scriptConnectionsInputSchema = z.object({
|
|
|
78
83
|
.string()
|
|
79
84
|
.optional()
|
|
80
85
|
.describe("Inline OpenAPI JSON for upsert-openapi. Mutually exclusive with openapiSpecUrl."),
|
|
86
|
+
specSource: z
|
|
87
|
+
.object({ kind: z.literal("vendored"), slug: z.string().regex(/^[a-z0-9][a-z0-9-]*$/) })
|
|
88
|
+
.optional()
|
|
89
|
+
.describe(
|
|
90
|
+
"Vendored OpenAPI source. Mutually exclusive with openapiSpecUrl and openapiSpecJson.",
|
|
91
|
+
),
|
|
81
92
|
enabled: z.boolean().optional().describe("Whether the connection is enabled."),
|
|
82
93
|
});
|
|
83
94
|
|
|
@@ -91,6 +102,14 @@ const scriptConnectionsOutputSchema = z.object({
|
|
|
91
102
|
type ScriptConnectionsArgs = z.infer<typeof scriptConnectionsInputSchema>;
|
|
92
103
|
type ExistingConnection = NonNullable<ReturnType<typeof getScriptConnectionById>>;
|
|
93
104
|
|
|
105
|
+
function baseUrlProvenanceText(connection: {
|
|
106
|
+
slug: string;
|
|
107
|
+
baseUrlSource: string;
|
|
108
|
+
baseUrlMismatch?: { specUrl: string; effectiveUrl: string };
|
|
109
|
+
}): string {
|
|
110
|
+
return `${connection.slug}: baseUrlSource=${connection.baseUrlSource}${connection.baseUrlMismatch ? `, baseUrlMismatch=${JSON.stringify(connection.baseUrlMismatch)}` : ""}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
94
113
|
function resolveConnectionScope(
|
|
95
114
|
args: ScriptConnectionsArgs,
|
|
96
115
|
existing: ExistingConnection | null,
|
|
@@ -164,8 +183,16 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
164
183
|
|
|
165
184
|
if (args.action === "list") {
|
|
166
185
|
const connections = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
186
|
+
const provenanceLines = connections
|
|
187
|
+
.filter((connection) => connection.kind === "openapi" || connection.baseUrl !== null)
|
|
188
|
+
.map(baseUrlProvenanceText);
|
|
167
189
|
return {
|
|
168
|
-
content: [
|
|
190
|
+
content: [
|
|
191
|
+
{
|
|
192
|
+
type: "text",
|
|
193
|
+
text: `Found ${connections.length} script connection(s).${provenanceLines.length ? `\n${provenanceLines.join("\n")}` : ""}`,
|
|
194
|
+
},
|
|
195
|
+
],
|
|
169
196
|
structuredContent: {
|
|
170
197
|
yourAgentId: requestInfo.agentId,
|
|
171
198
|
success: true,
|
|
@@ -226,7 +253,12 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
226
253
|
};
|
|
227
254
|
}
|
|
228
255
|
return {
|
|
229
|
-
content: [
|
|
256
|
+
content: [
|
|
257
|
+
{
|
|
258
|
+
type: "text",
|
|
259
|
+
text: `Script connection ${refreshed.slug} refreshed (${baseUrlProvenanceText(refreshed)}).`,
|
|
260
|
+
},
|
|
261
|
+
],
|
|
230
262
|
structuredContent: {
|
|
231
263
|
yourAgentId: requestInfo.agentId,
|
|
232
264
|
success: !refreshed.generationError,
|
|
@@ -292,23 +324,6 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
292
324
|
};
|
|
293
325
|
}
|
|
294
326
|
|
|
295
|
-
let credentialBindingId = args.credentialBindingId ?? null;
|
|
296
|
-
if (!credentialBindingId && args.configKey) {
|
|
297
|
-
const placeholder = placeholderForConfigKey(args.configKey);
|
|
298
|
-
const bindingScope = args.scope ?? "global";
|
|
299
|
-
const binding = upsertCredentialBinding({
|
|
300
|
-
configKey: args.configKey,
|
|
301
|
-
allowedHosts: args.allowedHosts,
|
|
302
|
-
headerTemplate:
|
|
303
|
-
args.headerTemplate ??
|
|
304
|
-
(args.queryTemplate ? undefined : `Authorization: Bearer ${placeholder}`),
|
|
305
|
-
queryTemplate: args.queryTemplate,
|
|
306
|
-
scope: bindingScope,
|
|
307
|
-
scopeId: resolveScopedResourceId(bindingScope, args.scopeId, "bindings"),
|
|
308
|
-
});
|
|
309
|
-
credentialBindingId = binding.id;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
327
|
const existing = args.id ? getScriptConnectionById(args.id) : null;
|
|
313
328
|
const { scope, scopeId } = resolveConnectionScope(args, existing);
|
|
314
329
|
const connection = await upsertScriptConnection({
|
|
@@ -320,7 +335,14 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
320
335
|
scopeId,
|
|
321
336
|
baseUrl: args.baseUrl,
|
|
322
337
|
allowedHosts: args.allowedHosts,
|
|
323
|
-
|
|
338
|
+
auth: connectionAuthInputFromFlat({
|
|
339
|
+
auth: args.auth,
|
|
340
|
+
configKey: args.configKey,
|
|
341
|
+
headerTemplate: args.headerTemplate,
|
|
342
|
+
queryTemplate: args.queryTemplate,
|
|
343
|
+
allowedHosts: args.allowedHosts,
|
|
344
|
+
}),
|
|
345
|
+
credentialBindingId: args.credentialBindingId ?? undefined,
|
|
324
346
|
enabled: resolveConnectionEnabled(args, existing),
|
|
325
347
|
});
|
|
326
348
|
|
|
@@ -338,56 +360,40 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
338
360
|
};
|
|
339
361
|
}
|
|
340
362
|
|
|
341
|
-
if (!args.slug || !args.
|
|
363
|
+
if (!args.slug || (!args.openapiSpecJson && !args.openapiSpecUrl && !args.specSource)) {
|
|
342
364
|
return {
|
|
343
365
|
content: [
|
|
344
366
|
{
|
|
345
367
|
type: "text",
|
|
346
|
-
text: "slug
|
|
368
|
+
text: "slug and exactly one OpenAPI spec source (openapiSpecJson, openapiSpecUrl, or specSource) are required.",
|
|
347
369
|
},
|
|
348
370
|
],
|
|
349
371
|
structuredContent: {
|
|
350
372
|
yourAgentId: requestInfo.agentId,
|
|
351
373
|
success: false,
|
|
352
|
-
message:
|
|
374
|
+
message:
|
|
375
|
+
"slug and exactly one OpenAPI spec source (openapiSpecJson, openapiSpecUrl, or specSource) are required.",
|
|
353
376
|
connections: listScriptConnections({ includeDisabled: true, allScopes: true }),
|
|
354
377
|
},
|
|
355
378
|
};
|
|
356
379
|
}
|
|
357
|
-
if (args.openapiSpecJson
|
|
380
|
+
if ([args.openapiSpecJson, args.openapiSpecUrl, args.specSource].filter(Boolean).length > 1) {
|
|
358
381
|
return {
|
|
359
382
|
content: [
|
|
360
383
|
{
|
|
361
384
|
type: "text",
|
|
362
|
-
text: "Provide
|
|
385
|
+
text: "Provide exactly one OpenAPI spec source.",
|
|
363
386
|
},
|
|
364
387
|
],
|
|
365
388
|
structuredContent: {
|
|
366
389
|
yourAgentId: requestInfo.agentId,
|
|
367
390
|
success: false,
|
|
368
|
-
message: "Provide
|
|
391
|
+
message: "Provide exactly one OpenAPI spec source.",
|
|
369
392
|
connections: listScriptConnections({ includeDisabled: true, allScopes: true }),
|
|
370
393
|
},
|
|
371
394
|
};
|
|
372
395
|
}
|
|
373
396
|
|
|
374
|
-
let credentialBindingId = args.credentialBindingId ?? null;
|
|
375
|
-
if (!credentialBindingId && args.configKey) {
|
|
376
|
-
const placeholder = placeholderForConfigKey(args.configKey);
|
|
377
|
-
const bindingScope = args.scope ?? "global";
|
|
378
|
-
const binding = upsertCredentialBinding({
|
|
379
|
-
configKey: args.configKey,
|
|
380
|
-
allowedHosts: args.allowedHosts ?? [new URL(args.baseUrl).hostname],
|
|
381
|
-
headerTemplate:
|
|
382
|
-
args.headerTemplate ??
|
|
383
|
-
(args.queryTemplate ? undefined : `Authorization: Bearer ${placeholder}`),
|
|
384
|
-
queryTemplate: args.queryTemplate,
|
|
385
|
-
scope: bindingScope,
|
|
386
|
-
scopeId: resolveScopedResourceId(bindingScope, args.scopeId, "bindings"),
|
|
387
|
-
});
|
|
388
|
-
credentialBindingId = binding.id;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
397
|
const existing = args.id ? getScriptConnectionById(args.id) : null;
|
|
392
398
|
const { scope, scopeId } = resolveConnectionScope(args, existing);
|
|
393
399
|
const connection = await upsertScriptConnection({
|
|
@@ -398,8 +404,17 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
398
404
|
scope,
|
|
399
405
|
scopeId,
|
|
400
406
|
baseUrl: args.baseUrl,
|
|
401
|
-
allowedHosts: args.allowedHosts
|
|
402
|
-
|
|
407
|
+
allowedHosts: args.allowedHosts,
|
|
408
|
+
auth: connectionAuthInputFromFlat({
|
|
409
|
+
auth: args.auth,
|
|
410
|
+
configKey: args.configKey,
|
|
411
|
+
headerTemplate: args.headerTemplate,
|
|
412
|
+
queryTemplate: args.queryTemplate,
|
|
413
|
+
allowedHosts: args.allowedHosts,
|
|
414
|
+
}),
|
|
415
|
+
credentialBindingId: args.credentialBindingId ?? undefined,
|
|
416
|
+
openapiSpecSourceKind: args.specSource ? "vendored" : undefined,
|
|
417
|
+
openapiSpecSource: args.specSource?.slug,
|
|
403
418
|
openapiSpecUrl: args.openapiSpecUrl,
|
|
404
419
|
openapiSpecJson: args.openapiSpecJson,
|
|
405
420
|
enabled: resolveConnectionEnabled(args, existing),
|
|
@@ -407,7 +422,12 @@ export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
|
407
422
|
|
|
408
423
|
const connections = listScriptConnections({ includeDisabled: true, allScopes: true });
|
|
409
424
|
return {
|
|
410
|
-
content: [
|
|
425
|
+
content: [
|
|
426
|
+
{
|
|
427
|
+
type: "text",
|
|
428
|
+
text: `Script connection ${connection.slug} saved (${baseUrlProvenanceText(connection)}).`,
|
|
429
|
+
},
|
|
430
|
+
],
|
|
411
431
|
structuredContent: {
|
|
412
432
|
yourAgentId: requestInfo.agentId,
|
|
413
433
|
success: !connection.generationError,
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
} from "@/be/swarm-config-guard";
|
|
9
9
|
import { scheduleIntegrationsReload } from "@/http/core";
|
|
10
10
|
import { can } from "@/rbac";
|
|
11
|
-
import { CREDENTIAL_BINDINGS_CONFIG_KEY } from "@/scripts-runtime/credential-broker";
|
|
12
11
|
import { createToolRegistrar } from "@/tools/utils";
|
|
13
12
|
import { SwarmConfigSchema, SwarmConfigScopeSchema } from "@/types";
|
|
14
13
|
|
|
@@ -96,56 +95,31 @@ export const registerSetConfigTool = (server: McpServer) => {
|
|
|
96
95
|
};
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
|
-
// Every other swarm-config key is lead-gated (DES-445 follow-up):
|
|
125
|
-
// previously ANY agent could write arbitrary config (incl. secret
|
|
126
|
-
// values), routing around the credential-bindings gate above.
|
|
127
|
-
const agent = getAgentById(requestInfo.agentId);
|
|
128
|
-
const decision = can({
|
|
129
|
-
principal: {
|
|
130
|
-
kind: "agent",
|
|
131
|
-
agentId: requestInfo.agentId,
|
|
132
|
-
isLead: agent?.isLead ?? false,
|
|
98
|
+
// Every swarm-config write is lead-gated (DES-445 follow-up): previously
|
|
99
|
+
// ANY agent could write arbitrary config (incl. secret values). The
|
|
100
|
+
// legacy SCRIPT_CREDENTIAL_BINDINGS blob is retired, so there is no
|
|
101
|
+
// special-cased key here anymore.
|
|
102
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
103
|
+
const decision = can({
|
|
104
|
+
principal: {
|
|
105
|
+
kind: "agent",
|
|
106
|
+
agentId: requestInfo.agentId,
|
|
107
|
+
isLead: agent?.isLead ?? false,
|
|
108
|
+
},
|
|
109
|
+
verb: "config.write.any",
|
|
110
|
+
resource: { kind: "none" },
|
|
111
|
+
source: "mcp",
|
|
112
|
+
});
|
|
113
|
+
if (!decision.allow) {
|
|
114
|
+
const message = "Writing swarm config requires the lead agent.";
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: "text", text: message }],
|
|
117
|
+
structuredContent: {
|
|
118
|
+
yourAgentId: requestInfo.agentId,
|
|
119
|
+
success: false,
|
|
120
|
+
message,
|
|
133
121
|
},
|
|
134
|
-
|
|
135
|
-
resource: { kind: "none" },
|
|
136
|
-
source: "mcp",
|
|
137
|
-
});
|
|
138
|
-
if (!decision.allow) {
|
|
139
|
-
const message = "Writing swarm config requires the lead agent.";
|
|
140
|
-
return {
|
|
141
|
-
content: [{ type: "text", text: message }],
|
|
142
|
-
structuredContent: {
|
|
143
|
-
yourAgentId: requestInfo.agentId,
|
|
144
|
-
success: false,
|
|
145
|
-
message,
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
}
|
|
122
|
+
};
|
|
149
123
|
}
|
|
150
124
|
|
|
151
125
|
const validationError = validateConfigValue(key, value);
|
|
@@ -6,7 +6,7 @@ import * as z from "zod";
|
|
|
6
6
|
import { getAgentById, updateAgentName, updateAgentProfile } from "@/be/db";
|
|
7
7
|
import { can } from "@/rbac";
|
|
8
8
|
import { createToolRegistrar } from "@/tools/utils";
|
|
9
|
-
import { type Agent, AgentSchema } from "@/types";
|
|
9
|
+
import { type Agent, AgentAvatarSchema, AgentSchema } from "@/types";
|
|
10
10
|
|
|
11
11
|
async function validateSetupScriptSyntax(setupScript: string): Promise<string | null> {
|
|
12
12
|
const proc = Bun.spawn(["bash", "-n", "-c", setupScript], {
|
|
@@ -121,6 +121,11 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
121
121
|
.describe(
|
|
122
122
|
"Heartbeat checklist content (HEARTBEAT.md). Checked periodically — add standing orders for the lead to review. Synced to /workspace/HEARTBEAT.md.",
|
|
123
123
|
),
|
|
124
|
+
avatar: AgentAvatarSchema.nullable()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe(
|
|
127
|
+
"Custom avatar: { type: 'lucide', icon: '<kebab-case-lucide-name>', color?: '#RRGGBB' }. Pass null to reset to the default deterministic icon/color.",
|
|
128
|
+
),
|
|
124
129
|
}),
|
|
125
130
|
outputSchema: z.object({
|
|
126
131
|
yourAgentId: z.string().uuid().optional(),
|
|
@@ -142,6 +147,7 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
142
147
|
setupScript,
|
|
143
148
|
toolsMd,
|
|
144
149
|
heartbeatMd,
|
|
150
|
+
avatar,
|
|
145
151
|
},
|
|
146
152
|
requestInfo,
|
|
147
153
|
_meta,
|
|
@@ -221,20 +227,21 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
221
227
|
identityMd === undefined &&
|
|
222
228
|
setupScript === undefined &&
|
|
223
229
|
toolsMd === undefined &&
|
|
224
|
-
heartbeatMd === undefined
|
|
230
|
+
heartbeatMd === undefined &&
|
|
231
|
+
avatar === undefined
|
|
225
232
|
) {
|
|
226
233
|
return {
|
|
227
234
|
content: [
|
|
228
235
|
{
|
|
229
236
|
type: "text",
|
|
230
|
-
text: "At least one field (name, description, role, capabilities, claudeMd, soulMd, identityMd, setupScript, toolsMd, or
|
|
237
|
+
text: "At least one field (name, description, role, capabilities, claudeMd, soulMd, identityMd, setupScript, toolsMd, heartbeatMd, or avatar) must be provided.",
|
|
231
238
|
},
|
|
232
239
|
],
|
|
233
240
|
structuredContent: {
|
|
234
241
|
yourAgentId: requestInfo.agentId,
|
|
235
242
|
success: false,
|
|
236
243
|
message:
|
|
237
|
-
"At least one field (name, description, role, capabilities, claudeMd, soulMd, identityMd, setupScript, toolsMd, or
|
|
244
|
+
"At least one field (name, description, role, capabilities, claudeMd, soulMd, identityMd, setupScript, toolsMd, heartbeatMd, or avatar) must be provided.",
|
|
238
245
|
},
|
|
239
246
|
};
|
|
240
247
|
}
|
|
@@ -273,7 +280,8 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
273
280
|
}
|
|
274
281
|
}
|
|
275
282
|
|
|
276
|
-
// Update profile fields if provided
|
|
283
|
+
// Update profile fields if provided. `avatar` is spread in only when
|
|
284
|
+
// present so `null` (reset) stays distinguishable from "not provided".
|
|
277
285
|
agent = updateAgentProfile(
|
|
278
286
|
targetAgentId,
|
|
279
287
|
{
|
|
@@ -286,6 +294,7 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
286
294
|
setupScript,
|
|
287
295
|
toolsMd,
|
|
288
296
|
heartbeatMd,
|
|
297
|
+
...(avatar !== undefined ? { avatar } : {}),
|
|
289
298
|
},
|
|
290
299
|
{
|
|
291
300
|
changeSource: isUpdatingSelf ? "self_edit" : "lead_coaching",
|
|
@@ -381,6 +390,7 @@ export const registerUpdateProfileTool = (server: McpServer) => {
|
|
|
381
390
|
if (setupScript !== undefined) updatedFields.push("setupScript");
|
|
382
391
|
if (toolsMd !== undefined) updatedFields.push("toolsMd");
|
|
383
392
|
if (heartbeatMd !== undefined) updatedFields.push("heartbeatMd");
|
|
393
|
+
if (avatar !== undefined) updatedFields.push("avatar");
|
|
384
394
|
|
|
385
395
|
const targetLabel = isUpdatingSelf ? "own" : `agent ${targetAgentId}`;
|
|
386
396
|
return {
|
package/src/tracker/types.ts
CHANGED
|
@@ -3,12 +3,23 @@ export type TrackerProvider = "linear" | "jira"; // extend as providers are adde
|
|
|
3
3
|
export interface OAuthApp {
|
|
4
4
|
id: string;
|
|
5
5
|
provider: string;
|
|
6
|
+
displayName: string | null;
|
|
6
7
|
clientId: string;
|
|
7
8
|
clientSecret: string;
|
|
9
|
+
clientSecretEncrypted: boolean;
|
|
8
10
|
authorizeUrl: string;
|
|
9
11
|
tokenUrl: string;
|
|
12
|
+
revocationUrl: string | null;
|
|
13
|
+
userinfoUrl: string | null;
|
|
10
14
|
redirectUri: string;
|
|
11
15
|
scopes: string;
|
|
16
|
+
scopeSeparator: string;
|
|
17
|
+
tokenAuthStyle: "body" | "basic";
|
|
18
|
+
tokenBodyFormat: "form" | "json";
|
|
19
|
+
requiresRefreshTokenRotation: boolean;
|
|
20
|
+
extraParamsJson: string | null;
|
|
21
|
+
source: "manual" | "dcr" | "curated-prefill";
|
|
22
|
+
mcpServerId: string | null;
|
|
12
23
|
metadata: string; // JSON string
|
|
13
24
|
createdAt: string;
|
|
14
25
|
updatedAt: string;
|
|
@@ -21,6 +32,7 @@ export interface OAuthTokens {
|
|
|
21
32
|
refreshToken: string | null;
|
|
22
33
|
expiresAt: string;
|
|
23
34
|
scope: string | null;
|
|
35
|
+
tokenVersion: number;
|
|
24
36
|
createdAt: string;
|
|
25
37
|
updatedAt: string;
|
|
26
38
|
}
|
package/src/types.ts
CHANGED
|
@@ -371,6 +371,7 @@ export const AgentTaskSchema = z.object({
|
|
|
371
371
|
agentId: z.uuid().nullable(), // Nullable for unassigned tasks
|
|
372
372
|
creatorAgentId: z.uuid().optional(), // Who created this task (optional for Slack/API)
|
|
373
373
|
task: z.string().min(1),
|
|
374
|
+
title: z.string().optional(), // Human-facing display title override (e.g. session rename); falls back to `task` when unset
|
|
374
375
|
status: AgentTaskStatusSchema,
|
|
375
376
|
source: AgentTaskSourceSchema.default("mcp"),
|
|
376
377
|
|
|
@@ -725,6 +726,25 @@ export type TaskTemplate = z.infer<typeof TaskTemplateSchema>;
|
|
|
725
726
|
|
|
726
727
|
export const AgentStatusSchema = z.enum(["idle", "busy", "offline", "waiting_for_credentials"]);
|
|
727
728
|
|
|
729
|
+
// Discriminated union so future avatar types (emoji, image, ...) can be added
|
|
730
|
+
// with zero migrations — just a new zod branch + a UI renderer branch. Server
|
|
731
|
+
// validates shape only; the UI owns the curated icon catalog and deterministic
|
|
732
|
+
// fallback, so an unrecognized/hand-set icon name can never break rendering.
|
|
733
|
+
export const AgentAvatarSchema = z.discriminatedUnion("type", [
|
|
734
|
+
z.object({
|
|
735
|
+
type: z.literal("lucide"),
|
|
736
|
+
icon: z
|
|
737
|
+
.string()
|
|
738
|
+
.regex(/^[a-z0-9-]+$/)
|
|
739
|
+
.max(64),
|
|
740
|
+
color: z
|
|
741
|
+
.string()
|
|
742
|
+
.regex(/^#[0-9a-fA-F]{6}$/)
|
|
743
|
+
.optional(),
|
|
744
|
+
}),
|
|
745
|
+
]);
|
|
746
|
+
export type AgentAvatar = z.infer<typeof AgentAvatarSchema>;
|
|
747
|
+
|
|
728
748
|
export const AgentSchema = z.object({
|
|
729
749
|
id: z.uuid(),
|
|
730
750
|
name: z.string().min(1),
|
|
@@ -784,6 +804,14 @@ export const AgentSchema = z.object({
|
|
|
784
804
|
.nullable()
|
|
785
805
|
.optional(),
|
|
786
806
|
|
|
807
|
+
// Custom avatar (icon + color). Null/missing = fall back to the
|
|
808
|
+
// deterministic hash-derived icon and color (see apps/ui/src/lib/agent-icon.ts
|
|
809
|
+
// and agent-color.ts). Migration 119 adds the column.
|
|
810
|
+
avatar: z
|
|
811
|
+
.lazy(() => AgentAvatarSchema)
|
|
812
|
+
.nullable()
|
|
813
|
+
.optional(),
|
|
814
|
+
|
|
787
815
|
createdAt: z.iso.datetime().default(() => new Date().toISOString()),
|
|
788
816
|
lastUpdatedAt: z.iso.datetime().default(() => new Date().toISOString()),
|
|
789
817
|
});
|
|
@@ -1767,6 +1795,7 @@ export type AgentTaskSummary = Pick<
|
|
|
1767
1795
|
| "agentId"
|
|
1768
1796
|
| "creatorAgentId"
|
|
1769
1797
|
| "task"
|
|
1798
|
+
| "title"
|
|
1770
1799
|
| "status"
|
|
1771
1800
|
| "source"
|
|
1772
1801
|
| "taskType"
|
|
@@ -27,6 +27,7 @@ export const CONTEXT_FORMULA = "input-cache-output" as const;
|
|
|
27
27
|
|
|
28
28
|
const CONTEXT_WINDOW_DEFAULTS: Record<string, number> = {
|
|
29
29
|
// Anthropic Fable / Mythos tier
|
|
30
|
+
"claude-opus-5": 1_000_000,
|
|
30
31
|
"claude-fable-5": 1_000_000,
|
|
31
32
|
"claude-mythos-5": 1_000_000,
|
|
32
33
|
"claude-sonnet-5": 1_000_000,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getScriptApiConnectionDescriptors,
|
|
4
4
|
getScriptMcpConnectionDescriptors,
|
|
5
5
|
} from "../../be/script-connections";
|
|
6
|
-
import {
|
|
6
|
+
import { buildScriptCredentialBindingsWithFailures } from "../../be/script-credential-broker";
|
|
7
7
|
import { getScript, getScriptVersion } from "../../be/scripts/db";
|
|
8
8
|
import { DEFAULT_SCRIPT_RESOURCES } from "../../scripts-runtime/executors/types";
|
|
9
9
|
import { runScript } from "../../scripts-runtime/loader";
|
|
@@ -72,12 +72,16 @@ export class SwarmScriptExecutor extends BaseExecutor<
|
|
|
72
72
|
return { status: "failed", error: resolved.error };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
const credentials = await buildScriptCredentialBindingsWithFailures({
|
|
76
|
+
agentId: agentId ?? undefined,
|
|
77
|
+
});
|
|
75
78
|
const output = await runScript({
|
|
76
79
|
source: resolved.source,
|
|
77
80
|
args: config.args,
|
|
78
81
|
fsMode: "none",
|
|
79
82
|
agentId: agentId ?? "workflow",
|
|
80
|
-
egressSecrets:
|
|
83
|
+
egressSecrets: credentials.egressSecrets,
|
|
84
|
+
failedBindings: credentials.failedBindings,
|
|
81
85
|
apiConnections: getScriptApiConnectionDescriptors({ agentId: agentId ?? undefined }),
|
|
82
86
|
mcpConnections: getScriptMcpConnectionDescriptors({ agentId: agentId ?? undefined }),
|
|
83
87
|
timeoutMs: config.timeoutMs,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Vendored OpenAPI specs
|
|
2
|
+
|
|
3
|
+
This directory is reviewed source, not a runtime download cache. `manifest.json` defines the
|
|
4
|
+
blessed catalog entries and their allowlisted `METHOD /path` operations. Each JSON file contains
|
|
5
|
+
only that operation subset, its real parameters/request bodies/responses, and the transitive
|
|
6
|
+
closure of locally referenced schemas needed by generated script clients.
|
|
7
|
+
|
|
8
|
+
Run `bun run refresh:vendored-openapi` to retrieve directly trim-compatible pinned upstream
|
|
9
|
+
documents, re-trim them, print which files changed, and update manifest checksums. It stages every
|
|
10
|
+
change before writing so a failed fetch cannot leave a partial refresh. Machine sources are pinned
|
|
11
|
+
by both their upstream version and raw-document SHA-256. `operator-review` entries are canonicalized
|
|
12
|
+
and checksummed locally but are never fetched. For those entries, `specSourceUrl` is an
|
|
13
|
+
operator-reference URL documenting provenance; it is not asserted to be a directly fetchable
|
|
14
|
+
OpenAPI document. Run `bun run check:vendored-openapi` offline in CI; it rejects non-canonical
|
|
15
|
+
trims, unknown operations, unsafe filenames, inconsistent provenance metadata, and hash drift.
|
|
16
|
+
|
|
17
|
+
Provenance: GitHub and Slack are pinned to upstream Git commits. Jira is pinned to the raw SHA-256
|
|
18
|
+
of Atlassian's Cloud v3 document because its published URL is mutable. Gmail is an
|
|
19
|
+
operator-reviewed OpenAPI façade based on Google's v1 Discovery model. Linear publishes a GraphQL
|
|
20
|
+
endpoint rather than an OpenAPI document, so `linear.json` is an operator-reviewed façade for the
|
|
21
|
+
documented `POST /graphql` issue query/mutation shapes. Both façades must remain narrow and be
|
|
22
|
+
reviewed when their reference APIs change.
|