@cursor/july 0.1.39 → 0.1.41
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/AGENTS.md +4 -3
- package/dist/bin/agent-serve.js +28 -9
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +18 -8
- package/dist/channels/slack/attachments.d.ts +82 -0
- package/dist/channels/slack/attachments.d.ts.map +1 -0
- package/dist/channels/slack/attachments.js +520 -0
- package/dist/channels/slack/cursor-account.d.ts +7 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +2 -2
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +26 -17
- package/dist/channels/slack/dispatch.d.ts +4 -3
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +84 -21
- package/dist/channels/slack/inbound.d.ts +6 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +48 -2
- 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/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +16 -4
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +1 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +7 -4
- package/dist/channels/slack/types.d.ts +49 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
- package/dist/docs/assets/{app.BQ8Hihdf.js → app.mIw24pb1.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BA7V8dEJ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BBCr8Yuy.js → VPLocalSearchBox.hOzpPwrG.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CK_NiGC-.js → theme.BtFhUYmh.js} +2 -2
- package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
- package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
- package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
- package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
- package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.js → reference_hooks.md.BHeG-vjK.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.BHeG-vjK.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
- package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +7 -7
- 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 +5 -5
- 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 +3 -3
- package/dist/docs/guides/webhooks.html +49 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +8 -8
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +8 -8
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +5 -5
- 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 +14 -8
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +22 -2
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +14 -4
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
- package/dist/internal/cli-mcp-oauth.js +3 -1
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/cursor-event-relay.d.ts +45 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +96 -2
- package/dist/internal/deploy-client.js +1 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +35 -7
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -1
- package/dist/internal/durable-session-store.d.ts +48 -0
- package/dist/internal/durable-session-store.d.ts.map +1 -0
- package/dist/internal/durable-session-store.js +86 -0
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +2 -2
- package/dist/internal/init-project.d.ts +34 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +121 -2
- package/dist/internal/ledger-serving.d.ts +101 -0
- package/dist/internal/ledger-serving.d.ts.map +1 -0
- package/dist/internal/ledger-serving.js +174 -0
- package/dist/internal/listen-port.d.ts +22 -0
- package/dist/internal/listen-port.d.ts.map +1 -0
- package/dist/internal/listen-port.js +77 -0
- package/dist/internal/mcp-oauth.d.ts +12 -1
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +25 -3
- package/dist/internal/playground/static.d.ts +21 -4
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +82 -18
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +10 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +67 -49
- package/dist/internal/session-engine.d.ts +57 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +117 -28
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/workspace.d.ts +6 -2
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +10 -2
- package/dist/kv/memory-kv.d.ts +23 -0
- package/dist/kv/memory-kv.d.ts.map +1 -0
- package/dist/kv/memory-kv.js +103 -0
- package/dist/kv.d.ts +22 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +20 -0
- package/dist/ledger/session-ledger.d.ts +204 -0
- package/dist/ledger/session-ledger.d.ts.map +1 -0
- package/dist/ledger/session-ledger.js +382 -0
- package/dist/ledger.d.ts +11 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +9 -0
- package/dist/playground/assets/index-B3HBneZZ.js +85 -0
- package/dist/playground/assets/index-Bqk9nplh.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +25 -3
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +50 -2
- package/dist/storage-backends/file-kv.d.ts +5 -2
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +107 -7
- package/dist/storage.d.ts +60 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +28 -4
- package/dist/types.d.ts +123 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -0
- package/docs/README.md +10 -7
- package/docs/ab.md +2 -2
- package/docs/building-with-agents.md +1 -1
- package/docs/deployment.md +34 -11
- package/docs/evals.md +3 -3
- package/docs/example-agents/index.md +1 -1
- package/docs/guides/webhooks.md +87 -0
- package/docs/quickstart.md +7 -8
- package/docs/reference/cli.md +15 -6
- package/docs/reference/hooks.md +8 -2
- package/docs/storage.md +67 -7
- package/docs/troubleshooting.md +10 -2
- package/package.json +20 -7
- package/skills/create-agent/SKILL.md +1 -1
- package/src/bin/agent-serve.ts +27 -11
- package/src/channels/slack/api.ts +19 -14
- package/src/channels/slack/attachments.ts +635 -0
- package/src/channels/slack/cursor-account.ts +8 -0
- package/src/channels/slack/defaults.ts +34 -18
- package/src/channels/slack/dispatch.ts +121 -6
- package/src/channels/slack/inbound.ts +60 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +17 -3
- package/src/channels/slack/manifest.ts +1 -0
- package/src/channels/slack/slack-channel.ts +7 -0
- package/src/channels/slack/types.ts +47 -1
- package/src/index.ts +9 -0
- package/src/internal/cli-ax.ts +25 -1
- package/src/internal/cli-deploy.ts +22 -4
- package/src/internal/cli-mcp-oauth.ts +3 -1
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/cursor-event-relay.ts +168 -0
- package/src/internal/deploy-client.ts +1 -1
- package/src/internal/discovery.ts +42 -5
- package/src/internal/distribution.ts +3 -1
- package/src/internal/durable-session-store.ts +95 -0
- package/src/internal/hosting.ts +2 -2
- package/src/internal/init-project.ts +151 -2
- package/src/internal/ledger-serving.ts +240 -0
- package/src/internal/listen-port.ts +85 -0
- package/src/internal/mcp-oauth.ts +29 -4
- package/src/internal/playground/static.ts +111 -20
- package/src/internal/sdk-runner.ts +11 -1
- package/src/internal/server.ts +76 -62
- package/src/internal/session-engine.ts +192 -16
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/workspace.ts +14 -3
- package/src/kv/memory-kv.ts +99 -0
- package/src/kv.ts +27 -0
- package/src/ledger/session-ledger.ts +535 -0
- package/src/ledger.ts +29 -0
- package/src/storage-backends/cursor-hosted.ts +108 -3
- package/src/storage-backends/file-kv.ts +128 -12
- package/src/storage.ts +90 -6
- package/src/types.ts +130 -4
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B-VTH4As.js +0 -1
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
- package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/multi-tenant.d.ts +0 -80
- package/dist/multi-tenant.d.ts.map +0 -1
- package/dist/multi-tenant.js +0 -69
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BRhBbnd4.css +0 -1
- package/dist/playground/assets/index-_2WKw9a-.js +0 -85
- package/dist/storage-backends/postgres-kv.d.ts +0 -82
- package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
- package/dist/storage-backends/postgres-kv.js +0 -185
- package/src/storage-backends/postgres-kv.ts +0 -253
- /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.C_b6ESpD.lean.js → quickstart.md.rIbfahJM.lean.js} +0 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Download and classify Slack file uploads for agent turns.
|
|
3
|
+
*
|
|
4
|
+
* Images become vision inputs (SDK `images`). Documents and videos land under
|
|
5
|
+
* `slack-attachments/` in the session workspace so the model can Read them.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
import { callSlackApiSoft, isSlackApiTransport } from "./api.js";
|
|
17
|
+
import { tryResolveBotToken } from "./credentials.js";
|
|
18
|
+
export const SLACK_ATTACHMENTS_DIR = "slack-attachments";
|
|
19
|
+
export const SLACK_ATTACHMENT_ONLY_PROMPT = "The user shared Slack attachment(s) with no message text. Review the attached files.";
|
|
20
|
+
const DEFAULT_MAX_FILE_BYTES = 15 * 1024 * 1024;
|
|
21
|
+
const DEFAULT_MAX_TOTAL_BYTES = 35 * 1024 * 1024;
|
|
22
|
+
const DEFAULT_MAX_FILES = 8;
|
|
23
|
+
const DEFAULT_DOWNLOAD_TIMEOUT_MS = 10000;
|
|
24
|
+
const TEXT_SLACK_FILETYPES = new Set([
|
|
25
|
+
"text",
|
|
26
|
+
"markdown",
|
|
27
|
+
"md",
|
|
28
|
+
"diff",
|
|
29
|
+
"csv",
|
|
30
|
+
"tsv",
|
|
31
|
+
"json",
|
|
32
|
+
"xml",
|
|
33
|
+
"yaml",
|
|
34
|
+
"c",
|
|
35
|
+
"csharp",
|
|
36
|
+
"cpp",
|
|
37
|
+
"css",
|
|
38
|
+
"clojure",
|
|
39
|
+
"coffeescript",
|
|
40
|
+
"dart",
|
|
41
|
+
"dockerfile",
|
|
42
|
+
"email",
|
|
43
|
+
"erlang",
|
|
44
|
+
"fsharp",
|
|
45
|
+
"go",
|
|
46
|
+
"groovy",
|
|
47
|
+
"html",
|
|
48
|
+
"haskell",
|
|
49
|
+
"java",
|
|
50
|
+
"javascript",
|
|
51
|
+
"kotlin",
|
|
52
|
+
"latex",
|
|
53
|
+
"lisp",
|
|
54
|
+
"lua",
|
|
55
|
+
"matlab",
|
|
56
|
+
"objc",
|
|
57
|
+
"ocaml",
|
|
58
|
+
"pascal",
|
|
59
|
+
"perl",
|
|
60
|
+
"php",
|
|
61
|
+
"powershell",
|
|
62
|
+
"python",
|
|
63
|
+
"r",
|
|
64
|
+
"ruby",
|
|
65
|
+
"rust",
|
|
66
|
+
"sql",
|
|
67
|
+
"sass",
|
|
68
|
+
"scala",
|
|
69
|
+
"scheme",
|
|
70
|
+
"shell",
|
|
71
|
+
"swift",
|
|
72
|
+
"typescript",
|
|
73
|
+
"vb",
|
|
74
|
+
"vbscript",
|
|
75
|
+
]);
|
|
76
|
+
function asRecord(value) {
|
|
77
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
function asString(value) {
|
|
83
|
+
return typeof value === "string" ? value : undefined;
|
|
84
|
+
}
|
|
85
|
+
function asNumber(value) {
|
|
86
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
87
|
+
? value
|
|
88
|
+
: undefined;
|
|
89
|
+
}
|
|
90
|
+
function normalizeMimeType(mimeType) {
|
|
91
|
+
return (mimeType !== null && mimeType !== void 0 ? mimeType : "").split(";")[0].trim().toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
function getLowercaseFileExtension(filename) {
|
|
94
|
+
if (filename === undefined || filename.length === 0) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
const extensionStart = filename.lastIndexOf(".");
|
|
98
|
+
if (extensionStart < 0 || extensionStart === filename.length - 1) {
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
return filename.slice(extensionStart + 1).toLowerCase();
|
|
102
|
+
}
|
|
103
|
+
/** Keep path-safe basename pieces (mirrors cloud-agent sanitizeFilename). */
|
|
104
|
+
export function sanitizeSlackFilename(name) {
|
|
105
|
+
const trimmed = name.trim().replace(/[/\\?%*:|"<>]/g, "_");
|
|
106
|
+
return trimmed.length > 0 ? trimmed.slice(0, 180) : "file";
|
|
107
|
+
}
|
|
108
|
+
export function isSupportedImageFormat(mimeType) {
|
|
109
|
+
return [
|
|
110
|
+
"image/jpeg",
|
|
111
|
+
"image/jpg",
|
|
112
|
+
"image/png",
|
|
113
|
+
"image/gif",
|
|
114
|
+
"image/webp",
|
|
115
|
+
].includes(normalizeMimeType(mimeType));
|
|
116
|
+
}
|
|
117
|
+
export function isSupportedDocumentFormat(args) {
|
|
118
|
+
const mimeType = normalizeMimeType(args.mimeType);
|
|
119
|
+
const extension = getLowercaseFileExtension(args.filename);
|
|
120
|
+
const supportedExtensions = new Set([
|
|
121
|
+
"7z",
|
|
122
|
+
"bz2",
|
|
123
|
+
"doc",
|
|
124
|
+
"docx",
|
|
125
|
+
"gz",
|
|
126
|
+
"pdf",
|
|
127
|
+
"ppt",
|
|
128
|
+
"pptx",
|
|
129
|
+
"rar",
|
|
130
|
+
"tar",
|
|
131
|
+
"tbz",
|
|
132
|
+
"tbz2",
|
|
133
|
+
"tgz",
|
|
134
|
+
"txt",
|
|
135
|
+
"md",
|
|
136
|
+
"markdown",
|
|
137
|
+
"csv",
|
|
138
|
+
"xlsx",
|
|
139
|
+
"xz",
|
|
140
|
+
"json",
|
|
141
|
+
"jsonl",
|
|
142
|
+
"xml",
|
|
143
|
+
"yaml",
|
|
144
|
+
"yml",
|
|
145
|
+
"toml",
|
|
146
|
+
"txz",
|
|
147
|
+
"log",
|
|
148
|
+
"tzst",
|
|
149
|
+
"zip",
|
|
150
|
+
"zst",
|
|
151
|
+
]);
|
|
152
|
+
const supportedMimeTypes = new Set([
|
|
153
|
+
"application/gzip",
|
|
154
|
+
"application/msword",
|
|
155
|
+
"application/pdf",
|
|
156
|
+
"application/json",
|
|
157
|
+
"application/jsonl",
|
|
158
|
+
"application/vnd.rar",
|
|
159
|
+
"application/vnd.ms-powerpoint",
|
|
160
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
161
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
162
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
163
|
+
"application/xml",
|
|
164
|
+
"application/x-7z-compressed",
|
|
165
|
+
"application/x-bzip2",
|
|
166
|
+
"application/x-compressed-tar",
|
|
167
|
+
"application/x-gzip",
|
|
168
|
+
"application/x-gtar",
|
|
169
|
+
"application/x-rar-compressed",
|
|
170
|
+
"application/x-tar",
|
|
171
|
+
"application/x-xz",
|
|
172
|
+
"application/x-yaml",
|
|
173
|
+
"application/x-zip-compressed",
|
|
174
|
+
"application/yaml",
|
|
175
|
+
"application/zip",
|
|
176
|
+
"application/toml",
|
|
177
|
+
"application/zstd",
|
|
178
|
+
"application/x-zstd",
|
|
179
|
+
"text/csv",
|
|
180
|
+
"text/markdown",
|
|
181
|
+
"text/plain",
|
|
182
|
+
"text/xml",
|
|
183
|
+
"text/x-log",
|
|
184
|
+
"text/x-markdown",
|
|
185
|
+
"text/yaml",
|
|
186
|
+
]);
|
|
187
|
+
return (mimeType.startsWith("text/") ||
|
|
188
|
+
supportedMimeTypes.has(mimeType) ||
|
|
189
|
+
supportedExtensions.has(extension));
|
|
190
|
+
}
|
|
191
|
+
export function isSupportedVideoFormat(mimeType) {
|
|
192
|
+
return normalizeMimeType(mimeType).startsWith("video/");
|
|
193
|
+
}
|
|
194
|
+
function hasTextSlackHint(file) {
|
|
195
|
+
if (file.mode === "snippet") {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
const filetype = typeof file.filetype === "string" ? file.filetype.trim().toLowerCase() : "";
|
|
199
|
+
return TEXT_SLACK_FILETYPES.has(filetype);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Classify a Slack file as image / document / video. Tolerates empty
|
|
203
|
+
* `mimetype` on snippets (Slack fills it asynchronously).
|
|
204
|
+
*/
|
|
205
|
+
export function classifySlackFile(file) {
|
|
206
|
+
const populatedMimeType = typeof file.mimetype === "string" ? normalizeMimeType(file.mimetype) : "";
|
|
207
|
+
const textHint = hasTextSlackHint(file);
|
|
208
|
+
const mimeType = populatedMimeType.length > 0
|
|
209
|
+
? populatedMimeType
|
|
210
|
+
: textHint
|
|
211
|
+
? "text/plain"
|
|
212
|
+
: "";
|
|
213
|
+
if (mimeType.length === 0) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
if (isSupportedImageFormat(mimeType)) {
|
|
217
|
+
return { kind: "image", mimeType };
|
|
218
|
+
}
|
|
219
|
+
const filename = typeof file.name === "string"
|
|
220
|
+
? file.name
|
|
221
|
+
: typeof file.title === "string"
|
|
222
|
+
? file.title
|
|
223
|
+
: undefined;
|
|
224
|
+
const isTextLike = textHint || mimeType.startsWith("text/");
|
|
225
|
+
if (isTextLike || isSupportedDocumentFormat({ mimeType, filename })) {
|
|
226
|
+
return { kind: "document", mimeType, isTextLike };
|
|
227
|
+
}
|
|
228
|
+
if (isSupportedVideoFormat(mimeType)) {
|
|
229
|
+
return { kind: "video", mimeType };
|
|
230
|
+
}
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
function isForwardedShareAttachment(value) {
|
|
234
|
+
const record = asRecord(value);
|
|
235
|
+
return record !== null && record.is_share === true;
|
|
236
|
+
}
|
|
237
|
+
/** Top-level uploads plus files nested in forwarded `is_share` attachments. */
|
|
238
|
+
export function collectSlackMessageFiles(message) {
|
|
239
|
+
const record = asRecord(message);
|
|
240
|
+
if (record === null) {
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
const files = Array.isArray(record.files)
|
|
244
|
+
? [...record.files]
|
|
245
|
+
: [];
|
|
246
|
+
if (Array.isArray(record.attachments)) {
|
|
247
|
+
for (const attachment of record.attachments) {
|
|
248
|
+
if (isForwardedShareAttachment(attachment) &&
|
|
249
|
+
Array.isArray(attachment.files)) {
|
|
250
|
+
files.push(...attachment.files);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return files;
|
|
255
|
+
}
|
|
256
|
+
export function parseSlackFileRefs(message) {
|
|
257
|
+
const files = collectSlackMessageFiles(message);
|
|
258
|
+
const refs = [];
|
|
259
|
+
for (const file of files) {
|
|
260
|
+
const id = asString(file.id);
|
|
261
|
+
if (id === undefined || id.length === 0) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
refs.push({
|
|
265
|
+
id,
|
|
266
|
+
name: asString(file.name),
|
|
267
|
+
title: asString(file.title),
|
|
268
|
+
mimetype: asString(file.mimetype),
|
|
269
|
+
filetype: asString(file.filetype),
|
|
270
|
+
mode: asString(file.mode),
|
|
271
|
+
size: asNumber(file.size),
|
|
272
|
+
dataBase64: asString(file.dataBase64),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return refs.length > 0 ? refs : undefined;
|
|
276
|
+
}
|
|
277
|
+
function attachmentFilename(file) {
|
|
278
|
+
var _a, _b;
|
|
279
|
+
return sanitizeSlackFilename((_b = (_a = file.name) !== null && _a !== void 0 ? _a : file.title) !== null && _b !== void 0 ? _b : file.id);
|
|
280
|
+
}
|
|
281
|
+
function looksLikeHtml(bytes) {
|
|
282
|
+
const head = Buffer.from(bytes.subarray(0, 100))
|
|
283
|
+
.toString("utf8")
|
|
284
|
+
.toLowerCase();
|
|
285
|
+
return head.includes("<html");
|
|
286
|
+
}
|
|
287
|
+
function isTextLikeBytes(args) {
|
|
288
|
+
if (args.isTextLike || args.mimeType.startsWith("text/")) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
// Reject obvious binary before attempting utf8 decode for docs.
|
|
292
|
+
for (let i = 0; i < Math.min(args.bytes.length, 512); i++) {
|
|
293
|
+
if (args.bytes[i] === 0) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return (args.mimeType === "application/json" ||
|
|
298
|
+
args.mimeType === "application/jsonl" ||
|
|
299
|
+
args.mimeType === "application/xml" ||
|
|
300
|
+
args.mimeType === "application/yaml" ||
|
|
301
|
+
args.mimeType === "application/x-yaml" ||
|
|
302
|
+
args.mimeType === "application/toml");
|
|
303
|
+
}
|
|
304
|
+
function downloadSlackFileBytes(args) {
|
|
305
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
306
|
+
var _a, _b, _c;
|
|
307
|
+
// cursorAccount transport cannot mint a Bearer for files.slack.com; the
|
|
308
|
+
// relay must pre-attach `dataBase64` on the file ref instead.
|
|
309
|
+
if (isSlackApiTransport(args.botToken)) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
const info = yield callSlackApiSoft({
|
|
313
|
+
botToken: args.botToken,
|
|
314
|
+
operation: "files.info",
|
|
315
|
+
body: { file: args.fileId },
|
|
316
|
+
});
|
|
317
|
+
if (info.ok !== true) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const file = asRecord(info.file);
|
|
321
|
+
if (file === null) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
const downloadUrl = asString(file.url_private_download);
|
|
325
|
+
if (downloadUrl === undefined || downloadUrl.length === 0) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
const fileSize = asNumber(file.size);
|
|
329
|
+
if (fileSize !== undefined && fileSize > args.maxBytes) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
const botToken = yield tryResolveBotToken({ botToken: args.botToken });
|
|
333
|
+
const headers = {};
|
|
334
|
+
if (botToken !== undefined && botToken.length > 0) {
|
|
335
|
+
headers.Authorization = `Bearer ${botToken}`;
|
|
336
|
+
}
|
|
337
|
+
let response;
|
|
338
|
+
try {
|
|
339
|
+
response = yield fetch(downloadUrl, {
|
|
340
|
+
headers,
|
|
341
|
+
signal: AbortSignal.timeout(args.downloadTimeoutMs),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
catch (_d) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const contentLengthHeader = response.headers.get("content-length");
|
|
351
|
+
if (contentLengthHeader !== null && contentLengthHeader.length > 0) {
|
|
352
|
+
const contentLength = Number.parseInt(contentLengthHeader, 10);
|
|
353
|
+
if (!Number.isNaN(contentLength) && contentLength > args.maxBytes) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const buffer = Buffer.from(yield response.arrayBuffer());
|
|
358
|
+
if (buffer.length > args.maxBytes) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const actualContentType = response.headers.get("content-type");
|
|
362
|
+
if (normalizeMimeType(actualContentType !== null && actualContentType !== void 0 ? actualContentType : undefined) === "text/html" ||
|
|
363
|
+
looksLikeHtml(buffer)) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const responseMimeType = normalizeMimeType(actualContentType !== null && actualContentType !== void 0 ? actualContentType : undefined);
|
|
367
|
+
const metadataMimeType = normalizeMimeType((_a = asString(file.mimetype)) !== null && _a !== void 0 ? _a : args.fallbackMimeType);
|
|
368
|
+
const effectiveMimeType = responseMimeType.length > 0 &&
|
|
369
|
+
responseMimeType !== "application/octet-stream"
|
|
370
|
+
? responseMimeType
|
|
371
|
+
: metadataMimeType;
|
|
372
|
+
return {
|
|
373
|
+
data: new Uint8Array(buffer),
|
|
374
|
+
mimeType: effectiveMimeType.length > 0 ? effectiveMimeType : args.fallbackMimeType,
|
|
375
|
+
filename: sanitizeSlackFilename((_c = (_b = asString(file.name)) !== null && _b !== void 0 ? _b : asString(file.title)) !== null && _c !== void 0 ? _c : args.fileId),
|
|
376
|
+
};
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Download (or use pre-attached) Slack files and split them into vision
|
|
381
|
+
* images + workspace blobs for the turn.
|
|
382
|
+
*/
|
|
383
|
+
export function prepareSlackAttachments(options) {
|
|
384
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
385
|
+
var _a, _b;
|
|
386
|
+
var _c, _d, _e, _f;
|
|
387
|
+
const maxFiles = (_c = options.maxFiles) !== null && _c !== void 0 ? _c : DEFAULT_MAX_FILES;
|
|
388
|
+
const maxFileBytes = (_d = options.maxFileBytes) !== null && _d !== void 0 ? _d : DEFAULT_MAX_FILE_BYTES;
|
|
389
|
+
const maxTotalBytes = (_e = options.maxTotalBytes) !== null && _e !== void 0 ? _e : DEFAULT_MAX_TOTAL_BYTES;
|
|
390
|
+
const downloadTimeoutMs = (_f = options.downloadTimeoutMs) !== null && _f !== void 0 ? _f : DEFAULT_DOWNLOAD_TIMEOUT_MS;
|
|
391
|
+
const loaded = yield Promise.all(options.files.slice(0, maxFiles).map((file) => __awaiter(this, void 0, void 0, function* () {
|
|
392
|
+
var _a, _b;
|
|
393
|
+
const classification = classifySlackFile(file);
|
|
394
|
+
if (classification === undefined) {
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
if (file.size !== undefined && file.size > maxFileBytes) {
|
|
398
|
+
(_a = options.log) === null || _a === void 0 ? void 0 : _a.info("slack attachment skipped (size)", {
|
|
399
|
+
file_id: file.id,
|
|
400
|
+
size: file.size,
|
|
401
|
+
max: maxFileBytes,
|
|
402
|
+
});
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
if (file.dataBase64 !== undefined && file.dataBase64.length > 0) {
|
|
406
|
+
return {
|
|
407
|
+
file,
|
|
408
|
+
classification,
|
|
409
|
+
bytes: new Uint8Array(Buffer.from(file.dataBase64, "base64")),
|
|
410
|
+
mimeType: classification.mimeType,
|
|
411
|
+
filename: attachmentFilename(file),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const downloaded = yield downloadSlackFileBytes({
|
|
415
|
+
botToken: options.botToken,
|
|
416
|
+
fileId: file.id,
|
|
417
|
+
fallbackMimeType: classification.mimeType,
|
|
418
|
+
maxBytes: maxFileBytes,
|
|
419
|
+
downloadTimeoutMs,
|
|
420
|
+
});
|
|
421
|
+
if (downloaded === null) {
|
|
422
|
+
(_b = options.log) === null || _b === void 0 ? void 0 : _b.info("slack attachment download failed", {
|
|
423
|
+
file_id: file.id,
|
|
424
|
+
kind: classification.kind,
|
|
425
|
+
});
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
file,
|
|
430
|
+
classification,
|
|
431
|
+
bytes: downloaded.data,
|
|
432
|
+
mimeType: downloaded.mimeType,
|
|
433
|
+
filename: downloaded.filename,
|
|
434
|
+
};
|
|
435
|
+
})));
|
|
436
|
+
const images = [];
|
|
437
|
+
const workspaceFiles = {};
|
|
438
|
+
const annotations = [];
|
|
439
|
+
let totalBytes = 0;
|
|
440
|
+
let imageIndex = 0;
|
|
441
|
+
let documentIndex = 0;
|
|
442
|
+
let videoIndex = 0;
|
|
443
|
+
for (const item of loaded) {
|
|
444
|
+
if (item === undefined) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const { file, classification, bytes, mimeType, filename } = item;
|
|
448
|
+
if (bytes.length === 0) {
|
|
449
|
+
(_a = options.log) === null || _a === void 0 ? void 0 : _a.info("slack attachment download failed", {
|
|
450
|
+
file_id: file.id,
|
|
451
|
+
kind: classification.kind,
|
|
452
|
+
});
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (bytes.length > maxFileBytes ||
|
|
456
|
+
totalBytes + bytes.length > maxTotalBytes) {
|
|
457
|
+
(_b = options.log) === null || _b === void 0 ? void 0 : _b.info("slack attachment skipped (budget)", {
|
|
458
|
+
file_id: file.id,
|
|
459
|
+
bytes: bytes.length,
|
|
460
|
+
});
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
totalBytes += bytes.length;
|
|
464
|
+
if (classification.kind === "image") {
|
|
465
|
+
if (!isSupportedImageFormat(mimeType)) {
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
imageIndex++;
|
|
469
|
+
images.push({
|
|
470
|
+
data: Buffer.from(bytes).toString("base64"),
|
|
471
|
+
mimeType,
|
|
472
|
+
});
|
|
473
|
+
annotations.push(`[Image ${imageIndex}: ${filename}]`);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const relativePath = `${SLACK_ATTACHMENTS_DIR}/${filename}`;
|
|
477
|
+
const textLike = classification.kind === "document" &&
|
|
478
|
+
isTextLikeBytes({
|
|
479
|
+
mimeType,
|
|
480
|
+
isTextLike: classification.isTextLike,
|
|
481
|
+
bytes,
|
|
482
|
+
});
|
|
483
|
+
if (textLike) {
|
|
484
|
+
workspaceFiles[relativePath] = Buffer.from(bytes).toString("utf8");
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
workspaceFiles[relativePath] = {
|
|
488
|
+
encoding: "base64",
|
|
489
|
+
data: Buffer.from(bytes).toString("base64"),
|
|
490
|
+
mimeType,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (classification.kind === "document") {
|
|
494
|
+
documentIndex++;
|
|
495
|
+
annotations.push(`[Document ${documentIndex}: ${filename} → ${relativePath}]`);
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
videoIndex++;
|
|
499
|
+
annotations.push(`[Video ${videoIndex}: ${filename} → ${relativePath}]`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return { images, workspaceFiles, annotations };
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
/** Merge attachment annotations into the user prompt. */
|
|
506
|
+
export function appendSlackAttachmentAnnotations(prompt, annotations) {
|
|
507
|
+
if (annotations.length === 0) {
|
|
508
|
+
return prompt;
|
|
509
|
+
}
|
|
510
|
+
const block = [
|
|
511
|
+
"<slack_attachments>",
|
|
512
|
+
...annotations,
|
|
513
|
+
"</slack_attachments>",
|
|
514
|
+
].join("\n");
|
|
515
|
+
const trimmed = prompt.trim();
|
|
516
|
+
if (trimmed.length === 0) {
|
|
517
|
+
return `${block}\n\n${SLACK_ATTACHMENT_ONLY_PROMPT}`;
|
|
518
|
+
}
|
|
519
|
+
return `${block}\n\n${trimmed}`;
|
|
520
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type { ArtifactsApi, HostContext, SendMessageFn } from "../../types.js";
|
|
15
15
|
import type { EventIdDedupe } from "./event-id-dedupe.js";
|
|
16
16
|
import type { SlackLog } from "./log.js";
|
|
17
|
-
import type { SlackApiTransport, SlackChannelOptions, SlackCredentials, SlackMessageHandler } from "./types.js";
|
|
17
|
+
import type { SlackApiTransport, SlackChannelOptions, SlackCredentials, SlackMessageFile, SlackMessageHandler } from "./types.js";
|
|
18
18
|
/**
|
|
19
19
|
* Transport placeholder created at `slackChannel()` definition time and
|
|
20
20
|
* bound to the real backend proxy caller when the serve host starts its
|
|
@@ -45,6 +45,12 @@ export interface CursorSlackEnvelope {
|
|
|
45
45
|
matchedBy: "name" | "thread";
|
|
46
46
|
eventId?: string;
|
|
47
47
|
receivedAtMs: number;
|
|
48
|
+
/**
|
|
49
|
+
* Slack file uploads on the triggering message. When `dataBase64` is set
|
|
50
|
+
* the Cursor backend already downloaded bytes (cursorAccount has no bot
|
|
51
|
+
* token for files.slack.com).
|
|
52
|
+
*/
|
|
53
|
+
files?: SlackMessageFile[];
|
|
48
54
|
}
|
|
49
55
|
/** Serve-time runtime handle for one cursor-account Slack channel. */
|
|
50
56
|
export interface SlackCursorAccountRuntime {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-account.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/cursor-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAezE;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"cursor-account.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/cursor-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAezE;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,sEAAsE;AACtE,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,WAAW,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,wBAAwB,CAAC;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,mBAAmB,CAAC;IAClC,eAAe,EAAE,mBAAmB,CAAC;IACrC,MAAM,EAAE,MAAM,QAAQ,CAAC;CACxB;AAID,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,GACjB,yBAAyB,GAAG,SAAS,CAEvC;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,yBAAyB,CAAC;IACnC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,YAAY,CAAC;IACxB,sBAAsB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,+BAA+B,CAAC,EAAE,CAChC,iBAAiB,EAAE,MAAM,KACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,qBAAqB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACzE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEhB"}
|
|
@@ -67,11 +67,11 @@ export function dispatchCursorSlackEnvelope(args) {
|
|
|
67
67
|
});
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
const message = Object.assign({ text: envelope.text, body: envelope.text, markdown: slackTextToMarkdown(envelope.text), ts: envelope.messageTs, threadTs: envelope.threadTs, channelId: envelope.channelId, teamId: envelope.slackTeamId }, (envelope.slackUserId === undefined
|
|
70
|
+
const message = Object.assign(Object.assign({ text: envelope.text, body: envelope.text, markdown: slackTextToMarkdown(envelope.text), ts: envelope.messageTs, threadTs: envelope.threadTs, channelId: envelope.channelId, teamId: envelope.slackTeamId }, (envelope.slackUserId === undefined
|
|
71
71
|
? {}
|
|
72
72
|
: {
|
|
73
73
|
author: { userId: envelope.slackUserId, isBot: false },
|
|
74
|
-
}));
|
|
74
|
+
})), { files: envelope.files });
|
|
75
75
|
// DMs to @Cursor route as direct messages; everything else (explicit
|
|
76
76
|
// `@Cursor <agent> …` mentions and claimed-thread replies) dispatches on
|
|
77
77
|
// the mention handler — a claimed-thread reply is addressed to the agent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAe3D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACpC,cAAc,CAEhB;AAED,qCAAqC;AACrC,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACpC,OAAO,CAET;AAED,6EAA6E;AAC7E,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAS7E;AA0BD,6EAA6E;AAC7E,wBAAgB,sBAAsB,CACpC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,EACnC,MAAM,CAAC,EAAE,iBAAiB,GACzB,mBAAmB,CAQrB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,EACnC,MAAM,CAAC,EAAE,iBAAiB,GACzB,mBAAmB,CAWrB;AAED,eAAO,MAAM,mBAAmB,EAAE,mBACR,CAAC;AAC3B,eAAO,MAAM,sBAAsB,EAAE,mBACX,CAAC;AAC3B,eAAO,MAAM,oBAAoB,EAAE,mBACL,CAAC;AAE/B,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mEAAmE;IACnE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,yBAA8B,GACtC,oBAAoB,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAe3D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACpC,cAAc,CAEhB;AAED,qCAAqC;AACrC,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACpC,OAAO,CAET;AAED,6EAA6E;AAC7E,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAS7E;AA0BD,6EAA6E;AAC7E,wBAAgB,sBAAsB,CACpC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,EACnC,MAAM,CAAC,EAAE,iBAAiB,GACzB,mBAAmB,CAQrB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,EACnC,MAAM,CAAC,EAAE,iBAAiB,GACzB,mBAAmB,CAWrB;AAED,eAAO,MAAM,mBAAmB,EAAE,mBACR,CAAC;AAC3B,eAAO,MAAM,sBAAsB,EAAE,mBACX,CAAC;AAC3B,eAAO,MAAM,oBAAoB,EAAE,mBACL,CAAC;AAE/B,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mEAAmE;IACnE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,yBAA8B,GACtC,oBAAoB,CAAC,iBAAiB,CAAC,CA8YzC"}
|
|
@@ -106,6 +106,21 @@ export function buildDefaultEvents(options = {}) {
|
|
|
106
106
|
const botToken = credentials === null || credentials === void 0 ? void 0 : credentials.botToken;
|
|
107
107
|
const getLog = (_b = options.getLog) !== null && _b !== void 0 ? _b : (() => defaultSlackLog);
|
|
108
108
|
const strategy = createStreamDeliveryStrategy({ botToken, getLog });
|
|
109
|
+
const clearWorkingStatus = (channelId, threadTs) => __awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
const result = yield setThreadStatus({
|
|
111
|
+
botToken,
|
|
112
|
+
channelId,
|
|
113
|
+
threadTs,
|
|
114
|
+
status: "",
|
|
115
|
+
});
|
|
116
|
+
if (!result.ok) {
|
|
117
|
+
getLog().warn("assistant.threads.setStatus not-ok", {
|
|
118
|
+
error: result.error,
|
|
119
|
+
channel: channelId,
|
|
120
|
+
thread_ts: threadTs,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
109
124
|
return {
|
|
110
125
|
"turn.started"(event, channel) {
|
|
111
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -297,14 +312,6 @@ export function buildDefaultEvents(options = {}) {
|
|
|
297
312
|
if (state.channelId === null || state.threadTs === null) {
|
|
298
313
|
return;
|
|
299
314
|
}
|
|
300
|
-
const clearStatus = () => __awaiter(this, void 0, void 0, function* () {
|
|
301
|
-
yield setThreadStatus({
|
|
302
|
-
botToken,
|
|
303
|
-
channelId: state.channelId,
|
|
304
|
-
threadTs: state.threadTs,
|
|
305
|
-
status: "",
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
315
|
// Empty final text: still close any open stream / clear the skeleton
|
|
309
316
|
// and clear typing.
|
|
310
317
|
if (event.data.text === "") {
|
|
@@ -316,7 +323,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
316
323
|
});
|
|
317
324
|
channel.state.streamTs = null;
|
|
318
325
|
}
|
|
319
|
-
yield
|
|
326
|
+
yield clearWorkingStatus(state.channelId, state.threadTs);
|
|
320
327
|
return;
|
|
321
328
|
}
|
|
322
329
|
const canStream = streaming &&
|
|
@@ -332,7 +339,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
332
339
|
sessionId: event.sessionId,
|
|
333
340
|
});
|
|
334
341
|
if (delivered) {
|
|
335
|
-
yield
|
|
342
|
+
yield clearWorkingStatus(state.channelId, state.threadTs);
|
|
336
343
|
return;
|
|
337
344
|
}
|
|
338
345
|
}
|
|
@@ -360,7 +367,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
360
367
|
session: event.sessionId,
|
|
361
368
|
});
|
|
362
369
|
}
|
|
363
|
-
yield
|
|
370
|
+
yield clearWorkingStatus(state.channelId, state.threadTs);
|
|
364
371
|
});
|
|
365
372
|
},
|
|
366
373
|
"turn.completed"(event, channel) {
|
|
@@ -373,6 +380,13 @@ export function buildDefaultEvents(options = {}) {
|
|
|
373
380
|
thread_ts: channel.state.threadTs,
|
|
374
381
|
});
|
|
375
382
|
yield strategy.cleanupOrphan({ channel });
|
|
383
|
+
// Always drop the assistant chip. message.completed already clears
|
|
384
|
+
// after a normal reply, but a tool-call-only finish (or a missed
|
|
385
|
+
// final assistant message) never hits that path — leaving
|
|
386
|
+
// "Working…" stuck until Slack expires it.
|
|
387
|
+
if (channel.state.channelId !== null && channel.state.threadTs !== null) {
|
|
388
|
+
yield clearWorkingStatus(channel.state.channelId, channel.state.threadTs);
|
|
389
|
+
}
|
|
376
390
|
if (suggestedPrompts.length === 0 ||
|
|
377
391
|
channel.state.channelId === null ||
|
|
378
392
|
channel.state.threadTs === null) {
|
|
@@ -426,12 +440,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
426
440
|
});
|
|
427
441
|
}
|
|
428
442
|
}
|
|
429
|
-
yield
|
|
430
|
-
botToken,
|
|
431
|
-
channelId: state.channelId,
|
|
432
|
-
threadTs: state.threadTs,
|
|
433
|
-
status: "",
|
|
434
|
-
});
|
|
443
|
+
yield clearWorkingStatus(state.channelId, state.threadTs);
|
|
435
444
|
});
|
|
436
445
|
},
|
|
437
446
|
};
|