@cursor/july 0.1.114 → 0.2.1
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/channels/slack/channel-watch.d.ts +19 -3
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +48 -9
- package/dist/channels/slack/inbound.d.ts +7 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +23 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +87 -8
- package/dist/channels/slack/types.d.ts +11 -12
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BqkJwOZ-.js → app.D23Y-7Tp.js} +4 -4
- package/dist/docs/assets/chunks/@localSearchIndexroot.CzCCM7N8.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BJAi2KiV.js → VPLocalSearchBox.CWBeTFRZ.js} +1 -1
- package/dist/docs/assets/chunks/{arc.BZpXTgvV.js → arc.DSF2O3pm.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.WYI-7F-Y.js → architectureDiagram-Q4EWVU46.J52Wzbkg.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.CZaUPpg0.js → baseUniq.CQS3LPCt.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.D6UES2pD.js → blockDiagram-DXYQGD6D.Dw339Gr5.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.cwebIe4i.js → c4Diagram-AHTNJAMY.BUdtOaRZ.js} +1 -1
- package/dist/docs/assets/chunks/channel.Bfu4df88.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.fVyFnjxg.js → chunk-4BX2VUAB.CuOrkEqk.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.BanufG1c.js → chunk-4TB4RGXK.BJNBcY7U.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.VaSMz5-2.js → chunk-55IACEB6.VJK5LAm_.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.CN2diZOM.js → chunk-EDXVE4YY.BYYLihvj.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.g4ivypu3.js → chunk-FMBD7UC4.CmoW8BXP.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.GZXKn9JJ.js → chunk-OYMX7WX6.DTGY4C-M.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.itXxJZCd.js → chunk-QZHKN3VN.Cg5n67vl.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.-rw2GfvX.js → chunk-YZCP3GAM.C3GR_ia5.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.DdfgtaWs.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.DdfgtaWs.js +1 -0
- package/dist/docs/assets/chunks/clone.rkmfti6d.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.CmaI5br0.js → cose-bilkent-S5V4N54A.BTRG8N3b.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.4wY9S4Kt.js → dagre-KV5264BT.Bob_bp_p.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.Pc3c0u9W.js → diagram-5BDNPKRD.ggPcs9uO.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CYrWz-nj.js → diagram-G4DWMVQ6.BP0qyJkp.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.Bgj5hukb.js → diagram-MMDJMWI5.B0X24UKr.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.DGMEXalS.js → diagram-TYMM5635.B4rXHFVt.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.GepTV9Im.js → erDiagram-SMLLAGMA._55Rt9oX.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.DVKywg3j.js → flowDiagram-DWJPFMVM.DGP4XvR5.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.C7qt9Mlo.js → ganttDiagram-T4ZO3ILL.BtXtkL4E.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.U30_r82P.js → gitGraphDiagram-UUTBAWPF.B9cPWblK.js} +1 -1
- package/dist/docs/assets/chunks/{graph.CyyMyAWv.js → graph.D8HzNexS.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.Dn9ACW3y.js → infoDiagram-42DDH7IO.Bw7CQUpi.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DlIdIGOA.js → ishikawaDiagram-UXIWVN3A.MwkzF6nQ.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.DZj4vy4E.js → journeyDiagram-VCZTEJTY.DIGFF-3C.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.Dl63eMUV.js → kanban-definition-6JOO6SKY.DhYef2BN.js} +1 -1
- package/dist/docs/assets/chunks/{layout.BLHZLWPH.js → layout.C0XUxuPi.js} +1 -1
- package/dist/docs/assets/chunks/{linear.aXKGKaNw.js → linear.BwNPpZex.js} +1 -1
- package/dist/docs/assets/chunks/{min.zWnFcpcc.js → min.CwAQdL7z.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.Qs4MQBea.js → mindmap-definition-QFDTVHPH.pWsSVLsP.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.BmPHgsk7.js → pieDiagram-DEJITSTG.BDJ3FbBy.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D5MQ3gwA.js → quadrantDiagram-34T5L4WZ.Co80izyB.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CkdUFrO7.js → requirementDiagram-MS252O5E.JveKw4yx.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.KZrljrAV.js → sankeyDiagram-XADWPNL6.B0A7adPi.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.XMoEW-Lx.js → sequenceDiagram-FGHM5R23.d6JZ5Hre.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BmTzePLj.js → stateDiagram-FHFEXIEX.DWnL0NQl.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.ZEetPk0E.js +1 -0
- package/dist/docs/assets/chunks/{theme.BfQzpxsg.js → theme.MJTLx0hh.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.Dug0oamp.js → timeline-definition-GMOUNBTQ.CFS7Ai4c.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.BOTHrEFu.js → vennDiagram-DHZGUBPP.CwSlnjCf.js} +1 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.3gurI8YA.js +162 -0
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.CoXKdfi6.js → wardleyDiagram-NUSXRM2D.B_8mvtjh.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.DXoSCjAW.js → xychartDiagram-5P7HB3ND.DtjU5H85.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.js → guides_slack.md.Bjw2r2gL.js} +5 -5
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.lean.js → guides_slack.md.Bjw2r2gL.lean.js} +1 -1
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.js +97 -0
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.lean.js +1 -0
- package/dist/docs/building-with-agents.html +35 -35
- package/dist/docs/deployment.html +35 -35
- package/dist/docs/evals.html +35 -35
- package/dist/docs/guides/agent-to-agent.html +35 -35
- package/dist/docs/guides/bitbucket.html +35 -35
- package/dist/docs/guides/cloud-agents.html +35 -35
- package/dist/docs/guides/convert-automation.html +35 -35
- package/dist/docs/guides/github.html +35 -35
- package/dist/docs/guides/gitlab.html +35 -35
- package/dist/docs/guides/grokbot-agents.html +35 -35
- package/dist/docs/guides/hooks.html +35 -35
- package/dist/docs/guides/improve.html +35 -35
- package/dist/docs/guides/jev.html +35 -35
- package/dist/docs/guides/mcp-oauth.html +35 -35
- package/dist/docs/guides/opentelemetry.html +35 -35
- package/dist/docs/guides/slack.html +39 -39
- package/dist/docs/guides/slack.md +16 -1
- package/dist/docs/guides/webhooks.html +35 -35
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +35 -35
- package/dist/docs/index.html +35 -35
- package/dist/docs/llms-full.txt +699 -752
- package/dist/docs/llms.txt +1 -1
- package/dist/docs/quickstart.html +35 -35
- package/dist/docs/reference/agent-config.html +35 -35
- package/dist/docs/reference/artifacts.html +35 -35
- package/dist/docs/reference/channels.html +35 -35
- package/dist/docs/reference/cli.html +127 -125
- package/dist/docs/reference/cli.md +685 -753
- package/dist/docs/reference/connections.html +35 -35
- package/dist/docs/reference/evals.html +35 -35
- package/dist/docs/reference/extensions.html +35 -35
- package/dist/docs/reference/hooks.html +35 -35
- package/dist/docs/reference/http-api.html +35 -35
- package/dist/docs/reference/instructions.html +35 -35
- package/dist/docs/reference/playground.html +35 -35
- package/dist/docs/reference/project-layout.html +35 -35
- package/dist/docs/reference/prompt.html +35 -35
- package/dist/docs/reference/schedules.html +35 -35
- package/dist/docs/reference/sessions.html +35 -35
- package/dist/docs/reference/skills.html +35 -35
- package/dist/docs/reference/subagents.html +35 -35
- package/dist/docs/reference/tools.html +35 -35
- package/dist/docs/templates/agentic-owners.html +35 -35
- package/dist/docs/templates/pr-autofixer.html +35 -35
- package/dist/docs/templates/security-reviewer.html +35 -35
- package/dist/docs/templates/thermo-quality-review.html +35 -35
- package/dist/docs/templates/thermo-review.html +35 -35
- package/dist/docs/templates/triage.html +35 -35
- package/dist/docs/troubleshooting.html +35 -35
- package/dist/files-backends/cursor-hosted.d.ts +11 -17
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +13 -41
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/artifacts-store.d.ts +11 -0
- package/dist/internal/artifacts-store.d.ts.map +1 -1
- package/dist/internal/artifacts-store.js +113 -18
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +9 -1
- package/dist/internal/cursor/cursor-api-transport.d.ts +37 -0
- package/dist/internal/cursor/cursor-api-transport.d.ts.map +1 -0
- package/dist/internal/cursor/cursor-api-transport.js +44 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts +21 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -1
- package/dist/internal/cursor/hosted-store-secrets.js +26 -0
- package/dist/internal/cursor/store-api-client.d.ts +82 -0
- package/dist/internal/cursor/store-api-client.d.ts.map +1 -0
- package/dist/internal/cursor/store-api-client.js +227 -0
- package/dist/internal/deploy-client.d.ts +6 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/deploy-manifest.d.ts +8 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +7 -1
- package/dist/internal/discovery/agent-config.d.ts +3 -1
- package/dist/internal/discovery/agent-config.d.ts.map +1 -1
- package/dist/internal/discovery/agent-config.js +7 -4
- package/dist/internal/framework-storage-selection.d.ts +1 -1
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/platform-timers.d.ts.map +1 -1
- package/dist/internal/platform-timers.js +20 -2
- package/dist/internal/reminder-runner.d.ts +79 -1
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +287 -46
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +7 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +13 -15
- package/dist/internal/store-api-protocol.d.ts +134 -0
- package/dist/internal/store-api-protocol.d.ts.map +1 -0
- package/dist/internal/store-api-protocol.js +126 -0
- package/dist/memory.d.ts +49 -10
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +193 -50
- package/dist/playground/assets/{index-CrMWlgUU.js → index-Cs0MKsv4.js} +30 -30
- package/dist/playground/assets/index-DLwnR9ys.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/reminders.d.ts +1 -1
- package/dist/reminders.d.ts.map +1 -1
- package/dist/types.d.ts +44 -10
- package/dist/types.d.ts.map +1 -1
- package/docs/guides/slack.md +16 -1
- package/docs/reference/cli.md +686 -754
- package/package.json +1 -1
- package/skills/setup-slack/SKILL.md +1 -1
- package/src/channels/slack/channel-watch.ts +57 -8
- package/src/channels/slack/inbound.ts +24 -0
- package/src/channels/slack/slack-channel.ts +127 -4
- package/src/channels/slack/types.ts +11 -12
- package/src/files-backends/cursor-hosted.ts +31 -68
- package/src/index.ts +1 -0
- package/src/internal/artifacts-store.ts +131 -25
- package/src/internal/cli-deploy.ts +12 -1
- package/src/internal/cursor/cursor-api-transport.ts +73 -0
- package/src/internal/cursor/hosted-store-secrets.ts +35 -0
- package/src/internal/cursor/store-api-client.ts +360 -0
- package/src/internal/deploy-client.ts +9 -0
- package/src/internal/deploy-manifest.ts +15 -0
- package/src/internal/discovery/agent-config.ts +8 -6
- package/src/internal/framework-storage-selection.ts +1 -1
- package/src/internal/platform-timers.ts +24 -2
- package/src/internal/reminder-runner.ts +454 -66
- package/src/internal/server.ts +8 -0
- package/src/internal/session-engine.ts +17 -22
- package/src/internal/store-api-protocol.ts +222 -0
- package/src/memory.ts +240 -59
- package/src/reminders.ts +1 -0
- package/src/types.ts +47 -10
- package/dist/docs/assets/chunks/@localSearchIndexroot.BnSgidYE.js +0 -1
- package/dist/docs/assets/chunks/channel.DdM5EfNW.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/clone.wSOICb_f.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.Cu5X28zZ.js +0 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.DXy2i1LS.js +0 -162
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.js +0 -95
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.lean.js +0 -1
- package/dist/playground/assets/index-C61EWMBK.css +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -123,7 +123,7 @@ export default slackChannel({
|
|
|
123
123
|
envPrefix: "JENNY",
|
|
124
124
|
engagement: {
|
|
125
125
|
channelPosts: {
|
|
126
|
-
allow: ["#alerts"], //
|
|
126
|
+
allow: ["C0123ABCDEF", "#alerts"], // ≥1 channel id required, ≤10 ids
|
|
127
127
|
posts: "top-level",
|
|
128
128
|
},
|
|
129
129
|
},
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Opt-in channel watch: dispatch on posts in allowlisted channels.
|
|
3
3
|
*
|
|
4
4
|
* Filtering rules (the anti-slop guarantees):
|
|
5
|
-
* - Only configured channels are watched
|
|
5
|
+
* - Only configured channels are watched. The allowlist is finite: watching
|
|
6
|
+
* every channel the bot is in is not expressible.
|
|
6
7
|
* - Top-level posts only by default; thread replies never dispatch unless
|
|
7
8
|
* `posts: "all"` is configured.
|
|
8
9
|
* - Posts that @mention the bot are skipped here (the `app_mention` path
|
|
@@ -21,21 +22,69 @@ import type { SlackChannelPostsOptions, SlackMessage } from "./types.js";
|
|
|
21
22
|
|
|
22
23
|
const CHANNEL_ID_PATTERN = /^[CG][A-Z0-9]+$/;
|
|
23
24
|
|
|
24
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Channel-watch allowlist contract, mirrored by the control plane's
|
|
27
|
+
* deploy-time validation (proto posture: both sides validate
|
|
28
|
+
* independently). Ids are required because on Cursor-managed hosting they
|
|
29
|
+
* become channel-scoped subscription edges — the control plane drops
|
|
30
|
+
* channel posts outside the id set before any compute wakes, and it cannot
|
|
31
|
+
* resolve `#names`.
|
|
32
|
+
*/
|
|
33
|
+
export const CHANNEL_POSTS_MAX_CHANNEL_IDS = 10;
|
|
34
|
+
|
|
35
|
+
/** The channel-id (`C…`/`G…`) entries of an allowlist, deduped. */
|
|
36
|
+
export function channelPostIdEntries(entries: readonly string[]): string[] {
|
|
37
|
+
const ids = new Set<string>();
|
|
38
|
+
for (const raw of entries) {
|
|
39
|
+
const entry = raw.trim();
|
|
40
|
+
if (CHANNEL_ID_PATTERN.test(entry)) {
|
|
41
|
+
ids.add(entry);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [...ids];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validate `channelPosts.allow` at definition time. Returns an actionable
|
|
49
|
+
* error string (to be prefixed with the option path), or undefined.
|
|
50
|
+
*/
|
|
51
|
+
export function validateChannelPostsAllow(
|
|
52
|
+
entries: readonly string[]
|
|
53
|
+
): string | undefined {
|
|
54
|
+
if (entries.some(entry => entry.trim() === "*")) {
|
|
55
|
+
return (
|
|
56
|
+
'no longer supports "*": list the channels to watch by id (C…/G…), ' +
|
|
57
|
+
`up to ${CHANNEL_POSTS_MAX_CHANNEL_IDS} channels.`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
const ids = channelPostIdEntries(entries);
|
|
61
|
+
if (ids.length === 0) {
|
|
62
|
+
return (
|
|
63
|
+
"must include at least one channel id (C…/G…). Ids define the " +
|
|
64
|
+
"watched set on Cursor-managed hosting; `#name` entries alone are " +
|
|
65
|
+
"not enough."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (ids.length > CHANNEL_POSTS_MAX_CHANNEL_IDS) {
|
|
69
|
+
return `lists ${ids.length} channel ids; the maximum is ${CHANNEL_POSTS_MAX_CHANNEL_IDS}.`;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Allowlist over channel ids and `#names` (names resolve lazily). */
|
|
25
75
|
export class SlackChannelAllowlist {
|
|
26
76
|
private readonly ids = new Set<string>();
|
|
27
77
|
private readonly names = new Set<string>();
|
|
28
|
-
private all = false;
|
|
29
78
|
|
|
30
79
|
constructor(entries: readonly string[]) {
|
|
31
80
|
for (const raw of entries) {
|
|
32
81
|
const entry = raw.trim();
|
|
33
|
-
|
|
82
|
+
// "*" is rejected at definition time (validateChannelPostsAllow);
|
|
83
|
+
// ignore it here so a stale config degrades to its explicit entries.
|
|
84
|
+
if (entry === "" || entry === "*") {
|
|
34
85
|
continue;
|
|
35
86
|
}
|
|
36
|
-
if (entry
|
|
37
|
-
this.all = true;
|
|
38
|
-
} else if (entry.startsWith("#")) {
|
|
87
|
+
if (entry.startsWith("#")) {
|
|
39
88
|
this.names.add(entry.slice(1).toLowerCase());
|
|
40
89
|
} else if (CHANNEL_ID_PATTERN.test(entry)) {
|
|
41
90
|
this.ids.add(entry);
|
|
@@ -47,7 +96,7 @@ export class SlackChannelAllowlist {
|
|
|
47
96
|
}
|
|
48
97
|
|
|
49
98
|
matches(channelId: string): boolean {
|
|
50
|
-
return this.
|
|
99
|
+
return this.ids.has(channelId);
|
|
51
100
|
}
|
|
52
101
|
|
|
53
102
|
unresolvedNames(): string[] {
|
|
@@ -218,6 +218,30 @@ export function parseAssistantThreadStarted(
|
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* The receiving app's own bot user id from an Events API envelope. Slack
|
|
223
|
+
* stamps `authorizations[]` on every `event_callback` with the installed
|
|
224
|
+
* bot user the delivery is for, so a hosted guest learns its identity from
|
|
225
|
+
* the verified body without an `auth.test` round trip.
|
|
226
|
+
*/
|
|
227
|
+
export function parseEventBodyBotUserId(body: unknown): string | undefined {
|
|
228
|
+
const root = asRecord(body);
|
|
229
|
+
if (root === null || root.type !== "event_callback") {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
if (!Array.isArray(root.authorizations)) {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
for (const entry of root.authorizations) {
|
|
236
|
+
const authorization = asRecord(entry);
|
|
237
|
+
const userId = asString(authorization?.user_id);
|
|
238
|
+
if (userId !== undefined && userId !== "") {
|
|
239
|
+
return userId;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
221
245
|
/**
|
|
222
246
|
* Parse DM / IM messages. More generous than a strict channel_type check:
|
|
223
247
|
* accepts `channel_type === "im"` or channel ids starting with `D`, and
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
} from "../../internal/continuation-identity.js";
|
|
26
26
|
import { AGENT_SERVE_GENERATION_ENV_VAR } from "../../internal/cursor-relay-core.js";
|
|
27
27
|
import { attachHostedAdmissionAdapter } from "../../internal/hosted-admission-adapter.js";
|
|
28
|
+
import type { HostedAdmissionPlatformHandoff } from "../../internal/hosted-delivery-protocol.js";
|
|
28
29
|
import type {
|
|
29
30
|
ArtifactsApi,
|
|
30
31
|
ChannelDefinition,
|
|
31
32
|
ChannelEventHandlers,
|
|
33
|
+
ChannelHandlerArgs,
|
|
32
34
|
HostContext,
|
|
33
35
|
JsonValue,
|
|
34
36
|
ReceiveInput,
|
|
@@ -46,6 +48,7 @@ import {
|
|
|
46
48
|
createChannelPostWatcher,
|
|
47
49
|
resolveChannelNames,
|
|
48
50
|
SlackChannelAllowlist,
|
|
51
|
+
validateChannelPostsAllow,
|
|
49
52
|
} from "./channel-watch.js";
|
|
50
53
|
import {
|
|
51
54
|
credentialsFromEnv,
|
|
@@ -68,6 +71,10 @@ import {
|
|
|
68
71
|
slackWakeChannelState,
|
|
69
72
|
} from "./dispatch.js";
|
|
70
73
|
import { createEventIdDedupe, type EventIdDedupe } from "./event-id-dedupe.js";
|
|
74
|
+
import {
|
|
75
|
+
parseChannelMessageEvent,
|
|
76
|
+
parseEventBodyBotUserId,
|
|
77
|
+
} from "./inbound.js";
|
|
71
78
|
import {
|
|
72
79
|
dispatchBlockAction,
|
|
73
80
|
dispatchInteractiveFromPayload,
|
|
@@ -181,10 +188,10 @@ export function slackChannel(
|
|
|
181
188
|
const followUpStatus = options.followUpStatus ?? !silent;
|
|
182
189
|
const channelPosts = engagement.channelPosts;
|
|
183
190
|
if (channelPosts !== undefined) {
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
191
|
+
const allowError = validateChannelPostsAllow(channelPosts.allow);
|
|
192
|
+
if (allowError !== undefined) {
|
|
186
193
|
throw new Error(
|
|
187
|
-
|
|
194
|
+
`slackChannel engagement.channelPosts.allow ${allowError}`
|
|
188
195
|
);
|
|
189
196
|
}
|
|
190
197
|
}
|
|
@@ -245,6 +252,113 @@ export function slackChannel(
|
|
|
245
252
|
let channelWatch: ChannelPostWatcher | undefined;
|
|
246
253
|
let botMentionGate: SlackBotMentionGate | undefined;
|
|
247
254
|
|
|
255
|
+
// Hosted admission never runs the Socket Mode branch of `onStart`, so the
|
|
256
|
+
// channel watch is built per delivery there. The allowlist and its `#name`
|
|
257
|
+
// resolution are shared across the pod; the bot's identity comes from the
|
|
258
|
+
// verified envelope.
|
|
259
|
+
let hostedAllowlist: SlackChannelAllowlist | undefined;
|
|
260
|
+
let hostedAllowlistReady: Promise<void> | undefined;
|
|
261
|
+
|
|
262
|
+
async function resolveHostedAllowlistNames(
|
|
263
|
+
allowlist: SlackChannelAllowlist
|
|
264
|
+
): Promise<void> {
|
|
265
|
+
const names = allowlist.unresolvedNames();
|
|
266
|
+
if (names.length === 0) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const botToken = await tryResolveBotToken(credentials);
|
|
271
|
+
if (botToken === undefined) {
|
|
272
|
+
getLog().error("channel watch setup degraded", {
|
|
273
|
+
error: "no bot token; #name entries stay unresolved",
|
|
274
|
+
});
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const { WebClient } = await import("@slack/web-api");
|
|
278
|
+
allowlist.applyResolvedNames(
|
|
279
|
+
await resolveChannelNames(new WebClient(botToken), names, getLog())
|
|
280
|
+
);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
getLog().error("channel watch setup degraded", {
|
|
283
|
+
error: error instanceof Error ? error.message : String(error),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Only a channel post needs the watcher, so mentions and DMs never wait on
|
|
290
|
+
* it, and a channel already matched by id never waits on `#name` resolution.
|
|
291
|
+
*/
|
|
292
|
+
async function hostedChannelWatch(
|
|
293
|
+
payload: unknown,
|
|
294
|
+
args: ChannelHandlerArgs,
|
|
295
|
+
platformHandoff: HostedAdmissionPlatformHandoff | undefined
|
|
296
|
+
): Promise<ChannelPostWatcher | undefined> {
|
|
297
|
+
if (channelPosts === undefined) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
const channelEvent = parseChannelMessageEvent(payload, {
|
|
301
|
+
includeBotAuthored: true,
|
|
302
|
+
});
|
|
303
|
+
if (channelEvent === null || channelEvent.kind === "deleted") {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
hostedAllowlist ??= new SlackChannelAllowlist(channelPosts.allow);
|
|
307
|
+
if (
|
|
308
|
+
!hostedAllowlist.matches(channelEvent.message.channelId) &&
|
|
309
|
+
hostedAllowlist.unresolvedNames().length > 0
|
|
310
|
+
) {
|
|
311
|
+
hostedAllowlistReady ??= resolveHostedAllowlistNames(hostedAllowlist);
|
|
312
|
+
await hostedAllowlistReady;
|
|
313
|
+
}
|
|
314
|
+
const botUserId = parseEventBodyBotUserId(payload);
|
|
315
|
+
return createChannelPostWatcher({
|
|
316
|
+
// Admission answers before a debounce timer could fire; edits arrive
|
|
317
|
+
// as their own deliveries and the edge drops them.
|
|
318
|
+
options: { ...channelPosts, debounceMs: 0 },
|
|
319
|
+
allowlist: hostedAllowlist,
|
|
320
|
+
getBotUserId: () => botUserId,
|
|
321
|
+
log: getLog(),
|
|
322
|
+
dispatch: (message, eventId) => {
|
|
323
|
+
args.waitUntil(
|
|
324
|
+
dispatchInboundMessage({
|
|
325
|
+
kind: "channel_post",
|
|
326
|
+
message,
|
|
327
|
+
handler: onChannelPost,
|
|
328
|
+
propagateHandlerErrors: true,
|
|
329
|
+
send: args.send,
|
|
330
|
+
credentials,
|
|
331
|
+
host: args.host,
|
|
332
|
+
artifacts: args.artifacts,
|
|
333
|
+
log: getLog(),
|
|
334
|
+
evalCommandsEnabled,
|
|
335
|
+
followUpStatus,
|
|
336
|
+
ack: reply.ack,
|
|
337
|
+
blockExternals,
|
|
338
|
+
continuation: options.continuation,
|
|
339
|
+
...(args.hasContinuationSession === undefined
|
|
340
|
+
? {}
|
|
341
|
+
: { hasContinuationSession: args.hasContinuationSession }),
|
|
342
|
+
...(args.isContinuationBusy === undefined
|
|
343
|
+
? {}
|
|
344
|
+
: { isContinuationBusy: args.isContinuationBusy }),
|
|
345
|
+
...(args.getContinuationLastBotMessageTs === undefined
|
|
346
|
+
? {}
|
|
347
|
+
: {
|
|
348
|
+
getContinuationLastBotMessageTs:
|
|
349
|
+
args.getContinuationLastBotMessageTs,
|
|
350
|
+
}),
|
|
351
|
+
...(args.interruptContinuation === undefined
|
|
352
|
+
? {}
|
|
353
|
+
: { interruptContinuation: args.interruptContinuation }),
|
|
354
|
+
...(eventId === undefined ? {} : { eventId }),
|
|
355
|
+
...(platformHandoff === undefined ? {} : { platformHandoff }),
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
248
362
|
function inboundDeps(args: {
|
|
249
363
|
send: SendMessageFn;
|
|
250
364
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
@@ -260,7 +374,10 @@ export function slackChannel(
|
|
|
260
374
|
) => Promise<string | undefined>;
|
|
261
375
|
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
262
376
|
platformHandoff?: SlackInboundDispatchDeps["platformHandoff"];
|
|
377
|
+
/** Per-delivery watcher (hosted); the Socket Mode watcher otherwise. */
|
|
378
|
+
channelWatch?: ChannelPostWatcher;
|
|
263
379
|
}): SlackInboundDispatchDeps {
|
|
380
|
+
const watch = args.channelWatch ?? channelWatch;
|
|
264
381
|
return {
|
|
265
382
|
send: args.send,
|
|
266
383
|
continuation: options.continuation,
|
|
@@ -299,7 +416,7 @@ export function slackChannel(
|
|
|
299
416
|
...(args.interruptContinuation === undefined
|
|
300
417
|
? {}
|
|
301
418
|
: { interruptContinuation: args.interruptContinuation }),
|
|
302
|
-
...(
|
|
419
|
+
...(watch === undefined ? {} : { channelWatch: watch }),
|
|
303
420
|
...(botMentionGate === undefined ? {} : { botMentionGate }),
|
|
304
421
|
suggestedPrompts: options.suggestedPrompts,
|
|
305
422
|
suggestedPromptsTitle: options.suggestedPromptsTitle,
|
|
@@ -661,6 +778,11 @@ export function slackChannel(
|
|
|
661
778
|
// would otherwise swallow the control plane's own retry of a delivery
|
|
662
779
|
// that failed after the id was marked handled.
|
|
663
780
|
dispatch: async ({ payload, args, platformHandoff }) => {
|
|
781
|
+
const hostedWatch = await hostedChannelWatch(
|
|
782
|
+
payload,
|
|
783
|
+
args,
|
|
784
|
+
platformHandoff
|
|
785
|
+
);
|
|
664
786
|
const dispatched = dispatchInboundFromEventBody(
|
|
665
787
|
payload,
|
|
666
788
|
inboundDeps({
|
|
@@ -675,6 +797,7 @@ export function slackChannel(
|
|
|
675
797
|
getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
|
|
676
798
|
interruptContinuation: args.interruptContinuation,
|
|
677
799
|
...(platformHandoff === undefined ? {} : { platformHandoff }),
|
|
800
|
+
...(hostedWatch === undefined ? {} : { channelWatch: hostedWatch }),
|
|
678
801
|
})
|
|
679
802
|
);
|
|
680
803
|
return skipped(dispatched ? "not_engaged" : "not_dispatchable");
|
|
@@ -517,28 +517,27 @@ export type SlackBlockActionHandler = (
|
|
|
517
517
|
|
|
518
518
|
/**
|
|
519
519
|
* Opt-in channel watch: dispatch on posts in configured channels without an
|
|
520
|
-
* @mention.
|
|
520
|
+
* @mention. The watched set is a finite list — mentions are global (any
|
|
521
|
+
* channel the bot is in), but listening without a mention names its
|
|
522
|
+
* channels.
|
|
521
523
|
*/
|
|
522
524
|
export interface SlackChannelPostsOptions {
|
|
523
525
|
/**
|
|
524
|
-
* Channels to watch
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
526
|
+
* Channels to watch. Must include at least one channel id (`C…` / `G…`)
|
|
527
|
+
* and at most 10 distinct ids; `"*"` is a definition error. `#name`
|
|
528
|
+
* entries may accompany ids (resolved via `conversations.list` on Socket
|
|
529
|
+
* Mode), but on Cursor-managed hosting the id entries alone define the
|
|
530
|
+
* watched set: each id becomes a channel-scoped subscription, and the
|
|
531
|
+
* control plane drops channel posts outside that set before any compute
|
|
532
|
+
* wakes. The bot must be a member of each watched channel to receive its
|
|
528
533
|
* messages.
|
|
529
|
-
*
|
|
530
|
-
* `"*"` suits agents whose handler decides per message (a thread the agent
|
|
531
|
-
* is already in, say) rather than per channel. Every delivered message then
|
|
532
|
-
* reaches {@link SlackChannelOptions.onChannelPost}, and each one costs a
|
|
533
|
-
* `users.info` external-sender check first unless
|
|
534
|
-
* {@link SlackAccessPolicy.blockExternals} is off.
|
|
535
534
|
*/
|
|
536
535
|
allow: string[];
|
|
537
536
|
/**
|
|
538
537
|
* Which posts dispatch. `"top-level"` (default) fires only on new
|
|
539
538
|
* channel posts — never on replies inside other people's threads, so the
|
|
540
539
|
* agent can take fresh intake but cannot barge into conversations.
|
|
541
|
-
* `"all"` also dispatches thread replies
|
|
540
|
+
* `"all"` also dispatches thread replies in allowlisted channels.
|
|
542
541
|
*/
|
|
543
542
|
posts?: "top-level" | "all";
|
|
544
543
|
/**
|
|
@@ -57,19 +57,19 @@ import {
|
|
|
57
57
|
type FileSinkPutResult,
|
|
58
58
|
} from "../files.js";
|
|
59
59
|
import {
|
|
60
|
-
|
|
60
|
+
type CursorApiTransportOptions,
|
|
61
|
+
resolveCursorApiBaseUrl,
|
|
62
|
+
resolveCursorApiFetch,
|
|
63
|
+
resolveCursorApiKey,
|
|
64
|
+
} from "../internal/cursor/cursor-api-transport.js";
|
|
65
|
+
import {
|
|
61
66
|
resolveDeploymentStoreSourceIdSync,
|
|
62
67
|
resolveFrameworkStoreSourceIdSync,
|
|
63
68
|
resolveStoreProtocolSync,
|
|
69
|
+
storeProtocolEnablesFactoryFlush,
|
|
64
70
|
} from "../internal/cursor/hosted-store-secrets.js";
|
|
65
71
|
import { createAgentStorePresignedUrlValidatorForBackend } from "./agent-store-presigned-url.js";
|
|
66
72
|
|
|
67
|
-
/**
|
|
68
|
-
* Same default as the hosted storage backend, inlined so this entrypoint does
|
|
69
|
-
* not import CLI code.
|
|
70
|
-
*/
|
|
71
|
-
const DEFAULT_CURSOR_EXTERNAL_API_URL = "https://api.cursor.com";
|
|
72
|
-
|
|
73
73
|
const AGENT_SERVE_FILES_PATH = "/v0/agent-serve-files";
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -156,18 +156,12 @@ export function isCursorUserStoreFilesAvailable(
|
|
|
156
156
|
return key !== undefined && key !== "";
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
* Lazy credential, re-resolved on every call and preferred over
|
|
166
|
-
* {@link apiKey} — hosted freeze snapshots listen unsigned and bind the
|
|
167
|
-
* key file after serve start. Kept separate so `apiKey` stays a plain
|
|
168
|
-
* string.
|
|
169
|
-
*/
|
|
170
|
-
resolveApiKey?: () => string | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Base URL / credential / fetch resolution is the shared
|
|
161
|
+
* {@link CursorApiTransportOptions} (`internal/cursor/cursor-api-transport.ts`),
|
|
162
|
+
* so this sink and the domain-lane store API client resolve identically.
|
|
163
|
+
*/
|
|
164
|
+
export interface CursorHostedFilesOptions extends CursorApiTransportOptions {
|
|
171
165
|
/** File store to address (default: `AGENT_SERVE_STORE_SOURCE_ID`). */
|
|
172
166
|
storeSourceId?: string;
|
|
173
167
|
/**
|
|
@@ -178,13 +172,12 @@ export interface CursorHostedFilesOptions {
|
|
|
178
172
|
resolveStoreSourceId?: () => string | undefined;
|
|
179
173
|
/**
|
|
180
174
|
* Lazy store protocol pin (default: env, then the task-bound file). When it
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
175
|
+
* enables the factory flush wire (`factory-flush-v1`, or the superset
|
|
176
|
+
* domain-API pin `factory-api-v1`) and the source id maps to a deployment
|
|
177
|
+
* store role, requests ride the factory store API instead of
|
|
178
|
+
* `/v0/agent-serve-files`. Any other value keeps `/v0`.
|
|
184
179
|
*/
|
|
185
180
|
resolveStoreProtocol?: () => string | undefined;
|
|
186
|
-
/** Test seam; defaults to global fetch. */
|
|
187
|
-
fetch?: typeof fetch;
|
|
188
181
|
}
|
|
189
182
|
|
|
190
183
|
/**
|
|
@@ -295,7 +288,7 @@ export function cursorHostedFiles(
|
|
|
295
288
|
const sourceId = resolveStoreSourceId(options);
|
|
296
289
|
const protocol =
|
|
297
290
|
options.resolveStoreProtocol?.() ?? resolveStoreProtocolSync();
|
|
298
|
-
if (protocol
|
|
291
|
+
if (storeProtocolEnablesFactoryFlush(protocol)) {
|
|
299
292
|
// The factory API addresses stores by role, so map the pinned source id
|
|
300
293
|
// back to the role it was pinned from. A source id matching neither (a
|
|
301
294
|
// local-dev override) has no role there and stays on `/v0`, as does any
|
|
@@ -567,7 +560,7 @@ export function cursorHostedFiles(
|
|
|
567
560
|
};
|
|
568
561
|
}
|
|
569
562
|
try {
|
|
570
|
-
const response = await
|
|
563
|
+
const response = await resolveCursorApiFetch(options)(
|
|
571
564
|
assertPresignedUrlSafe(options, instruction.url),
|
|
572
565
|
{
|
|
573
566
|
method: "PUT",
|
|
@@ -818,7 +811,7 @@ export function cursorHostedFiles(
|
|
|
818
811
|
if (url === undefined) {
|
|
819
812
|
return undefined;
|
|
820
813
|
}
|
|
821
|
-
const response = await
|
|
814
|
+
const response = await resolveCursorApiFetch(options)(
|
|
822
815
|
assertPresignedUrlSafe(options, url),
|
|
823
816
|
{
|
|
824
817
|
method: "GET",
|
|
@@ -992,9 +985,9 @@ function assertPresignedUrlSafe(
|
|
|
992
985
|
return url.toString();
|
|
993
986
|
}
|
|
994
987
|
try {
|
|
995
|
-
createAgentStorePresignedUrlValidatorForBackend(
|
|
996
|
-
|
|
997
|
-
);
|
|
988
|
+
createAgentStorePresignedUrlValidatorForBackend(
|
|
989
|
+
resolveCursorApiBaseUrl(options)
|
|
990
|
+
)(url);
|
|
998
991
|
} catch (error) {
|
|
999
992
|
throw new Error(
|
|
1000
993
|
`cursorHostedFiles: refused presigned URL: ${
|
|
@@ -1005,14 +998,6 @@ function assertPresignedUrlSafe(
|
|
|
1005
998
|
return url.toString();
|
|
1006
999
|
}
|
|
1007
1000
|
|
|
1008
|
-
function fetchImpl(options: CursorHostedFilesOptions): typeof fetch {
|
|
1009
|
-
const impl = options.fetch ?? globalThis.fetch;
|
|
1010
|
-
if (typeof impl !== "function") {
|
|
1011
|
-
throw new Error("cursorHostedFiles requires fetch");
|
|
1012
|
-
}
|
|
1013
|
-
return impl;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
1001
|
/**
|
|
1017
1002
|
* The file store this engine's deployment owns. Every request names it, so
|
|
1018
1003
|
* the server resolves the store row and this process never handles a store id.
|
|
@@ -1034,17 +1019,6 @@ function resolveStoreSourceId(options: CursorHostedFilesOptions): string {
|
|
|
1034
1019
|
return id;
|
|
1035
1020
|
}
|
|
1036
1021
|
|
|
1037
|
-
function resolveApiKey(options: CursorHostedFilesOptions): string {
|
|
1038
|
-
const configured = options.resolveApiKey?.() ?? options.apiKey;
|
|
1039
|
-
const key = (configured ?? process.env.CURSOR_API_KEY)?.trim();
|
|
1040
|
-
if (key === undefined || key === "") {
|
|
1041
|
-
throw new Error(
|
|
1042
|
-
"cursorHostedFiles requires CURSOR_API_KEY (deployment pod credential on Cursor hosting)"
|
|
1043
|
-
);
|
|
1044
|
-
}
|
|
1045
|
-
return key;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
1022
|
const DEV_PRESIGN_HOSTS: ReadonlySet<string> = new Set(
|
|
1049
1023
|
(process.env.CURSOR_HOSTED_FILES_DEV_PRESIGN_HOSTS ?? "")
|
|
1050
1024
|
.split(",")
|
|
@@ -1052,19 +1026,6 @@ const DEV_PRESIGN_HOSTS: ReadonlySet<string> = new Set(
|
|
|
1052
1026
|
.filter(host => host.length > 0)
|
|
1053
1027
|
);
|
|
1054
1028
|
|
|
1055
|
-
function resolveBaseUrl(options: CursorHostedFilesOptions): string {
|
|
1056
|
-
return trimTrailingSlash(
|
|
1057
|
-
options.baseUrl ??
|
|
1058
|
-
process.env.CURSOR_API_BASE_URL ??
|
|
1059
|
-
DEFAULT_CURSOR_EXTERNAL_API_URL
|
|
1060
|
-
);
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
function trimTrailingSlash(raw: string): string {
|
|
1064
|
-
const trimmed = raw.trim();
|
|
1065
|
-
return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
1029
|
/**
|
|
1069
1030
|
* Public agent-serve-files API call. The pod credential is the whole authorization:
|
|
1070
1031
|
* the API forwards this caller's identity to the store service, which checks it
|
|
@@ -1077,7 +1038,7 @@ async function storePost<T>(
|
|
|
1077
1038
|
): Promise<T> {
|
|
1078
1039
|
return await postJson<T>(
|
|
1079
1040
|
options,
|
|
1080
|
-
`${
|
|
1041
|
+
`${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`,
|
|
1081
1042
|
body
|
|
1082
1043
|
);
|
|
1083
1044
|
}
|
|
@@ -1088,7 +1049,7 @@ async function storeGet<T>(
|
|
|
1088
1049
|
): Promise<T> {
|
|
1089
1050
|
return await sendJson<T>(
|
|
1090
1051
|
options,
|
|
1091
|
-
`${
|
|
1052
|
+
`${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`,
|
|
1092
1053
|
"GET"
|
|
1093
1054
|
);
|
|
1094
1055
|
}
|
|
@@ -1096,7 +1057,9 @@ async function storeGet<T>(
|
|
|
1096
1057
|
/**
|
|
1097
1058
|
* Factory store API call — same base URL and pod credential as
|
|
1098
1059
|
* {@link storePost}, different path family. The server resolves the
|
|
1099
|
-
* deployment (and the addressed store role) from the credential.
|
|
1060
|
+
* deployment (and the addressed store role) from the credential. The
|
|
1061
|
+
* domain-call lane one path family deeper is NOT here: it belongs to the
|
|
1062
|
+
* store API client (`../internal/cursor/store-api-client.ts`).
|
|
1100
1063
|
*/
|
|
1101
1064
|
async function flushPost<T>(
|
|
1102
1065
|
options: CursorHostedFilesOptions,
|
|
@@ -1105,7 +1068,7 @@ async function flushPost<T>(
|
|
|
1105
1068
|
): Promise<T> {
|
|
1106
1069
|
return await postJson<T>(
|
|
1107
1070
|
options,
|
|
1108
|
-
`${
|
|
1071
|
+
`${resolveCursorApiBaseUrl(options)}${AGENTSDK_STORE_PATH}${path}`,
|
|
1109
1072
|
body
|
|
1110
1073
|
);
|
|
1111
1074
|
}
|
|
@@ -1124,10 +1087,10 @@ async function sendJson<T>(
|
|
|
1124
1087
|
method: "GET" | "POST",
|
|
1125
1088
|
body?: Record<string, unknown>
|
|
1126
1089
|
): Promise<T> {
|
|
1127
|
-
const response = await
|
|
1090
|
+
const response = await resolveCursorApiFetch(options)(url, {
|
|
1128
1091
|
method,
|
|
1129
1092
|
headers: {
|
|
1130
|
-
Authorization: `Bearer ${
|
|
1093
|
+
Authorization: `Bearer ${resolveCursorApiKey(options)}`,
|
|
1131
1094
|
...(body === undefined ? {} : { "Content-Type": "application/json" }),
|
|
1132
1095
|
},
|
|
1133
1096
|
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|