@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.115.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "desplega.sh <contact@desplega.sh>",
|
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
"lead": "bun src/cli.tsx lead",
|
|
84
84
|
"lead:yolo": "bun src/cli.tsx lead --yolo",
|
|
85
85
|
"dev": "bun --hot src/stdio.ts",
|
|
86
|
-
"dev:http": "portless api.swarm bun --hot src/http.ts",
|
|
86
|
+
"dev:http": "NODE_ENV=development portless api.swarm bun --hot src/http.ts",
|
|
87
87
|
"start": "bun src/stdio.ts",
|
|
88
|
-
"start:http": "bun --expose-gc src/http.ts",
|
|
88
|
+
"start:http": "NODE_ENV=development bun --expose-gc src/http.ts",
|
|
89
89
|
"start:portless": "portless api.swarm bun --expose-gc src/http.ts",
|
|
90
90
|
"inspector": "bunx @modelcontextprotocol/inspector --transport stdio bun src/stdio.ts",
|
|
91
91
|
"inspector:http": "bunx @modelcontextprotocol/inspector --transport http https://api.swarm.localhost:1355/mcp",
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getAgentMailInboxMapping,
|
|
5
5
|
getAllAgents,
|
|
6
6
|
} from "../be/db";
|
|
7
|
+
import { renderIdentity, resolveIdentityByEmail } from "../be/identity";
|
|
7
8
|
import { findOrCreateUserByEmail } from "../be/users";
|
|
8
9
|
import { resolveTemplate } from "../prompts/resolver";
|
|
9
10
|
import { createIngressBuffer } from "../tasks/additive-ingress";
|
|
@@ -184,6 +185,15 @@ export async function handleMessageReceived(
|
|
|
184
185
|
);
|
|
185
186
|
requestedByUserId = user.id;
|
|
186
187
|
}
|
|
188
|
+
// Render the resolved canonical name (or the UNKNOWN sentinel) for
|
|
189
|
+
// agent-visible text — never the raw From header. `findOrCreateUserByEmail`
|
|
190
|
+
// above auto-creates on a real email, so `senderEmail` present implies
|
|
191
|
+
// resolved; a missing/unparseable From header has no machine-carried
|
|
192
|
+
// identifier at all, so it renders the same non-name sentinel shape via
|
|
193
|
+
// the identity primitive rather than echoing the raw header string.
|
|
194
|
+
const senderDisplay = senderEmail
|
|
195
|
+
? renderIdentity(resolveIdentityByEmail(senderEmail))
|
|
196
|
+
: renderIdentity({ status: "unknown", kind: "email", externalId: "unknown" });
|
|
187
197
|
const preview = body.length > 500 ? `${body.substring(0, 500)}...` : body;
|
|
188
198
|
|
|
189
199
|
// Emit workflow trigger event
|
|
@@ -207,7 +217,7 @@ export async function handleMessageReceived(
|
|
|
207
217
|
if (
|
|
208
218
|
agentmailBuffer.enabled &&
|
|
209
219
|
agentmailBuffer.maybeBuffer(contextKey, siblingInFlight, {
|
|
210
|
-
from,
|
|
220
|
+
from: senderDisplay,
|
|
211
221
|
subject,
|
|
212
222
|
inboxId: inbox_id,
|
|
213
223
|
threadId: thread_id,
|
|
@@ -226,7 +236,7 @@ export async function handleMessageReceived(
|
|
|
226
236
|
|
|
227
237
|
// Create a follow-up task with parentTaskId to continue the session
|
|
228
238
|
const followupResult = resolveTemplate("agentmail.email.followup", {
|
|
229
|
-
from,
|
|
239
|
+
from: senderDisplay,
|
|
230
240
|
subject,
|
|
231
241
|
inbox_id,
|
|
232
242
|
thread_id,
|
|
@@ -264,7 +274,7 @@ export async function handleMessageReceived(
|
|
|
264
274
|
if (agent.isLead) {
|
|
265
275
|
// Route to lead as task
|
|
266
276
|
const leadResult = resolveTemplate("agentmail.email.mapped_lead", {
|
|
267
|
-
from,
|
|
277
|
+
from: senderDisplay,
|
|
268
278
|
subject,
|
|
269
279
|
inbox_id,
|
|
270
280
|
thread_id,
|
|
@@ -295,7 +305,7 @@ export async function handleMessageReceived(
|
|
|
295
305
|
|
|
296
306
|
// Route to worker as task
|
|
297
307
|
const workerResult = resolveTemplate("agentmail.email.mapped_worker", {
|
|
298
|
-
from,
|
|
308
|
+
from: senderDisplay,
|
|
299
309
|
subject,
|
|
300
310
|
inbox_id,
|
|
301
311
|
thread_id,
|
|
@@ -328,7 +338,7 @@ export async function handleMessageReceived(
|
|
|
328
338
|
const lead = findLeadAgent();
|
|
329
339
|
if (lead) {
|
|
330
340
|
const unmappedResult = resolveTemplate("agentmail.email.unmapped", {
|
|
331
|
-
from,
|
|
341
|
+
from: senderDisplay,
|
|
332
342
|
subject,
|
|
333
343
|
inbox_id,
|
|
334
344
|
thread_id,
|
|
@@ -359,7 +369,7 @@ export async function handleMessageReceived(
|
|
|
359
369
|
|
|
360
370
|
// No lead available - create unassigned task
|
|
361
371
|
const noAgentResult = resolveTemplate("agentmail.email.no_agent", {
|
|
362
|
-
from,
|
|
372
|
+
from: senderDisplay,
|
|
363
373
|
subject,
|
|
364
374
|
inbox_id,
|
|
365
375
|
thread_id,
|
|
@@ -21,7 +21,11 @@ Thread: {{thread_id}}
|
|
|
21
21
|
|
|
22
22
|
{{preview}}`,
|
|
23
23
|
variables: [
|
|
24
|
-
{
|
|
24
|
+
{
|
|
25
|
+
name: "from",
|
|
26
|
+
description:
|
|
27
|
+
"Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel",
|
|
28
|
+
},
|
|
25
29
|
{ name: "subject", description: "Email subject" },
|
|
26
30
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
27
31
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -41,7 +45,11 @@ Message: {{message_id}}
|
|
|
41
45
|
|
|
42
46
|
{{preview}}`,
|
|
43
47
|
variables: [
|
|
44
|
-
{
|
|
48
|
+
{
|
|
49
|
+
name: "from",
|
|
50
|
+
description:
|
|
51
|
+
"Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel",
|
|
52
|
+
},
|
|
45
53
|
{ name: "subject", description: "Email subject" },
|
|
46
54
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
47
55
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -61,7 +69,11 @@ Thread: {{thread_id}}
|
|
|
61
69
|
|
|
62
70
|
{{preview}}`,
|
|
63
71
|
variables: [
|
|
64
|
-
{
|
|
72
|
+
{
|
|
73
|
+
name: "from",
|
|
74
|
+
description:
|
|
75
|
+
"Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel",
|
|
76
|
+
},
|
|
65
77
|
{ name: "subject", description: "Email subject" },
|
|
66
78
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
67
79
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -81,7 +93,11 @@ Message: {{message_id}}
|
|
|
81
93
|
|
|
82
94
|
{{preview}}`,
|
|
83
95
|
variables: [
|
|
84
|
-
{
|
|
96
|
+
{
|
|
97
|
+
name: "from",
|
|
98
|
+
description:
|
|
99
|
+
"Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel",
|
|
100
|
+
},
|
|
85
101
|
{ name: "subject", description: "Email subject" },
|
|
86
102
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
87
103
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
|
@@ -101,7 +117,11 @@ Thread: {{thread_id}}
|
|
|
101
117
|
|
|
102
118
|
{{preview}}`,
|
|
103
119
|
variables: [
|
|
104
|
-
{
|
|
120
|
+
{
|
|
121
|
+
name: "from",
|
|
122
|
+
description:
|
|
123
|
+
"Sender identity — resolved canonical name (e.g. 'Luis (email:luis@x.com)') or the UNKNOWN sentinel",
|
|
124
|
+
},
|
|
105
125
|
{ name: "subject", description: "Email subject" },
|
|
106
126
|
{ name: "inbox_id", description: "AgentMail inbox ID" },
|
|
107
127
|
{ name: "thread_id", description: "AgentMail thread ID" },
|
package/src/be/audit-user.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IncomingMessage } from "node:http";
|
|
2
2
|
import { getRequestAuth } from "../utils/request-auth-context";
|
|
3
|
-
import { getTaskById } from "./db";
|
|
3
|
+
import { getAgentCurrentTask, getTaskById } from "./db";
|
|
4
|
+
import { findUserByExternalId } from "./users";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Resolve the trusted audit-actor user id for a write to an audited table
|
|
@@ -14,6 +15,13 @@ import { getTaskById } from "./db";
|
|
|
14
15
|
* attribute a write to a task they already own, whose requester is legitimately
|
|
15
16
|
* theirs.
|
|
16
17
|
*
|
|
18
|
+
* Two fallbacks layer on top of the header, both still gated by ownership:
|
|
19
|
+
* 1. No header at all → the caller's own current in-progress task (never a
|
|
20
|
+
* client-supplied id, so this can't be spoofed).
|
|
21
|
+
* 2. The resolved task has no `requestedByUserId` but carries a
|
|
22
|
+
* machine-recorded provider external id (today: the Slack user field) →
|
|
23
|
+
* the same generic reverse lookup used everywhere else.
|
|
24
|
+
*
|
|
17
25
|
* Returns `null` when no trusted actor can be established — which leaves the
|
|
18
26
|
* audit column untouched on updates and NULL on inserts.
|
|
19
27
|
*/
|
|
@@ -21,13 +29,29 @@ export function resolveTaskAuditUserId(
|
|
|
21
29
|
sourceTaskId: string | undefined,
|
|
22
30
|
callerAgentId: string | undefined,
|
|
23
31
|
): string | null {
|
|
24
|
-
if (!
|
|
25
|
-
|
|
32
|
+
if (!callerAgentId) return null;
|
|
33
|
+
|
|
34
|
+
let resolvedSourceTaskId = sourceTaskId;
|
|
35
|
+
if (!resolvedSourceTaskId) {
|
|
36
|
+
const currentTask = getAgentCurrentTask(callerAgentId);
|
|
37
|
+
if (currentTask) resolvedSourceTaskId = currentTask.id;
|
|
38
|
+
}
|
|
39
|
+
if (!resolvedSourceTaskId) return null;
|
|
40
|
+
|
|
41
|
+
const task = getTaskById(resolvedSourceTaskId);
|
|
26
42
|
if (!task) return null;
|
|
27
43
|
// Bind the header to the caller's own task — otherwise it is just a
|
|
28
44
|
// client-chosen value and its requester cannot be trusted.
|
|
29
45
|
if (task.agentId !== callerAgentId) return null;
|
|
30
|
-
|
|
46
|
+
|
|
47
|
+
if (task.requestedByUserId) return task.requestedByUserId;
|
|
48
|
+
|
|
49
|
+
if (task.slackUserId) {
|
|
50
|
+
const user = findUserByExternalId("slack", task.slackUserId);
|
|
51
|
+
if (user) return user.id;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
31
55
|
}
|
|
32
56
|
|
|
33
57
|
/**
|
|
@@ -113,6 +113,7 @@ export function storeOAuthTokens(
|
|
|
113
113
|
scope?: string | null;
|
|
114
114
|
},
|
|
115
115
|
): void {
|
|
116
|
+
// TODO(secrets-cipher): encrypt OAuth tokens at rest with src/be/crypto/secrets-cipher.ts.
|
|
116
117
|
getDb()
|
|
117
118
|
.query(
|
|
118
119
|
`INSERT INTO oauth_tokens (provider, accessToken, refreshToken, expiresAt, scope)
|
|
@@ -170,6 +171,47 @@ export function updateOAuthTokensAfterRefresh(
|
|
|
170
171
|
throw new Error(`OAuth token refresh persistence failed for ${provider}: no rows updated`);
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Presence-flags-only projection of oauth_tokens for the background refresh
|
|
176
|
+
* sweep. Deliberately excludes token values so sweep code can never leak
|
|
177
|
+
* them into logs.
|
|
178
|
+
*/
|
|
179
|
+
export type OAuthTokenSweepRow = {
|
|
180
|
+
provider: string;
|
|
181
|
+
hasApp: boolean;
|
|
182
|
+
hasRefreshToken: boolean;
|
|
183
|
+
expiresAt: string;
|
|
184
|
+
updatedAt: string;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export function listOAuthTokenSweepRows(): OAuthTokenSweepRow[] {
|
|
188
|
+
const rows = getDb()
|
|
189
|
+
.query(
|
|
190
|
+
`SELECT t.provider,
|
|
191
|
+
CASE WHEN a.provider IS NOT NULL THEN 1 ELSE 0 END AS hasApp,
|
|
192
|
+
CASE WHEN t.refreshToken IS NOT NULL AND t.refreshToken != '' THEN 1 ELSE 0 END AS hasRefreshToken,
|
|
193
|
+
t.expiresAt,
|
|
194
|
+
t.updatedAt
|
|
195
|
+
FROM oauth_tokens t
|
|
196
|
+
LEFT JOIN oauth_apps a ON a.provider = t.provider
|
|
197
|
+
ORDER BY t.provider ASC`,
|
|
198
|
+
)
|
|
199
|
+
.all() as Array<{
|
|
200
|
+
provider: string;
|
|
201
|
+
hasApp: number;
|
|
202
|
+
hasRefreshToken: number;
|
|
203
|
+
expiresAt: string;
|
|
204
|
+
updatedAt: string;
|
|
205
|
+
}>;
|
|
206
|
+
return rows.map((row) => ({
|
|
207
|
+
provider: row.provider,
|
|
208
|
+
hasApp: row.hasApp === 1,
|
|
209
|
+
hasRefreshToken: row.hasRefreshToken === 1,
|
|
210
|
+
expiresAt: normalizeDateRequired(row.expiresAt),
|
|
211
|
+
updatedAt: normalizeDateRequired(row.updatedAt),
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
|
|
173
215
|
export function deleteOAuthTokens(provider: string): void {
|
|
174
216
|
getDb().query("DELETE FROM oauth_tokens WHERE provider = ?").run(provider);
|
|
175
217
|
}
|