@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
|
@@ -117,6 +117,12 @@ export interface DeployCliOptions {
|
|
|
117
117
|
err?: (text: string) => void;
|
|
118
118
|
/** `secrets set` value input (hidden prompt on a TTY, lines otherwise). */
|
|
119
119
|
stdin?: SecretInputStream;
|
|
120
|
+
/**
|
|
121
|
+
* Opt in to `NAME=VALUE` argv secrets. Default is names only (hidden
|
|
122
|
+
* prompt / stdin) so values never land in shell history or agent-captured
|
|
123
|
+
* terminals.
|
|
124
|
+
*/
|
|
125
|
+
fromArgv?: boolean;
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
/** Minimal stdin surface `secrets set` reads values from (test-injectable). */
|
|
@@ -1143,8 +1149,9 @@ export async function cmdSecretsSet(
|
|
|
1143
1149
|
const usageErr = options.err ?? ((t: string) => void process.stderr.write(t));
|
|
1144
1150
|
if (slug === undefined || slug === "" || specs.length === 0) {
|
|
1145
1151
|
usageErr(
|
|
1146
|
-
`Usage: ${CLI} secrets set <slug> NAME
|
|
1147
|
-
`
|
|
1152
|
+
`Usage: ${CLI} secrets set <slug> NAME [NAME2 ...] [--team <id>] [--json]\n` +
|
|
1153
|
+
` Enter values at the hidden prompt, or pipe one line per NAME.\n` +
|
|
1154
|
+
` Opt-in (leaks into argv / agent terminals): NAME=VALUE … --from-argv\n`
|
|
1148
1155
|
);
|
|
1149
1156
|
return 1;
|
|
1150
1157
|
}
|
|
@@ -1162,9 +1169,20 @@ export async function cmdSecretsSet(
|
|
|
1162
1169
|
}
|
|
1163
1170
|
parsed.push(eq === -1 ? { name } : { name, value: spec.slice(eq + 1) });
|
|
1164
1171
|
}
|
|
1165
|
-
|
|
1172
|
+
const hasArgvValues = parsed.some((entry) => entry.value !== undefined);
|
|
1173
|
+
if (hasArgvValues && options.fromArgv !== true) {
|
|
1174
|
+
usageErr(
|
|
1175
|
+
`Refusing NAME=VALUE on argv (shows up in shell history and agent-captured terminals).\n` +
|
|
1176
|
+
`Pass names only:\n` +
|
|
1177
|
+
` ${CLI} secrets set ${slug} NAME\n` +
|
|
1178
|
+
`Hidden prompt on a TTY; one stdin line per NAME when piped.\n` +
|
|
1179
|
+
`Or redirect a file: ${CLI} secrets set ${slug} NAME < ./secret.txt\n`
|
|
1180
|
+
);
|
|
1181
|
+
return 1;
|
|
1182
|
+
}
|
|
1183
|
+
if (hasArgvValues) {
|
|
1166
1184
|
usageErr(
|
|
1167
|
-
`warning: secret values
|
|
1185
|
+
`warning: --from-argv puts secret values in argv (shell history and agent-captured terminals).\n`
|
|
1168
1186
|
);
|
|
1169
1187
|
}
|
|
1170
1188
|
|
|
@@ -209,7 +209,9 @@ export async function authorizeHostMcpOauth(
|
|
|
209
209
|
|
|
210
210
|
let callback: Awaited<ReturnType<typeof waitForMcpOAuthCallback>>;
|
|
211
211
|
try {
|
|
212
|
-
callback = await waitForMcpOAuthCallback(
|
|
212
|
+
callback = await waitForMcpOAuthCallback({
|
|
213
|
+
authorizationUrl: redirect.toString(),
|
|
214
|
+
});
|
|
213
215
|
} catch (error) {
|
|
214
216
|
err(`${LOG_PREFIX} OAuth callback failed: ${describe(error)}\n`);
|
|
215
217
|
return { ok: false };
|
package/src/internal/cli-mcp.ts
CHANGED
|
@@ -654,15 +654,15 @@ async function cmdMcpInstallRemote(options: McpCliOptions): Promise<number> {
|
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
// Verify the deployment resolves before writing config that cannot work.
|
|
657
|
-
//
|
|
658
|
-
//
|
|
659
|
-
//
|
|
657
|
+
// A 403 here is team membership or cloud-agent entitlement, not an
|
|
658
|
+
// admin-tier read. Still write the entry: calling the gateway only
|
|
659
|
+
// needs the API key.
|
|
660
660
|
try {
|
|
661
661
|
await auth.client.getDeployment({ teamId: auth.teamId, slug });
|
|
662
662
|
} catch (error) {
|
|
663
663
|
if (error instanceof DeployApiError && error.status === 403) {
|
|
664
664
|
err(
|
|
665
|
-
`Could not verify deployment "${slug}" (
|
|
665
|
+
`Could not verify deployment "${slug}" (not authorized for this team); writing the entry anyway.\n`
|
|
666
666
|
);
|
|
667
667
|
} else {
|
|
668
668
|
err(`${describeError(error)}\n`);
|
|
@@ -57,6 +57,40 @@ export type CursorScmPullRequestMeta = {
|
|
|
57
57
|
baseSha?: string;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
/** PR ref on a Checks / Actions webhook object. */
|
|
61
|
+
export type CursorScmCiPullRequestMeta = {
|
|
62
|
+
number: number;
|
|
63
|
+
url?: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type CursorScmCiAppMeta = {
|
|
67
|
+
slug?: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** Shared Checks / Actions fields. `id` + `headSha` satisfy the channel Zod schemas. */
|
|
72
|
+
type CursorScmCiBaseMeta = {
|
|
73
|
+
id: number;
|
|
74
|
+
headSha: string;
|
|
75
|
+
status?: string;
|
|
76
|
+
conclusion?: string | null;
|
|
77
|
+
htmlUrl?: string;
|
|
78
|
+
app?: CursorScmCiAppMeta;
|
|
79
|
+
pullRequests: CursorScmCiPullRequestMeta[];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type CursorScmCheckRunMeta = CursorScmCiBaseMeta & {
|
|
83
|
+
name?: string;
|
|
84
|
+
checkSuiteId?: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type CursorScmCheckSuiteMeta = CursorScmCiBaseMeta;
|
|
88
|
+
|
|
89
|
+
export type CursorScmWorkflowRunMeta = CursorScmCiBaseMeta & {
|
|
90
|
+
name?: string;
|
|
91
|
+
workflowId?: number;
|
|
92
|
+
};
|
|
93
|
+
|
|
60
94
|
/** One event delivered by `GET /v0/scm-events` (metadata only). */
|
|
61
95
|
export interface CursorScmEvent {
|
|
62
96
|
offset: string;
|
|
@@ -81,6 +115,12 @@ export interface CursorScmEvent {
|
|
|
81
115
|
* Zod-valid `issue_comment` / `pull_request_review_comment` webhook body.
|
|
82
116
|
*/
|
|
83
117
|
comment?: CursorScmCommentMeta;
|
|
118
|
+
/** `check_run` snapshot; enough to stub `onCheckRun`. */
|
|
119
|
+
checkRun?: CursorScmCheckRunMeta;
|
|
120
|
+
/** `check_suite` snapshot; enough to stub `onCheckSuite`. */
|
|
121
|
+
checkSuite?: CursorScmCheckSuiteMeta;
|
|
122
|
+
/** `workflow_run` snapshot; enough to stub `onWorkflowRun`. */
|
|
123
|
+
workflowRun?: CursorScmWorkflowRunMeta;
|
|
84
124
|
/** GitHub-side event time from the payload, when present. */
|
|
85
125
|
occurredAtMs?: number;
|
|
86
126
|
}
|
|
@@ -138,12 +178,37 @@ export function formatCursorScmEventLog(event: {
|
|
|
138
178
|
return `${event.eventName}${action} on ${pr} received=${received}${occurred} (${delivery})`;
|
|
139
179
|
}
|
|
140
180
|
|
|
181
|
+
/** Relay log suffix for one fan-out target, including parse errors on 4xx. */
|
|
182
|
+
export function formatCursorScmDispatchOutcome(target: {
|
|
183
|
+
slug: string;
|
|
184
|
+
status: number;
|
|
185
|
+
body: unknown;
|
|
186
|
+
}): string {
|
|
187
|
+
const slug = target.slug === "" ? "default" : target.slug;
|
|
188
|
+
if (target.status < 400) {
|
|
189
|
+
return `${slug}:${target.status}`;
|
|
190
|
+
}
|
|
191
|
+
const error = readDispatchError(target.body);
|
|
192
|
+
return error === undefined
|
|
193
|
+
? `${slug}:${target.status}`
|
|
194
|
+
: `${slug}:${target.status} ${error}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function readDispatchError(body: unknown): string | undefined {
|
|
198
|
+
if (typeof body !== "object" || body === null) return undefined;
|
|
199
|
+
if (!("error" in body)) return undefined;
|
|
200
|
+
const error = body.error;
|
|
201
|
+
return typeof error === "string" && error !== "" ? error : undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
141
204
|
/**
|
|
142
205
|
* Minimal GitHub webhook body from an SCM-events metadata envelope.
|
|
143
206
|
* When `pullRequest` has title + head/base refs+shas, emits a Zod-valid
|
|
144
207
|
* `pull_request` object for `onPullRequest`; otherwise identity-only stubs.
|
|
145
208
|
* When `comment` is present, emits a Zod-valid `comment` object so relayed
|
|
146
209
|
* `issue_comment` / `pull_request_review_comment` deliveries dispatch.
|
|
210
|
+
* When a CI snapshot is present, emits `check_run` / `check_suite` /
|
|
211
|
+
* `workflow_run` so those typed hooks parse on the `--cursor-events` path.
|
|
147
212
|
*/
|
|
148
213
|
export function scmMetadataToGitHubPayload(event: {
|
|
149
214
|
repo: string;
|
|
@@ -152,6 +217,9 @@ export function scmMetadataToGitHubPayload(event: {
|
|
|
152
217
|
prUrl?: string;
|
|
153
218
|
pullRequest?: CursorScmPullRequestMeta;
|
|
154
219
|
comment?: CursorScmCommentMeta;
|
|
220
|
+
checkRun?: CursorScmCheckRunMeta;
|
|
221
|
+
checkSuite?: CursorScmCheckSuiteMeta;
|
|
222
|
+
workflowRun?: CursorScmWorkflowRunMeta;
|
|
155
223
|
}): Record<string, unknown> {
|
|
156
224
|
const slash = event.repo.indexOf("/");
|
|
157
225
|
const owner = slash === -1 ? "" : event.repo.slice(0, slash);
|
|
@@ -210,6 +278,30 @@ export function scmMetadataToGitHubPayload(event: {
|
|
|
210
278
|
payload.comment = comment;
|
|
211
279
|
}
|
|
212
280
|
|
|
281
|
+
const checkPullRequests = stubGitHubCiPullRequests({
|
|
282
|
+
snapshot:
|
|
283
|
+
event.checkRun?.pullRequests ??
|
|
284
|
+
event.checkSuite?.pullRequests ??
|
|
285
|
+
event.workflowRun?.pullRequests,
|
|
286
|
+
prNumber,
|
|
287
|
+
prUrl,
|
|
288
|
+
});
|
|
289
|
+
if (event.checkRun !== undefined) {
|
|
290
|
+
payload.check_run = stubGitHubCheckRun(event.checkRun, checkPullRequests);
|
|
291
|
+
}
|
|
292
|
+
if (event.checkSuite !== undefined) {
|
|
293
|
+
payload.check_suite = stubGitHubCheckSuite(
|
|
294
|
+
event.checkSuite,
|
|
295
|
+
checkPullRequests
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (event.workflowRun !== undefined) {
|
|
299
|
+
payload.workflow_run = stubGitHubWorkflowRun(
|
|
300
|
+
event.workflowRun,
|
|
301
|
+
checkPullRequests
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
213
305
|
const title = prMeta?.title;
|
|
214
306
|
const headRef = prMeta?.headRef;
|
|
215
307
|
const headSha = prMeta?.headSha;
|
|
@@ -261,6 +353,82 @@ export function scmMetadataToGitHubPayload(event: {
|
|
|
261
353
|
return payload;
|
|
262
354
|
}
|
|
263
355
|
|
|
356
|
+
function stubGitHubCiPullRequests(input: {
|
|
357
|
+
snapshot: CursorScmCiPullRequestMeta[] | undefined;
|
|
358
|
+
prNumber: number | undefined;
|
|
359
|
+
prUrl: string | undefined;
|
|
360
|
+
}): Array<{ number: number; html_url?: string }> {
|
|
361
|
+
if (input.snapshot !== undefined && input.snapshot.length > 0) {
|
|
362
|
+
return input.snapshot.map((pr) => ({
|
|
363
|
+
number: pr.number,
|
|
364
|
+
...(pr.url === undefined ? {} : { html_url: pr.url }),
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
if (input.prNumber === undefined) return [];
|
|
368
|
+
return [
|
|
369
|
+
{
|
|
370
|
+
number: input.prNumber,
|
|
371
|
+
...(input.prUrl === undefined ? {} : { html_url: input.prUrl }),
|
|
372
|
+
},
|
|
373
|
+
];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function stubGitHubCiApp(
|
|
377
|
+
app: CursorScmCiAppMeta | undefined
|
|
378
|
+
): Record<string, unknown> | undefined {
|
|
379
|
+
if (app === undefined) return undefined;
|
|
380
|
+
const out: Record<string, unknown> = {};
|
|
381
|
+
if (app.slug !== undefined) out.slug = app.slug;
|
|
382
|
+
if (app.name !== undefined) out.name = app.name;
|
|
383
|
+
return out;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function stubGitHubCiBase(
|
|
387
|
+
meta: CursorScmCiBaseMeta,
|
|
388
|
+
pullRequests: Array<{ number: number; html_url?: string }>
|
|
389
|
+
): Record<string, unknown> {
|
|
390
|
+
const object: Record<string, unknown> = {
|
|
391
|
+
id: meta.id,
|
|
392
|
+
head_sha: meta.headSha,
|
|
393
|
+
};
|
|
394
|
+
if (meta.status !== undefined) object.status = meta.status;
|
|
395
|
+
if (meta.conclusion !== undefined) object.conclusion = meta.conclusion;
|
|
396
|
+
if (meta.htmlUrl !== undefined) object.html_url = meta.htmlUrl;
|
|
397
|
+
const app = stubGitHubCiApp(meta.app);
|
|
398
|
+
if (app !== undefined) object.app = app;
|
|
399
|
+
if (pullRequests.length > 0) object.pull_requests = pullRequests;
|
|
400
|
+
return object;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function stubGitHubCheckRun(
|
|
404
|
+
meta: CursorScmCheckRunMeta,
|
|
405
|
+
pullRequests: Array<{ number: number; html_url?: string }>
|
|
406
|
+
): Record<string, unknown> {
|
|
407
|
+
const object = stubGitHubCiBase(meta, pullRequests);
|
|
408
|
+
if (meta.name !== undefined) object.name = meta.name;
|
|
409
|
+
if (meta.checkSuiteId !== undefined) {
|
|
410
|
+
object.check_suite = { id: meta.checkSuiteId };
|
|
411
|
+
}
|
|
412
|
+
return object;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function stubGitHubCheckSuite(
|
|
416
|
+
meta: CursorScmCheckSuiteMeta,
|
|
417
|
+
pullRequests: Array<{ number: number; html_url?: string }>
|
|
418
|
+
): Record<string, unknown> {
|
|
419
|
+
return stubGitHubCiBase(meta, pullRequests);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function stubGitHubWorkflowRun(
|
|
423
|
+
meta: CursorScmWorkflowRunMeta,
|
|
424
|
+
pullRequests: Array<{ number: number; html_url?: string }>
|
|
425
|
+
): Record<string, unknown> {
|
|
426
|
+
const object = stubGitHubCiBase(meta, pullRequests);
|
|
427
|
+
if (meta.name !== undefined) object.name = meta.name;
|
|
428
|
+
if (meta.workflowId !== undefined) object.workflow_id = meta.workflowId;
|
|
429
|
+
return object;
|
|
430
|
+
}
|
|
431
|
+
|
|
264
432
|
/**
|
|
265
433
|
* GitHub SCM-events relay: a thin {@link CursorRelayCore} adapter. Consumers
|
|
266
434
|
* keep the same `new CursorEventRelay(options).start()/.stop()` surface.
|
|
@@ -705,7 +705,7 @@ function mapErrorResponse(
|
|
|
705
705
|
);
|
|
706
706
|
case 403:
|
|
707
707
|
return new DeployApiError(
|
|
708
|
-
`${serverError ?? "Not authorized"} — deploying needs team
|
|
708
|
+
`${serverError ?? "Not authorized"} — deploying needs team membership and the cloud-agent entitlement on that team.`,
|
|
709
709
|
403
|
|
710
710
|
);
|
|
711
711
|
case 404: {
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
type AgentProject,
|
|
29
29
|
type AgentProjectInfo,
|
|
30
30
|
type AgentRuntime,
|
|
31
|
+
type AgentServingMode,
|
|
31
32
|
type ArtifactsDefinition,
|
|
32
33
|
type BuiltinToolsConfig,
|
|
33
34
|
type ChannelDefinition,
|
|
@@ -188,11 +189,20 @@ export async function loadAgentProjects(
|
|
|
188
189
|
);
|
|
189
190
|
}
|
|
190
191
|
const results: Array<{ slug: string; project: AgentProject }> = [];
|
|
192
|
+
// Storage namespaces (session mirror, host kv, durable-session ledger)
|
|
193
|
+
// key on the project NAME, not the mount slug — two co-hosted agents
|
|
194
|
+
// sharing a name would silently share sessions and coordination state.
|
|
195
|
+
const slugByName = new Map<string, string>();
|
|
191
196
|
for (const child of children) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
const project = await loadAgentProject(child.dir, options);
|
|
198
|
+
const priorSlug = slugByName.get(project.name);
|
|
199
|
+
if (priorSlug !== undefined) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
`Duplicate agent name "${project.name}" under ${resolved}: agents "${priorSlug}" and "${child.slug}" both resolve to it (package.json "name", or the directory name when unset). Co-hosted agents must have distinct names — their storage and session namespaces key on the name.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
slugByName.set(project.name, child.slug);
|
|
205
|
+
results.push({ slug: child.slug, project });
|
|
196
206
|
}
|
|
197
207
|
return results;
|
|
198
208
|
}
|
|
@@ -420,6 +430,7 @@ async function loadAgent(
|
|
|
420
430
|
};
|
|
421
431
|
const hosting = resolveHosting(ctx, agentDir, config?.hosting);
|
|
422
432
|
const concurrency = resolveConcurrency(ctx, agentDir, config?.concurrency);
|
|
433
|
+
const serving = resolveServing(ctx, agentDir, config?.serving);
|
|
423
434
|
|
|
424
435
|
if (runtime === "cloud") {
|
|
425
436
|
warnCloudRuntimeLimitations(ctx, agentDir, {
|
|
@@ -443,6 +454,7 @@ async function loadAgent(
|
|
|
443
454
|
local,
|
|
444
455
|
hosting,
|
|
445
456
|
concurrency,
|
|
457
|
+
serving,
|
|
446
458
|
tools,
|
|
447
459
|
skills,
|
|
448
460
|
connections,
|
|
@@ -451,6 +463,27 @@ async function loadAgent(
|
|
|
451
463
|
};
|
|
452
464
|
}
|
|
453
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Validate the authored serving mode. An unrecognized value is an error
|
|
468
|
+
* diagnostic and falls back to undefined (resident) — a typo must not
|
|
469
|
+
* silently opt an agent into (or out of) ledger coordination.
|
|
470
|
+
*/
|
|
471
|
+
function resolveServing(
|
|
472
|
+
ctx: DiscoveryContext,
|
|
473
|
+
agentDir: string,
|
|
474
|
+
serving: AgentServingMode | undefined
|
|
475
|
+
): AgentServingMode | undefined {
|
|
476
|
+
if (serving === undefined || serving === "resident" || serving === "ledger") {
|
|
477
|
+
return serving;
|
|
478
|
+
}
|
|
479
|
+
ctx.diagnostics.push({
|
|
480
|
+
severity: "error",
|
|
481
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
482
|
+
message: `serving must be "resident" or "ledger"; got ${JSON.stringify(serving)}.`,
|
|
483
|
+
});
|
|
484
|
+
return undefined;
|
|
485
|
+
}
|
|
486
|
+
|
|
454
487
|
/** Absolute harness cwd parent, or undefined when unset / blank. */
|
|
455
488
|
function resolveAgentCwd(
|
|
456
489
|
ctx: DiscoveryContext,
|
|
@@ -504,7 +537,7 @@ function resolveHosting(
|
|
|
504
537
|
warn(`hosting.secretNames: ${nameError}`);
|
|
505
538
|
} else if (isReservedSecretName(name)) {
|
|
506
539
|
warn(
|
|
507
|
-
`hosting.secretNames: ${JSON.stringify(name)} is platform-managed (CURSOR_* /
|
|
540
|
+
`hosting.secretNames: ${JSON.stringify(name)} is platform-managed (CURSOR_* / reserved hosted-storage names); omit it from secretNames.`
|
|
508
541
|
);
|
|
509
542
|
}
|
|
510
543
|
}
|
|
@@ -1863,6 +1896,10 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
|
|
|
1863
1896
|
name: connection.name,
|
|
1864
1897
|
transport: connectionTransportLabel(connection.transport),
|
|
1865
1898
|
hostOnly: connection.hostOnly,
|
|
1899
|
+
cursorAccountServers:
|
|
1900
|
+
"cursorAccount" in connection.transport
|
|
1901
|
+
? (connection.transport.servers ?? "*")
|
|
1902
|
+
: undefined,
|
|
1866
1903
|
})),
|
|
1867
1904
|
subagents: agent.subagents.map((subagent) => ({
|
|
1868
1905
|
name: subagent.name,
|
|
@@ -108,8 +108,10 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
|
|
|
108
108
|
["evals/loaders", "evals/loaders.js"],
|
|
109
109
|
["ab", "ab.js"],
|
|
110
110
|
["artifacts", "artifacts.js"],
|
|
111
|
+
["kv", "kv.js"],
|
|
112
|
+
["kv/memory", "kv/memory-kv.js"],
|
|
113
|
+
["ledger", "ledger.js"],
|
|
111
114
|
["storage", "storage.js"],
|
|
112
115
|
["storage/file-kv", "storage-backends/file-kv.js"],
|
|
113
|
-
["storage/postgres-kv", "storage-backends/postgres-kv.js"],
|
|
114
116
|
["storage/cursor-hosted", "storage-backends/cursor-hosted.js"],
|
|
115
117
|
];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable-session store resolution.
|
|
3
|
+
*
|
|
4
|
+
* Two APIs, one backend: `defineStorage` is the **storage API** (agent
|
|
5
|
+
* state — session records, event chunks, author KV), and the session
|
|
6
|
+
* ledger is the **durable session API** (session identity, leases,
|
|
7
|
+
* fenced commits). The ledger consumes {@link SessionLedgerKv} — exactly
|
|
8
|
+
* the three CAS methods it uses, nothing more; this module adapts a
|
|
9
|
+
* storage backend's `cas` group into that interface, so a deployment's
|
|
10
|
+
* one authored backend serves both APIs by default.
|
|
11
|
+
*
|
|
12
|
+
* Calls go straight at the config's methods — NOT through the
|
|
13
|
+
* StorageCoordinator: the coordinator's queue is bounded, serialized, and
|
|
14
|
+
* at-most-once (mirror semantics), while ledger CAS calls are the
|
|
15
|
+
* correctness path and must observe their own results synchronously.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { SessionLedgerKv } from "../ledger/session-ledger.js";
|
|
19
|
+
import {
|
|
20
|
+
keySegment,
|
|
21
|
+
STORAGE_KEY_ROOT,
|
|
22
|
+
type StorageConfig,
|
|
23
|
+
type StorageContext,
|
|
24
|
+
} from "../storage.js";
|
|
25
|
+
|
|
26
|
+
export interface StorageCasKvArgs {
|
|
27
|
+
agentName: string;
|
|
28
|
+
projectRoot: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Adapt a storage backend's `cas` group into the ledger's KV interface.
|
|
33
|
+
* Throws when the backend does not implement `cas` — the caller turns
|
|
34
|
+
* that into the fail-fast startup error for `serving: "ledger"`. Every
|
|
35
|
+
* call carries a `reason: "coordination"` {@link StorageContext}.
|
|
36
|
+
*/
|
|
37
|
+
export function storageCasKv(
|
|
38
|
+
config: StorageConfig,
|
|
39
|
+
args: StorageCasKvArgs
|
|
40
|
+
): SessionLedgerKv {
|
|
41
|
+
const ctx: StorageContext = {
|
|
42
|
+
agentName: args.agentName,
|
|
43
|
+
projectRoot: args.projectRoot,
|
|
44
|
+
reason: "coordination",
|
|
45
|
+
};
|
|
46
|
+
const { cas } = config;
|
|
47
|
+
if (cas === undefined) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"storageCasKv: the storage backend does not implement the cas group (conditional writes)"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
async getWithVersion(key) {
|
|
54
|
+
return await cas.getWithVersion(key, ctx);
|
|
55
|
+
},
|
|
56
|
+
async putIfAbsent(key, value) {
|
|
57
|
+
return await cas.putIfAbsent(key, value, ctx);
|
|
58
|
+
},
|
|
59
|
+
async putIfVersion(key, value, expectedVersion) {
|
|
60
|
+
return await cas.putIfVersion(key, value, expectedVersion, ctx);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The one place the ledger's physical namespace is minted:
|
|
67
|
+
* `agentkit/v1/<agent>/durable-session/` — the {@link STORAGE_KEY_ROOT}
|
|
68
|
+
* conventions with the agent segment encoded like every other
|
|
69
|
+
* caller-controlled segment. The ledger itself never sees this string;
|
|
70
|
+
* it speaks bare `session/…` / `ledger/…` keys against a handle that
|
|
71
|
+
* {@link namespacedKv} has already scoped.
|
|
72
|
+
*/
|
|
73
|
+
export function ledgerKeyPrefix(agentName: string): string {
|
|
74
|
+
return `${STORAGE_KEY_ROOT}/${keySegment(agentName)}/durable-session/`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Scope a raw store handle under a namespace, prepending it to every
|
|
79
|
+
* key on the way in. Applied exactly once, where the engine constructs
|
|
80
|
+
* the ledger's store handle — the same conceptual boundary where
|
|
81
|
+
* `host.kv` gets its agent scoping. Internal: not part of the public kv
|
|
82
|
+
* interface, and callers (including the explicit `durableSessionStore`
|
|
83
|
+
* override) always supply the raw store — they never write prefixes.
|
|
84
|
+
*/
|
|
85
|
+
export function namespacedKv(
|
|
86
|
+
store: SessionLedgerKv,
|
|
87
|
+
namespace: string
|
|
88
|
+
): SessionLedgerKv {
|
|
89
|
+
return {
|
|
90
|
+
getWithVersion: (key) => store.getWithVersion(namespace + key),
|
|
91
|
+
putIfAbsent: (key, value) => store.putIfAbsent(namespace + key, value),
|
|
92
|
+
putIfVersion: (key, value, expectedVersion) =>
|
|
93
|
+
store.putIfVersion(namespace + key, value, expectedVersion),
|
|
94
|
+
};
|
|
95
|
+
}
|
package/src/internal/hosting.ts
CHANGED
|
@@ -15,7 +15,7 @@ export const MAX_SECRETS = 32;
|
|
|
15
15
|
export const MAX_SECRET_VALUE_BYTES = 4096;
|
|
16
16
|
/** Max secret name length. */
|
|
17
17
|
export const MAX_SECRET_NAME_LENGTH = 64;
|
|
18
|
-
/** Secret names the platform
|
|
18
|
+
/** Secret names the platform manages; user writes are rejected. */
|
|
19
19
|
export const RESERVED_SECRET_NAME_PREFIX = "CURSOR_";
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -84,7 +84,7 @@ export function validateSettableSecretName(name: string): string | undefined {
|
|
|
84
84
|
return nameError;
|
|
85
85
|
}
|
|
86
86
|
if (isReservedSecretName(name)) {
|
|
87
|
-
return `Secret name ${JSON.stringify(name)} is platform-managed;
|
|
87
|
+
return `Secret name ${JSON.stringify(name)} is platform-managed; user secrets cannot claim CURSOR_* or reserved hosted-storage names.`;
|
|
88
88
|
}
|
|
89
89
|
return undefined;
|
|
90
90
|
}
|