@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
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_zod
|
|
3
|
+
} from "./cli-bw80ck94.js";
|
|
4
|
+
import {
|
|
5
|
+
_enum
|
|
6
|
+
} from "./cli-xz9aq0rf.js";
|
|
7
|
+
|
|
8
|
+
// src/rbac/permissions.ts
|
|
9
|
+
init_zod();
|
|
10
|
+
var PERMISSIONS = {
|
|
11
|
+
"user.manage": {
|
|
12
|
+
description: "Create, update, or deactivate user profiles.",
|
|
13
|
+
namespace: "user"
|
|
14
|
+
},
|
|
15
|
+
"agent.profile.update.any": {
|
|
16
|
+
description: "Update another agent's profile.",
|
|
17
|
+
namespace: "agent"
|
|
18
|
+
},
|
|
19
|
+
"agent.context.read.any": {
|
|
20
|
+
description: "View or diff another agent's context history.",
|
|
21
|
+
namespace: "agent"
|
|
22
|
+
},
|
|
23
|
+
"task.cancel.any": {
|
|
24
|
+
description: "Cancel any task (beyond tasks the caller created).",
|
|
25
|
+
namespace: "task"
|
|
26
|
+
},
|
|
27
|
+
"task.create.own": {
|
|
28
|
+
description: "Create a task the caller owns.",
|
|
29
|
+
namespace: "task"
|
|
30
|
+
},
|
|
31
|
+
"task.read.own": {
|
|
32
|
+
description: "Read details of a task the principal requested.",
|
|
33
|
+
namespace: "task"
|
|
34
|
+
},
|
|
35
|
+
"task.cancel.own": {
|
|
36
|
+
description: "Cancel a task the principal requested.",
|
|
37
|
+
namespace: "task"
|
|
38
|
+
},
|
|
39
|
+
"task.action.own": {
|
|
40
|
+
description: "Run actions (follow-up, retry, ...) on a task the principal requested.",
|
|
41
|
+
namespace: "task"
|
|
42
|
+
},
|
|
43
|
+
"task.fs.mutate": {
|
|
44
|
+
description: "Mutate a task's filesystem artifacts and attachments.",
|
|
45
|
+
namespace: "task"
|
|
46
|
+
},
|
|
47
|
+
"favorite.write.own": {
|
|
48
|
+
description: "Set a favorite the caller owns.",
|
|
49
|
+
namespace: "favorite"
|
|
50
|
+
},
|
|
51
|
+
"memory.learning.inject": {
|
|
52
|
+
description: "Inject a learning into another agent's memory.",
|
|
53
|
+
namespace: "memory"
|
|
54
|
+
},
|
|
55
|
+
"memory.delete.any": {
|
|
56
|
+
description: "Delete a memory entry (own entries, or swarm-scoped entries as lead).",
|
|
57
|
+
namespace: "memory"
|
|
58
|
+
},
|
|
59
|
+
"channel.delete": {
|
|
60
|
+
description: "Delete a Slack channel.",
|
|
61
|
+
namespace: "channel"
|
|
62
|
+
},
|
|
63
|
+
"integration.kapso.manage": {
|
|
64
|
+
description: "Register or unregister a Kapso inbound number.",
|
|
65
|
+
namespace: "integration"
|
|
66
|
+
},
|
|
67
|
+
"integration.slack.post": {
|
|
68
|
+
description: "Post to a direct Slack channel.",
|
|
69
|
+
namespace: "integration"
|
|
70
|
+
},
|
|
71
|
+
"integration.slack.read": {
|
|
72
|
+
description: "Read a direct Slack channel.",
|
|
73
|
+
namespace: "integration"
|
|
74
|
+
},
|
|
75
|
+
"integration.slack.thread.start": {
|
|
76
|
+
description: "Start a thread in a direct Slack channel.",
|
|
77
|
+
namespace: "integration"
|
|
78
|
+
},
|
|
79
|
+
"integration.slack.upload": {
|
|
80
|
+
description: "Upload a file to a direct Slack channel.",
|
|
81
|
+
namespace: "integration"
|
|
82
|
+
},
|
|
83
|
+
"integration.slack.delete": {
|
|
84
|
+
description: "Delete a Slack message.",
|
|
85
|
+
namespace: "integration"
|
|
86
|
+
},
|
|
87
|
+
"integration.slack.update": {
|
|
88
|
+
description: "Update (edit) a Slack message.",
|
|
89
|
+
namespace: "integration"
|
|
90
|
+
},
|
|
91
|
+
"credential-binding.manage": {
|
|
92
|
+
description: "Manage script credential bindings.",
|
|
93
|
+
namespace: "credential-binding"
|
|
94
|
+
},
|
|
95
|
+
"script-connection.manage": {
|
|
96
|
+
description: "Manage script connections.",
|
|
97
|
+
namespace: "script-connection"
|
|
98
|
+
},
|
|
99
|
+
"script-connection.invoke": {
|
|
100
|
+
description: "Invoke a script MCP connection through the server-side proxy.",
|
|
101
|
+
namespace: "script-connection"
|
|
102
|
+
},
|
|
103
|
+
"config.credential-bindings.write": {
|
|
104
|
+
description: "Write the SCRIPT_CREDENTIAL_BINDINGS swarm-config key.",
|
|
105
|
+
namespace: "config"
|
|
106
|
+
},
|
|
107
|
+
"config.write.any": {
|
|
108
|
+
description: "Write any swarm-config key.",
|
|
109
|
+
namespace: "config"
|
|
110
|
+
},
|
|
111
|
+
"config.delete.any": {
|
|
112
|
+
description: "Delete any swarm-config entry.",
|
|
113
|
+
namespace: "config"
|
|
114
|
+
},
|
|
115
|
+
"config.read.secrets": {
|
|
116
|
+
description: "Read unmasked secret config values.",
|
|
117
|
+
namespace: "config"
|
|
118
|
+
},
|
|
119
|
+
"skill.create.swarm": {
|
|
120
|
+
description: "Create a swarm-scoped skill.",
|
|
121
|
+
namespace: "skill"
|
|
122
|
+
},
|
|
123
|
+
"skill.install.any": {
|
|
124
|
+
description: "Install a skill for another agent.",
|
|
125
|
+
namespace: "skill"
|
|
126
|
+
},
|
|
127
|
+
"skill.install.global": {
|
|
128
|
+
description: "Install a remote/global skill.",
|
|
129
|
+
namespace: "skill"
|
|
130
|
+
},
|
|
131
|
+
"skill.uninstall.any": {
|
|
132
|
+
description: "Uninstall a skill for another agent.",
|
|
133
|
+
namespace: "skill"
|
|
134
|
+
},
|
|
135
|
+
"skill.update.any": {
|
|
136
|
+
description: "Update a skill the caller does not own.",
|
|
137
|
+
namespace: "skill"
|
|
138
|
+
},
|
|
139
|
+
"skill.promote.swarm": {
|
|
140
|
+
description: "Promote a skill to swarm scope (skill-approval path).",
|
|
141
|
+
namespace: "skill"
|
|
142
|
+
},
|
|
143
|
+
"skill.delete.any": {
|
|
144
|
+
description: "Delete a skill the caller does not own.",
|
|
145
|
+
namespace: "skill"
|
|
146
|
+
},
|
|
147
|
+
"mcp-server.create.swarm": {
|
|
148
|
+
description: "Create a swarm- or global-scoped MCP server.",
|
|
149
|
+
namespace: "mcp-server"
|
|
150
|
+
},
|
|
151
|
+
"mcp-server.install.any": {
|
|
152
|
+
description: "Install an MCP server for another agent.",
|
|
153
|
+
namespace: "mcp-server"
|
|
154
|
+
},
|
|
155
|
+
"mcp-server.uninstall.any": {
|
|
156
|
+
description: "Uninstall an MCP server for another agent.",
|
|
157
|
+
namespace: "mcp-server"
|
|
158
|
+
},
|
|
159
|
+
"mcp-server.delete.any": {
|
|
160
|
+
description: "Delete an MCP server the caller does not own.",
|
|
161
|
+
namespace: "mcp-server"
|
|
162
|
+
},
|
|
163
|
+
"mcp-server.update.any": {
|
|
164
|
+
description: "Update an MCP server the caller does not own.",
|
|
165
|
+
namespace: "mcp-server"
|
|
166
|
+
},
|
|
167
|
+
"mcp-server.read.secrets": {
|
|
168
|
+
description: "Read resolved MCP server secret env/header values.",
|
|
169
|
+
namespace: "mcp-server"
|
|
170
|
+
},
|
|
171
|
+
"mcp-oauth.authorize.any": {
|
|
172
|
+
description: "Start an MCP-server OAuth authorize flow for a caller-supplied user scope.",
|
|
173
|
+
namespace: "mcp-oauth"
|
|
174
|
+
},
|
|
175
|
+
"kv.write.any": {
|
|
176
|
+
description: "Write another agent's task:agent: KV namespace.",
|
|
177
|
+
namespace: "kv"
|
|
178
|
+
},
|
|
179
|
+
"page.delete.any": {
|
|
180
|
+
description: "Delete a page the caller does not own.",
|
|
181
|
+
namespace: "page"
|
|
182
|
+
},
|
|
183
|
+
"script.global.write": {
|
|
184
|
+
description: "Create or update a global-scope script.",
|
|
185
|
+
namespace: "script"
|
|
186
|
+
},
|
|
187
|
+
"script.global.delete": {
|
|
188
|
+
description: "Delete a global-scope script.",
|
|
189
|
+
namespace: "script"
|
|
190
|
+
},
|
|
191
|
+
"script.search": {
|
|
192
|
+
description: "Search reusable scripts visible to the caller.",
|
|
193
|
+
namespace: "script"
|
|
194
|
+
},
|
|
195
|
+
"script.api.read.secrets": {
|
|
196
|
+
description: "Reveal an external script API endpoint bearer token.",
|
|
197
|
+
namespace: "script"
|
|
198
|
+
},
|
|
199
|
+
"script.api.create": {
|
|
200
|
+
description: "Expose a script as an external HTTP API endpoint.",
|
|
201
|
+
namespace: "script"
|
|
202
|
+
},
|
|
203
|
+
"script.api.update": {
|
|
204
|
+
description: "Update an external script API endpoint.",
|
|
205
|
+
namespace: "script"
|
|
206
|
+
},
|
|
207
|
+
"script.api.rotate": {
|
|
208
|
+
description: "Rotate an external script API endpoint bearer token.",
|
|
209
|
+
namespace: "script"
|
|
210
|
+
},
|
|
211
|
+
"script.api.delete": {
|
|
212
|
+
description: "Delete an external script API endpoint.",
|
|
213
|
+
namespace: "script"
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
var PERMISSION_VERBS = Object.keys(PERMISSIONS);
|
|
217
|
+
var PermissionVerbSchema = _enum(PERMISSION_VERBS);
|
|
218
|
+
|
|
219
|
+
// src/rbac/admission.ts
|
|
220
|
+
function isRbacEnabled() {
|
|
221
|
+
return process.env.RBAC_ENABLED === "true";
|
|
222
|
+
}
|
|
223
|
+
function decideAdmission(input) {
|
|
224
|
+
if (input.grant.grantsAll) {
|
|
225
|
+
return { allow: true };
|
|
226
|
+
}
|
|
227
|
+
if (input.rbac && "permission" in input.rbac) {
|
|
228
|
+
const verb = input.rbac.permission;
|
|
229
|
+
if (input.grant.verbs.has(verb)) {
|
|
230
|
+
return { allow: true, verb };
|
|
231
|
+
}
|
|
232
|
+
return { allow: false, reason: `admission: missing permission '${verb}'`, verb };
|
|
233
|
+
}
|
|
234
|
+
const method = input.method.toUpperCase();
|
|
235
|
+
if (method === "GET" || method === "HEAD") {
|
|
236
|
+
return { allow: true };
|
|
237
|
+
}
|
|
238
|
+
return { allow: false, reason: "admission: route has no permission verb (operator-only)" };
|
|
239
|
+
}
|
|
240
|
+
function decideToolAdmission(input) {
|
|
241
|
+
if (input.grant.grantsAll) {
|
|
242
|
+
return { allow: true };
|
|
243
|
+
}
|
|
244
|
+
if (input.rbac && "permission" in input.rbac) {
|
|
245
|
+
const verb = input.rbac.permission;
|
|
246
|
+
if (input.grant.verbs.has(verb)) {
|
|
247
|
+
return { allow: true, verb };
|
|
248
|
+
}
|
|
249
|
+
return { allow: false, reason: `admission: missing permission '${verb}'`, verb };
|
|
250
|
+
}
|
|
251
|
+
if (input.readOnly) {
|
|
252
|
+
return { allow: true };
|
|
253
|
+
}
|
|
254
|
+
return { allow: false, reason: "admission: tool has no permission verb (operator-only)" };
|
|
255
|
+
}
|
|
256
|
+
// src/rbac/legacy-policy.ts
|
|
257
|
+
var leadOnly = {
|
|
258
|
+
name: "lead-only",
|
|
259
|
+
denyReason: "requires lead agent",
|
|
260
|
+
evaluate: (principal) => principal.kind === "agent" && principal.isLead
|
|
261
|
+
};
|
|
262
|
+
var leadOrTaskCreator = {
|
|
263
|
+
name: "lead-or-task-creator",
|
|
264
|
+
denyReason: "requires lead agent or task creator",
|
|
265
|
+
evaluate: (principal, resource) => {
|
|
266
|
+
if (principal.kind !== "agent")
|
|
267
|
+
return false;
|
|
268
|
+
if (principal.isLead)
|
|
269
|
+
return true;
|
|
270
|
+
return resource?.kind === "task" && resource.creatorAgentId != null && resource.creatorAgentId === principal.agentId;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
var leadOrResourceOwner = {
|
|
274
|
+
name: "lead-or-resource-owner",
|
|
275
|
+
denyReason: "requires lead agent or resource owner",
|
|
276
|
+
evaluate: (principal, resource) => {
|
|
277
|
+
if (principal.kind !== "agent")
|
|
278
|
+
return false;
|
|
279
|
+
if (principal.isLead)
|
|
280
|
+
return true;
|
|
281
|
+
return resource?.kind === "owned" && resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
var leadOrOwnNamespace = {
|
|
285
|
+
name: "lead-or-own-namespace",
|
|
286
|
+
denyReason: "requires lead agent or your own task:agent: namespace",
|
|
287
|
+
evaluate: (principal, resource) => {
|
|
288
|
+
if (principal.kind !== "agent")
|
|
289
|
+
return false;
|
|
290
|
+
if (principal.isLead)
|
|
291
|
+
return true;
|
|
292
|
+
return principal.agentId !== "" && resource?.kind === "kv-namespace" && resource.namespace === `task:agent:${principal.agentId}`;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var anyAuthenticated = {
|
|
296
|
+
name: "any-authenticated",
|
|
297
|
+
denyReason: "requires an authenticated principal",
|
|
298
|
+
evaluate: () => true
|
|
299
|
+
};
|
|
300
|
+
var requesterOwnsTask = {
|
|
301
|
+
name: "requester-owns-task",
|
|
302
|
+
denyReason: "not the task requester",
|
|
303
|
+
evaluate: (principal, resource) => {
|
|
304
|
+
if (principal.kind !== "user")
|
|
305
|
+
return true;
|
|
306
|
+
return resource?.kind === "task" && resource.requestedByUserId === principal.userId;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
var memoryOwnerOrLeadSwarm = {
|
|
310
|
+
name: "memory-owner-or-lead-swarm",
|
|
311
|
+
denyReason: "requires memory owner, or lead agent for swarm-scoped memories",
|
|
312
|
+
evaluate: (principal, resource) => {
|
|
313
|
+
if (principal.kind !== "agent" || resource?.kind !== "owned")
|
|
314
|
+
return false;
|
|
315
|
+
if (resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId)
|
|
316
|
+
return true;
|
|
317
|
+
return principal.isLead && resource.scope === "swarm";
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
var taskFsMutate = {
|
|
321
|
+
name: "operator-or-user-or-lead-or-task-owner",
|
|
322
|
+
denyReason: "requires operator, user, lead agent, task assignee, or task creator",
|
|
323
|
+
evaluate: (principal, resource) => {
|
|
324
|
+
if (principal.kind === "operator" || principal.kind === "user")
|
|
325
|
+
return true;
|
|
326
|
+
if (principal.isLead)
|
|
327
|
+
return true;
|
|
328
|
+
if (resource?.kind !== "task")
|
|
329
|
+
return false;
|
|
330
|
+
return resource.agentId != null && resource.agentId === principal.agentId || resource.creatorAgentId != null && resource.creatorAgentId === principal.agentId;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
var LEGACY_POLICY = {
|
|
334
|
+
"user.manage": leadOnly,
|
|
335
|
+
"agent.profile.update.any": leadOnly,
|
|
336
|
+
"agent.context.read.any": leadOnly,
|
|
337
|
+
"task.cancel.any": leadOrTaskCreator,
|
|
338
|
+
"task.create.own": anyAuthenticated,
|
|
339
|
+
"task.read.own": requesterOwnsTask,
|
|
340
|
+
"task.cancel.own": requesterOwnsTask,
|
|
341
|
+
"task.action.own": requesterOwnsTask,
|
|
342
|
+
"task.fs.mutate": taskFsMutate,
|
|
343
|
+
"favorite.write.own": anyAuthenticated,
|
|
344
|
+
"memory.learning.inject": leadOnly,
|
|
345
|
+
"memory.delete.any": memoryOwnerOrLeadSwarm,
|
|
346
|
+
"channel.delete": leadOnly,
|
|
347
|
+
"integration.kapso.manage": leadOnly,
|
|
348
|
+
"integration.slack.post": leadOnly,
|
|
349
|
+
"integration.slack.read": leadOnly,
|
|
350
|
+
"integration.slack.thread.start": leadOnly,
|
|
351
|
+
"integration.slack.upload": leadOnly,
|
|
352
|
+
"integration.slack.delete": leadOnly,
|
|
353
|
+
"integration.slack.update": leadOnly,
|
|
354
|
+
"credential-binding.manage": leadOnly,
|
|
355
|
+
"script-connection.manage": leadOnly,
|
|
356
|
+
"script-connection.invoke": anyAuthenticated,
|
|
357
|
+
"config.credential-bindings.write": leadOnly,
|
|
358
|
+
"config.write.any": leadOnly,
|
|
359
|
+
"config.delete.any": leadOnly,
|
|
360
|
+
"config.read.secrets": leadOnly,
|
|
361
|
+
"skill.create.swarm": leadOnly,
|
|
362
|
+
"skill.install.any": leadOnly,
|
|
363
|
+
"skill.install.global": leadOnly,
|
|
364
|
+
"skill.uninstall.any": leadOnly,
|
|
365
|
+
"skill.update.any": leadOrResourceOwner,
|
|
366
|
+
"skill.promote.swarm": leadOnly,
|
|
367
|
+
"skill.delete.any": leadOrResourceOwner,
|
|
368
|
+
"mcp-server.create.swarm": leadOnly,
|
|
369
|
+
"mcp-server.install.any": leadOnly,
|
|
370
|
+
"mcp-server.uninstall.any": leadOnly,
|
|
371
|
+
"mcp-server.delete.any": leadOrResourceOwner,
|
|
372
|
+
"mcp-server.update.any": leadOrResourceOwner,
|
|
373
|
+
"mcp-server.read.secrets": leadOnly,
|
|
374
|
+
"mcp-oauth.authorize.any": anyAuthenticated,
|
|
375
|
+
"kv.write.any": leadOrOwnNamespace,
|
|
376
|
+
"page.delete.any": leadOrResourceOwner,
|
|
377
|
+
"script.global.write": leadOnly,
|
|
378
|
+
"script.global.delete": leadOnly,
|
|
379
|
+
"script.search": anyAuthenticated,
|
|
380
|
+
"script.api.read.secrets": leadOnly,
|
|
381
|
+
"script.api.create": leadOnly,
|
|
382
|
+
"script.api.update": leadOnly,
|
|
383
|
+
"script.api.rotate": leadOnly,
|
|
384
|
+
"script.api.delete": leadOnly
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/rbac/can.ts
|
|
388
|
+
var auditSink = null;
|
|
389
|
+
function setAuditSink(fn) {
|
|
390
|
+
auditSink = fn;
|
|
391
|
+
}
|
|
392
|
+
function clearAuditSink() {
|
|
393
|
+
auditSink = null;
|
|
394
|
+
}
|
|
395
|
+
function can(check) {
|
|
396
|
+
const rule = LEGACY_POLICY[check.verb];
|
|
397
|
+
const decision = rule.evaluate(check.principal, check.resource) ? { allow: true } : { allow: false, reason: rule.denyReason, missing: check.verb };
|
|
398
|
+
if (auditSink) {
|
|
399
|
+
try {
|
|
400
|
+
auditSink(check, decision);
|
|
401
|
+
} catch {}
|
|
402
|
+
}
|
|
403
|
+
return decision;
|
|
404
|
+
}
|
|
405
|
+
export { isRbacEnabled, decideAdmission, decideToolAdmission, setAuditSink, clearAuditSink, can, PermissionVerbSchema };
|
|
@@ -7,7 +7,7 @@ var package_default;
|
|
|
7
7
|
var init_package = __esm(() => {
|
|
8
8
|
package_default = {
|
|
9
9
|
name: "@desplega.ai/agent-swarm",
|
|
10
|
-
version: "1.
|
|
10
|
+
version: "1.115.0",
|
|
11
11
|
description: "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
12
12
|
license: "MIT",
|
|
13
13
|
author: "desplega.sh <contact@desplega.sh>",
|
|
@@ -90,9 +90,9 @@ var init_package = __esm(() => {
|
|
|
90
90
|
lead: "bun src/cli.tsx lead",
|
|
91
91
|
"lead:yolo": "bun src/cli.tsx lead --yolo",
|
|
92
92
|
dev: "bun --hot src/stdio.ts",
|
|
93
|
-
"dev:http": "portless api.swarm bun --hot src/http.ts",
|
|
93
|
+
"dev:http": "NODE_ENV=development portless api.swarm bun --hot src/http.ts",
|
|
94
94
|
start: "bun src/stdio.ts",
|
|
95
|
-
"start:http": "bun --expose-gc src/http.ts",
|
|
95
|
+
"start:http": "NODE_ENV=development bun --expose-gc src/http.ts",
|
|
96
96
|
"start:portless": "portless api.swarm bun --expose-gc src/http.ts",
|
|
97
97
|
inspector: "bunx @modelcontextprotocol/inspector --transport stdio bun src/stdio.ts",
|
|
98
98
|
"inspector:http": "bunx @modelcontextprotocol/inspector --transport http https://api.swarm.localhost:1355/mcp",
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
REBOOT_RETRY_PIN_TAG,
|
|
3
|
+
createPoolStarvationDecisionTask,
|
|
2
4
|
createRerouteDecisionTask,
|
|
3
5
|
createResumeFollowUp,
|
|
4
6
|
getNextResumeGeneration,
|
|
7
|
+
getPinCandidateAgent,
|
|
5
8
|
getResumeGeneration,
|
|
6
9
|
repointTrackerSyncBySwarmId
|
|
7
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-dcca6j8m.js";
|
|
8
11
|
import {
|
|
9
12
|
getExecutorRegistry,
|
|
10
13
|
recoverIncompleteRuns
|
|
11
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-q1rx7g0d.js";
|
|
12
15
|
import {
|
|
13
16
|
MAX_EMPTY_POLLS,
|
|
14
17
|
assignUnassignedTaskPending,
|
|
15
18
|
backfillSupersedeTaskResumeTaskId,
|
|
19
|
+
buildRoutingAffinityFromAgent,
|
|
16
20
|
cleanupStaleSessions,
|
|
17
21
|
createTaskExtended,
|
|
18
22
|
deleteActiveSession,
|
|
@@ -28,6 +32,7 @@ import {
|
|
|
28
32
|
getRecentFailedCount,
|
|
29
33
|
getRecentFailedTasks,
|
|
30
34
|
getStalePinnedResumes,
|
|
35
|
+
getStaleUnassignedAffinityTasks,
|
|
31
36
|
getStalledInProgressTasks,
|
|
32
37
|
getTaskById,
|
|
33
38
|
getTaskStats,
|
|
@@ -37,6 +42,8 @@ import {
|
|
|
37
42
|
init_db,
|
|
38
43
|
init_registry,
|
|
39
44
|
init_resolver,
|
|
45
|
+
isAgentEligibleForTask,
|
|
46
|
+
isPoolAffinityEnforcementEnabled,
|
|
40
47
|
registerTemplate,
|
|
41
48
|
releaseStaleMentionProcessing,
|
|
42
49
|
releaseStaleProcessingInbox,
|
|
@@ -44,7 +51,7 @@ import {
|
|
|
44
51
|
resolveTemplate,
|
|
45
52
|
supersedeTask,
|
|
46
53
|
updateAgentStatus
|
|
47
|
-
} from "./cli-
|
|
54
|
+
} from "./cli-15y7qhzp.js";
|
|
48
55
|
|
|
49
56
|
// src/heartbeat/heartbeat.ts
|
|
50
57
|
init_db();
|
|
@@ -155,6 +162,8 @@ var STALL_THRESHOLD_NO_SESSION_MIN = Number(process.env.HEARTBEAT_STALL_NO_SESSI
|
|
|
155
162
|
var STALL_THRESHOLD_STALE_HEARTBEAT_MIN = Number(process.env.HEARTBEAT_STALL_STALE_HB_MIN) || 15;
|
|
156
163
|
var STALE_CLEANUP_THRESHOLD_MINUTES = Number(process.env.HEARTBEAT_STALE_CLEANUP_MIN) || 30;
|
|
157
164
|
var MAX_AUTO_ASSIGN_PER_SWEEP = Number(process.env.HEARTBEAT_MAX_AUTO_ASSIGN) || 5;
|
|
165
|
+
var POOL_SCAN_BATCH_SIZE = Number(process.env.HEARTBEAT_POOL_SCAN_BATCH_SIZE) || 50;
|
|
166
|
+
var POOL_SCAN_CAP = Number(process.env.HEARTBEAT_POOL_SCAN_CAP) || 500;
|
|
158
167
|
var MAX_RESUME_GENERATIONS = Number(process.env.HEARTBEAT_MAX_RESUME_GENERATIONS) || 3;
|
|
159
168
|
var RESUME_BUDGET_EXHAUSTED_REASON = "resume_budget_exhausted";
|
|
160
169
|
var HEARTBEAT_RESUME_PIN_GRACE_MIN = (() => {
|
|
@@ -164,6 +173,7 @@ var HEARTBEAT_RESUME_PIN_GRACE_MIN = (() => {
|
|
|
164
173
|
const parsed = Number(raw);
|
|
165
174
|
return Number.isFinite(parsed) ? parsed : 10;
|
|
166
175
|
})();
|
|
176
|
+
var POOL_AFFINITY_ESCALATION_MIN = Number(process.env.POOL_AFFINITY_ESCALATION_MIN) || 15;
|
|
167
177
|
var HEARTBEAT_CHECKLIST_INTERVAL_MS = Number(process.env.HEARTBEAT_CHECKLIST_INTERVAL_MS) || 30 * 60 * 1000;
|
|
168
178
|
var HEARTBEAT_CHECKLIST_DISABLE = Boolean(process.env.HEARTBEAT_CHECKLIST_DISABLE);
|
|
169
179
|
var heartbeatInterval = null;
|
|
@@ -412,12 +422,28 @@ async function runRebootSweep() {
|
|
|
412
422
|
LIMIT 1`).get(task.id);
|
|
413
423
|
if (!existingRetry) {
|
|
414
424
|
try {
|
|
425
|
+
let preferredAgentId;
|
|
426
|
+
const candidate = getPinCandidateAgent(task.agentId);
|
|
427
|
+
if (candidate) {
|
|
428
|
+
const activeCount = getActiveTaskCount(candidate.id);
|
|
429
|
+
const hasCap = activeCount < (candidate.maxTasks ?? 1);
|
|
430
|
+
if (hasCap) {
|
|
431
|
+
preferredAgentId = candidate.id;
|
|
432
|
+
} else {
|
|
433
|
+
console.warn(`[Heartbeat] Reboot retry for task ${task.id.slice(0, 8)} NOT pinned: agent ${candidate.id.slice(0, 8)} at capacity (${activeCount}/${candidate.maxTasks ?? 1}); falling back to affinity-gated pool`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const tags = ["reboot-retry", "auto-generated"];
|
|
437
|
+
if (preferredAgentId !== undefined)
|
|
438
|
+
tags.push(REBOOT_RETRY_PIN_TAG);
|
|
415
439
|
const retryTask = createTaskExtended(task.task, {
|
|
416
440
|
parentTaskId: task.id,
|
|
417
|
-
|
|
441
|
+
agentId: preferredAgentId,
|
|
442
|
+
tags,
|
|
418
443
|
priority: task.priority,
|
|
419
444
|
source: task.source,
|
|
420
|
-
taskType: task.taskType ?? undefined
|
|
445
|
+
taskType: task.taskType ?? undefined,
|
|
446
|
+
routingAffinity: buildRoutingAffinityFromAgent(task.agentId) ?? undefined
|
|
421
447
|
});
|
|
422
448
|
retryTaskId = retryTask.id;
|
|
423
449
|
console.log(`[Heartbeat] Reboot retry created: ${retryTaskId} (parent: ${task.id})`);
|
|
@@ -461,10 +487,6 @@ function autoAssignPoolTasks(findings) {
|
|
|
461
487
|
const idleWorkers = getIdleWorkersWithCapacity().filter((w) => (w.emptyPollCount ?? 0) < MAX_EMPTY_POLLS);
|
|
462
488
|
if (idleWorkers.length === 0)
|
|
463
489
|
return;
|
|
464
|
-
const poolTasks = getUnassignedPoolTasks(MAX_AUTO_ASSIGN_PER_SWEEP);
|
|
465
|
-
if (poolTasks.length === 0)
|
|
466
|
-
return;
|
|
467
|
-
let workerIndex = 0;
|
|
468
490
|
const reservedByWorker = new Map;
|
|
469
491
|
const reservedForWorker = (agentId) => {
|
|
470
492
|
const cached = reservedByWorker.get(agentId);
|
|
@@ -475,24 +497,28 @@ function autoAssignPoolTasks(findings) {
|
|
|
475
497
|
reservedByWorker.set(agentId, reserved);
|
|
476
498
|
return reserved;
|
|
477
499
|
};
|
|
478
|
-
|
|
479
|
-
|
|
500
|
+
let assignedCount = 0;
|
|
501
|
+
let offset = 0;
|
|
502
|
+
while (assignedCount < MAX_AUTO_ASSIGN_PER_SWEEP && offset < POOL_SCAN_CAP) {
|
|
503
|
+
const batch = getUnassignedPoolTasks(POOL_SCAN_BATCH_SIZE, offset);
|
|
504
|
+
if (batch.length === 0)
|
|
480
505
|
break;
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (remaining <= 0) {
|
|
493
|
-
workerIndex++;
|
|
506
|
+
for (const task of batch) {
|
|
507
|
+
if (assignedCount >= MAX_AUTO_ASSIGN_PER_SWEEP)
|
|
508
|
+
break;
|
|
509
|
+
const worker = idleWorkers.find((w) => reservedForWorker(w.id) < (w.maxTasks ?? 1) && isAgentEligibleForTask(w, task));
|
|
510
|
+
if (!worker)
|
|
511
|
+
continue;
|
|
512
|
+
const assigned = assignUnassignedTaskPending(task.id, worker.id);
|
|
513
|
+
if (assigned) {
|
|
514
|
+
findings.autoAssigned.push({ taskId: task.id, agentId: worker.id });
|
|
515
|
+
reservedByWorker.set(worker.id, reservedForWorker(worker.id) + 1);
|
|
516
|
+
assignedCount++;
|
|
494
517
|
}
|
|
495
518
|
}
|
|
519
|
+
offset += batch.length;
|
|
520
|
+
if (batch.length < POOL_SCAN_BATCH_SIZE)
|
|
521
|
+
break;
|
|
496
522
|
}
|
|
497
523
|
})();
|
|
498
524
|
}
|
|
@@ -550,12 +576,35 @@ function escalateUnreclaimedResumes(findings) {
|
|
|
550
576
|
console.log(`[Heartbeat] Escalated unreclaimed pinned resume ${resume.id.slice(0, 8)} → Lead reroute-decision ${escalation.decisionTaskId.slice(0, 8)} (original ${original.id.slice(0, 8)})`);
|
|
551
577
|
}
|
|
552
578
|
}
|
|
579
|
+
function escalateStarvedPoolTasks(findings) {
|
|
580
|
+
if (!isPoolAffinityEnforcementEnabled())
|
|
581
|
+
return;
|
|
582
|
+
const cutoff = new Date(Date.now() - POOL_AFFINITY_ESCALATION_MIN * 60 * 1000).toISOString();
|
|
583
|
+
const candidates = getStaleUnassignedAffinityTasks(cutoff);
|
|
584
|
+
if (candidates.length === 0)
|
|
585
|
+
return;
|
|
586
|
+
const registeredAgents = getAllAgents().filter((a) => !a.isLead);
|
|
587
|
+
for (const task of candidates) {
|
|
588
|
+
const hasEligibleAgent = registeredAgents.some((agent) => isAgentEligibleForTask(agent, task));
|
|
589
|
+
if (hasEligibleAgent)
|
|
590
|
+
continue;
|
|
591
|
+
const decision = createPoolStarvationDecisionTask({ original: task });
|
|
592
|
+
if (decision.kind === "created") {
|
|
593
|
+
findings.escalatedReroutes.push({
|
|
594
|
+
originalTaskId: task.id,
|
|
595
|
+
decisionTaskId: decision.task.id
|
|
596
|
+
});
|
|
597
|
+
console.log(`[Heartbeat] Escalated starved pool task ${task.id.slice(0, 8)} → Lead reroute-decision ${decision.task.id.slice(0, 8)} (zero eligible agents)`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
553
601
|
async function cleanupStaleResources(findings) {
|
|
554
602
|
findings.staleCleanup.sessions = cleanupStaleSessions(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
555
603
|
findings.staleCleanup.reviewingTasks = releaseStaleReviewingTasks(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
556
604
|
findings.staleCleanup.mentionProcessing = releaseStaleMentionProcessing(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
557
605
|
findings.staleCleanup.inboxProcessing = releaseStaleProcessingInbox(STALE_CLEANUP_THRESHOLD_MINUTES);
|
|
558
606
|
escalateUnreclaimedResumes(findings);
|
|
607
|
+
escalateStarvedPoolTasks(findings);
|
|
559
608
|
try {
|
|
560
609
|
findings.staleCleanup.workflowRuns = await recoverIncompleteRuns(getExecutorRegistry());
|
|
561
610
|
} catch {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
recordUnmappedIdentity
|
|
3
|
-
} from "./cli-c9mtm09b.js";
|
|
4
1
|
import {
|
|
5
2
|
findOrCreateUserByEmail,
|
|
6
3
|
findUserByExternalId,
|
|
7
|
-
linkIdentity
|
|
8
|
-
|
|
4
|
+
linkIdentity,
|
|
5
|
+
recordUnmappedIdentity,
|
|
6
|
+
resolveIdentity
|
|
7
|
+
} from "./cli-6aq8xhvm.js";
|
|
9
8
|
import {
|
|
10
9
|
getKv,
|
|
11
10
|
init_db,
|
|
12
11
|
upsertKv
|
|
13
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-15y7qhzp.js";
|
|
14
13
|
|
|
15
14
|
// src/slack/enrich.ts
|
|
16
15
|
init_db();
|
|
@@ -70,5 +69,11 @@ async function resolveSlackUserId(client, slackUserId, eventContext) {
|
|
|
70
69
|
recordUnmappedIdentity("slack", slackUserId, eventContext);
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
72
|
+
function rewriteSlackMentions(text) {
|
|
73
|
+
return text.replace(/<@([A-Z0-9]+)>/g, (_match, userId) => {
|
|
74
|
+
const resolution = resolveIdentity("slack", userId);
|
|
75
|
+
return resolution.status === "resolved" ? `<@${userId}|${resolution.name}>` : `<@${userId}> (unknown user)`;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
73
78
|
|
|
74
|
-
export { enrichSlackUserEmail, resolveSlackUserId };
|
|
79
|
+
export { enrichSlackUserEmail, resolveSlackUserId, rewriteSlackMentions };
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
getEmbeddingProvider,
|
|
5
5
|
init_embedding,
|
|
6
6
|
serializeEmbedding
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-7xje5amz.js";
|
|
8
8
|
import {
|
|
9
9
|
getDb,
|
|
10
10
|
init_db
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-15y7qhzp.js";
|
|
12
12
|
import {
|
|
13
13
|
init_secret_scrubber,
|
|
14
14
|
scrubSecrets
|