@cursor/july 0.1.26 → 0.1.28
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/ab.d.ts +6 -0
- package/dist/ab.d.ts.map +1 -1
- package/dist/ab.js +1 -0
- package/dist/artifacts.d.ts +34 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +57 -0
- package/dist/bin/agent-serve.js +43 -12
- package/dist/channels/github/github-channel.d.ts +1 -1
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +14 -1
- package/dist/channels/github/types.d.ts +6 -1
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/api.d.ts +2 -1
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +1 -0
- package/dist/channels/slack/auth.d.ts +13 -13
- package/dist/channels/slack/auth.d.ts.map +1 -1
- package/dist/channels/slack/auth.js +19 -10
- package/dist/channels/slack/cursor-account.d.ts +2 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +3 -1
- package/dist/channels/slack/defaults.d.ts +7 -4
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +14 -4
- package/dist/channels/slack/dispatch.d.ts +10 -1
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +59 -21
- package/dist/channels/slack/external-policy.d.ts +27 -0
- package/dist/channels/slack/external-policy.d.ts.map +1 -0
- package/dist/channels/slack/external-policy.js +53 -0
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/interactive.d.ts +8 -1
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +43 -15
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +22 -8
- package/dist/channels/slack/types.d.ts +16 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.DYcC9FY-.js → app.CqjrYaT2.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.VWQoPFJ1.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.o4N_knTV.js → VPLocalSearchBox.ag-MwUel.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DQ-njyo0.js → theme.BS-DJWat.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.D_xFKlnF.js → guides_slack.md.CjmJSvZS.js} +8 -4
- package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +1 -0
- package/dist/docs/assets/guides_webhooks.md.wSOYas3X.js +183 -0
- package/dist/docs/assets/{guides_webhooks.md.B1EswtUu.lean.js → guides_webhooks.md.wSOYas3X.lean.js} +1 -1
- package/dist/docs/assets/{index.md.Dfv5ic9t.js → index.md.CH_s5uZe.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.DdmiKgqf.js → reference_channels.md.CDhTRfUz.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.DdmiKgqf.lean.js → reference_channels.md.CDhTRfUz.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +3 -3
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/slack.html +11 -7
- package/dist/docs/guides/webhooks.html +138 -5
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +5 -5
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +5 -5
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/evals/assertions.d.ts +10 -1
- package/dist/evals/assertions.d.ts.map +1 -1
- package/dist/evals/assertions.js +12 -0
- package/dist/evals.d.ts +1 -1
- package/dist/evals.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/ab-fold.d.ts.map +1 -1
- package/dist/internal/ab-fold.js +4 -0
- package/dist/internal/ab-snapshot.d.ts.map +1 -1
- package/dist/internal/ab-snapshot.js +1 -0
- package/dist/internal/artifacts-store.d.ts +45 -0
- package/dist/internal/artifacts-store.d.ts.map +1 -0
- package/dist/internal/artifacts-store.js +250 -0
- package/dist/internal/builtin-tools/artifacts.d.ts +10 -0
- package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -0
- package/dist/internal/builtin-tools/artifacts.js +73 -0
- package/dist/internal/builtin-tools/index.d.ts +8 -1
- package/dist/internal/builtin-tools/index.d.ts.map +1 -1
- package/dist/internal/builtin-tools/index.js +15 -0
- package/dist/internal/cli-ax.d.ts +19 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +196 -57
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +14 -6
- package/dist/internal/cursor-slack-relay.d.ts +2 -0
- package/dist/internal/cursor-slack-relay.d.ts.map +1 -1
- package/dist/internal/cursor-slack-relay.js +1 -0
- package/dist/internal/deploy-client.d.ts +2 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +1 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +91 -3
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/model-pricing.d.ts +49 -0
- package/dist/internal/model-pricing.d.ts.map +1 -0
- package/dist/internal/model-pricing.js +377 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +1 -0
- package/dist/internal/schedule-runner.d.ts.map +1 -1
- package/dist/internal/schedule-runner.js +1 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +9 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +49 -5
- package/dist/internal/session-cost.d.ts +49 -0
- package/dist/internal/session-cost.d.ts.map +1 -0
- package/dist/internal/session-cost.js +175 -0
- package/dist/internal/session-engine.d.ts +35 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +128 -7
- package/dist/internal/storage-coordinator.d.ts +15 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +52 -0
- package/dist/internal/trajectory.d.ts +9 -1
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +32 -5
- package/dist/playground/assets/index-Bul1WfrB.css +1 -0
- package/dist/playground/assets/index-CkN74U_L.js +87 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage.d.ts +4 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +4 -0
- package/dist/types.d.ts +164 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/guides/slack.md +32 -7
- package/docs/guides/webhooks.md +183 -0
- package/docs/reference/channels.md +2 -1
- package/package.json +26 -26
- package/skills/setup-slack/SKILL.md +3 -0
- package/src/ab.ts +7 -0
- package/src/bin/agent-serve.ts +42 -5
- package/src/channels/slack/auth.ts +29 -22
- package/src/channels/slack/cursor-account.ts +2 -0
- package/src/channels/slack/defaults.ts +24 -4
- package/src/channels/slack/dispatch.ts +42 -1
- package/src/channels/slack/external-policy.ts +62 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/interactive.ts +42 -10
- package/src/channels/slack/slack-channel.ts +20 -3
- package/src/channels/slack/types.ts +12 -0
- package/src/internal/ab-fold.ts +4 -0
- package/src/internal/ab-snapshot.ts +1 -0
- package/src/internal/cli-ax.ts +205 -34
- package/src/internal/cursor-slack-relay.ts +3 -0
- package/src/internal/deploy-client.ts +3 -0
- package/src/internal/discovery.ts +8 -1
- package/src/internal/model-pricing.ts +426 -0
- package/src/internal/sdk-runner.ts +10 -2
- package/src/internal/server.ts +9 -5
- package/src/internal/session-cost.ts +231 -0
- package/src/internal/session-engine.ts +28 -0
- package/src/internal/trajectory.ts +45 -3
- package/src/types.ts +24 -1
- package/dist/channels/github/instrument.d.ts +0 -20
- package/dist/channels/github/instrument.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BQTzJjR_.js +0 -1
- package/dist/docs/assets/guides_slack.md.D_xFKlnF.lean.js +0 -1
- package/dist/docs/assets/guides_webhooks.md.B1EswtUu.js +0 -50
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/json-dir-store.js +0 -100
- package/dist/playground/assets/index-CjOQ4hN9.css +0 -1
- package/dist/playground/assets/index-DqXdAFGa.js +0 -85
- package/src/bin/agent-serve.version.test.ts +0 -64
- package/src/channels/github/api.test.ts +0 -64
- package/src/channels/github/auth.test.ts +0 -105
- package/src/channels/github/cursor-account.test.ts +0 -204
- package/src/channels/github/forward.test.ts +0 -457
- package/src/channels/github/github.test.ts +0 -985
- package/src/channels/github/replay.test.ts +0 -179
- package/src/channels/slack/api.post-message.test.ts +0 -148
- package/src/channels/slack/approvals.test.ts +0 -328
- package/src/channels/slack/block-actions.test.ts +0 -469
- package/src/channels/slack/bot-mentions.test.ts +0 -267
- package/src/channels/slack/channel-watch.test.ts +0 -363
- package/src/channels/slack/cursor-account.test.ts +0 -301
- package/src/channels/slack/defaults.final-post.test.ts +0 -182
- package/src/channels/slack/dispatch.test.ts +0 -875
- package/src/channels/slack/eval-directive.test.ts +0 -273
- package/src/channels/slack/message-body.test.ts +0 -54
- package/src/channels/slack/nudge-store.test.ts +0 -143
- package/src/channels/slack/slack.test.ts +0 -391
- package/src/channels/slack/stop.test.ts +0 -23
- package/src/channels/slack/thread-context.test.ts +0 -202
- package/src/evals/assertions.test.ts +0 -617
- package/src/evals/expect.test.ts +0 -144
- package/src/evals/judge.test.ts +0 -181
- package/src/evals/loaders.test.ts +0 -132
- package/src/evals/matchers.test.ts +0 -95
- package/src/evals/reporters.test.ts +0 -303
- package/src/evals/run-facts.test.ts +0 -259
- package/src/internal/ab-snapshot.test.ts +0 -325
- package/src/internal/approval-gate.test.ts +0 -49
- package/src/internal/approvals.integration.test.ts +0 -383
- package/src/internal/artifacts-store.test.ts +0 -283
- package/src/internal/authored-loaders.test.ts +0 -31
- package/src/internal/builtin-tools/artifacts.test.ts +0 -247
- package/src/internal/builtin-tools/reminders.test.ts +0 -201
- package/src/internal/channel-route-schema.test.ts +0 -294
- package/src/internal/chat-attach.test.ts +0 -262
- package/src/internal/cli-deploy.test.ts +0 -1991
- package/src/internal/cli-docs.test.ts +0 -161
- package/src/internal/cli-mcp.test.ts +0 -789
- package/src/internal/cli-skills.test.ts +0 -133
- package/src/internal/cli-slack.test.ts +0 -1654
- package/src/internal/cloud-merge.test.ts +0 -74
- package/src/internal/cron.test.ts +0 -22
- package/src/internal/cursor/account-mcp.test.ts +0 -807
- package/src/internal/cursor/backend-client.test.ts +0 -591
- package/src/internal/cursor/credentials.test.ts +0 -351
- package/src/internal/cursor/github-credentials.test.ts +0 -136
- package/src/internal/cursor-account-mcp-auth.test.ts +0 -310
- package/src/internal/cursor-account.integration.test.ts +0 -441
- package/src/internal/cursor-event-relay.test.ts +0 -746
- package/src/internal/cursor-github-credentials.integration.test.ts +0 -271
- package/src/internal/cursor-slack-relay.test.ts +0 -525
- package/src/internal/deploy-source.test.ts +0 -111
- package/src/internal/discovery.artifact-tool.test.ts +0 -136
- package/src/internal/discovery.artifacts.test.ts +0 -119
- package/src/internal/discovery.builtin-tools.test.ts +0 -94
- package/src/internal/discovery.concurrency.test.ts +0 -60
- package/src/internal/discovery.cursor-account.test.ts +0 -133
- package/src/internal/discovery.cwd.test.ts +0 -83
- package/src/internal/discovery.hosting.test.ts +0 -80
- package/src/internal/discovery.identity.test.ts +0 -44
- package/src/internal/docs-site.test.ts +0 -66
- package/src/internal/duration.test.ts +0 -29
- package/src/internal/eval-judge-model.test.ts +0 -187
- package/src/internal/eval-run-store.cancel.test.ts +0 -142
- package/src/internal/eval-run-store.storage.test.ts +0 -211
- package/src/internal/eval-runner.http.test.ts +0 -403
- package/src/internal/eval-runner.run.test.ts +0 -928
- package/src/internal/evals-client.test.ts +0 -307
- package/src/internal/event-mapper.test.ts +0 -243
- package/src/internal/github-fanout.test.ts +0 -213
- package/src/internal/handleAgentServeTrigger.test.ts +0 -185
- package/src/internal/host-kv.test.ts +0 -82
- package/src/internal/host-platforms.test.ts +0 -126
- package/src/internal/http-channel.test.ts +0 -402
- package/src/internal/init-project.test.ts +0 -270
- package/src/internal/install-cursor-skills.test.ts +0 -262
- package/src/internal/local-env.test.ts +0 -120
- package/src/internal/log-ring.test.ts +0 -31
- package/src/internal/logs-client.test.ts +0 -350
- package/src/internal/mcp-endpoint.test.ts +0 -436
- package/src/internal/mcp-host.test.ts +0 -298
- package/src/internal/mcp-oauth.test.ts +0 -148
- package/src/internal/net.test.ts +0 -17
- package/src/internal/peer-connections.test.ts +0 -128
- package/src/internal/peer-mcp.integration.test.ts +0 -289
- package/src/internal/playground/toolchain.test.ts +0 -53
- package/src/internal/playground-cli.test.ts +0 -187
- package/src/internal/playground-proxy.test.ts +0 -376
- package/src/internal/prompt-context.integration.test.ts +0 -232
- package/src/internal/prompt-context.test.ts +0 -127
- package/src/internal/reminder-runner.test.ts +0 -432
- package/src/internal/reminder-store.test.ts +0 -53
- package/src/internal/request-headers.test.ts +0 -27
- package/src/internal/resolve-prod-target.test.ts +0 -787
- package/src/internal/resolved-connections.test.ts +0 -295
- package/src/internal/router.test.ts +0 -57
- package/src/internal/sdk-runner.test.ts +0 -290
- package/src/internal/server.artifacts.test.ts +0 -334
- package/src/internal/session-engine.artifacts.test.ts +0 -293
- package/src/internal/session-engine.coalesce.test.ts +0 -169
- package/src/internal/session-engine.concurrency.test.ts +0 -250
- package/src/internal/session-engine.host-oauth-mcp.test.ts +0 -110
- package/src/internal/session-engine.interrupt.test.ts +0 -577
- package/src/internal/session-engine.storage.test.ts +0 -547
- package/src/internal/session-urls.test.ts +0 -28
- package/src/internal/sessions-client.test.ts +0 -518
- package/src/internal/storage-coordinator.test.ts +0 -517
- package/src/internal/tool-call.test.ts +0 -458
- package/src/internal/tool-result.test.ts +0 -52
- package/src/internal/trajectory.approvals.test.ts +0 -83
- package/src/internal/trajectory.subagents.test.ts +0 -198
- package/src/internal/turn-governor.test.ts +0 -137
- package/src/internal/update-check.test.ts +0 -485
- package/src/internal/workspace.test.ts +0 -207
- package/src/storage-backends/cursor-hosted.test.ts +0 -121
- /package/dist/docs/assets/{index.md.Dfv5ic9t.lean.js → index.md.CH_s5uZe.lean.js} +0 -0
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
parseSlackEvalDirective,
|
|
18
18
|
} from "./eval-directive.js";
|
|
19
19
|
import type { EventIdDedupe } from "./event-id-dedupe.js";
|
|
20
|
+
import { isExternalSlackSender } from "./external-policy.js";
|
|
20
21
|
import {
|
|
21
22
|
formatSlackContextBlock,
|
|
22
23
|
parseAppMentionEvent,
|
|
@@ -91,6 +92,11 @@ export interface SlackInboundDispatchDeps extends SlackContinuationProbes {
|
|
|
91
92
|
evalCommandsEnabled?: boolean;
|
|
92
93
|
/** cursorAccount agent name stripped before `eval` directive parsing. */
|
|
93
94
|
cursorAgentName?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Drop external senders before the handler. Defaults to `true`; pass
|
|
97
|
+
* `false` to admit them (or when an upstream gate already refused them).
|
|
98
|
+
*/
|
|
99
|
+
blockExternals?: boolean;
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
function triggeringMergeMessage(
|
|
@@ -132,6 +138,7 @@ export async function dispatchInboundMessage(args: {
|
|
|
132
138
|
* (`OncallBuddy eval list`).
|
|
133
139
|
*/
|
|
134
140
|
cursorAgentName?: string;
|
|
141
|
+
blockExternals?: boolean;
|
|
135
142
|
}): Promise<void> {
|
|
136
143
|
const { message, kind } = args;
|
|
137
144
|
const log = args.log ?? defaultSlackLog;
|
|
@@ -142,7 +149,7 @@ export async function dispatchInboundMessage(args: {
|
|
|
142
149
|
host: args.host,
|
|
143
150
|
artifacts: args.artifacts,
|
|
144
151
|
log,
|
|
145
|
-
|
|
152
|
+
teamId: message.teamId,
|
|
146
153
|
});
|
|
147
154
|
|
|
148
155
|
log.info("inbound", {
|
|
@@ -155,6 +162,38 @@ export async function dispatchInboundMessage(args: {
|
|
|
155
162
|
team: message.teamId,
|
|
156
163
|
});
|
|
157
164
|
|
|
165
|
+
if (args.blockExternals !== false && message.author?.isBot !== true) {
|
|
166
|
+
const userId = message.author?.userId ?? "";
|
|
167
|
+
const teamId = message.teamId;
|
|
168
|
+
if (teamId === undefined || teamId === "") {
|
|
169
|
+
log.info("inbound dropped (missing team)", {
|
|
170
|
+
kind,
|
|
171
|
+
channel: message.channelId,
|
|
172
|
+
thread_ts: message.threadTs,
|
|
173
|
+
user: userId,
|
|
174
|
+
event_id: args.eventId,
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (
|
|
179
|
+
await isExternalSlackSender({
|
|
180
|
+
botToken: args.credentials?.botToken,
|
|
181
|
+
slackTeamId: teamId,
|
|
182
|
+
userId,
|
|
183
|
+
})
|
|
184
|
+
) {
|
|
185
|
+
log.info("inbound dropped (external sender)", {
|
|
186
|
+
kind,
|
|
187
|
+
channel: message.channelId,
|
|
188
|
+
thread_ts: message.threadTs,
|
|
189
|
+
user: userId,
|
|
190
|
+
team: teamId,
|
|
191
|
+
event_id: args.eventId,
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
158
197
|
const continuation = slackContinuationKey(
|
|
159
198
|
message.channelId,
|
|
160
199
|
message.threadTs
|
|
@@ -463,6 +502,7 @@ export function dispatchInboundFromEventBody(
|
|
|
463
502
|
log,
|
|
464
503
|
evalCommandsEnabled: deps.evalCommandsEnabled,
|
|
465
504
|
cursorAgentName: deps.cursorAgentName,
|
|
505
|
+
blockExternals: deps.blockExternals,
|
|
466
506
|
...(deps.hasContinuationSession === undefined
|
|
467
507
|
? {}
|
|
468
508
|
: { hasContinuationSession: deps.hasContinuationSession }),
|
|
@@ -504,6 +544,7 @@ export function dispatchInboundFromEventBody(
|
|
|
504
544
|
log,
|
|
505
545
|
evalCommandsEnabled: deps.evalCommandsEnabled,
|
|
506
546
|
cursorAgentName: deps.cursorAgentName,
|
|
547
|
+
blockExternals: deps.blockExternals,
|
|
507
548
|
...(deps.hasContinuationSession === undefined
|
|
508
549
|
? {}
|
|
509
550
|
: { hasContinuationSession: deps.hasContinuationSession }),
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace-membership checks for AgentKit Slack agents.
|
|
3
|
+
* Mirrors backend `isExternalSlackUser` (cloud-agent/slack/externalChannelPolicy).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { callSlackApi } from "./api.js";
|
|
7
|
+
import type { SlackBotToken } from "./types.js";
|
|
8
|
+
|
|
9
|
+
type SlackUserInfo = {
|
|
10
|
+
team_id?: string;
|
|
11
|
+
is_stranger?: boolean;
|
|
12
|
+
is_restricted?: boolean;
|
|
13
|
+
is_ultra_restricted?: boolean;
|
|
14
|
+
enterprise_user?: { teams?: string[] };
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Pure classifier over a `users.info` user object. Fails open to external. */
|
|
18
|
+
export function classifySlackUserExternality(args: {
|
|
19
|
+
slackTeamId: string;
|
|
20
|
+
user: SlackUserInfo;
|
|
21
|
+
}): boolean {
|
|
22
|
+
const { slackTeamId, user } = args;
|
|
23
|
+
if (
|
|
24
|
+
user.is_stranger === true ||
|
|
25
|
+
user.is_restricted === true ||
|
|
26
|
+
user.is_ultra_restricted === true
|
|
27
|
+
) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
user.team_id !== undefined &&
|
|
32
|
+
user.team_id !== slackTeamId &&
|
|
33
|
+
!(user.enterprise_user?.teams ?? []).includes(slackTeamId)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Lookup + classify. Empty userId / API failure → external. */
|
|
38
|
+
export async function isExternalSlackSender(args: {
|
|
39
|
+
botToken: SlackBotToken | undefined;
|
|
40
|
+
slackTeamId: string;
|
|
41
|
+
userId: string;
|
|
42
|
+
}): Promise<boolean> {
|
|
43
|
+
if (args.userId === "") {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const result = await callSlackApi({
|
|
48
|
+
botToken: args.botToken,
|
|
49
|
+
operation: "users.info",
|
|
50
|
+
body: { user: args.userId },
|
|
51
|
+
});
|
|
52
|
+
if (result.ok !== true || result.user === undefined) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return classifySlackUserExternality({
|
|
56
|
+
slackTeamId: args.slackTeamId,
|
|
57
|
+
user: result.user as SlackUserInfo,
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -33,6 +33,7 @@ export * from "./dispatch.js";
|
|
|
33
33
|
export * from "./doctor.js";
|
|
34
34
|
export * from "./eval-directive.js";
|
|
35
35
|
export * from "./event-id-dedupe.js";
|
|
36
|
+
export * from "./external-policy.js";
|
|
36
37
|
export * from "./inbound.js";
|
|
37
38
|
export * from "./init.js";
|
|
38
39
|
export * from "./interactive.js";
|
|
@@ -20,6 +20,7 @@ import { updateMessage } from "./api.js";
|
|
|
20
20
|
import { decisionFromActionId, parseApprovalActionValue } from "./approvals.js";
|
|
21
21
|
import { buildSlackInteractiveApprovalAuth } from "./auth.js";
|
|
22
22
|
import { dispatchInboundMessage } from "./dispatch.js";
|
|
23
|
+
import { isExternalSlackSender } from "./external-policy.js";
|
|
23
24
|
import { defaultSlackLog, type SlackLog } from "./log.js";
|
|
24
25
|
import type {
|
|
25
26
|
SlackBlockAction,
|
|
@@ -41,6 +42,8 @@ export interface SlackInteractiveDispatchDeps {
|
|
|
41
42
|
) => Promise<PendingApproval>;
|
|
42
43
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
43
44
|
log?: SlackLog;
|
|
45
|
+
/** Defaults to true. */
|
|
46
|
+
blockExternals?: boolean;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
/**
|
|
@@ -116,11 +119,35 @@ export async function dispatchInteractiveFromPayload(
|
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
const teamId = attrs.team_id;
|
|
122
|
+
if (deps.blockExternals !== false && parsed.userId !== "") {
|
|
123
|
+
if (teamId === undefined || teamId === "") {
|
|
124
|
+
log.info("interactive approval dropped (missing team)", {
|
|
125
|
+
session: value.sessionId,
|
|
126
|
+
user: parsed.userId,
|
|
127
|
+
});
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
await isExternalSlackSender({
|
|
132
|
+
botToken: deps.credentials?.botToken,
|
|
133
|
+
slackTeamId: teamId,
|
|
134
|
+
userId: parsed.userId,
|
|
135
|
+
})
|
|
136
|
+
) {
|
|
137
|
+
log.info("interactive approval dropped (external sender)", {
|
|
138
|
+
session: value.sessionId,
|
|
139
|
+
user: parsed.userId,
|
|
140
|
+
team: teamId,
|
|
141
|
+
});
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
119
146
|
const clickingAuth = buildSlackInteractiveApprovalAuth({
|
|
120
147
|
sessionAuth,
|
|
121
148
|
channelId: parsed.channelId || sessionChannel,
|
|
122
149
|
threadTs: parsed.threadTs || sessionThread,
|
|
123
|
-
|
|
150
|
+
teamId: teamId === undefined || teamId === "" ? undefined : teamId,
|
|
124
151
|
clickingUserId: parsed.userId,
|
|
125
152
|
});
|
|
126
153
|
|
|
@@ -204,12 +231,9 @@ export function parseSlackBlockAction(
|
|
|
204
231
|
: typeof user.name === "string"
|
|
205
232
|
? user.name
|
|
206
233
|
: undefined;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
: typeof user.team_id === "string"
|
|
211
|
-
? user.team_id
|
|
212
|
-
: undefined;
|
|
234
|
+
// Payload `team.id` only — never `user.team_id` (Connect home team).
|
|
235
|
+
// Membership gates must baseline the install workspace separately.
|
|
236
|
+
const teamId = typeof team.id === "string" ? team.id : undefined;
|
|
213
237
|
const label =
|
|
214
238
|
typeof action.text === "object" &&
|
|
215
239
|
action.text !== null &&
|
|
@@ -278,6 +302,10 @@ export interface SlackBlockActionDispatchDeps extends SlackContinuationProbes {
|
|
|
278
302
|
host: HostContext;
|
|
279
303
|
artifacts: ArtifactsApi;
|
|
280
304
|
log?: SlackLog;
|
|
305
|
+
/** Defaults to true. */
|
|
306
|
+
blockExternals?: boolean;
|
|
307
|
+
/** Install workspace from `auth.test`; baseline for the external gate. */
|
|
308
|
+
installTeamId?: string;
|
|
281
309
|
}
|
|
282
310
|
|
|
283
311
|
/**
|
|
@@ -285,7 +313,10 @@ export interface SlackBlockActionDispatchDeps extends SlackContinuationProbes {
|
|
|
285
313
|
* `action_ts` (unique per click, never a real thread message), so ask-dedupe
|
|
286
314
|
* claims and `<slack_thread>` exclusions stay per-click.
|
|
287
315
|
*/
|
|
288
|
-
function blockActionAsMessage(
|
|
316
|
+
function blockActionAsMessage(
|
|
317
|
+
action: SlackBlockAction,
|
|
318
|
+
installTeamId: string | undefined
|
|
319
|
+
): SlackMessage {
|
|
289
320
|
const text = `[clicked: ${action.label ?? action.actionId}]`;
|
|
290
321
|
return {
|
|
291
322
|
text,
|
|
@@ -294,7 +325,7 @@ function blockActionAsMessage(action: SlackBlockAction): SlackMessage {
|
|
|
294
325
|
ts: action.actionTs,
|
|
295
326
|
threadTs: action.threadTs,
|
|
296
327
|
channelId: action.channelId,
|
|
297
|
-
teamId:
|
|
328
|
+
teamId: installTeamId,
|
|
298
329
|
author: {
|
|
299
330
|
userId: action.userId,
|
|
300
331
|
userName: action.userName,
|
|
@@ -344,7 +375,7 @@ export async function dispatchBlockAction(
|
|
|
344
375
|
|
|
345
376
|
await dispatchInboundMessage({
|
|
346
377
|
kind: "block_action",
|
|
347
|
-
message: blockActionAsMessage(action),
|
|
378
|
+
message: blockActionAsMessage(action, deps.installTeamId),
|
|
348
379
|
handler: (ctx) => deps.handler(ctx, action),
|
|
349
380
|
send: deps.send,
|
|
350
381
|
credentials: deps.credentials,
|
|
@@ -353,6 +384,7 @@ export async function dispatchBlockAction(
|
|
|
353
384
|
log,
|
|
354
385
|
// Click text is synthetic — never treat it as a stop/eval directive.
|
|
355
386
|
evalCommandsEnabled: false,
|
|
387
|
+
blockExternals: deps.blockExternals,
|
|
356
388
|
hasContinuationSession: deps.hasContinuationSession,
|
|
357
389
|
isContinuationBusy: deps.isContinuationBusy,
|
|
358
390
|
getContinuationLastBotMessageTs: deps.getContinuationLastBotMessageTs,
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
buildDefaultEvents,
|
|
44
44
|
createDefaultOnChannelPost,
|
|
45
45
|
createDefaultOnInbound,
|
|
46
|
+
resolveSlackBlockExternals,
|
|
46
47
|
} from "./defaults.js";
|
|
47
48
|
import {
|
|
48
49
|
dispatchInboundFromEventBody,
|
|
@@ -152,11 +153,14 @@ export function slackChannel<const Name extends string = string>(
|
|
|
152
153
|
: (options.credentials ?? credentialsFromEnv(options.envPrefix));
|
|
153
154
|
const envKeys = slackEnvKeys(options.envPrefix);
|
|
154
155
|
const loadingMessages = options.loadingMessages;
|
|
155
|
-
const
|
|
156
|
+
const policy = options.policy;
|
|
157
|
+
const blockExternals = resolveSlackBlockExternals(policy);
|
|
158
|
+
const defaultInbound = createDefaultOnInbound(loadingMessages, policy);
|
|
156
159
|
const onAppMention = options.onAppMention ?? defaultInbound;
|
|
157
160
|
const onDirectMessage = options.onDirectMessage ?? defaultInbound;
|
|
158
161
|
const onChannelPost =
|
|
159
|
-
options.onChannelPost ??
|
|
162
|
+
options.onChannelPost ??
|
|
163
|
+
createDefaultOnChannelPost(loadingMessages, policy);
|
|
160
164
|
const engagement = options.engagement ?? {};
|
|
161
165
|
const mentionsEnabled = engagement.mentions !== false;
|
|
162
166
|
const directMessagesEnabled = engagement.directMessages !== false;
|
|
@@ -237,6 +241,8 @@ export function slackChannel<const Name extends string = string>(
|
|
|
237
241
|
mentionsEnabled,
|
|
238
242
|
directMessagesEnabled,
|
|
239
243
|
evalCommandsEnabled,
|
|
244
|
+
// cursorAccount: backend router already refuses externals.
|
|
245
|
+
blockExternals: cursorAccount ? false : blockExternals,
|
|
240
246
|
...(args.hasContinuationSession === undefined
|
|
241
247
|
? {}
|
|
242
248
|
: { hasContinuationSession: args.hasContinuationSession }),
|
|
@@ -329,10 +335,15 @@ export function slackChannel<const Name extends string = string>(
|
|
|
329
335
|
|
|
330
336
|
let botUserId: string | undefined;
|
|
331
337
|
let botId: string | undefined;
|
|
338
|
+
let installTeamId: string | undefined;
|
|
332
339
|
let webClient: InstanceType<
|
|
333
340
|
typeof import("@slack/web-api").WebClient
|
|
334
341
|
> | null = null;
|
|
335
|
-
if (
|
|
342
|
+
if (
|
|
343
|
+
channelPosts !== undefined ||
|
|
344
|
+
botMentions !== undefined ||
|
|
345
|
+
routeInteractive
|
|
346
|
+
) {
|
|
336
347
|
try {
|
|
337
348
|
const { WebClient } = await import("@slack/web-api");
|
|
338
349
|
webClient = new WebClient(botToken);
|
|
@@ -341,6 +352,8 @@ export function slackChannel<const Name extends string = string>(
|
|
|
341
352
|
typeof identity.user_id === "string" ? identity.user_id : undefined;
|
|
342
353
|
botId =
|
|
343
354
|
typeof identity.bot_id === "string" ? identity.bot_id : undefined;
|
|
355
|
+
installTeamId =
|
|
356
|
+
typeof identity.team_id === "string" ? identity.team_id : undefined;
|
|
344
357
|
} catch (error) {
|
|
345
358
|
getLog().error("bot identity lookup degraded", {
|
|
346
359
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -416,6 +429,7 @@ export function slackChannel<const Name extends string = string>(
|
|
|
416
429
|
artifacts: args.artifacts,
|
|
417
430
|
log: getLog(),
|
|
418
431
|
evalCommandsEnabled,
|
|
432
|
+
blockExternals,
|
|
419
433
|
...(args.hasContinuationSession === undefined
|
|
420
434
|
? {}
|
|
421
435
|
: {
|
|
@@ -491,6 +505,7 @@ export function slackChannel<const Name extends string = string>(
|
|
|
491
505
|
resolveApproval: args.resolveApproval,
|
|
492
506
|
waitUntil: args.waitUntil,
|
|
493
507
|
log: getLog(),
|
|
508
|
+
blockExternals,
|
|
494
509
|
}
|
|
495
510
|
);
|
|
496
511
|
if (handledAsApproval || onBlockAction === undefined) {
|
|
@@ -503,6 +518,8 @@ export function slackChannel<const Name extends string = string>(
|
|
|
503
518
|
host: args.host,
|
|
504
519
|
artifacts: args.artifacts,
|
|
505
520
|
log: getLog(),
|
|
521
|
+
blockExternals,
|
|
522
|
+
installTeamId,
|
|
506
523
|
hasContinuationSession: args.hasContinuationSession,
|
|
507
524
|
isContinuationBusy: args.isContinuationBusy,
|
|
508
525
|
getContinuationLastBotMessageTs:
|
|
@@ -432,8 +432,20 @@ export function assertSlackCursorAgentName(name: string): void {
|
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
/** `"thread"` = anyone in the thread (default); `"author"` = session starter only. */
|
|
436
|
+
export type SlackRespondTo = "thread" | "author";
|
|
437
|
+
|
|
438
|
+
export interface SlackAccessPolicy {
|
|
439
|
+
/** Defaults to `"thread"`. Applied by the default inbound handlers. */
|
|
440
|
+
respondTo?: SlackRespondTo;
|
|
441
|
+
/** Refuse Slack Connect / guest / other-workspace senders. Defaults to `true`. */
|
|
442
|
+
blockExternals?: boolean;
|
|
443
|
+
}
|
|
444
|
+
|
|
435
445
|
export interface SlackChannelOptions {
|
|
436
446
|
credentials?: SlackCredentials;
|
|
447
|
+
/** Defaults to `{ respondTo: "thread", blockExternals: true }`. */
|
|
448
|
+
policy?: SlackAccessPolicy;
|
|
437
449
|
/**
|
|
438
450
|
* Per-agent env prefix for tokens. `envPrefix: "MY_AGENT"` reads
|
|
439
451
|
* `MY_AGENT_SLACK_BOT_TOKEN` + `MY_AGENT_SLACK_APP_TOKEN`. Prefer this over
|
package/src/internal/ab-fold.ts
CHANGED
|
@@ -187,6 +187,10 @@ export function applyBuiltinMetrics(
|
|
|
187
187
|
m.cacheReadTokens += usage.cacheReadTokens;
|
|
188
188
|
m.cacheWriteTokens += usage.cacheWriteTokens;
|
|
189
189
|
}
|
|
190
|
+
const cost = event.data.cost;
|
|
191
|
+
if (cost !== undefined) {
|
|
192
|
+
m.costUsd += cost.totalUsd;
|
|
193
|
+
}
|
|
190
194
|
addWallTime(accum, event.at);
|
|
191
195
|
break;
|
|
192
196
|
}
|
|
@@ -323,6 +323,7 @@ function addMetrics(target: ABMetrics, delta: ABMetrics): void {
|
|
|
323
323
|
target.outputTokens += delta.outputTokens;
|
|
324
324
|
target.cacheReadTokens += delta.cacheReadTokens;
|
|
325
325
|
target.cacheWriteTokens += delta.cacheWriteTokens;
|
|
326
|
+
target.costUsd += delta.costUsd;
|
|
326
327
|
target.wallTimeMs += delta.wallTimeMs;
|
|
327
328
|
for (const [key, value] of Object.entries(delta.custom)) {
|
|
328
329
|
target.custom[key] = (target.custom[key] ?? 0) + value;
|