@cursor/july 0.1.100 → 0.1.101
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/bin/agent-serve.js +3 -2
- package/dist/channels/deployments/deployments-channel.d.ts +41 -5
- package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
- package/dist/channels/deployments/deployments-channel.js +88 -8
- package/dist/channels/deployments/types.d.ts +4 -3
- package/dist/channels/deployments/types.d.ts.map +1 -1
- package/dist/channels/origin/defaults.d.ts +43 -0
- package/dist/channels/origin/defaults.d.ts.map +1 -0
- package/dist/channels/origin/defaults.js +111 -0
- package/dist/channels/origin/index.d.ts +2 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +2 -0
- package/dist/channels/origin/origin-channel.d.ts +2 -1
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +24 -3
- package/dist/channels/origin/state.d.ts +32 -0
- package/dist/channels/origin/state.d.ts.map +1 -0
- package/dist/channels/origin/state.js +23 -0
- package/dist/channels/origin/types.d.ts +23 -1
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +2 -1
- package/dist/channels/slack/code-fences.d.ts +17 -0
- package/dist/channels/slack/code-fences.d.ts.map +1 -0
- package/dist/channels/slack/code-fences.js +168 -0
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +11 -4
- package/dist/connections.d.ts +18 -2
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +18 -2
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.DZ1e0Ycq.js → app.BASO9Kih.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DbFXINq2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.l8omwc6D.js → VPLocalSearchBox.DwkqxoE0.js} +1 -1
- package/dist/docs/assets/chunks/{theme.JVcD6gel.js → theme.CCil_13e.js} +2 -2
- package/dist/docs/assets/{reference_connections.md.BiGoBAk2.js → reference_connections.md.Di6jJAXF.js} +12 -2
- package/dist/docs/assets/{reference_connections.md.BiGoBAk2.lean.js → reference_connections.md.Di6jJAXF.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.js → reference_http-api.md.oySXBO8o.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +4 -4
- 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 +4 -4
- package/dist/docs/llms-full.txt +32 -1
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +16 -6
- package/dist/docs/reference/connections.md +31 -0
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +1 -1
- 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/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 +4 -4
- package/dist/docs/skills/ab.html +4 -4
- package/dist/docs/skills/create-agent.html +4 -4
- package/dist/docs/skills/debug.html +4 -4
- package/dist/docs/skills/evals.html +4 -4
- package/dist/docs/skills/framework-map.html +4 -4
- package/dist/docs/skills/github.html +4 -4
- 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/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 +4 -4
- package/dist/extensions/cursor-cloud-agents/extension.d.ts +55 -0
- package/dist/extensions/cursor-cloud-agents/extension.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/extension.js +64 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts +30 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.js +45 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts +25 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.js +85 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts +15 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.js +55 -0
- package/dist/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.js +37 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.js +83 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.js +36 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.js +41 -0
- package/dist/extensions.d.ts +49 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +75 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/internal/advertise-tools.d.ts +4 -1
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +20 -1
- package/dist/internal/as-of.d.ts +18 -0
- package/dist/internal/as-of.d.ts.map +1 -1
- package/dist/internal/as-of.js +131 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +64 -19
- package/dist/internal/continuation-identity.d.ts.map +1 -1
- package/dist/internal/continuation-identity.js +3 -1
- package/dist/internal/cursor/hosted-deployment-secrets.d.ts +16 -0
- package/dist/internal/cursor/hosted-deployment-secrets.d.ts.map +1 -0
- package/dist/internal/cursor/hosted-deployment-secrets.js +61 -0
- package/dist/internal/cursor-deployment-relay.d.ts +15 -1
- package/dist/internal/cursor-deployment-relay.d.ts.map +1 -1
- package/dist/internal/cursor-deployment-relay.js +46 -7
- package/dist/internal/deploy-client.d.ts +23 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +54 -12
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +415 -120
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +5 -0
- package/dist/internal/framework-file-storage.d.ts +3 -3
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +34 -5
- package/dist/internal/hosted-delivery.d.ts +3 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +19 -32
- package/dist/internal/hosted-execution-diag.d.ts +5 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
- package/dist/internal/hosted-execution-diag.js +5 -0
- package/dist/internal/hosted-execution-flush.d.ts +46 -0
- package/dist/internal/hosted-execution-flush.d.ts.map +1 -0
- package/dist/internal/hosted-execution-flush.js +81 -0
- package/dist/internal/mcp-endpoint.js +1 -0
- package/dist/internal/mcp-host.d.ts +2 -1
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +35 -15
- package/dist/internal/review-comments.d.ts +1 -1
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +4 -4
- package/dist/internal/server.d.ts +3 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +79 -104
- package/dist/internal/session-engine.d.ts +9 -7
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +45 -34
- package/dist/internal/session-run-log.d.ts +2 -1
- package/dist/internal/session-run-log.d.ts.map +1 -1
- package/dist/internal/session-run-log.js +2 -1
- package/dist/internal/start-log-store.d.ts +60 -0
- package/dist/internal/start-log-store.d.ts.map +1 -0
- package/dist/internal/start-log-store.js +151 -0
- package/dist/internal/tool-policy.d.ts +8 -0
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +19 -7
- package/dist/playground/assets/{index-DVs98vPL.js → index-BnNN1-EK.js} +45 -45
- package/dist/playground/assets/index-DBQCwFp0.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-protocol.d.ts +24 -0
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +33 -0
- package/dist/storage.d.ts +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +118 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +29 -1
- package/docs/reference/connections.md +31 -0
- package/docs/reference/http-api.md +1 -1
- package/package.json +18 -4
- package/src/bin/agent-serve.ts +11 -2
- package/src/channels/deployments/deployments-channel.ts +117 -8
- package/src/channels/deployments/types.ts +4 -3
- package/src/channels/origin/defaults.ts +143 -0
- package/src/channels/origin/index.ts +2 -0
- package/src/channels/origin/origin-channel.ts +37 -1
- package/src/channels/origin/state.ts +54 -0
- package/src/channels/origin/types.ts +24 -0
- package/src/channels/slack/api.ts +2 -1
- package/src/channels/slack/code-fences.ts +183 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +16 -13
- package/src/connections.ts +18 -1
- package/src/extensions/cursor-cloud-agents/extension.ts +118 -0
- package/src/extensions/cursor-cloud-agents/lib/cloud.ts +79 -0
- package/src/extensions/cursor-cloud-agents/lib/fleet.ts +109 -0
- package/src/extensions/cursor-cloud-agents/lib/repos.ts +81 -0
- package/src/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
- package/src/extensions/cursor-cloud-agents/tools/follow_up.ts +29 -0
- package/src/extensions/cursor-cloud-agents/tools/launch.ts +84 -0
- package/src/extensions/cursor-cloud-agents/tools/list.ts +31 -0
- package/src/extensions/cursor-cloud-agents/tools/status.ts +39 -0
- package/src/extensions.ts +98 -0
- package/src/index.ts +2 -0
- package/src/internal/advertise-tools.ts +37 -12
- package/src/internal/as-of.ts +163 -0
- package/src/internal/cli-deploy.ts +86 -23
- package/src/internal/continuation-identity.ts +3 -1
- package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
- package/src/internal/cursor-deployment-relay.ts +65 -8
- package/src/internal/deploy-client.ts +73 -18
- package/src/internal/discovery.ts +470 -113
- package/src/internal/distribution.ts +5 -0
- package/src/internal/framework-file-storage.ts +39 -5
- package/src/internal/hosted-delivery.ts +38 -63
- package/src/internal/hosted-execution-diag.ts +6 -0
- package/src/internal/hosted-execution-flush.ts +142 -0
- package/src/internal/mcp-endpoint.ts +1 -0
- package/src/internal/mcp-host.ts +40 -14
- package/src/internal/review-comments.ts +5 -2
- package/src/internal/server.ts +81 -100
- package/src/internal/session-engine.ts +56 -28
- package/src/internal/session-run-log.ts +2 -1
- package/src/internal/start-log-store.ts +177 -0
- package/src/internal/tool-policy.ts +39 -9
- package/src/storage-protocol.ts +37 -0
- package/src/storage.ts +1 -0
- package/src/types.ts +172 -14
- package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +0 -1
- package/dist/playground/assets/index-BszoQDc6.css +0 -1
- /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
|
@@ -329,6 +329,14 @@ export async function cmdDeploy(options: DeployCliOptions): Promise<number> {
|
|
|
329
329
|
if (manifests.every((manifest) => manifest.architecture === "v2")) {
|
|
330
330
|
return deployAgentsdkApplication(ctx, options, targets, {
|
|
331
331
|
hasScmChannels: manifests.some((manifest) => manifest.hasScmChannels),
|
|
332
|
+
declaredSecretNames: [
|
|
333
|
+
...new Set(
|
|
334
|
+
manifests.flatMap((manifest) => manifest.hosting?.secretNames ?? [])
|
|
335
|
+
),
|
|
336
|
+
],
|
|
337
|
+
hasDeploymentsChannels: manifests.some(
|
|
338
|
+
(manifest) => manifest.hasDeploymentsChannels
|
|
339
|
+
),
|
|
332
340
|
});
|
|
333
341
|
}
|
|
334
342
|
if (
|
|
@@ -741,6 +749,8 @@ async function deployOne(
|
|
|
741
749
|
agentPath,
|
|
742
750
|
repositories: options.cursorEventsRepos,
|
|
743
751
|
hasScmChannels: manifest.hasScmChannels,
|
|
752
|
+
declaredSecretNames: hosting?.secretNames,
|
|
753
|
+
hasDeploymentsChannels: manifest.hasDeploymentsChannels,
|
|
744
754
|
multiTenant: options.multiTenant === true,
|
|
745
755
|
});
|
|
746
756
|
}
|
|
@@ -871,7 +881,11 @@ async function deployAgentsdkApplication(
|
|
|
871
881
|
ctx: DeployCliContext,
|
|
872
882
|
options: DeployCliOptions,
|
|
873
883
|
targets: readonly DeployTarget[],
|
|
874
|
-
declarations: {
|
|
884
|
+
declarations: {
|
|
885
|
+
hasScmChannels: boolean;
|
|
886
|
+
declaredSecretNames: string[];
|
|
887
|
+
hasDeploymentsChannels: boolean;
|
|
888
|
+
}
|
|
875
889
|
): Promise<number> {
|
|
876
890
|
const parentDir = resolve(options.dir ?? ".");
|
|
877
891
|
const slug = slugFromDirectoryName(basename(parentDir));
|
|
@@ -936,16 +950,7 @@ async function deployAgentsdkApplication(
|
|
|
936
950
|
);
|
|
937
951
|
}
|
|
938
952
|
|
|
939
|
-
|
|
940
|
-
// budget is per component; otherwise a 2+ component deploy routinely hits
|
|
941
|
-
// the client-side timeout while the server-side deploy is still fine. An
|
|
942
|
-
// explicitly passed timeout always wins.
|
|
943
|
-
const waitCtx =
|
|
944
|
-
options.timeoutMs === undefined
|
|
945
|
-
? { ...ctx, timeoutMs: ctx.timeoutMs * targets.length }
|
|
946
|
-
: ctx;
|
|
947
|
-
|
|
948
|
-
return deployOneAgentsdk(waitCtx, undefined, {
|
|
953
|
+
return deployOneAgentsdk(ctx, undefined, {
|
|
949
954
|
slug,
|
|
950
955
|
gitRepoUrl,
|
|
951
956
|
gitRef,
|
|
@@ -953,6 +958,8 @@ async function deployAgentsdkApplication(
|
|
|
953
958
|
components,
|
|
954
959
|
repositories: options.cursorEventsRepos,
|
|
955
960
|
hasScmChannels: declarations.hasScmChannels,
|
|
961
|
+
declaredSecretNames: declarations.declaredSecretNames,
|
|
962
|
+
hasDeploymentsChannels: declarations.hasDeploymentsChannels,
|
|
956
963
|
multiTenant: options.multiTenant === true,
|
|
957
964
|
});
|
|
958
965
|
}
|
|
@@ -974,6 +981,10 @@ async function deployOneAgentsdk(
|
|
|
974
981
|
repositories: string[] | undefined;
|
|
975
982
|
/** Any component declares a GitHub/Origin channel. */
|
|
976
983
|
hasScmChannels: boolean;
|
|
984
|
+
/** Union of application component secret declarations. */
|
|
985
|
+
declaredSecretNames?: string[];
|
|
986
|
+
/** Any component declares a deployments channel (same repo scope). */
|
|
987
|
+
hasDeploymentsChannels?: boolean;
|
|
977
988
|
/** Redeploy an existing Cursor-managed product. */
|
|
978
989
|
multiTenant: boolean;
|
|
979
990
|
}
|
|
@@ -1048,6 +1059,9 @@ async function deployOneAgentsdk(
|
|
|
1048
1059
|
);
|
|
1049
1060
|
return 1;
|
|
1050
1061
|
}
|
|
1062
|
+
warnMissingSecrets(ctx, slug, args.declaredSecretNames, detail.secretNames);
|
|
1063
|
+
const watchesRepositories =
|
|
1064
|
+
args.hasScmChannels || args.hasDeploymentsChannels === true;
|
|
1051
1065
|
ctx.out(
|
|
1052
1066
|
`Deployed ${slug} (team ${ctx.teamId})\n` +
|
|
1053
1067
|
` status: running\n` +
|
|
@@ -1059,15 +1073,16 @@ async function deployOneAgentsdk(
|
|
|
1059
1073
|
: ` components: ${args.components
|
|
1060
1074
|
.map((component) => component.componentKey)
|
|
1061
1075
|
.join(", ")}\n`) +
|
|
1062
|
-
(detail.repositories === undefined || !
|
|
1076
|
+
(detail.repositories === undefined || !watchesRepositories
|
|
1063
1077
|
? ""
|
|
1064
1078
|
: ` watching: ${detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")}\n`)
|
|
1065
1079
|
);
|
|
1066
|
-
// An agent with GitHub/Origin channels bound to no repository
|
|
1067
|
-
// no deliveries at all
|
|
1068
|
-
|
|
1080
|
+
// An agent with GitHub/Origin/deployments channels bound to no repository
|
|
1081
|
+
// scope gets no deliveries at all (deployments channels receive the
|
|
1082
|
+
// watched repos' deployment events), which is otherwise invisible here.
|
|
1083
|
+
if (watchesRepositories && detail.repositories?.length === 0) {
|
|
1069
1084
|
ctx.err(
|
|
1070
|
-
`warning: ${slug} watches no repositories, so its GitHub/Origin channels receive no events.\n` +
|
|
1085
|
+
`warning: ${slug} watches no repositories, so its GitHub/Origin/deployments channels receive no events.\n` +
|
|
1071
1086
|
` Redeploy with --cursor-events-repo <owner>/<name> to set the scope.\n`
|
|
1072
1087
|
);
|
|
1073
1088
|
}
|
|
@@ -1185,6 +1200,12 @@ interface DeployManifest {
|
|
|
1185
1200
|
* while the deployment is bound to at least one `owner/name` scope.
|
|
1186
1201
|
*/
|
|
1187
1202
|
hasScmChannels: boolean;
|
|
1203
|
+
/**
|
|
1204
|
+
* The agent has deployments channels; deploy-source edges derive from
|
|
1205
|
+
* the same watched-repo set as GitHub/Origin, so it too receives
|
|
1206
|
+
* nothing while the deployment watches no repositories.
|
|
1207
|
+
*/
|
|
1208
|
+
hasDeploymentsChannels: boolean;
|
|
1188
1209
|
}
|
|
1189
1210
|
|
|
1190
1211
|
/**
|
|
@@ -1224,6 +1245,9 @@ async function readDeployManifest(dir: string): Promise<DeployManifest> {
|
|
|
1224
1245
|
const kind = channel.definition.meta?.kind;
|
|
1225
1246
|
return kind === "github" || kind === "origin";
|
|
1226
1247
|
}),
|
|
1248
|
+
hasDeploymentsChannels: project.channels.some(
|
|
1249
|
+
(channel) => channel.definition.meta?.kind === "deployments"
|
|
1250
|
+
),
|
|
1227
1251
|
};
|
|
1228
1252
|
}
|
|
1229
1253
|
|
|
@@ -1450,6 +1474,9 @@ function renderAgentkitDeploymentStatus(
|
|
|
1450
1474
|
}`
|
|
1451
1475
|
);
|
|
1452
1476
|
}
|
|
1477
|
+
if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
|
|
1478
|
+
lines.push(` secrets: ${detail.secretNames.join(", ")}`);
|
|
1479
|
+
}
|
|
1453
1480
|
if (detail.lastError !== null && detail.lastError !== undefined) {
|
|
1454
1481
|
lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
|
|
1455
1482
|
}
|
|
@@ -1650,6 +1677,21 @@ export async function cmdRotatePodCredential(
|
|
|
1650
1677
|
// secrets set|list|unset
|
|
1651
1678
|
// ============================================================================
|
|
1652
1679
|
|
|
1680
|
+
async function secretDeploymentArchitecture(
|
|
1681
|
+
ctx: DeployCliContext,
|
|
1682
|
+
slug: string
|
|
1683
|
+
): Promise<"v1" | "v2"> {
|
|
1684
|
+
try {
|
|
1685
|
+
await ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug });
|
|
1686
|
+
return "v2";
|
|
1687
|
+
} catch (error) {
|
|
1688
|
+
if (error instanceof DeployApiError && error.status === 404) {
|
|
1689
|
+
return "v1";
|
|
1690
|
+
}
|
|
1691
|
+
throw error;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1653
1695
|
export async function cmdSecretsSet(
|
|
1654
1696
|
slug: string | undefined,
|
|
1655
1697
|
specs: string[],
|
|
@@ -1712,11 +1754,19 @@ export async function cmdSecretsSet(
|
|
|
1712
1754
|
|
|
1713
1755
|
let secretNames: string[];
|
|
1714
1756
|
try {
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1757
|
+
const architecture = await secretDeploymentArchitecture(ctx, slug);
|
|
1758
|
+
secretNames =
|
|
1759
|
+
architecture === "v2"
|
|
1760
|
+
? await ctx.client.setAgentkitSecrets({
|
|
1761
|
+
teamId: ctx.teamId,
|
|
1762
|
+
slug,
|
|
1763
|
+
secrets,
|
|
1764
|
+
})
|
|
1765
|
+
: await ctx.client.setSecrets({
|
|
1766
|
+
teamId: ctx.teamId,
|
|
1767
|
+
slug,
|
|
1768
|
+
secrets,
|
|
1769
|
+
});
|
|
1720
1770
|
} catch (error) {
|
|
1721
1771
|
return renderApiError(error, ctx.err);
|
|
1722
1772
|
}
|
|
@@ -1748,7 +1798,11 @@ export async function cmdSecretsList(
|
|
|
1748
1798
|
}
|
|
1749
1799
|
let secrets: SecretInfo[];
|
|
1750
1800
|
try {
|
|
1751
|
-
|
|
1801
|
+
const architecture = await secretDeploymentArchitecture(ctx, slug);
|
|
1802
|
+
secrets =
|
|
1803
|
+
architecture === "v2"
|
|
1804
|
+
? await ctx.client.listAgentkitSecrets({ teamId: ctx.teamId, slug })
|
|
1805
|
+
: await ctx.client.listSecrets({ teamId: ctx.teamId, slug });
|
|
1752
1806
|
} catch (error) {
|
|
1753
1807
|
return renderApiError(error, ctx.err);
|
|
1754
1808
|
}
|
|
@@ -1787,7 +1841,16 @@ export async function cmdSecretsUnset(
|
|
|
1787
1841
|
return ctx;
|
|
1788
1842
|
}
|
|
1789
1843
|
try {
|
|
1790
|
-
await
|
|
1844
|
+
const architecture = await secretDeploymentArchitecture(ctx, slug);
|
|
1845
|
+
if (architecture === "v2") {
|
|
1846
|
+
await ctx.client.deleteAgentkitSecret({
|
|
1847
|
+
teamId: ctx.teamId,
|
|
1848
|
+
slug,
|
|
1849
|
+
name,
|
|
1850
|
+
});
|
|
1851
|
+
} else {
|
|
1852
|
+
await ctx.client.deleteSecret({ teamId: ctx.teamId, slug, name });
|
|
1853
|
+
}
|
|
1791
1854
|
} catch (error) {
|
|
1792
1855
|
if (error instanceof DeployApiError && error.status === 404) {
|
|
1793
1856
|
ctx.err(
|
|
@@ -119,7 +119,9 @@ export const BUILTINS: readonly ContinuationBuiltin[] = [
|
|
|
119
119
|
{
|
|
120
120
|
type: "deployment",
|
|
121
121
|
kind: "deployments",
|
|
122
|
-
events
|
|
122
|
+
// All three factory stream events carry `deploymentId`; keep in
|
|
123
|
+
// lockstep with the control plane's `conversation/deployments.ts`.
|
|
124
|
+
events: ["deployment.created", "deployment.succeeded", "deployment.failed"],
|
|
123
125
|
format: "deployments:{deploymentId}",
|
|
124
126
|
},
|
|
125
127
|
] as const;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task-time application secrets for hosted v2 freeze restores.
|
|
3
|
+
*
|
|
4
|
+
* The deployment host rewrites this tmpfs document before each admission and
|
|
5
|
+
* execution request. July reloads it synchronously because the process was
|
|
6
|
+
* already running in the frozen snapshot when the task-specific values
|
|
7
|
+
* arrived.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_AGENT_SERVE_DEPLOYMENT_SECRETS_FILE =
|
|
13
|
+
"/run/cursor/secrets/AGENT_SERVE_DEPLOYMENT_SECRETS.json";
|
|
14
|
+
|
|
15
|
+
const SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
16
|
+
const appliedSecretNames = new Set<string>();
|
|
17
|
+
|
|
18
|
+
function parseBoundSecrets(path: string): Record<string, string> | undefined {
|
|
19
|
+
let parsed: unknown;
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
22
|
+
} catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const envelope = parsed as { v?: unknown; secrets?: unknown };
|
|
29
|
+
if (
|
|
30
|
+
envelope.v !== 1 ||
|
|
31
|
+
envelope.secrets === null ||
|
|
32
|
+
typeof envelope.secrets !== "object" ||
|
|
33
|
+
Array.isArray(envelope.secrets)
|
|
34
|
+
) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const secrets: Record<string, string> = {};
|
|
38
|
+
for (const [name, value] of Object.entries(envelope.secrets)) {
|
|
39
|
+
if (
|
|
40
|
+
SECRET_NAME_PATTERN.test(name) &&
|
|
41
|
+
!name.startsWith("CURSOR_") &&
|
|
42
|
+
typeof value === "string"
|
|
43
|
+
) {
|
|
44
|
+
secrets[name] = value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return secrets;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Refresh `process.env` from the latest bound document. A missing or malformed
|
|
52
|
+
* file is a no-op; an empty valid document removes values loaded by an earlier
|
|
53
|
+
* bind after the deployment secret was unset.
|
|
54
|
+
*/
|
|
55
|
+
export function refreshBoundDeploymentSecrets(
|
|
56
|
+
path: string = DEFAULT_AGENT_SERVE_DEPLOYMENT_SECRETS_FILE
|
|
57
|
+
): void {
|
|
58
|
+
const secrets = parseBoundSecrets(path);
|
|
59
|
+
if (secrets === undefined) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const name of appliedSecretNames) {
|
|
63
|
+
if (!(name in secrets)) {
|
|
64
|
+
delete process.env[name];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
appliedSecretNames.clear();
|
|
68
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
69
|
+
process.env[name] = value;
|
|
70
|
+
appliedSecretNames.add(name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -33,17 +33,33 @@ interface SubscriptionStatus {
|
|
|
33
33
|
detail?: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export type DeploymentSubscriptionSource =
|
|
37
|
+
| readonly ResolvedSubscription[]
|
|
38
|
+
| (() => readonly ResolvedSubscription[]);
|
|
39
|
+
|
|
36
40
|
export interface DeploymentEventRelayOptions {
|
|
37
41
|
baseUrl: string;
|
|
38
42
|
apiKey: string;
|
|
39
43
|
stateDir: string;
|
|
40
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Snapshot or a getter. A getter is re-read on every registration
|
|
46
|
+
* heartbeat so a channel that refreshes `deploySourceUris` after start
|
|
47
|
+
* can add sources without restarting the relay.
|
|
48
|
+
*/
|
|
49
|
+
subscriptions: DeploymentSubscriptionSource;
|
|
41
50
|
dispatch: (event: DeploymentEvent) => Promise<void>;
|
|
42
51
|
logger: (line: string) => void;
|
|
43
52
|
fetchImpl?: typeof fetch;
|
|
44
53
|
pollWaitMs?: number;
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
/** Current subscriptions: a live getter, otherwise the snapshot. */
|
|
57
|
+
export function currentDeploymentSubscriptions(
|
|
58
|
+
subscriptions: DeploymentSubscriptionSource
|
|
59
|
+
): readonly ResolvedSubscription[] {
|
|
60
|
+
return typeof subscriptions === "function" ? subscriptions() : subscriptions;
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
/** Normalize the channel's `deploySourceUris` option into concrete subscriptions. */
|
|
48
64
|
export function resolveDeploymentSubscriptions(options: {
|
|
49
65
|
deploySourceUris: readonly (string | DeploymentSubscription)[];
|
|
@@ -90,10 +106,46 @@ export function resolveDeploymentSubscriptions(options: {
|
|
|
90
106
|
? []
|
|
91
107
|
: [...new Set([...existing.environments, ...environments])];
|
|
92
108
|
}
|
|
93
|
-
// Empty is legal here and means "this channel wants nothing"
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
109
|
+
// Empty is legal here and means "this channel wants nothing". The
|
|
110
|
+
// wire-level empty list means deregister. The host re-resolves on each
|
|
111
|
+
// heartbeat, so a channel that later fills `deploySourceUris` can
|
|
112
|
+
// register without a restart.
|
|
113
|
+
return [...bySource.values()];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Union per-channel subscriptions, widening events and environments when
|
|
118
|
+
* the same deploy source appears more than once. An empty environment
|
|
119
|
+
* list means every environment and absorbs a narrower list.
|
|
120
|
+
*/
|
|
121
|
+
export function mergeResolvedSubscriptions(
|
|
122
|
+
groups: readonly (readonly ResolvedSubscription[])[]
|
|
123
|
+
): ResolvedSubscription[] {
|
|
124
|
+
const bySource = new Map<string, ResolvedSubscription>();
|
|
125
|
+
for (const group of groups) {
|
|
126
|
+
for (const subscription of group) {
|
|
127
|
+
const existing = bySource.get(subscription.deploySourceUri);
|
|
128
|
+
if (existing === undefined) {
|
|
129
|
+
bySource.set(subscription.deploySourceUri, {
|
|
130
|
+
deploySourceUri: subscription.deploySourceUri,
|
|
131
|
+
environments: [...subscription.environments],
|
|
132
|
+
events: new Set(subscription.events),
|
|
133
|
+
});
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
for (const event of subscription.events) existing.events.add(event);
|
|
137
|
+
existing.environments =
|
|
138
|
+
existing.environments.length === 0 ||
|
|
139
|
+
subscription.environments.length === 0
|
|
140
|
+
? []
|
|
141
|
+
: [
|
|
142
|
+
...new Set([
|
|
143
|
+
...existing.environments,
|
|
144
|
+
...subscription.environments,
|
|
145
|
+
]),
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
97
149
|
return [...bySource.values()];
|
|
98
150
|
}
|
|
99
151
|
|
|
@@ -176,7 +228,9 @@ export class DeploymentEventRelay {
|
|
|
176
228
|
pollPath: "/v0/deployment-events",
|
|
177
229
|
buildRegistrationBody: (consumerId) => ({
|
|
178
230
|
consumerId,
|
|
179
|
-
subscriptions:
|
|
231
|
+
subscriptions: currentDeploymentSubscriptions(
|
|
232
|
+
options.subscriptions
|
|
233
|
+
).map((subscription) => ({
|
|
180
234
|
deploySourceUri: subscription.deploySourceUri,
|
|
181
235
|
environments: subscription.environments,
|
|
182
236
|
events: [...subscription.events],
|
|
@@ -190,12 +244,15 @@ export class DeploymentEventRelay {
|
|
|
190
244
|
}),
|
|
191
245
|
applyRegistrationResponse: (json) => {
|
|
192
246
|
const result = json as { deploySourceUris?: SubscriptionStatus[] };
|
|
247
|
+
const wantedSubscriptions = currentDeploymentSubscriptions(
|
|
248
|
+
options.subscriptions
|
|
249
|
+
);
|
|
193
250
|
this.subscribed = new Map();
|
|
194
251
|
this.loggedSkippedSources.clear();
|
|
195
252
|
const lines: string[] = [];
|
|
196
253
|
const confirmed: string[] = [];
|
|
197
254
|
for (const status of result.deploySourceUris ?? []) {
|
|
198
|
-
const wanted =
|
|
255
|
+
const wanted = wantedSubscriptions.find(
|
|
199
256
|
(subscription) =>
|
|
200
257
|
subscription.deploySourceUri === status.deploySourceUri
|
|
201
258
|
);
|
|
@@ -210,7 +267,7 @@ export class DeploymentEventRelay {
|
|
|
210
267
|
}
|
|
211
268
|
if (confirmed.length > 0) {
|
|
212
269
|
const kinds = [
|
|
213
|
-
...new Set(
|
|
270
|
+
...new Set(wantedSubscriptions.flatMap((s) => [...s.events])),
|
|
214
271
|
];
|
|
215
272
|
lines.push(
|
|
216
273
|
`subscribed to ${confirmed.join(", ")} for events: ${kinds.join(", ")}`
|
|
@@ -267,6 +267,8 @@ export interface AgentkitDeployStatus {
|
|
|
267
267
|
* Absent on control planes that predate the field.
|
|
268
268
|
*/
|
|
269
269
|
repositories?: string[];
|
|
270
|
+
/** Names of application-scoped secrets (values are never returned). */
|
|
271
|
+
secretNames?: string[];
|
|
270
272
|
}
|
|
271
273
|
|
|
272
274
|
export const TERMINAL_AGENTKIT_DEPLOY_STATUSES: ReadonlySet<AgentkitCustomerStatus> =
|
|
@@ -359,6 +361,7 @@ const agentkitDeployStatusSchema = z
|
|
|
359
361
|
statusMessage: z.string().nullable(),
|
|
360
362
|
// Optional: backends that predate the v2 bake-failure column omit it.
|
|
361
363
|
lastError: z.string().nullable().optional(),
|
|
364
|
+
secretNames: z.array(z.string()).optional(),
|
|
362
365
|
})
|
|
363
366
|
.passthrough();
|
|
364
367
|
|
|
@@ -740,24 +743,7 @@ export class AgentServeDeployClient {
|
|
|
740
743
|
slug: string;
|
|
741
744
|
secrets: Array<{ name: string; value: string }>;
|
|
742
745
|
}): Promise<string[]> {
|
|
743
|
-
|
|
744
|
-
const nameError = validateSettableSecretName(name);
|
|
745
|
-
if (nameError !== undefined) {
|
|
746
|
-
throw new DeployApiError(nameError, 400);
|
|
747
|
-
}
|
|
748
|
-
if (Buffer.byteLength(value, "utf8") > MAX_SECRET_VALUE_BYTES) {
|
|
749
|
-
throw new DeployApiError(
|
|
750
|
-
`The value for ${name} is too large (max ${MAX_SECRET_VALUE_BYTES} bytes).`,
|
|
751
|
-
400
|
|
752
|
-
);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
if (args.secrets.length > MAX_SECRETS) {
|
|
756
|
-
throw new DeployApiError(
|
|
757
|
-
`Too many secrets in one request (${args.secrets.length}); deployments hold at most ${MAX_SECRETS}.`,
|
|
758
|
-
400
|
|
759
|
-
);
|
|
760
|
-
}
|
|
746
|
+
this.validateSecrets(args.secrets);
|
|
761
747
|
const raw = await this.request({
|
|
762
748
|
method: "PUT",
|
|
763
749
|
path: `/internal/agent-serve/deployments/${encodeURIComponent(args.slug)}/secrets`,
|
|
@@ -767,6 +753,22 @@ export class AgentServeDeployClient {
|
|
|
767
753
|
return setSecretsResponseSchema.parse(raw).secretNames;
|
|
768
754
|
}
|
|
769
755
|
|
|
756
|
+
/** Upsert application-scoped secrets on an AgentSDK v2 deployment. */
|
|
757
|
+
async setAgentkitSecrets(args: {
|
|
758
|
+
teamId: number;
|
|
759
|
+
slug: string;
|
|
760
|
+
secrets: Array<{ name: string; value: string }>;
|
|
761
|
+
}): Promise<string[]> {
|
|
762
|
+
this.validateSecrets(args.secrets);
|
|
763
|
+
const raw = await this.request({
|
|
764
|
+
method: "PUT",
|
|
765
|
+
path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}/secrets`,
|
|
766
|
+
body: { teamId: args.teamId, secrets: args.secrets },
|
|
767
|
+
context: { verb: "set secrets", slug: args.slug },
|
|
768
|
+
});
|
|
769
|
+
return setSecretsResponseSchema.parse(raw).secretNames;
|
|
770
|
+
}
|
|
771
|
+
|
|
770
772
|
/** Secret names + creation times; values are never returned. */
|
|
771
773
|
async listSecrets(args: {
|
|
772
774
|
teamId: number;
|
|
@@ -780,6 +782,19 @@ export class AgentServeDeployClient {
|
|
|
780
782
|
return listSecretsResponseSchema.parse(raw).secrets;
|
|
781
783
|
}
|
|
782
784
|
|
|
785
|
+
/** Secret names + creation times for an AgentSDK v2 application. */
|
|
786
|
+
async listAgentkitSecrets(args: {
|
|
787
|
+
teamId: number;
|
|
788
|
+
slug: string;
|
|
789
|
+
}): Promise<SecretInfo[]> {
|
|
790
|
+
const raw = await this.request({
|
|
791
|
+
method: "GET",
|
|
792
|
+
path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}/secrets?teamId=${args.teamId}`,
|
|
793
|
+
context: { verb: "list secrets", slug: args.slug },
|
|
794
|
+
});
|
|
795
|
+
return listSecretsResponseSchema.parse(raw).secrets;
|
|
796
|
+
}
|
|
797
|
+
|
|
783
798
|
/** Remove one secret by name; 404 when it is not set. */
|
|
784
799
|
async deleteSecret(args: {
|
|
785
800
|
teamId: number;
|
|
@@ -797,6 +812,46 @@ export class AgentServeDeployClient {
|
|
|
797
812
|
});
|
|
798
813
|
}
|
|
799
814
|
|
|
815
|
+
/** Remove one application-scoped secret from an AgentSDK v2 deployment. */
|
|
816
|
+
async deleteAgentkitSecret(args: {
|
|
817
|
+
teamId: number;
|
|
818
|
+
slug: string;
|
|
819
|
+
name: string;
|
|
820
|
+
}): Promise<void> {
|
|
821
|
+
const nameError = validateSettableSecretName(args.name);
|
|
822
|
+
if (nameError !== undefined) {
|
|
823
|
+
throw new DeployApiError(nameError, 400);
|
|
824
|
+
}
|
|
825
|
+
await this.request({
|
|
826
|
+
method: "DELETE",
|
|
827
|
+
path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}/secrets/${encodeURIComponent(args.name)}?teamId=${args.teamId}`,
|
|
828
|
+
context: { verb: "unset secret", slug: args.slug },
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private validateSecrets(
|
|
833
|
+
secrets: Array<{ name: string; value: string }>
|
|
834
|
+
): void {
|
|
835
|
+
for (const { name, value } of secrets) {
|
|
836
|
+
const nameError = validateSettableSecretName(name);
|
|
837
|
+
if (nameError !== undefined) {
|
|
838
|
+
throw new DeployApiError(nameError, 400);
|
|
839
|
+
}
|
|
840
|
+
if (Buffer.byteLength(value, "utf8") > MAX_SECRET_VALUE_BYTES) {
|
|
841
|
+
throw new DeployApiError(
|
|
842
|
+
`The value for ${name} is too large (max ${MAX_SECRET_VALUE_BYTES} bytes).`,
|
|
843
|
+
400
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (secrets.length > MAX_SECRETS) {
|
|
848
|
+
throw new DeployApiError(
|
|
849
|
+
`Too many secrets in one request (${secrets.length}); deployments hold at most ${MAX_SECRETS}.`,
|
|
850
|
+
400
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
800
855
|
/**
|
|
801
856
|
* Rotate the deployment's pod credential. Returns the masked new key —
|
|
802
857
|
* the raw key is injected into the pod on the next deploy, never
|