@desplega.ai/agent-swarm 1.172.0 → 1.173.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/dist/{acp-adapter-fpecx1g1.js → acp-adapter-ccm9xrep.js} +8 -8
- package/dist/{actions-pw87a1a8.js → actions-sgeyv08k.js} +44 -19
- package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-gpxp3kc9.js} +1 -1
- package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
- package/dist/{app-wmf0m843.js → app-km9qnv2f.js} +6 -4
- package/dist/{assistant-emp1e108.js → assistant-5r8tcvvd.js} +44 -22
- package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-16rv9843.js} +4 -3
- package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-swwzdgd7.js} +4 -3
- package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-zkr6vkqb.js} +5 -4
- package/dist/{boot-seeds-8q637aew.js → boot-seeds-d8sp49t2.js} +7 -6
- package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-yzzzh8jp.js} +9 -9
- package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-4whxere4.js} +9458 -9164
- package/dist/{cli-g4f5pj26.js → cli-0a7mm3zp.js} +92 -10
- package/dist/{cli-pj6x9qce.js → cli-0kxf81jj.js} +1 -1
- package/dist/{cli-kb4ehzx5.js → cli-1w0vj3gw.js} +4 -4
- package/dist/{cli-e0a9sk00.js → cli-3nxdmjrc.js} +1 -1
- package/dist/{cli-6jb2rf77.js → cli-42qhyvwx.js} +3 -3
- package/dist/{cli-esnpehf5.js → cli-5er5gjbm.js} +4 -4
- package/dist/{cli-04emfe2q.js → cli-5wpw4rab.js} +1 -1
- package/dist/{cli-aspcaef3.js → cli-6r2f7edk.js} +4 -4
- package/dist/{cli-xczpdp9e.js → cli-6thk4jz3.js} +1 -1
- package/dist/{cli-j6kpj9az.js → cli-7a93cv8c.js} +1458 -48
- package/dist/{cli-k46r9hmk.js → cli-94b48jhk.js} +2 -2
- package/dist/{cli-gp1rtyvk.js → cli-9xf7fdtp.js} +2 -2
- package/dist/{cli-qsztpfry.js → cli-anzdk0z4.js} +1 -1
- package/dist/{cli-cceskcvt.js → cli-b07hr3bt.js} +8 -8
- package/dist/{cli-c2pq2rjb.js → cli-bv2etw2y.js} +2 -2
- package/dist/{cli-hwwvy36w.js → cli-c3rk1v0x.js} +3 -3
- package/dist/{cli-tgpfnm6r.js → cli-fmhj1ehj.js} +53 -13
- package/dist/{cli-r8smj8b8.js → cli-jpc4r224.js} +1 -1
- package/dist/{cli-4nz8p1p5.js → cli-m89t9jdf.js} +5 -5
- package/dist/{cli-bf7485pm.js → cli-na2pxe4f.js} +1 -1
- package/dist/{cli-prrt9fa0.js → cli-ne7smj1b.js} +4 -4
- package/dist/{cli-cf69s3ew.js → cli-nwrdx840.js} +2 -2
- package/dist/cli-p0sg24zp.js +16 -0
- package/dist/{cli-gj81e47t.js → cli-phcqp1b9.js} +1 -1
- package/dist/{cli-5rv1j9ga.js → cli-qm1448f9.js} +51 -5
- package/dist/{cli-8hzfb6xz.js → cli-r0byd61h.js} +7 -7
- package/dist/{cli-nyhb1r6x.js → cli-r4fqfpwf.js} +3 -3
- package/dist/{cli-1hgat6pa.js → cli-rfs4vddv.js} +5 -5
- package/dist/{cli-ztrv9y21.js → cli-rfz2ve55.js} +861 -246
- package/dist/{cli-pstq9888.js → cli-s8z6x4b4.js} +22 -21
- package/dist/{cli-j1pmc07z.js → cli-saqyage0.js} +92 -16
- package/dist/{cli-zxm9p3x4.js → cli-srqq3gc5.js} +1 -1
- package/dist/{cli-9xsmdpdt.js → cli-tcc4wd5d.js} +136 -42
- package/dist/cli-v3zhnxsb.js +263 -0
- package/dist/{cli-388egyf6.js → cli-w1apjecb.js} +1 -1
- package/dist/{cli-g6t9texm.js → cli-wrh08zjd.js} +4 -4
- package/dist/{cli-8vs9trd4.js → cli-x119kdba.js} +1 -1
- package/dist/{cli-nv4zd0b9.js → cli-xc7p7s3g.js} +1 -1
- package/dist/cli.js +16 -16
- package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-r3dn4fp5.js} +6 -6
- package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-fwt793h4.js} +6 -6
- package/dist/{commands-n0hshcvs.js → commands-z8fq9qna.js} +14 -4
- package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-3mf2btyj.js} +21 -19
- package/dist/{db-4w7tmt1g.js → db-qfpq4bt7.js} +4 -3
- package/dist/{db-hkqvrdcb.js → db-yyhqqrbf.js} +5 -4
- package/dist/{dispatcher-5sd69y14.js → dispatcher-x0x7qfcq.js} +20 -18
- package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-34etvb5m.js} +1 -1
- package/dist/external-channel-h1fjecwe.js +51 -0
- package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-e7mr287e.js} +9 -9
- package/dist/{handlers-s20xr10r.js → handlers-znb9n7d4.js} +23 -21
- package/dist/{heartbeat-3k31q4g2.js → heartbeat-bm4qkn8d.js} +22 -20
- package/dist/{hook-gdn6a2fn.js → hook-254r4mza.js} +7 -7
- package/dist/{hook-ygwerrdh.js → hook-xaa3q80s.js} +8 -8
- package/dist/{http-jdteeg81.js → http-3dgrgp8y.js} +135 -64
- package/dist/{index-6ksewd5y.js → index-2ybk7khy.js} +618 -120
- package/dist/{index-tsszt7g9.js → index-bdsqa799.js} +22 -20
- package/dist/{index-e0snym4t.js → index-fx3jqq1e.js} +20 -18
- package/dist/{index-vm3bm9t7.js → index-g2byveez.js} +20 -18
- package/dist/{index-ffqzqgwb.js → index-jd7sejm2.js} +4 -3
- package/dist/{keepalive-jekc896t.js → keepalive-6ywhpja1.js} +6 -5
- package/dist/{lead-4k9s9szx.js → lead-cw45n21s.js} +32 -30
- package/dist/{maintenance-shazch4n.js → maintenance-ss1a1ge9.js} +4 -3
- package/dist/node-c9we95xf.js +1 -1
- package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-3c6f8vyy.js} +5 -4
- package/dist/{onboard-ydrbnvww.js → onboard-8hzdhc1k.js} +2 -2
- package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-qbchbcfz.js} +6 -6
- package/dist/{otel-impl-6pf5cv86.js → otel-impl-e6mnvc4v.js} +7 -2
- package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-3c9g9snh.js} +6 -6
- package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-gedkjdw0.js} +6 -5
- package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-dt4vh1yy.js} +4 -3
- package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-eszdg6pm.js} +5 -4
- package/dist/{render-v2-pd1rg54q.js → render-v2-907cy6sa.js} +6 -4
- package/dist/{resume-gw4a2c6v.js → resume-42stcaz0.js} +11 -9
- package/dist/{setup-jda1ksdh.js → setup-adbc1c10.js} +2 -2
- package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-rtmt494q.js} +3 -3
- package/dist/{work-objects-tb7ycye8.js → work-objects-wpj8ck95.js} +28 -21
- package/dist/{worker-njjccz5d.js → worker-bzdra9rf.js} +32 -30
- package/openapi.json +423 -7
- package/package.json +4 -4
- package/src/apps/catalog.generated.json +1309 -53
- package/src/apps/page-validator.ts +93 -31
- package/src/azure-devops/api.ts +94 -18
- package/src/azure-devops/auth.ts +32 -0
- package/src/azure-devops/boards-sync.ts +708 -0
- package/src/azure-devops/handlers.ts +52 -8
- package/src/azure-devops/html.ts +26 -0
- package/src/azure-devops/index.ts +15 -0
- package/src/azure-devops/templates.ts +86 -0
- package/src/azure-devops/types.ts +65 -1
- package/src/be/db.ts +22 -6
- package/src/be/migrations/213_script_connections_sql.sql +79 -0
- package/src/be/script-connections.ts +47 -8
- package/src/be/seed-skills/bundled-files.generated.json +10 -0
- package/src/be/seed-skills/index.ts +3 -0
- package/src/be/sql-connections.ts +118 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/commands/profile-sync.ts +5 -3
- package/src/commands/runner.ts +6 -2
- package/src/http/mcp-oauth.ts +6 -13
- package/src/http/pages-public.ts +3 -2
- package/src/http/pages.ts +2 -1
- package/src/http/route-def.ts +7 -6
- package/src/http/script-connection-proxy.ts +51 -4
- package/src/http/script-connections.ts +5 -2
- package/src/http/session-cost-recompute.ts +12 -2
- package/src/http/session-data.ts +4 -0
- package/src/http/webhooks.ts +24 -1
- package/src/jira/adf.ts +3 -1
- package/src/kv-reserved-namespaces.ts +2 -0
- package/src/oauth/mcp-wrapper.ts +10 -6
- package/src/otel-impl.ts +2 -1
- package/src/prompts/base-prompt.ts +3 -3
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +27 -2
- package/src/providers/claude-flag-settings.ts +121 -0
- package/src/providers/claude-sdk-session.ts +7 -0
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +26 -12
- package/src/providers/opencode-billing.ts +86 -0
- package/src/providers/opencode-swarm-plugin.ts +20 -0
- package/src/providers/pricing-sources.md +4 -1
- package/src/providers/types.ts +5 -0
- package/src/scripts-runtime/api-client.ts +15 -1
- package/src/scripts-runtime/api-types.ts +9 -1
- package/src/scripts-runtime/ctx.ts +1 -1
- package/src/scripts-runtime/mcp-client.ts +30 -19
- package/src/slack/actions.ts +29 -1
- package/src/slack/app.ts +14 -2
- package/src/slack/assistant.ts +36 -2
- package/src/slack/channel-join.ts +3 -16
- package/src/slack/commands.ts +9 -1
- package/src/slack/external-channel-egress.ts +113 -0
- package/src/slack/external-channel.ts +309 -0
- package/src/slack/handlers.ts +61 -0
- package/src/slack/render-v2.ts +40 -47
- package/src/slack/work-objects.ts +5 -0
- package/src/tasks/context-key.ts +34 -1
- package/src/telemetry.ts +2 -1
- package/src/tests/apps-catalog-feedback.test.ts +310 -0
- package/src/tests/apps-catalog-inputs.test.ts +70 -0
- package/src/tests/apps-catalog-table.test.ts +113 -0
- package/src/tests/azure-devops-boards-sync.test.ts +584 -0
- package/src/tests/azure-devops-html.test.ts +13 -0
- package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
- package/src/tests/claude-adapter-binary.test.ts +139 -0
- package/src/tests/claude-flag-settings.test.ts +106 -0
- package/src/tests/claude-sdk-lifecycle.test.ts +142 -1
- package/src/tests/claude-sdk-process.fixture.ts +7 -0
- package/src/tests/context-key.test.ts +32 -0
- package/src/tests/deferred-task-wake.test.ts +52 -4
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
- package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
- package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
- package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
- package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
- package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
- package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
- package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
- package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
- package/src/tests/node-env-runtime.test.ts +98 -0
- package/src/tests/opencode-adapter.test.ts +132 -1
- package/src/tests/opencode-billing.test.ts +28 -0
- package/src/tests/runner-identity-refresh.test.ts +3 -0
- package/src/tests/script-connections-sql.test.ts +675 -0
- package/src/tests/script-connections.test.ts +5 -1
- package/src/tests/session-cost-recompute-unit.test.ts +48 -0
- package/src/tests/slack-channel-join.test.ts +4 -1
- package/src/tests/slack-external-channel-config.test.ts +65 -0
- package/src/tests/slack-external-channel-egress.test.ts +237 -0
- package/src/tests/slack-external-channel-guard.test.ts +280 -0
- package/src/tests/slack-external-channel-tools.test.ts +173 -0
- package/src/tests/slack-external-channel.test.ts +370 -0
- package/src/tests/slack-render-v2.test.ts +86 -10
- package/src/tests/spec-base-url.test.ts +16 -1
- package/src/tests/vendored-openapi.test.ts +16 -1
- package/src/tools/defer-task.ts +17 -0
- package/src/tools/slack-post.ts +6 -0
- package/src/tools/slack-read.ts +8 -0
- package/src/tools/slack-reply.ts +6 -0
- package/src/tools/slack-start-thread.ts +6 -0
- package/src/tools/slack-update.ts +6 -0
- package/src/tools/slack-upload-file.ts +6 -0
- package/src/utils/node-env.ts +24 -0
- package/templates/skills/apps/SKILL.md +742 -0
- package/templates/skills/apps/content.md +52 -21
- package/templates/skills/qa-loom/config.json +14 -0
- package/templates/skills/qa-loom/content.md +187 -0
- package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
- package/templates/skills/qa-loom/files/run-qa.sh +57 -0
- package/templates/skills/slack-interaction/content.md +4 -0
- package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
- package/dist/{cli-4fnb6884.js → cli-h7k0xtry.js} +3 -3
- package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
- package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-szdxbpqg.js} +1 -1
- package/dist/{google-vertex-3f1jk41f.js → google-vertex-qzw3p36d.js} +1 -1
- package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
- package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
- package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
- package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
require_jws,
|
|
9
9
|
require_p_retry
|
|
10
10
|
} from "./cli-yatxqynm.js";
|
|
11
|
+
import {
|
|
12
|
+
getChannelBlockReason
|
|
13
|
+
} from "./cli-v3zhnxsb.js";
|
|
11
14
|
import {
|
|
12
15
|
exports_supports_color,
|
|
13
16
|
init_supports_color
|
|
@@ -70,7 +73,7 @@ import {
|
|
|
70
73
|
setSlackMessageTracking,
|
|
71
74
|
slackContextKey,
|
|
72
75
|
updateSlackMessageRecord
|
|
73
|
-
} from "./cli-
|
|
76
|
+
} from "./cli-fmhj1ehj.js";
|
|
74
77
|
import {
|
|
75
78
|
init_types,
|
|
76
79
|
isTerminalTaskStatus
|
|
@@ -78,7 +81,7 @@ import {
|
|
|
78
81
|
import {
|
|
79
82
|
init_task_attachment_links,
|
|
80
83
|
taskAttachmentDisplayUrl
|
|
81
|
-
} from "./cli-
|
|
84
|
+
} from "./cli-r4fqfpwf.js";
|
|
82
85
|
import {
|
|
83
86
|
getSlackConfiguration,
|
|
84
87
|
init_config
|
|
@@ -93,6 +96,10 @@ import {
|
|
|
93
96
|
object,
|
|
94
97
|
string
|
|
95
98
|
} from "./cli-w5e1d1vv.js";
|
|
99
|
+
import {
|
|
100
|
+
getNodeEnv,
|
|
101
|
+
init_node_env
|
|
102
|
+
} from "./cli-p0sg24zp.js";
|
|
96
103
|
import {
|
|
97
104
|
getAppUrl,
|
|
98
105
|
init_constants
|
|
@@ -52921,7 +52928,7 @@ async function initOtel(serviceRole = process.env.AGENT_ROLE || "api") {
|
|
|
52921
52928
|
return;
|
|
52922
52929
|
initialized = true;
|
|
52923
52930
|
try {
|
|
52924
|
-
const impl = await import("./otel-impl-
|
|
52931
|
+
const impl = await import("./otel-impl-e6mnvc4v.js");
|
|
52925
52932
|
await impl.boot(serviceRole, {
|
|
52926
52933
|
exportConsoleLogs: serviceRole === "api" && isApiLogExportEnabled()
|
|
52927
52934
|
});
|
|
@@ -52997,8 +53004,9 @@ init_secret_scrubber();
|
|
|
52997
53004
|
|
|
52998
53005
|
// src/slack/app.ts
|
|
52999
53006
|
init_db();
|
|
53007
|
+
init_node_env();
|
|
53000
53008
|
init_config();
|
|
53001
|
-
var
|
|
53009
|
+
var import_bolt3 = __toESM(require_dist7(), 1);
|
|
53002
53010
|
|
|
53003
53011
|
// src/slack/connection-state.ts
|
|
53004
53012
|
var state = "disconnected";
|
|
@@ -53066,6 +53074,77 @@ function installSlackEgressScrub() {
|
|
|
53066
53074
|
proto[INSTALLED] = true;
|
|
53067
53075
|
}
|
|
53068
53076
|
|
|
53077
|
+
// src/slack/external-channel-egress.ts
|
|
53078
|
+
var import_bolt2 = __toESM(require_dist7(), 1);
|
|
53079
|
+
var GUARDED_METHODS = {
|
|
53080
|
+
"chat.postMessage": ["channel"],
|
|
53081
|
+
"chat.postEphemeral": ["channel"],
|
|
53082
|
+
"chat.update": ["channel"],
|
|
53083
|
+
"chat.scheduleMessage": ["channel"],
|
|
53084
|
+
"chat.meMessage": ["channel"],
|
|
53085
|
+
"chat.startStream": ["channel"],
|
|
53086
|
+
"chat.appendStream": ["channel"],
|
|
53087
|
+
"chat.stopStream": ["channel"],
|
|
53088
|
+
"assistant.threads.setStatus": ["channel_id"],
|
|
53089
|
+
"assistant.threads.setSuggestedPrompts": ["channel_id"],
|
|
53090
|
+
"assistant.threads.setTitle": ["channel_id"],
|
|
53091
|
+
"files.completeUploadExternal": ["channel_id", "channels"]
|
|
53092
|
+
};
|
|
53093
|
+
var EXTERNAL_CHANNEL_BLOCKED_CODE = "external_channel_blocked";
|
|
53094
|
+
var EXTERNAL_CHANNEL_UNVERIFIED_CODE = "external_channel_unverified";
|
|
53095
|
+
function targetChannels(fields, args) {
|
|
53096
|
+
if (!args)
|
|
53097
|
+
return [];
|
|
53098
|
+
const out = [];
|
|
53099
|
+
for (const field of fields) {
|
|
53100
|
+
const value = args[field];
|
|
53101
|
+
if (typeof value !== "string")
|
|
53102
|
+
continue;
|
|
53103
|
+
for (const id of value.split(",")) {
|
|
53104
|
+
const trimmed = id.trim();
|
|
53105
|
+
if (trimmed)
|
|
53106
|
+
out.push(trimmed);
|
|
53107
|
+
}
|
|
53108
|
+
}
|
|
53109
|
+
return out;
|
|
53110
|
+
}
|
|
53111
|
+
function blockedError(method, channelId, reason) {
|
|
53112
|
+
const code = reason === "external" ? EXTERNAL_CHANNEL_BLOCKED_CODE : EXTERNAL_CHANNEL_UNVERIFIED_CODE;
|
|
53113
|
+
const error = new Error(`An API error occurred: ${code} (${method} to ${channelId} refused by SLACK_BLOCK_EXTERNAL_CHANNELS)`);
|
|
53114
|
+
return Object.assign(error, {
|
|
53115
|
+
code: import_bolt2.webApi.ErrorCode.PlatformError,
|
|
53116
|
+
data: { ok: false, error: code }
|
|
53117
|
+
});
|
|
53118
|
+
}
|
|
53119
|
+
async function assertChannelsAllowed(client, method, channels) {
|
|
53120
|
+
for (const channelId of channels) {
|
|
53121
|
+
const reason = await getChannelBlockReason(client, channelId);
|
|
53122
|
+
if (reason) {
|
|
53123
|
+
console.warn(`[Slack] Refused ${method} to ${channelId} (${reason})`);
|
|
53124
|
+
throw blockedError(method, channelId, reason);
|
|
53125
|
+
}
|
|
53126
|
+
}
|
|
53127
|
+
}
|
|
53128
|
+
var INSTALLED2 = Symbol.for("agent-swarm.slack-external-channel-guard");
|
|
53129
|
+
function installSlackExternalChannelGuard() {
|
|
53130
|
+
const proto = import_bolt2.webApi.WebClient.prototype;
|
|
53131
|
+
if (proto[INSTALLED2])
|
|
53132
|
+
return;
|
|
53133
|
+
const originalApiCall = proto.apiCall;
|
|
53134
|
+
const originalUpload = proto.filesUploadV2;
|
|
53135
|
+
proto.apiCall = async function(method, options) {
|
|
53136
|
+
const fields = GUARDED_METHODS[method];
|
|
53137
|
+
if (fields)
|
|
53138
|
+
await assertChannelsAllowed(this, method, targetChannels(fields, options));
|
|
53139
|
+
return originalApiCall.call(this, method, options);
|
|
53140
|
+
};
|
|
53141
|
+
proto.filesUploadV2 = async function(options) {
|
|
53142
|
+
await assertChannelsAllowed(this, "files.uploadV2", targetChannels(["channel_id", "channels"], options));
|
|
53143
|
+
return originalUpload.call(this, options);
|
|
53144
|
+
};
|
|
53145
|
+
proto[INSTALLED2] = true;
|
|
53146
|
+
}
|
|
53147
|
+
|
|
53069
53148
|
// src/slack/inbound-dispatch.ts
|
|
53070
53149
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
53071
53150
|
init_crypto();
|
|
@@ -54575,16 +54654,17 @@ async function initSlackApp() {
|
|
|
54575
54654
|
return null;
|
|
54576
54655
|
}
|
|
54577
54656
|
installSlackEgressScrub();
|
|
54657
|
+
installSlackExternalChannelGuard();
|
|
54578
54658
|
const slackApiUrl = process.env.SLACK_API_URL;
|
|
54579
54659
|
const clientOptions = slackApiUrl ? { slackApiUrl } : undefined;
|
|
54580
|
-
const logLevel =
|
|
54581
|
-
receiver = new
|
|
54660
|
+
const logLevel = getNodeEnv() === "development" ? import_bolt3.LogLevel.DEBUG : import_bolt3.LogLevel.INFO;
|
|
54661
|
+
receiver = new import_bolt3.SocketModeReceiver({
|
|
54582
54662
|
appToken,
|
|
54583
54663
|
logLevel,
|
|
54584
54664
|
installerOptions: clientOptions ? { clientOptions } : {}
|
|
54585
54665
|
});
|
|
54586
54666
|
trackConnectionState(receiver);
|
|
54587
|
-
app = new
|
|
54667
|
+
app = new import_bolt3.App({
|
|
54588
54668
|
token: botToken,
|
|
54589
54669
|
receiver,
|
|
54590
54670
|
socketMode: true,
|
|
@@ -54593,16 +54673,22 @@ async function initSlackApp() {
|
|
|
54593
54673
|
});
|
|
54594
54674
|
initialized2 = true;
|
|
54595
54675
|
app.use(slackInboundOutcomeMiddleware());
|
|
54596
|
-
const { registerMessageHandler } = await import("./handlers-
|
|
54597
|
-
const { registerCommandHandler } = await import("./commands-
|
|
54598
|
-
const { registerActionHandlers } = await import("./actions-
|
|
54599
|
-
const { registerWorkObjectHandlers } = await import("./work-objects-
|
|
54676
|
+
const { registerMessageHandler } = await import("./handlers-znb9n7d4.js");
|
|
54677
|
+
const { registerCommandHandler } = await import("./commands-z8fq9qna.js");
|
|
54678
|
+
const { registerActionHandlers } = await import("./actions-sgeyv08k.js");
|
|
54679
|
+
const { registerWorkObjectHandlers } = await import("./work-objects-wpj8ck95.js");
|
|
54600
54680
|
registerMessageHandler(app);
|
|
54601
54681
|
registerCommandHandler(app);
|
|
54602
54682
|
registerActionHandlers(app);
|
|
54603
54683
|
registerWorkObjectHandlers(app);
|
|
54604
|
-
const { createAssistant } = await import("./assistant-
|
|
54684
|
+
const { createAssistant } = await import("./assistant-5r8tcvvd.js");
|
|
54605
54685
|
app.assistant(createAssistant());
|
|
54686
|
+
const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel-h1fjecwe.js");
|
|
54687
|
+
if (isBlockExternalEnabled()) {
|
|
54688
|
+
scanExternalChannelsOnBoot(app.client).catch((error) => {
|
|
54689
|
+
console.error("[Slack] External channel boot scan failed:", error);
|
|
54690
|
+
});
|
|
54691
|
+
}
|
|
54606
54692
|
return app;
|
|
54607
54693
|
}
|
|
54608
54694
|
async function startSlackApp() {
|
|
@@ -54610,7 +54696,7 @@ async function startSlackApp() {
|
|
|
54610
54696
|
await initSlackApp();
|
|
54611
54697
|
}
|
|
54612
54698
|
if (app) {
|
|
54613
|
-
const { isSlackRenderV2Enabled: isSlackRenderV2Enabled2 } = await import("./render-v2-
|
|
54699
|
+
const { isSlackRenderV2Enabled: isSlackRenderV2Enabled2 } = await import("./render-v2-907cy6sa.js");
|
|
54614
54700
|
if (isSlackRenderV2Enabled2())
|
|
54615
54701
|
await ensureSlackRenderV2Activation();
|
|
54616
54702
|
await app.start();
|
|
@@ -54797,7 +54883,7 @@ init_reaction_shortcode();
|
|
|
54797
54883
|
init_db();
|
|
54798
54884
|
init_types();
|
|
54799
54885
|
init_secret_scrubber();
|
|
54800
|
-
var
|
|
54886
|
+
var import_bolt4 = __toESM(require_dist7(), 1);
|
|
54801
54887
|
var REFRESH_MS = 30 * 60000;
|
|
54802
54888
|
var DEFAULT_CALL_TIMEOUT_MS = 8000;
|
|
54803
54889
|
var TRANSPORT_MARGIN_MS = 500;
|
|
@@ -54871,12 +54957,12 @@ function withTimeout(promise, ms) {
|
|
|
54871
54957
|
}
|
|
54872
54958
|
var transports = new WeakMap;
|
|
54873
54959
|
function statusTransport(client) {
|
|
54874
|
-
if (!(client instanceof
|
|
54960
|
+
if (!(client instanceof import_bolt4.webApi.WebClient))
|
|
54875
54961
|
return client;
|
|
54876
54962
|
let transport = transports.get(client);
|
|
54877
54963
|
if (!transport) {
|
|
54878
54964
|
const timeout = Math.max(callTimeoutMs - TRANSPORT_MARGIN_MS, 1);
|
|
54879
|
-
transport = new
|
|
54965
|
+
transport = new import_bolt4.webApi.WebClient(client.token ?? process.env.SLACK_BOT_TOKEN, {
|
|
54880
54966
|
slackApiUrl: client.slackApiUrl,
|
|
54881
54967
|
retryConfig: { retries: 0 },
|
|
54882
54968
|
rejectRateLimitedCalls: true,
|
|
@@ -55738,14 +55824,14 @@ async function childOutcomeContent(task, slackReplySent) {
|
|
|
55738
55824
|
}
|
|
55739
55825
|
return withStatusLead(`↳ ✅ ${agentName} — result:`, outcomeText(slackTaskOutput(task), "Task completed."));
|
|
55740
55826
|
}
|
|
55741
|
-
function isSlackContinuation(task) {
|
|
55742
|
-
return task.source === "schedule" && task.taskType === "deferred" && !!task.slackChannelId && !!task.slackThreadTs;
|
|
55827
|
+
async function isSlackContinuation(task) {
|
|
55828
|
+
return task.source === "schedule" && task.taskType === "deferred" && !!task.slackChannelId && !!task.slackThreadTs && !!task.agentId && !!(await getAgentById(task.agentId))?.isLead;
|
|
55743
55829
|
}
|
|
55744
55830
|
function isChildCardCandidate(task, delegationActivatedAt) {
|
|
55745
|
-
return task.source !== "slack" && !
|
|
55831
|
+
return task.source !== "slack" && !(task.source === "schedule" && task.taskType === "deferred") && !!task.slackChannelId && !!task.slackThreadTs && (task.status === "completed" || task.status === "failed") && task.taskType !== "follow-up" && task.taskType !== "reroute-decision" && task.createdAt >= delegationActivatedAt;
|
|
55746
55832
|
}
|
|
55747
|
-
function taskNeedsDirectOutcome(task, activatedAt) {
|
|
55748
|
-
return (task.source === "slack" && isAskOutcomeStatus(task.status) || isSlackContinuation(task) && isOutcomeStatus(task.status)) && task.createdAt >= activatedAt;
|
|
55833
|
+
async function taskNeedsDirectOutcome(task, activatedAt) {
|
|
55834
|
+
return (task.source === "slack" && isAskOutcomeStatus(task.status) || await isSlackContinuation(task) && isOutcomeStatus(task.status)) && task.createdAt >= activatedAt;
|
|
55749
55835
|
}
|
|
55750
55836
|
async function conclusionResultsLines(closure) {
|
|
55751
55837
|
const lines = [];
|
|
@@ -56044,24 +56130,26 @@ async function streamOutcomeCard(task, tree, options) {
|
|
|
56044
56130
|
});
|
|
56045
56131
|
}
|
|
56046
56132
|
async function resolvedDeferralContent(wake) {
|
|
56047
|
-
|
|
56048
|
-
|
|
56049
|
-
|
|
56050
|
-
|
|
56051
|
-
return { text: presentation, blocks: [{ type: "markdown", text: presentation }, ...captions] };
|
|
56052
|
-
}
|
|
56053
|
-
const card = await getSlackOutcomeMessage(wake.id);
|
|
56054
|
-
const pointer = card?.permalink ? ` — <${card.permalink}|next update>` : ".";
|
|
56055
|
-
return { text: `↪️ Resumed by ${await agentDisplayNameFor(wake)} and deferred again${pointer}` };
|
|
56133
|
+
const content = await outcomeContent(wake, wake.slackReplySent);
|
|
56134
|
+
const presentation = await outcomePresentation(wake, content);
|
|
56135
|
+
const captions = await outcomeCaptionBlocks(wake, content);
|
|
56136
|
+
return { text: presentation, blocks: [{ type: "markdown", text: presentation }, ...captions] };
|
|
56056
56137
|
}
|
|
56057
56138
|
async function isAnsweredByDeferralCard(task, threadTasks) {
|
|
56058
|
-
|
|
56059
|
-
|
|
56060
|
-
|
|
56061
|
-
|
|
56062
|
-
|
|
56063
|
-
|
|
56064
|
-
|
|
56139
|
+
const seen = new Set;
|
|
56140
|
+
let current = task;
|
|
56141
|
+
while (await isSlackContinuation(current) && current.parentTaskId && !seen.has(current.id)) {
|
|
56142
|
+
seen.add(current.id);
|
|
56143
|
+
const deferred = threadTasks.find((candidate) => candidate.id === current.parentTaskId);
|
|
56144
|
+
if (!deferred?.deferredAt)
|
|
56145
|
+
return false;
|
|
56146
|
+
const card = await getSlackOutcomeMessage(deferred.id);
|
|
56147
|
+
if (card) {
|
|
56148
|
+
return !!card.finalizedAt && !isPendingSlackMessage(card) && !card.deferralAbandonedAt;
|
|
56149
|
+
}
|
|
56150
|
+
current = deferred;
|
|
56151
|
+
}
|
|
56152
|
+
return false;
|
|
56065
56153
|
}
|
|
56066
56154
|
var TRANSIENT_SLACK_ERROR_CODES = new Set([
|
|
56067
56155
|
"ratelimited",
|
|
@@ -56069,7 +56157,8 @@ var TRANSIENT_SLACK_ERROR_CODES = new Set([
|
|
|
56069
56157
|
"internal_error",
|
|
56070
56158
|
"service_unavailable",
|
|
56071
56159
|
"fatal_error",
|
|
56072
|
-
"request_timeout"
|
|
56160
|
+
"request_timeout",
|
|
56161
|
+
"external_channel_unverified"
|
|
56073
56162
|
]);
|
|
56074
56163
|
function slackErrorCode2(error) {
|
|
56075
56164
|
const code = error?.data?.error;
|
|
@@ -56111,9 +56200,14 @@ async function refreshResolvedDeferralCards() {
|
|
|
56111
56200
|
ts: card.ts,
|
|
56112
56201
|
...content
|
|
56113
56202
|
});
|
|
56114
|
-
|
|
56203
|
+
if (isDeferredTask(wake)) {
|
|
56204
|
+
await updateSlackMessageRecord(card.id, {});
|
|
56205
|
+
} else {
|
|
56206
|
+
await markSlackDeferralResolved(card.id);
|
|
56207
|
+
}
|
|
56115
56208
|
deferralRefreshAttempts.delete(card.id);
|
|
56116
|
-
|
|
56209
|
+
if (!isDeferredTask(wake))
|
|
56210
|
+
await finalizeTerminalSlackReactions([wake]);
|
|
56117
56211
|
} catch (error) {
|
|
56118
56212
|
const attempts = (deferralRefreshAttempts.get(card.id) ?? 0) + 1;
|
|
56119
56213
|
deferralRefreshAttempts.set(card.id, attempts);
|
|
@@ -56185,7 +56279,7 @@ async function processSlackRenderV2() {
|
|
|
56185
56279
|
const card = await getSlackOutcomeMessage(task.id);
|
|
56186
56280
|
if (card && isSettledSlackMessage(card))
|
|
56187
56281
|
continue;
|
|
56188
|
-
const isDirectCandidate = taskNeedsDirectOutcome(task, activatedAt) && isOutcomeStatus(task.status) && !await isAnsweredByDeferralCard(task, tasks);
|
|
56282
|
+
const isDirectCandidate = await taskNeedsDirectOutcome(task, activatedAt) && isOutcomeStatus(task.status) && !await isAnsweredByDeferralCard(task, tasks);
|
|
56189
56283
|
const isChildCandidate = delegationEnabled && delegationActivatedAt !== null && isChildCardCandidate(task, delegationActivatedAt) && !task.slackReplySent;
|
|
56190
56284
|
if (isDirectCandidate || isChildCandidate) {
|
|
56191
56285
|
needsOutcome = true;
|
|
@@ -56284,7 +56378,7 @@ async function processSlackRenderV2() {
|
|
|
56284
56378
|
for (const task of tasks) {
|
|
56285
56379
|
if (!isSlackRenderV2Enabled())
|
|
56286
56380
|
return;
|
|
56287
|
-
if (!taskNeedsDirectOutcome(task, activatedAt))
|
|
56381
|
+
if (!await taskNeedsDirectOutcome(task, activatedAt))
|
|
56288
56382
|
continue;
|
|
56289
56383
|
const card = await getSlackOutcomeMessage(task.id);
|
|
56290
56384
|
if (card && isSettledSlackMessage(card))
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {
|
|
2
|
+
claimKv,
|
|
3
|
+
deleteKv,
|
|
4
|
+
init_db1 as init_db,
|
|
5
|
+
sweepExpiredKv,
|
|
6
|
+
upsertKv
|
|
7
|
+
} from "./cli-fmhj1ehj.js";
|
|
8
|
+
import {
|
|
9
|
+
init_env_flag,
|
|
10
|
+
isEnvFlagEnabled
|
|
11
|
+
} from "./cli-ej6gbxfb.js";
|
|
12
|
+
import {
|
|
13
|
+
init_secret_scrubber,
|
|
14
|
+
scrubSecrets
|
|
15
|
+
} from "./cli-d161g69q.js";
|
|
16
|
+
|
|
17
|
+
// src/slack/external-channel.ts
|
|
18
|
+
init_db();
|
|
19
|
+
init_env_flag();
|
|
20
|
+
init_secret_scrubber();
|
|
21
|
+
|
|
22
|
+
// src/slack/channel-join.ts
|
|
23
|
+
function slackErrorData(error) {
|
|
24
|
+
if (!(error instanceof Error))
|
|
25
|
+
return;
|
|
26
|
+
return error.data;
|
|
27
|
+
}
|
|
28
|
+
function slackCode(error) {
|
|
29
|
+
const d = slackErrorData(error);
|
|
30
|
+
return typeof d?.error === "string" ? d.error : undefined;
|
|
31
|
+
}
|
|
32
|
+
function slackMissingScopeMessage(error) {
|
|
33
|
+
const data = slackErrorData(error);
|
|
34
|
+
if (data?.error !== "missing_scope" || typeof data.needed !== "string")
|
|
35
|
+
return;
|
|
36
|
+
const needed = data.needed.trim();
|
|
37
|
+
if (!needed)
|
|
38
|
+
return;
|
|
39
|
+
return `Slack requires the \`${needed}\` scope. Add it to slack-manifest.json, apply the updated manifest to the Slack app, then reinstall the app to the workspace for the change to take effect.`;
|
|
40
|
+
}
|
|
41
|
+
async function isKnownExternalChannel(client, channelId) {
|
|
42
|
+
return await getChannelExternality(client, channelId) === "external";
|
|
43
|
+
}
|
|
44
|
+
async function withAutoJoin(client, channelId, fn) {
|
|
45
|
+
try {
|
|
46
|
+
return await fn();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (slackCode(error) !== "not_in_channel")
|
|
49
|
+
throw error;
|
|
50
|
+
if (await isKnownExternalChannel(client, channelId)) {
|
|
51
|
+
throw new Error(`Cannot auto-join external channel ${channelId} — invite the bot with /invite @<bot-name> first.`);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await client.conversations.join({ channel: channelId });
|
|
55
|
+
} catch (joinError) {
|
|
56
|
+
if (slackCode(joinError) === "method_not_supported_for_channel_type") {
|
|
57
|
+
throw new Error(`Cannot access private channel ${channelId} — invite the bot with /invite @<bot-name> first.`);
|
|
58
|
+
}
|
|
59
|
+
throw joinError;
|
|
60
|
+
}
|
|
61
|
+
return await fn();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/slack/external-channel.ts
|
|
66
|
+
var EXTERNALITY_TTL_MS = 10 * 60 * 1000;
|
|
67
|
+
var EXTERNALITY_CACHE_MAX = 500;
|
|
68
|
+
var ALERT_DEDUPE_MS = 60 * 60 * 1000;
|
|
69
|
+
var ALERT_SENDING_TTL_MS = 2 * 60 * 1000;
|
|
70
|
+
var EXTERNAL_ALERT_KV_NAMESPACE = "slack-external-alert";
|
|
71
|
+
var externalityCache = new Map;
|
|
72
|
+
var channelGeneration = new Map;
|
|
73
|
+
var generationCounter = 0;
|
|
74
|
+
var EXTERNAL_CHANNEL_BLOCKED_REPLY = "This channel is shared with another organization. The swarm does not work here.";
|
|
75
|
+
function externalChannelToolError(channelId, reason = "external") {
|
|
76
|
+
if (reason === "unverified") {
|
|
77
|
+
return `Could not verify that channel ${channelId} is internal to this organization. SLACK_BLOCK_EXTERNAL_CHANNELS blocks swarm messages there until Slack confirms it. Try again later.`;
|
|
78
|
+
}
|
|
79
|
+
return `Channel ${channelId} is shared with another organization. SLACK_BLOCK_EXTERNAL_CHANNELS blocks swarm messages there.`;
|
|
80
|
+
}
|
|
81
|
+
function isBlockExternalEnabled() {
|
|
82
|
+
return isEnvFlagEnabled("SLACK_BLOCK_EXTERNAL_CHANNELS", false);
|
|
83
|
+
}
|
|
84
|
+
function resetExternalChannelStateForTesting() {
|
|
85
|
+
externalityCache.clear();
|
|
86
|
+
channelGeneration.clear();
|
|
87
|
+
}
|
|
88
|
+
function setBounded(map, key, value) {
|
|
89
|
+
map.delete(key);
|
|
90
|
+
if (map.size >= EXTERNALITY_CACHE_MAX) {
|
|
91
|
+
const oldest = map.keys().next().value;
|
|
92
|
+
if (oldest !== undefined)
|
|
93
|
+
map.delete(oldest);
|
|
94
|
+
}
|
|
95
|
+
map.set(key, value);
|
|
96
|
+
}
|
|
97
|
+
function bumpGeneration(channelId) {
|
|
98
|
+
generationCounter += 1;
|
|
99
|
+
setBounded(channelGeneration, channelId, generationCounter);
|
|
100
|
+
}
|
|
101
|
+
function invalidateChannelExternality(channelId) {
|
|
102
|
+
externalityCache.delete(channelId);
|
|
103
|
+
bumpGeneration(channelId);
|
|
104
|
+
}
|
|
105
|
+
function recordExternalChannel(channelId) {
|
|
106
|
+
bumpGeneration(channelId);
|
|
107
|
+
setBounded(externalityCache, channelId, {
|
|
108
|
+
value: "external",
|
|
109
|
+
expiresAt: Date.now() + EXTERNALITY_TTL_MS
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async function getChannelExternality(client, channelId) {
|
|
113
|
+
const cached = externalityCache.get(channelId);
|
|
114
|
+
if (cached && cached.expiresAt > Date.now())
|
|
115
|
+
return cached.value;
|
|
116
|
+
if (cached)
|
|
117
|
+
externalityCache.delete(channelId);
|
|
118
|
+
const generation = channelGeneration.get(channelId);
|
|
119
|
+
let value;
|
|
120
|
+
try {
|
|
121
|
+
const resp = await client.conversations.info({ channel: channelId });
|
|
122
|
+
const ch = resp.channel ?? {};
|
|
123
|
+
value = ch.is_ext_shared === true || ch.is_pending_ext_shared === true ? "external" : "internal";
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.warn(`[Slack] conversations.info failed for ${channelId}:`, scrubSecrets(error instanceof Error ? error.message : String(error)));
|
|
126
|
+
return "unknown";
|
|
127
|
+
}
|
|
128
|
+
if (channelGeneration.get(channelId) !== generation) {
|
|
129
|
+
const fresher = externalityCache.get(channelId);
|
|
130
|
+
if (fresher && fresher.expiresAt > Date.now())
|
|
131
|
+
return fresher.value;
|
|
132
|
+
return value === "external" ? "external" : "unknown";
|
|
133
|
+
}
|
|
134
|
+
setBounded(externalityCache, channelId, { value, expiresAt: Date.now() + EXTERNALITY_TTL_MS });
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
async function getChannelBlockReason(client, channelId, envelopeFlag) {
|
|
138
|
+
if (!isBlockExternalEnabled())
|
|
139
|
+
return null;
|
|
140
|
+
if (envelopeFlag === true) {
|
|
141
|
+
recordExternalChannel(channelId);
|
|
142
|
+
return "external";
|
|
143
|
+
}
|
|
144
|
+
const externality = await getChannelExternality(client, channelId);
|
|
145
|
+
if (externality === "external")
|
|
146
|
+
return "external";
|
|
147
|
+
if (externality === "unknown") {
|
|
148
|
+
console.warn(`[Slack] Could not tell if channel ${channelId} is external; blocking (fail closed)`);
|
|
149
|
+
return "unverified";
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
async function shouldBlockChannel(client, channelId, envelopeFlag) {
|
|
154
|
+
return await getChannelBlockReason(client, channelId, envelopeFlag) !== null;
|
|
155
|
+
}
|
|
156
|
+
async function postExternalChannelAlert(client, channelId, trigger, leave, scopeHint) {
|
|
157
|
+
const alertsChannel = process.env.SLACK_ALERTS_CHANNEL?.trim();
|
|
158
|
+
if (!alertsChannel) {
|
|
159
|
+
console.warn("[Slack] SLACK_ALERTS_CHANNEL not set; skipping external channel alert");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const key = `${channelId}:${trigger}`;
|
|
163
|
+
if (!await reserveAlert(key))
|
|
164
|
+
return;
|
|
165
|
+
const lines = [
|
|
166
|
+
`:no_entry: Swarm bot in external Slack channel <#${channelId}> (${channelId})`,
|
|
167
|
+
`Trigger: ${trigger}`,
|
|
168
|
+
`Leave: ${leave}`,
|
|
169
|
+
...scopeHint ? [scopeHint] : [],
|
|
170
|
+
"Inbound guard: active. The swarm creates no task from this channel."
|
|
171
|
+
];
|
|
172
|
+
try {
|
|
173
|
+
await client.chat.postMessage({
|
|
174
|
+
channel: alertsChannel,
|
|
175
|
+
text: scrubSecrets(lines.join(`
|
|
176
|
+
`)),
|
|
177
|
+
unfurl_links: false,
|
|
178
|
+
unfurl_media: false
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error("[Slack] Failed to send external channel alert:", scrubSecrets(error instanceof Error ? error.message : String(error)));
|
|
182
|
+
await settleAlert(key, false);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
await settleAlert(key, true);
|
|
186
|
+
}
|
|
187
|
+
async function reserveAlert(key) {
|
|
188
|
+
try {
|
|
189
|
+
return await claimKv({
|
|
190
|
+
namespace: EXTERNAL_ALERT_KV_NAMESPACE,
|
|
191
|
+
key,
|
|
192
|
+
value: "sending",
|
|
193
|
+
valueType: "string",
|
|
194
|
+
expiresAt: Date.now() + ALERT_SENDING_TTL_MS
|
|
195
|
+
});
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.warn("[Slack] External channel alert dedupe unavailable:", error);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function settleAlert(key, sent) {
|
|
202
|
+
try {
|
|
203
|
+
if (sent) {
|
|
204
|
+
await upsertKv({
|
|
205
|
+
namespace: EXTERNAL_ALERT_KV_NAMESPACE,
|
|
206
|
+
key,
|
|
207
|
+
value: "sent",
|
|
208
|
+
valueType: "string",
|
|
209
|
+
expiresAt: Date.now() + ALERT_DEDUPE_MS
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
await deleteKv(EXTERNAL_ALERT_KV_NAMESPACE, key);
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.warn("[Slack] Failed to record external channel alert state:", error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function leaveExternalChannel(client, channelId, reason) {
|
|
219
|
+
let leave;
|
|
220
|
+
let scopeHint;
|
|
221
|
+
try {
|
|
222
|
+
await client.conversations.leave({ channel: channelId });
|
|
223
|
+
leave = "left";
|
|
224
|
+
} catch (error) {
|
|
225
|
+
const code = slackCode(error);
|
|
226
|
+
const notInChannel = code === "not_in_channel" || error?.data?.not_in_channel === true;
|
|
227
|
+
if (notInChannel) {
|
|
228
|
+
leave = "left";
|
|
229
|
+
} else {
|
|
230
|
+
leave = `failed (${code ?? "unknown_error"})`;
|
|
231
|
+
if (code === "missing_scope")
|
|
232
|
+
scopeHint = slackMissingScopeMessage(error);
|
|
233
|
+
console.error(`[Slack] Failed to leave external channel ${channelId}: ${leave}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (leave === "left")
|
|
237
|
+
console.log(`[Slack] Left external channel ${channelId} (${reason})`);
|
|
238
|
+
await postExternalChannelAlert(client, channelId, reason, leave, scopeHint);
|
|
239
|
+
}
|
|
240
|
+
async function scanExternalChannelsOnBoot(client) {
|
|
241
|
+
if (!isBlockExternalEnabled())
|
|
242
|
+
return;
|
|
243
|
+
await sweepExpiredKv(EXTERNAL_ALERT_KV_NAMESPACE).catch((error) => {
|
|
244
|
+
console.warn("[Slack] Failed to sweep expired external channel alert keys:", error);
|
|
245
|
+
});
|
|
246
|
+
let cursor;
|
|
247
|
+
do {
|
|
248
|
+
const resp = await client.users.conversations({
|
|
249
|
+
types: "public_channel,private_channel",
|
|
250
|
+
exclude_archived: true,
|
|
251
|
+
limit: 200,
|
|
252
|
+
cursor
|
|
253
|
+
});
|
|
254
|
+
for (const ch of resp.channels ?? []) {
|
|
255
|
+
if (!ch.id || !(ch.is_ext_shared === true || ch.is_pending_ext_shared === true))
|
|
256
|
+
continue;
|
|
257
|
+
await postExternalChannelAlert(client, ch.id, "boot-scan", "not attempted (report only)");
|
|
258
|
+
}
|
|
259
|
+
cursor = resp.response_metadata?.next_cursor || undefined;
|
|
260
|
+
} while (cursor);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export { slackCode, slackMissingScopeMessage, withAutoJoin, EXTERNAL_ALERT_KV_NAMESPACE, EXTERNAL_CHANNEL_BLOCKED_REPLY, externalChannelToolError, isBlockExternalEnabled, resetExternalChannelStateForTesting, invalidateChannelExternality, recordExternalChannel, getChannelExternality, getChannelBlockReason, shouldBlockChannel, leaveExternalChannel, scanExternalChannelsOnBoot };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
materializeClaudeMd,
|
|
3
3
|
stopClaudeMd
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-0kxf81jj.js";
|
|
5
5
|
import {
|
|
6
6
|
guardGhPrBody
|
|
7
7
|
} from "./cli-v6vv7dy8.js";
|
|
8
8
|
import {
|
|
9
9
|
summarizeSession
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-nwrdx840.js";
|
|
11
11
|
import {
|
|
12
12
|
checkToolLoop,
|
|
13
13
|
clearToolHistory
|
|
@@ -26,11 +26,11 @@ import {
|
|
|
26
26
|
init_profile_sync,
|
|
27
27
|
readIdentityBaselines,
|
|
28
28
|
warnProfileFileTooLarge
|
|
29
|
-
} from "./cli-
|
|
29
|
+
} from "./cli-r4fqfpwf.js";
|
|
30
30
|
import {
|
|
31
31
|
init_package,
|
|
32
32
|
package_default
|
|
33
|
-
} from "./cli-
|
|
33
|
+
} from "./cli-5er5gjbm.js";
|
|
34
34
|
import {
|
|
35
35
|
MAX_PROFILE_FILE_LENGTH,
|
|
36
36
|
getMcpBaseUrl,
|