@cursor/july 0.1.107 → 0.1.108
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/README.md +10 -5
- package/dist/bin/agent-serve.js +30 -8
- package/dist/channels/github/github-channel.js +8 -5
- package/dist/channels/github/types.d.ts +5 -1
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +27 -13
- package/dist/channels/origin/types.d.ts +5 -1
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels.d.ts +45 -0
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +106 -7
- package/dist/connections.d.ts +2 -1
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +2 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.CtuckIiL.js → app.BASKM3M4.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BHZYsNVi.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.Bkkhnu8K.js → VPLocalSearchBox.BOKxlYGP.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DhpIe0Pa.js → theme.DbDZW-zb.js} +2 -2
- package/dist/docs/assets/{deployment.md.MFPKqsqI.js → deployment.md.JenwuCCB.js} +4 -4
- package/dist/docs/assets/{deployment.md.MFPKqsqI.lean.js → deployment.md.JenwuCCB.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.CbMoebP1.js → evals.md.C1ekS3k2.js} +1 -1
- package/dist/docs/assets/guides_cloud-agents.md.BsloyHdY.js +9 -0
- package/dist/docs/assets/{guides_cloud-agents.md.DS8RIjwx.lean.js → guides_cloud-agents.md.BsloyHdY.lean.js} +1 -1
- package/dist/docs/assets/{guides_github.md.c0gdGJ-D.js → guides_github.md.BH33UEBJ.js} +1 -1
- package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.js → guides_grokbot-agents.md.DyV-WArv.js} +1 -1
- package/dist/docs/assets/guides_improve.md.BGVk32bK.js +14 -0
- package/dist/docs/assets/guides_improve.md.BGVk32bK.lean.js +1 -0
- package/dist/docs/assets/{guides_slack.md.9oHPye9o.js → guides_slack.md.D4RVMM4G.js} +3 -3
- package/dist/docs/assets/{guides_slack.md.9oHPye9o.lean.js → guides_slack.md.D4RVMM4G.lean.js} +1 -1
- package/dist/docs/assets/index.md.BjH1w2ZW.js +5 -0
- package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.js → reference_agent-config.md.CvoL6pof.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.Dm67hd2D.js → reference_cli.md.Ca26u0Es.js} +6 -6
- package/dist/docs/assets/{reference_cli.md.Dm67hd2D.lean.js → reference_cli.md.Ca26u0Es.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Di6jJAXF.js → reference_connections.md.BojkC6c5.js} +1 -1
- package/dist/docs/assets/{reference_extensions.md.CGmMLblt.js → reference_extensions.md.CPWt00ds.js} +1 -1
- package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.js → scaffolding-agents.md.Kctn3OVb.js} +1 -1
- package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.js → skills_create-agent.md.Q3h6Je-e.js} +1 -1
- package/dist/docs/assets/{skills_debug.md.CDbPhHfg.js → skills_debug.md.CVjCXMFF.js} +1 -1
- package/dist/docs/assets/{skills_debug.md.CDbPhHfg.lean.js → skills_debug.md.CVjCXMFF.lean.js} +1 -1
- package/dist/docs/assets/{skills_evals.md.723kpUmA.js → skills_evals.md.BhovOvrl.js} +1 -1
- package/dist/docs/assets/skills_framework-map.md.D-tFZhFS.js +1 -0
- package/dist/docs/assets/{skills_framework-map.md.haibFyoB.lean.js → skills_framework-map.md.D-tFZhFS.lean.js} +1 -1
- package/dist/docs/assets/{skills_github.md.D0JahM8c.js → skills_github.md.hgFX_oKY.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.CYEAO9bM.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/deployment.md +7 -2
- package/dist/docs/evals.html +6 -6
- package/dist/docs/evals.md +3 -2
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-agents.html +6 -6
- package/dist/docs/guides/cloud-agents.md +4 -3
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +5 -5
- package/dist/docs/guides/github.md +2 -1
- package/dist/docs/guides/grokbot-agents.html +6 -6
- package/dist/docs/guides/grokbot-agents.md +2 -2
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/improve.html +40 -0
- package/dist/docs/guides/improve.md +91 -0
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +5 -5
- package/dist/docs/guides/slack.html +6 -6
- package/dist/docs/guides/slack.md +2 -1
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +4 -0
- package/dist/docs/llms-full.txt +158 -33
- package/dist/docs/llms.txt +1 -0
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/agent-config.md +5 -2
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +10 -10
- package/dist/docs/reference/cli.md +18 -11
- package/dist/docs/reference/connections.html +6 -6
- package/dist/docs/reference/connections.md +2 -1
- package/dist/docs/reference/extensions.html +6 -6
- package/dist/docs/reference/extensions.md +2 -0
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/result.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/scaffolding-agents.md +2 -1
- package/dist/docs/skills/ab.html +4 -4
- package/dist/docs/skills/create-agent.html +6 -6
- package/dist/docs/skills/create-agent.md +1 -1
- package/dist/docs/skills/debug.html +5 -5
- package/dist/docs/skills/debug.md +1 -1
- package/dist/docs/skills/evals.html +6 -6
- package/dist/docs/skills/evals.md +1 -1
- package/dist/docs/skills/framework-map.html +5 -5
- package/dist/docs/skills/framework-map.md +4 -2
- package/dist/docs/skills/github.html +6 -6
- package/dist/docs/skills/github.md +1 -1
- package/dist/docs/skills/hillclimb.html +4 -4
- package/dist/docs/skills/index.html +4 -4
- package/dist/docs/skills/mcp-auth.html +4 -4
- package/dist/docs/skills/otel.html +4 -4
- package/dist/docs/skills/setup-slack.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +4 -4
- package/dist/docs/templates/code-wiki.html +4 -4
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/grokbot-agents.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +4 -4
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +1 -1
- package/dist/extensions/improve/extension.d.ts +46 -0
- package/dist/extensions/improve/extension.d.ts.map +1 -0
- package/dist/extensions/improve/extension.js +41 -0
- package/dist/extensions/improve/skills/yourself.d.ts +4 -0
- package/dist/extensions/improve/skills/yourself.d.ts.map +1 -0
- package/dist/extensions/improve/skills/yourself.js +43 -0
- package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -1
- package/dist/internal/builtin-tools/artifacts.js +2 -3
- package/dist/internal/channel-route-dispatch.d.ts +13 -0
- package/dist/internal/channel-route-dispatch.d.ts.map +1 -0
- package/dist/internal/channel-route-dispatch.js +62 -0
- package/dist/internal/channel-state.d.ts +17 -0
- package/dist/internal/channel-state.d.ts.map +1 -0
- package/dist/internal/channel-state.js +78 -0
- package/dist/internal/cli-ax.d.ts +7 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +99 -1
- package/dist/internal/cli-cursor.d.ts.map +1 -1
- package/dist/internal/cli-cursor.js +2 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +38 -14
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
- package/dist/internal/cli-mcp-oauth.js +15 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -1
- package/dist/internal/cli-mcp.js +12 -0
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +8 -2
- package/dist/internal/cursor/credentials.d.ts +8 -2
- package/dist/internal/cursor/credentials.d.ts.map +1 -1
- package/dist/internal/cursor/credentials.js +27 -5
- package/dist/internal/deploy-client.d.ts +27 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +32 -0
- package/dist/internal/deploy-manifest.d.ts +23 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +84 -1
- package/dist/internal/describe-error.d.ts +1 -0
- package/dist/internal/describe-error.d.ts.map +1 -1
- package/dist/internal/describe-error.js +25 -0
- package/dist/internal/guest-network.d.ts +4 -10
- package/dist/internal/guest-network.d.ts.map +1 -1
- package/dist/internal/guest-network.js +42 -26
- package/dist/internal/hosted-admission-adapter.d.ts +2 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
- package/dist/internal/hosted-catch-protocol.d.ts +51 -0
- package/dist/internal/hosted-catch-protocol.d.ts.map +1 -0
- package/dist/internal/hosted-catch-protocol.js +103 -0
- package/dist/internal/hosted-catch.d.ts +40 -0
- package/dist/internal/hosted-catch.d.ts.map +1 -0
- package/dist/internal/hosted-catch.js +149 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +41 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +249 -0
- package/dist/internal/hosted-delivery.d.ts +10 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +100 -22
- package/dist/internal/hosted-execution-diag.d.ts +4 -1
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
- package/dist/internal/hosted-execution-diag.js +13 -4
- package/dist/internal/hosted-execution-flush.d.ts +3 -0
- package/dist/internal/hosted-execution-flush.d.ts.map +1 -1
- package/dist/internal/hosted-execution-flush.js +2 -4
- package/dist/internal/http-control-plane-session.d.ts +30 -0
- package/dist/internal/http-control-plane-session.d.ts.map +1 -0
- package/dist/internal/http-control-plane-session.js +83 -0
- package/dist/internal/legacy-command-guard.d.ts +22 -0
- package/dist/internal/legacy-command-guard.d.ts.map +1 -0
- package/dist/internal/legacy-command-guard.js +51 -0
- package/dist/internal/platform-timers.d.ts +7 -0
- package/dist/internal/platform-timers.d.ts.map +1 -1
- package/dist/internal/platform-timers.js +139 -0
- package/dist/internal/reminder-control-plane-protocol.d.ts +2 -0
- package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -1
- package/dist/internal/reminder-control-plane-protocol.js +9 -2
- package/dist/internal/reminder-runner.d.ts +8 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +36 -9
- package/dist/internal/resolve-prod-target.d.ts +2 -0
- package/dist/internal/resolve-prod-target.d.ts.map +1 -1
- package/dist/internal/resolve-prod-target.js +13 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +4 -3
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +57 -56
- package/dist/internal/session-engine.d.ts +2 -6
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +95 -67
- package/dist/playground/assets/{index-Bq2HpEQB.js → index-BMDqAeXu.js} +28 -28
- package/dist/playground/assets/index-LUgJoWdL.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +6 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +29 -1
- package/dist/types.d.ts +33 -5
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +4 -0
- package/docs/deployment.md +7 -2
- package/docs/evals.md +3 -2
- package/docs/guides/cloud-agents.md +4 -3
- package/docs/guides/github.md +2 -1
- package/docs/guides/grokbot-agents.md +2 -2
- package/docs/guides/improve.md +96 -0
- package/docs/guides/slack.md +2 -1
- package/docs/reference/agent-config.md +5 -2
- package/docs/reference/cli.md +18 -11
- package/docs/reference/connections.md +2 -1
- package/docs/reference/extensions.md +2 -0
- package/docs/scaffolding-agents.md +2 -1
- package/docs/troubleshooting.md +1 -1
- package/package.json +8 -1
- package/skills/create-agent/SKILL.md +1 -1
- package/skills/debug/SKILL.md +1 -1
- package/skills/evals/SKILL.md +1 -1
- package/skills/framework-map/SKILL.md +4 -2
- package/skills/github/SKILL.md +1 -1
- package/src/bin/agent-serve.ts +27 -2
- package/src/channels/github/github-channel.ts +8 -8
- package/src/channels/github/types.ts +5 -0
- package/src/channels/origin/origin-channel.ts +29 -13
- package/src/channels/origin/types.ts +5 -0
- package/src/channels.ts +157 -10
- package/src/connections.ts +2 -1
- package/src/extensions/improve/extension.ts +70 -0
- package/src/extensions/improve/skills/yourself.ts +50 -0
- package/src/internal/builtin-tools/artifacts.ts +2 -3
- package/src/internal/channel-route-dispatch.ts +66 -0
- package/src/internal/channel-state.ts +96 -0
- package/src/internal/cli-ax.ts +110 -1
- package/src/internal/cli-cursor.ts +4 -1
- package/src/internal/cli-deploy.ts +50 -10
- package/src/internal/cli-mcp-oauth.ts +18 -0
- package/src/internal/cli-mcp.ts +11 -0
- package/src/internal/cli-slack.ts +15 -2
- package/src/internal/cursor/credentials.ts +35 -7
- package/src/internal/deploy-client.ts +54 -0
- package/src/internal/deploy-manifest.ts +115 -1
- package/src/internal/describe-error.ts +28 -0
- package/src/internal/guest-network.ts +43 -29
- package/src/internal/hosted-admission-adapter.ts +2 -0
- package/src/internal/hosted-catch-protocol.ts +130 -0
- package/src/internal/hosted-catch.ts +192 -0
- package/src/internal/hosted-delivery-protocol.ts +387 -0
- package/src/internal/hosted-delivery.ts +155 -22
- package/src/internal/hosted-execution-diag.ts +21 -3
- package/src/internal/hosted-execution-flush.ts +6 -3
- package/src/internal/http-control-plane-session.ts +104 -0
- package/src/internal/legacy-command-guard.ts +59 -0
- package/src/internal/platform-timers.ts +191 -0
- package/src/internal/reminder-control-plane-protocol.ts +15 -2
- package/src/internal/reminder-runner.ts +60 -9
- package/src/internal/resolve-prod-target.ts +15 -0
- package/src/internal/sdk-runner.ts +2 -1
- package/src/internal/server.ts +89 -79
- package/src/internal/session-engine.ts +141 -83
- package/src/storage-backends/cursor-hosted.ts +40 -1
- package/src/types.ts +39 -6
- package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +0 -1
- package/dist/docs/assets/guides_cloud-agents.md.DS8RIjwx.js +0 -9
- package/dist/docs/assets/index.md.BW_6tOgR.js +0 -5
- package/dist/docs/assets/skills_framework-map.md.haibFyoB.js +0 -1
- package/dist/docs/assets/troubleshooting.md.Cus_YZga.js +0 -1
- package/dist/playground/assets/index-CZKKNlmb.css +0 -1
- /package/dist/docs/assets/{evals.md.CbMoebP1.lean.js → evals.md.C1ekS3k2.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.c0gdGJ-D.lean.js → guides_github.md.BH33UEBJ.lean.js} +0 -0
- /package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.lean.js → guides_grokbot-agents.md.DyV-WArv.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.BW_6tOgR.lean.js → index.md.BjH1w2ZW.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.lean.js → reference_agent-config.md.CvoL6pof.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.Di6jJAXF.lean.js → reference_connections.md.BojkC6c5.lean.js} +0 -0
- /package/dist/docs/assets/{reference_extensions.md.CGmMLblt.lean.js → reference_extensions.md.CPWt00ds.lean.js} +0 -0
- /package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.lean.js → scaffolding-agents.md.Kctn3OVb.lean.js} +0 -0
- /package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.lean.js → skills_create-agent.md.Q3h6Je-e.lean.js} +0 -0
- /package/dist/docs/assets/{skills_evals.md.723kpUmA.lean.js → skills_evals.md.BhovOvrl.lean.js} +0 -0
- /package/dist/docs/assets/{skills_github.md.D0JahM8c.lean.js → skills_github.md.hgFX_oKY.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.Cus_YZga.lean.js → troubleshooting.md.CYEAO9bM.lean.js} +0 -0
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
revokeMintedUserApiKey,
|
|
18
18
|
} from "./cursor/backend-client.js";
|
|
19
19
|
import {
|
|
20
|
+
type ApiKeySource,
|
|
20
21
|
clearStoredCredentials,
|
|
21
22
|
credentialsFilePath,
|
|
22
23
|
cursorBackendUrl,
|
|
@@ -255,7 +256,7 @@ function formatIdentity(identity: CursorIdentity): string {
|
|
|
255
256
|
return name === "" ? `${email}${team}` : `${name} <${email}>${team}`;
|
|
256
257
|
}
|
|
257
258
|
|
|
258
|
-
function describeSource(source:
|
|
259
|
+
function describeSource(source: ApiKeySource): string {
|
|
259
260
|
switch (source) {
|
|
260
261
|
case "option":
|
|
261
262
|
return "explicit --api-key / serve({ apiKey })";
|
|
@@ -263,6 +264,8 @@ function describeSource(source: "option" | "env" | "file" | "login"): string {
|
|
|
263
264
|
return "CURSOR_API_KEY environment variable";
|
|
264
265
|
case "file":
|
|
265
266
|
return "CURSOR_API_KEY_FILE (task bind)";
|
|
267
|
+
case "service-account":
|
|
268
|
+
return "CURSOR_SERVICE_ACCOUNT_KEY environment variable";
|
|
266
269
|
case "login":
|
|
267
270
|
return `stored login (${credentialsFilePath()})`;
|
|
268
271
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { basename, resolve } from "node:path";
|
|
14
|
-
import { isPublicEndpointPolicy } from "../channels.js";
|
|
14
|
+
import { catchAuthDeclaration, isPublicEndpointPolicy } from "../channels.js";
|
|
15
15
|
import {
|
|
16
16
|
type AgentArchitecture,
|
|
17
17
|
type AgentHostingOptions,
|
|
@@ -62,6 +62,10 @@ import {
|
|
|
62
62
|
isValidCursorEventRepo,
|
|
63
63
|
validateSettableSecretName,
|
|
64
64
|
} from "./hosting.js";
|
|
65
|
+
import {
|
|
66
|
+
deploymentArchitecture,
|
|
67
|
+
rejectV2ForLegacyCommand,
|
|
68
|
+
} from "./legacy-command-guard.js";
|
|
65
69
|
import { deployProgressLabel, sanitizeCustomerError } from "./logs-client.js";
|
|
66
70
|
import { sleep } from "./sleep.js";
|
|
67
71
|
import { stderrPalette } from "./terminal-style.js";
|
|
@@ -739,6 +743,17 @@ async function deployOne(
|
|
|
739
743
|
` public: ${publicRoutePaths.join(", ")} (served WITHOUT the alias token — these channels authenticate requests themselves)\n`
|
|
740
744
|
);
|
|
741
745
|
}
|
|
746
|
+
const deadSecretChannels =
|
|
747
|
+
manifest?.publicChannelIdsWithDeadSecretPolicies ?? [];
|
|
748
|
+
if (!ctx.json && deadSecretChannels.length > 0) {
|
|
749
|
+
ctx.err(
|
|
750
|
+
`warning: ${deadSecretChannels
|
|
751
|
+
.map((channelId) => `/v1/channels/${channelId}`)
|
|
752
|
+
.join(
|
|
753
|
+
", "
|
|
754
|
+
)}: publicEndpoint() sits beside sharedSecretAuth()/hmacSignatureAuth() — auth chains are any-of, so every request is admitted and those secret policies never run. Drop publicEndpoint() to enforce them, or drop them to make the intent explicit.\n`
|
|
755
|
+
);
|
|
756
|
+
}
|
|
742
757
|
|
|
743
758
|
if (manifest?.architecture === "v2") {
|
|
744
759
|
if (!ctx.json) {
|
|
@@ -1192,6 +1207,13 @@ interface DeployManifest {
|
|
|
1192
1207
|
* `X-Agent-Alias-Token` (the channel authenticates deliveries itself).
|
|
1193
1208
|
*/
|
|
1194
1209
|
publicChannelIds: string[];
|
|
1210
|
+
/**
|
|
1211
|
+
* Public channels whose auth chain also carries `sharedSecretAuth` /
|
|
1212
|
+
* `hmacSignatureAuth`. Chains are any-of, so `publicEndpoint()` admits
|
|
1213
|
+
* every request and those secret policies never gate anything — locally
|
|
1214
|
+
* or on the control plane; surfaced as a warning.
|
|
1215
|
+
*/
|
|
1216
|
+
publicChannelIdsWithDeadSecretPolicies: string[];
|
|
1195
1217
|
/**
|
|
1196
1218
|
* `publicEndpoint()` on the built-in HTTP channel — a no-op on hosting
|
|
1197
1219
|
* (only `/v1/channels/…` subtrees can be public); surfaced as a warning.
|
|
@@ -1240,6 +1262,18 @@ async function readDeployManifest(dir: string): Promise<DeployManifest> {
|
|
|
1240
1262
|
(channel.definition.auth ?? []).some(isPublicEndpointPolicy)
|
|
1241
1263
|
)
|
|
1242
1264
|
.map((channel) => channel.id),
|
|
1265
|
+
publicChannelIdsWithDeadSecretPolicies: project.channels
|
|
1266
|
+
.filter((channel) => {
|
|
1267
|
+
const auth = channel.definition.auth ?? [];
|
|
1268
|
+
return (
|
|
1269
|
+
auth.some(isPublicEndpointPolicy) &&
|
|
1270
|
+
auth.some((policy) => {
|
|
1271
|
+
const kind = catchAuthDeclaration(policy)?.kind;
|
|
1272
|
+
return kind !== undefined && kind !== "public";
|
|
1273
|
+
})
|
|
1274
|
+
);
|
|
1275
|
+
})
|
|
1276
|
+
.map((channel) => channel.id),
|
|
1243
1277
|
httpChannelPublicEndpoint: (project.httpChannel.auth ?? []).some(
|
|
1244
1278
|
isPublicEndpointPolicy
|
|
1245
1279
|
),
|
|
@@ -1636,6 +1670,11 @@ export async function cmdRotateToken(
|
|
|
1636
1670
|
}
|
|
1637
1671
|
let aliasToken: string;
|
|
1638
1672
|
try {
|
|
1673
|
+
await rejectV2ForLegacyCommand({
|
|
1674
|
+
client: ctx.client,
|
|
1675
|
+
teamId: ctx.teamId,
|
|
1676
|
+
slug,
|
|
1677
|
+
});
|
|
1639
1678
|
aliasToken = await ctx.client.rotateAliasToken({
|
|
1640
1679
|
teamId: ctx.teamId,
|
|
1641
1680
|
slug,
|
|
@@ -1673,6 +1712,11 @@ export async function cmdRotatePodCredential(
|
|
|
1673
1712
|
}
|
|
1674
1713
|
let podCredentialMaskedKey: string;
|
|
1675
1714
|
try {
|
|
1715
|
+
await rejectV2ForLegacyCommand({
|
|
1716
|
+
client: ctx.client,
|
|
1717
|
+
teamId: ctx.teamId,
|
|
1718
|
+
slug,
|
|
1719
|
+
});
|
|
1676
1720
|
podCredentialMaskedKey = await ctx.client.rotatePodCredential({
|
|
1677
1721
|
teamId: ctx.teamId,
|
|
1678
1722
|
slug,
|
|
@@ -1699,15 +1743,11 @@ async function secretDeploymentArchitecture(
|
|
|
1699
1743
|
ctx: DeployCliContext,
|
|
1700
1744
|
slug: string
|
|
1701
1745
|
): Promise<"v1" | "v2"> {
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
return "v1";
|
|
1708
|
-
}
|
|
1709
|
-
throw error;
|
|
1710
|
-
}
|
|
1746
|
+
return deploymentArchitecture({
|
|
1747
|
+
client: ctx.client,
|
|
1748
|
+
teamId: ctx.teamId,
|
|
1749
|
+
slug,
|
|
1750
|
+
});
|
|
1711
1751
|
}
|
|
1712
1752
|
|
|
1713
1753
|
export async function cmdSecretsSet(
|
|
@@ -20,6 +20,10 @@ import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
|
|
|
20
20
|
import { deploymentServiceAccountId } from "./deploy-client.js";
|
|
21
21
|
import { loadAgentProject } from "./discovery.js";
|
|
22
22
|
import { CLI_COMMAND_NAME as CLI, LOG_PREFIX } from "./distribution.js";
|
|
23
|
+
import {
|
|
24
|
+
isUnsupportedV2LegacyCommandError,
|
|
25
|
+
rejectV2ForLegacyCommand,
|
|
26
|
+
} from "./legacy-command-guard.js";
|
|
23
27
|
import {
|
|
24
28
|
createHostMcpOAuthProvider,
|
|
25
29
|
MCP_OAUTH_CALLBACK_URL,
|
|
@@ -290,12 +294,21 @@ async function cmdMcpOauthCursorAccount(
|
|
|
290
294
|
|
|
291
295
|
let serviceAccountId: string | undefined;
|
|
292
296
|
try {
|
|
297
|
+
await rejectV2ForLegacyCommand({
|
|
298
|
+
client: auth.client,
|
|
299
|
+
teamId: auth.teamId,
|
|
300
|
+
slug,
|
|
301
|
+
});
|
|
293
302
|
const detail = await auth.client.getDeployment({
|
|
294
303
|
teamId: auth.teamId,
|
|
295
304
|
slug,
|
|
296
305
|
});
|
|
297
306
|
serviceAccountId = deploymentServiceAccountId(detail);
|
|
298
307
|
} catch (error) {
|
|
308
|
+
if (isUnsupportedV2LegacyCommandError(error)) {
|
|
309
|
+
err(`${LOG_PREFIX} ${error.message}\n`);
|
|
310
|
+
return 1;
|
|
311
|
+
}
|
|
299
312
|
err(
|
|
300
313
|
`${LOG_PREFIX} Could not load deployment "${slug}" (team ${auth.teamId}): ${describe(error)}\n` +
|
|
301
314
|
`${LOG_PREFIX} Deploy first with \`${CLI} deploy\`.\n`
|
|
@@ -382,6 +395,11 @@ async function storeOauthSecrets(args: {
|
|
|
382
395
|
}
|
|
383
396
|
|
|
384
397
|
try {
|
|
398
|
+
await rejectV2ForLegacyCommand({
|
|
399
|
+
client: auth.client,
|
|
400
|
+
teamId: auth.teamId,
|
|
401
|
+
slug,
|
|
402
|
+
});
|
|
385
403
|
const secretNames = await upsertHostMcpOauthSecrets({
|
|
386
404
|
connection: args.connection,
|
|
387
405
|
tokens,
|
package/src/internal/cli-mcp.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { dirname, join } from "node:path";
|
|
|
32
32
|
import { resolveDeployAuth } from "./cli-deploy.js";
|
|
33
33
|
import { DeployApiError } from "./deploy-client.js";
|
|
34
34
|
import { CLI_COMMAND_NAME as CLI, LOG_PREFIX } from "./distribution.js";
|
|
35
|
+
import { rejectV2ForLegacyCommand } from "./legacy-command-guard.js";
|
|
35
36
|
import {
|
|
36
37
|
ProdTargetError,
|
|
37
38
|
resolveProdSlug,
|
|
@@ -653,6 +654,16 @@ async function cmdMcpInstallRemote(options: McpCliOptions): Promise<number> {
|
|
|
653
654
|
if (typeof auth === "number") {
|
|
654
655
|
return auth;
|
|
655
656
|
}
|
|
657
|
+
try {
|
|
658
|
+
await rejectV2ForLegacyCommand({
|
|
659
|
+
client: auth.client,
|
|
660
|
+
teamId: auth.teamId,
|
|
661
|
+
slug,
|
|
662
|
+
});
|
|
663
|
+
} catch (error) {
|
|
664
|
+
err(`${describeError(error)}\n`);
|
|
665
|
+
return 1;
|
|
666
|
+
}
|
|
656
667
|
|
|
657
668
|
// Verify the deployment resolves before writing config that cannot work.
|
|
658
669
|
// A 403 here is team membership or cloud-agent entitlement, not an
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
runSlackManifest,
|
|
21
21
|
type SlackCliExec,
|
|
22
22
|
} from "./cli-slack-manual.js";
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
cursorExternalApiUrl,
|
|
25
|
+
resolveApiKeySync,
|
|
26
|
+
} from "./cursor/credentials.js";
|
|
24
27
|
import { slugFromDirectoryName } from "./deploy-client.js";
|
|
25
28
|
import { inferDeployGitSource } from "./deploy-source.js";
|
|
26
29
|
import { describeError } from "./describe-error.js";
|
|
@@ -113,7 +116,8 @@ create/destroy/icon — dedicated Socket Mode app via the Cursor dashboard:
|
|
|
113
116
|
create Opens the signed-in dashboard wizard. Finish name, workspace,
|
|
114
117
|
and Slack consent there. The CLI writes the token pair into
|
|
115
118
|
<dir>/.env.local and runs doctor. Requires \`${CLI} login\`
|
|
116
|
-
(or CURSOR_API_KEY).
|
|
119
|
+
(or CURSOR_API_KEY). A team service-account key cannot
|
|
120
|
+
provision Slack apps. --prod provisions the prod app (default
|
|
117
121
|
dev). --name / --icon / --channel-posts prefill the wizard.
|
|
118
122
|
destroy Delete the provisioned Slack app for this agent (+env). Tokens
|
|
119
123
|
already in .env.local are left in place (they just stop working).
|
|
@@ -397,6 +401,15 @@ async function prepareProvision(
|
|
|
397
401
|
const out =
|
|
398
402
|
options.out ?? ((text: string) => void process.stdout.write(text));
|
|
399
403
|
const err = errStream(options);
|
|
404
|
+
const credential = resolveApiKeySync(
|
|
405
|
+
options.apiKey === undefined ? undefined : { apiKey: options.apiKey }
|
|
406
|
+
);
|
|
407
|
+
if (credential?.source === "service-account") {
|
|
408
|
+
err(
|
|
409
|
+
`A team service-account key cannot provision Slack apps. Sign in with \`${CLI} login\` or set CURSOR_API_KEY.\n`
|
|
410
|
+
);
|
|
411
|
+
return 1;
|
|
412
|
+
}
|
|
400
413
|
const auth = await resolveDeployAuth({
|
|
401
414
|
team: options.team,
|
|
402
415
|
apiKey: options.apiKey,
|
|
@@ -176,10 +176,15 @@ export async function clearStoredCredentials(): Promise<boolean> {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
// ============================================================================
|
|
179
|
-
// Resolution (option > env > file > stored login)
|
|
179
|
+
// Resolution (option > env > file > service account > stored login)
|
|
180
180
|
// ============================================================================
|
|
181
181
|
|
|
182
|
-
export type ApiKeySource =
|
|
182
|
+
export type ApiKeySource =
|
|
183
|
+
| "option"
|
|
184
|
+
| "env"
|
|
185
|
+
| "file"
|
|
186
|
+
| "service-account"
|
|
187
|
+
| "login";
|
|
183
188
|
|
|
184
189
|
export interface ResolvedApiKey {
|
|
185
190
|
apiKey: string;
|
|
@@ -274,10 +279,25 @@ export function consumeBoundCursorApiKey(options?: {
|
|
|
274
279
|
};
|
|
275
280
|
}
|
|
276
281
|
|
|
282
|
+
function presentEnvKey(name: string): string | undefined {
|
|
283
|
+
const value = process.env[name];
|
|
284
|
+
if (value === undefined) {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
const trimmed = value.trim();
|
|
288
|
+
return trimmed === "" ? undefined : trimmed;
|
|
289
|
+
}
|
|
290
|
+
|
|
277
291
|
/**
|
|
278
292
|
* First present source wins. We define the order; operators do not.
|
|
279
293
|
* `--api-key` / `serve({ apiKey })` → `CURSOR_API_KEY` → `CURSOR_API_KEY_FILE`
|
|
280
|
-
* (hosted default path if unset) →
|
|
294
|
+
* (hosted default path if unset) → `CURSOR_SERVICE_ACCOUNT_KEY` → stored
|
|
295
|
+
* `july login`.
|
|
296
|
+
*
|
|
297
|
+
* A cloud-agent VM often has the service-account key and no user API key.
|
|
298
|
+
* The explicit key and the hosted bind file still win, so a task credential
|
|
299
|
+
* is not replaced by the ambient service-account key. The service-account
|
|
300
|
+
* key wins over a leftover personal login.
|
|
281
301
|
*/
|
|
282
302
|
export function resolveApiKeySync(options?: {
|
|
283
303
|
apiKey?: string;
|
|
@@ -287,14 +307,22 @@ export function resolveApiKeySync(options?: {
|
|
|
287
307
|
if (options?.apiKey !== undefined && options.apiKey.trim() !== "") {
|
|
288
308
|
return { apiKey: options.apiKey.trim(), source: "option", backendUrl };
|
|
289
309
|
}
|
|
290
|
-
const envKey =
|
|
291
|
-
if (envKey !== undefined
|
|
292
|
-
return { apiKey: envKey
|
|
310
|
+
const envKey = presentEnvKey("CURSOR_API_KEY");
|
|
311
|
+
if (envKey !== undefined) {
|
|
312
|
+
return { apiKey: envKey, source: "env", backendUrl };
|
|
293
313
|
}
|
|
294
314
|
const fileKey = readApiKeyFromFile();
|
|
295
315
|
if (fileKey !== undefined) {
|
|
296
316
|
return { apiKey: fileKey, source: "file", backendUrl };
|
|
297
317
|
}
|
|
318
|
+
const serviceAccountKey = presentEnvKey("CURSOR_SERVICE_ACCOUNT_KEY");
|
|
319
|
+
if (serviceAccountKey !== undefined) {
|
|
320
|
+
return {
|
|
321
|
+
apiKey: serviceAccountKey,
|
|
322
|
+
source: "service-account",
|
|
323
|
+
backendUrl,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
298
326
|
const stored = readStoredCredentialsSync();
|
|
299
327
|
if (stored !== undefined && stored.backendUrl === backendUrl) {
|
|
300
328
|
return { apiKey: stored.apiKey, source: "login", backendUrl };
|
|
@@ -313,7 +341,7 @@ export async function resolveApiKey(options?: {
|
|
|
313
341
|
}
|
|
314
342
|
|
|
315
343
|
/** One-line hint for "no credentials" errors, shared across surfaces. */
|
|
316
|
-
export const SIGN_IN_HINT: string = `Run \`${CLI_COMMAND_NAME} login\` (or set CURSOR_API_KEY / CURSOR_API_KEY_FILE / pass serve({ apiKey })).`;
|
|
344
|
+
export const SIGN_IN_HINT: string = `Run \`${CLI_COMMAND_NAME} login\` (or set CURSOR_API_KEY / CURSOR_API_KEY_FILE / CURSOR_SERVICE_ACCOUNT_KEY / pass serve({ apiKey })).`;
|
|
317
345
|
|
|
318
346
|
// ============================================================================
|
|
319
347
|
// PKCE browser login (mirrors cursor-agent / Sand)
|
|
@@ -285,6 +285,21 @@ export interface AgentkitStopAccepted {
|
|
|
285
285
|
status: string;
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
/**
|
|
289
|
+
* `POST /internal/agentsdk/deployments/:slug/sessions` 202 body. A hosted v2
|
|
290
|
+
* session start is a Temporal delivery: a fresh start allocates `ses_…`
|
|
291
|
+
* only after admission (poll the session list), so the ack is the delivery
|
|
292
|
+
* and workflow ids. `sessionId` is present only when the call resumed one.
|
|
293
|
+
*/
|
|
294
|
+
export interface AgentkitStartSessionAccepted {
|
|
295
|
+
deliveryId: string;
|
|
296
|
+
workflowId: string;
|
|
297
|
+
sessionMode: "event" | "continuation";
|
|
298
|
+
sessionId?: string;
|
|
299
|
+
dryRun?: true;
|
|
300
|
+
asOf?: string;
|
|
301
|
+
}
|
|
302
|
+
|
|
288
303
|
/** One secret's metadata from the list endpoint — names only, never values. */
|
|
289
304
|
export interface SecretInfo {
|
|
290
305
|
name: string;
|
|
@@ -373,6 +388,17 @@ const agentkitStopAcceptedSchema = z
|
|
|
373
388
|
})
|
|
374
389
|
.passthrough();
|
|
375
390
|
|
|
391
|
+
const agentkitStartSessionAcceptedSchema = z
|
|
392
|
+
.object({
|
|
393
|
+
deliveryId: z.string().min(1),
|
|
394
|
+
workflowId: z.string().min(1),
|
|
395
|
+
sessionMode: z.enum(["event", "continuation"]),
|
|
396
|
+
sessionId: z.string().min(1).optional(),
|
|
397
|
+
dryRun: z.literal(true).optional(),
|
|
398
|
+
asOf: z.string().min(1).optional(),
|
|
399
|
+
})
|
|
400
|
+
.passthrough();
|
|
401
|
+
|
|
376
402
|
const deploymentSchema = z.object({
|
|
377
403
|
id: z.number(),
|
|
378
404
|
slug: z.string(),
|
|
@@ -691,6 +717,34 @@ export class AgentServeDeployClient {
|
|
|
691
717
|
return agentkitStopAcceptedSchema.parse(raw);
|
|
692
718
|
}
|
|
693
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Start (or, with `sessionId`, resume) a hosted v2 session through the
|
|
722
|
+
* control plane (`POST /internal/agentsdk/deployments/:slug/sessions`).
|
|
723
|
+
* Does not talk to the v1 engine alias or `/engine/*`.
|
|
724
|
+
*/
|
|
725
|
+
async startSession(args: {
|
|
726
|
+
teamId: number;
|
|
727
|
+
slug: string;
|
|
728
|
+
message: string;
|
|
729
|
+
sessionId?: string;
|
|
730
|
+
dryRun?: boolean;
|
|
731
|
+
asOf?: string;
|
|
732
|
+
}): Promise<AgentkitStartSessionAccepted> {
|
|
733
|
+
const raw = await this.request({
|
|
734
|
+
method: "POST",
|
|
735
|
+
path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}/sessions`,
|
|
736
|
+
body: {
|
|
737
|
+
teamId: args.teamId,
|
|
738
|
+
message: args.message,
|
|
739
|
+
sessionId: args.sessionId,
|
|
740
|
+
dryRun: args.dryRun === true ? true : undefined,
|
|
741
|
+
asOf: args.asOf,
|
|
742
|
+
},
|
|
743
|
+
context: { verb: "start session", slug: args.slug },
|
|
744
|
+
});
|
|
745
|
+
return agentkitStartSessionAcceptedSchema.parse(raw);
|
|
746
|
+
}
|
|
747
|
+
|
|
694
748
|
async listDeployments(args: { teamId: number }): Promise<Deployment[]> {
|
|
695
749
|
const raw = await this.request({
|
|
696
750
|
method: "GET",
|
|
@@ -30,7 +30,11 @@
|
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
import { z } from "zod";
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
type CatchAuthDeclaration,
|
|
35
|
+
catchAuthDeclaration,
|
|
36
|
+
isPublicEndpointPolicy,
|
|
37
|
+
} from "../channels.js";
|
|
34
38
|
import { isCursorHostedStorage } from "../storage-backends/cursor-hosted.js";
|
|
35
39
|
import type { AgentProject, AgentProjectInfo } from "../types.js";
|
|
36
40
|
import {
|
|
@@ -58,6 +62,40 @@ export const DEPLOY_MANIFEST_VERSION: 1 = 1;
|
|
|
58
62
|
*/
|
|
59
63
|
const continuationIdentitySchema = z.enum(CONTINUATION_SELECTORS);
|
|
60
64
|
|
|
65
|
+
const CATCH_MAX_ROUTES = 32;
|
|
66
|
+
const CATCH_MAX_AUTH_POLICIES = 4;
|
|
67
|
+
|
|
68
|
+
const catchDeclarationSchema = z.object({
|
|
69
|
+
routes: z
|
|
70
|
+
.array(
|
|
71
|
+
z.object({
|
|
72
|
+
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
73
|
+
path: z.string().min(1).max(1024),
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
.min(1)
|
|
77
|
+
.max(CATCH_MAX_ROUTES),
|
|
78
|
+
auth: z
|
|
79
|
+
.array(
|
|
80
|
+
z.discriminatedUnion("kind", [
|
|
81
|
+
z.object({
|
|
82
|
+
kind: z.literal("header"),
|
|
83
|
+
header: z.string().min(1).max(128),
|
|
84
|
+
secret: z.string().min(1).max(64),
|
|
85
|
+
}),
|
|
86
|
+
z.object({
|
|
87
|
+
kind: z.literal("hmac-sha256"),
|
|
88
|
+
header: z.string().min(1).max(128),
|
|
89
|
+
secret: z.string().min(1).max(64),
|
|
90
|
+
prefix: z.string().max(32).optional(),
|
|
91
|
+
}),
|
|
92
|
+
z.object({ kind: z.literal("public") }),
|
|
93
|
+
])
|
|
94
|
+
)
|
|
95
|
+
.min(1)
|
|
96
|
+
.max(CATCH_MAX_AUTH_POLICIES),
|
|
97
|
+
});
|
|
98
|
+
|
|
61
99
|
const agentDeployManifestV1Schema = z.object({
|
|
62
100
|
manifestVersion: z.literal(DEPLOY_MANIFEST_VERSION),
|
|
63
101
|
generatedAtMs: z.number().int().nonnegative(),
|
|
@@ -78,6 +116,7 @@ const agentDeployManifestV1Schema = z.object({
|
|
|
78
116
|
kind: z.string().min(1).max(32).optional(),
|
|
79
117
|
eventTypes: z.array(z.string().min(1).max(64)).max(64).optional(),
|
|
80
118
|
continuation: continuationIdentitySchema,
|
|
119
|
+
catch: catchDeclarationSchema.optional(),
|
|
81
120
|
})
|
|
82
121
|
)
|
|
83
122
|
.max(64),
|
|
@@ -110,7 +149,22 @@ export interface AgentDeployManifestDeclarations {
|
|
|
110
149
|
kind?: string;
|
|
111
150
|
eventTypes?: string[];
|
|
112
151
|
continuation: ContinuationIdentity;
|
|
152
|
+
/**
|
|
153
|
+
* Control-plane catch routes: present only for an authored channel
|
|
154
|
+
* whose auth chain carries a `sharedSecretAuth` / `hmacSignatureAuth`
|
|
155
|
+
* policy. The control plane accepts exactly these `(method, path)`
|
|
156
|
+
* pairs and verifies the named deployment secret before any compute.
|
|
157
|
+
*/
|
|
158
|
+
catch?: AgentDeployManifestCatchDeclaration;
|
|
159
|
+
}>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface AgentDeployManifestCatchDeclaration {
|
|
163
|
+
routes: Array<{
|
|
164
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
165
|
+
path: string;
|
|
113
166
|
}>;
|
|
167
|
+
auth: CatchAuthDeclaration[];
|
|
114
168
|
}
|
|
115
169
|
|
|
116
170
|
export interface AgentDeployManifestV1 {
|
|
@@ -158,6 +212,7 @@ export function buildAgentDeployManifest(
|
|
|
158
212
|
kind,
|
|
159
213
|
eventTypes,
|
|
160
214
|
continuation: channelContinuationIdentity(channel.definition),
|
|
215
|
+
catch: channelCatchDeclaration(channel.definition),
|
|
161
216
|
};
|
|
162
217
|
});
|
|
163
218
|
|
|
@@ -195,6 +250,65 @@ export function buildAgentDeployManifest(
|
|
|
195
250
|
};
|
|
196
251
|
}
|
|
197
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Catch declaration for one authored channel: its routes, gated by the
|
|
255
|
+
* catch-capable policies in its auth chain (`sharedSecretAuth`,
|
|
256
|
+
* `hmacSignatureAuth`, or `publicEndpoint()` for handler-verified routes).
|
|
257
|
+
* A routed channel with none of those declares nothing and is not reachable
|
|
258
|
+
* through the catch API.
|
|
259
|
+
*/
|
|
260
|
+
export function channelCatchDeclaration(
|
|
261
|
+
definition: AgentProject["channels"][number]["definition"]
|
|
262
|
+
): AgentDeployManifestCatchDeclaration | undefined {
|
|
263
|
+
const routes = definition.routes ?? [];
|
|
264
|
+
if (routes.length === 0) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
const declared = (definition.auth ?? [])
|
|
268
|
+
.map(catchAuthDeclaration)
|
|
269
|
+
.filter((declaration) => declaration !== undefined);
|
|
270
|
+
if (declared.length === 0) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
// An auth chain is any-of, so `publicEndpoint()` beside secret policies
|
|
274
|
+
// admits everything locally and on the control plane alike. Declare one
|
|
275
|
+
// `public` entry (the control plane then decrypts nothing) but keep the
|
|
276
|
+
// shared-secret header policies next to it: they are what the control
|
|
277
|
+
// plane uses to strip those header values before the request is
|
|
278
|
+
// claim-checked, and senders keep sending the secret regardless of
|
|
279
|
+
// whether anything still checks it. HMAC policies carry body digests,
|
|
280
|
+
// not secrets, so nothing is lost by dropping them.
|
|
281
|
+
const isPublic = declared.some((policy) => policy.kind === "public");
|
|
282
|
+
const auth = isPublic
|
|
283
|
+
? [
|
|
284
|
+
{ kind: "public" as const },
|
|
285
|
+
...declared.filter((policy) => policy.kind === "header"),
|
|
286
|
+
]
|
|
287
|
+
: declared;
|
|
288
|
+
if (routes.length > CATCH_MAX_ROUTES) {
|
|
289
|
+
if (isPublic) {
|
|
290
|
+
// publicEndpoint() channels deployed before catch existed; they stay
|
|
291
|
+
// reachable the way they were (not through catch) rather than
|
|
292
|
+
// failing the deploy.
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
throw new Error(
|
|
296
|
+
`Catch channels may declare at most ${CATCH_MAX_ROUTES} routes (got ${routes.length}).`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
if (auth.length > CATCH_MAX_AUTH_POLICIES) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
isPublic
|
|
302
|
+
? `Catch channels may declare at most ${CATCH_MAX_AUTH_POLICIES} auth policies; publicEndpoint() plus ${String(auth.length - 1)} sharedSecretAuth() policies is ${String(auth.length)}. Drop publicEndpoint() or the shared-secret policies it makes dead.`
|
|
303
|
+
: `Catch channels may declare at most ${CATCH_MAX_AUTH_POLICIES} secret policies (got ${auth.length}).`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
routes: routes.map((route) => ({ method: route.method, path: route.path })),
|
|
308
|
+
auth,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
198
312
|
/**
|
|
199
313
|
* Parse an untrusted manifest (round-trip check for the CLI's own output;
|
|
200
314
|
* the CP re-validates server-side with its own copy of the contract).
|
|
@@ -2,3 +2,31 @@
|
|
|
2
2
|
export function describeError(error: unknown): string {
|
|
3
3
|
return error instanceof Error ? error.message : String(error);
|
|
4
4
|
}
|
|
5
|
+
|
|
6
|
+
export function describeErrorCode(error: unknown): string | undefined {
|
|
7
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
8
|
+
const numericCode = (error as { code?: unknown }).code;
|
|
9
|
+
if (numericCode === 1) {
|
|
10
|
+
return "canceled";
|
|
11
|
+
}
|
|
12
|
+
if (numericCode === 14) {
|
|
13
|
+
return "unavailable";
|
|
14
|
+
}
|
|
15
|
+
if (numericCode === 2) {
|
|
16
|
+
return "unknown";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (
|
|
20
|
+
typeof error === "object" &&
|
|
21
|
+
error !== null &&
|
|
22
|
+
"name" in error &&
|
|
23
|
+
(error as { name?: unknown }).name === "AbortError"
|
|
24
|
+
) {
|
|
25
|
+
return "ABORT_ERR";
|
|
26
|
+
}
|
|
27
|
+
if (typeof error !== "object" || error === null || !("code" in error)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const code = (error as { code?: unknown }).code;
|
|
31
|
+
return typeof code === "string" && code.length <= 64 ? code : undefined;
|
|
32
|
+
}
|