@cursor/july 0.1.7 → 0.1.9
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 +31 -2
- package/dist/channels/slack/channel-watch.d.ts +6 -1
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +22 -1
- package/dist/channels/slack/cursor-account.d.ts +4 -0
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +12 -2
- package/dist/channels/slack/defaults.d.ts +10 -5
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +39 -17
- package/dist/channels/slack/dispatch.d.ts +18 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +141 -38
- package/dist/channels/slack/inbound.d.ts +13 -3
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +17 -9
- package/dist/channels/slack/index.d.ts +4 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +4 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +1 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +3 -0
- package/dist/channels/slack/nudge-carrier.d.ts +19 -0
- package/dist/channels/slack/nudge-carrier.d.ts.map +1 -0
- package/dist/channels/slack/nudge-carrier.js +166 -0
- package/dist/channels/slack/nudge-store.d.ts +61 -0
- package/dist/channels/slack/nudge-store.d.ts.map +1 -0
- package/dist/channels/slack/nudge-store.js +266 -0
- package/dist/channels/slack/post-update-delivery.js +318 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +74 -25
- package/dist/channels/slack/stop.d.ts +14 -0
- package/dist/channels/slack/stop.d.ts.map +1 -0
- package/dist/channels/slack/stop.js +22 -0
- package/dist/channels/slack/thread-context.d.ts +81 -0
- package/dist/channels/slack/thread-context.d.ts.map +1 -0
- package/dist/channels/slack/thread-context.js +470 -0
- package/dist/channels/slack/types.d.ts +27 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.COTN7wgo.js → app.Ciosf24M.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BW3TBdT0.js → VPLocalSearchBox.BcRDly7n.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BEJW0vE7.js → theme.CMpbjdfx.js} +2 -2
- package/dist/docs/assets/{deployment.md.BtfEsc9S.js → deployment.md.DC5-ImcM.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.js → example-agents_approval-buddy.md.DFGBYLcc.js} +2 -2
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.lean.js → example-agents_approval-buddy.md.DFGBYLcc.lean.js} +1 -1
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.js +2 -0
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.lean.js +1 -0
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +10 -0
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.lean.js +1 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.D2rtwDTO.js → example-agents_security-reviewer.md.CE9v-aKm.js} +2 -2
- package/dist/docs/assets/{example-agents_security-reviewer.md.D2rtwDTO.lean.js → example-agents_security-reviewer.md.CE9v-aKm.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.js → guides_slack.md.FWale6Ip.js} +4 -3
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.lean.js → guides_slack.md.FWale6Ip.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.js → reference_sessions.md.DLd6mvbv.js} +2 -2
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.lean.js → reference_sessions.md.DLd6mvbv.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.CVnInNiN.js → storage.md.DRTdnFvd.js} +9 -2
- package/dist/docs/assets/{storage.md.CVnInNiN.lean.js → storage.md.DRTdnFvd.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +5 -5
- package/dist/docs/example-agents/benny.html +5 -5
- package/dist/docs/example-agents/bugbot.html +5 -5
- package/dist/docs/example-agents/codebase-wiki.html +4 -4
- package/dist/docs/example-agents/codeowners-review.html +4 -4
- package/dist/docs/example-agents/concierge.html +4 -4
- package/dist/docs/example-agents/fsd.html +4 -4
- package/dist/docs/example-agents/index.html +6 -6
- package/dist/docs/example-agents/knowledge-base.html +4 -4
- package/dist/docs/example-agents/oncall.html +34 -0
- package/dist/docs/example-agents/security-reviewer.html +6 -6
- package/dist/docs/example-agents/slack-agent.html +4 -4
- package/dist/docs/example-agents/weather-agent.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/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/slack.html +7 -6
- 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/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.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 +4 -4
- 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/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- 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/storage.html +13 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +45 -18
- package/dist/internal/cli-mcp.d.ts +64 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -0
- package/dist/internal/cli-mcp.js +570 -0
- package/dist/internal/deploy-client.d.ts +7 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/deploy-source.d.ts +3 -0
- package/dist/internal/deploy-source.d.ts.map +1 -1
- package/dist/internal/deploy-source.js +25 -7
- package/dist/internal/discovery.js +1 -1
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -0
- package/dist/internal/host-kv.d.ts +17 -0
- package/dist/internal/host-kv.d.ts.map +1 -0
- package/dist/internal/host-kv.js +77 -0
- package/dist/internal/hosting.d.ts +12 -2
- package/dist/internal/hosting.d.ts.map +1 -1
- package/dist/internal/hosting.js +21 -4
- package/dist/internal/json-dir-store.js +100 -0
- package/dist/internal/logs-client.d.ts +16 -2
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +51 -16
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +8 -0
- package/dist/internal/session-engine.d.ts +42 -7
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +276 -66
- package/dist/internal/storage-coordinator.d.ts +18 -1
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +43 -0
- package/dist/internal/workspace.d.ts +19 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +47 -13
- package/dist/playground/assets/{index-72vCOBWO.js → index-C0-QEG4O.js} +42 -42
- package/dist/playground/assets/index-z3JY9O2x.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +65 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -0
- package/dist/storage-backends/cursor-hosted.js +203 -0
- package/dist/storage-backends/file-kv.d.ts +42 -0
- package/dist/storage-backends/file-kv.d.ts.map +1 -0
- package/dist/storage-backends/file-kv.js +190 -0
- package/dist/storage-backends/postgres-kv.d.ts +82 -0
- package/dist/storage-backends/postgres-kv.d.ts.map +1 -0
- package/dist/storage-backends/postgres-kv.js +185 -0
- package/dist/storage.d.ts +10 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +10 -1
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/deployment.md +7 -3
- package/docs/example-agents/approval-buddy.md +1 -1
- package/docs/example-agents/index.md +15 -10
- package/docs/example-agents/oncall.md +216 -0
- package/docs/example-agents/security-reviewer.md +5 -5
- package/docs/guides/slack.md +11 -2
- package/docs/reference/sessions.md +13 -4
- package/docs/storage.md +41 -0
- package/package.json +22 -1
- package/skills/framework-map/SKILL.md +6 -4
- package/src/bin/agent-serve.ts +32 -2
- package/src/channels/slack/channel-watch.ts +28 -1
- package/src/channels/slack/cursor-account.ts +20 -0
- package/src/channels/slack/defaults.ts +51 -20
- package/src/channels/slack/dispatch.ts +215 -40
- package/src/channels/slack/inbound.ts +30 -10
- package/src/channels/slack/index.ts +4 -0
- package/src/channels/slack/live-delivery.ts +1 -0
- package/src/channels/slack/manifest.ts +3 -0
- package/src/channels/slack/nudge-carrier.ts +182 -0
- package/src/channels/slack/nudge-store.ts +308 -0
- package/src/channels/slack/slack-channel.ts +106 -31
- package/src/channels/slack/stop.ts +25 -0
- package/src/channels/slack/thread-context.ts +572 -0
- package/src/channels/slack/types.ts +27 -0
- package/src/internal/cli-deploy.ts +58 -20
- package/src/internal/cli-mcp.ts +708 -0
- package/src/internal/deploy-client.ts +11 -0
- package/src/internal/deploy-source.ts +24 -6
- package/src/internal/discovery.ts +1 -1
- package/src/internal/distribution.ts +3 -0
- package/src/internal/host-kv.ts +85 -0
- package/src/internal/hosting.ts +24 -4
- package/src/internal/logs-client.ts +67 -21
- package/src/internal/server.ts +31 -0
- package/src/internal/session-engine.ts +379 -61
- package/src/internal/storage-coordinator.ts +41 -0
- package/src/internal/workspace.ts +48 -11
- package/src/storage-backends/cursor-hosted.ts +246 -0
- package/src/storage-backends/file-kv.ts +221 -0
- package/src/storage-backends/postgres-kv.ts +253 -0
- package/src/storage.ts +11 -1
- package/src/types.ts +83 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.B7UcKvIn.js +0 -1
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.js +0 -2
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.lean.js +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BjnMwYoR.css +0 -1
- /package/dist/docs/assets/{deployment.md.BtfEsc9S.lean.js → deployment.md.DC5-ImcM.lean.js} +0 -0
|
@@ -31,7 +31,9 @@ export type DeploymentStatus =
|
|
|
31
31
|
export type DeploymentProgress =
|
|
32
32
|
| "queued"
|
|
33
33
|
| "preparing"
|
|
34
|
+
| "creating"
|
|
34
35
|
| "building"
|
|
36
|
+
| "starting"
|
|
35
37
|
| "finalizing"
|
|
36
38
|
| "running"
|
|
37
39
|
| "failed"
|
|
@@ -135,6 +137,12 @@ export interface Deployment {
|
|
|
135
137
|
* backends; older responses omit it.
|
|
136
138
|
*/
|
|
137
139
|
progress?: DeploymentProgress;
|
|
140
|
+
/**
|
|
141
|
+
* Live step while the deploy converges (e.g. "Checking out source…").
|
|
142
|
+
* Null when running / stopped or when only a failure is on the row.
|
|
143
|
+
* Present on newer backends; older responses omit it.
|
|
144
|
+
*/
|
|
145
|
+
statusMessage?: string | null;
|
|
138
146
|
generation: number;
|
|
139
147
|
observedGeneration?: number | null;
|
|
140
148
|
engineGeneration?: number | null;
|
|
@@ -218,7 +226,9 @@ const deploymentSchema = z.object({
|
|
|
218
226
|
.enum([
|
|
219
227
|
"queued",
|
|
220
228
|
"preparing",
|
|
229
|
+
"creating",
|
|
221
230
|
"building",
|
|
231
|
+
"starting",
|
|
222
232
|
"finalizing",
|
|
223
233
|
"running",
|
|
224
234
|
"failed",
|
|
@@ -227,6 +237,7 @@ const deploymentSchema = z.object({
|
|
|
227
237
|
"degraded",
|
|
228
238
|
])
|
|
229
239
|
.optional(),
|
|
240
|
+
statusMessage: z.string().nullable().optional(),
|
|
230
241
|
generation: z.number(),
|
|
231
242
|
observedGeneration: z.number().nullable().optional(),
|
|
232
243
|
engineGeneration: z.number().nullable().optional(),
|
|
@@ -39,17 +39,35 @@ const defaultGitRunner: GitRunner = async (args, cwd) => {
|
|
|
39
39
|
* Normalize a git remote URL to the https form the control plane accepts
|
|
40
40
|
* (`https://host/owner/repo`, no `.git` suffix). Returns undefined for
|
|
41
41
|
* unrecognized shapes.
|
|
42
|
+
*
|
|
43
|
+
* Accepts HTTPS, `git@host:path`, GitHub org-scoped SSH
|
|
44
|
+
* (`org-123@github.com:owner/repo.git`), and `ssh://user@host[:port]/path`.
|
|
42
45
|
*/
|
|
43
46
|
export function httpsGitRepoUrlFromRemote(remote: string): string | undefined {
|
|
44
47
|
let url = remote.trim();
|
|
45
48
|
if (url === "") {
|
|
46
49
|
return undefined;
|
|
47
50
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
|
|
52
|
+
// SCP-like SSH: user@host:owner/repo(.git) — includes git@ and GitHub
|
|
53
|
+
// org deploy keys (org-NNNN@github.com:…).
|
|
54
|
+
const scpMatch = /^([^@/\s]+)@([^:/\s]+):(.+)$/.exec(url);
|
|
55
|
+
if (scpMatch !== null) {
|
|
56
|
+
const host = scpMatch[2]!;
|
|
57
|
+
const path = scpMatch[3]!;
|
|
58
|
+
url = `https://${host}/${path}`;
|
|
59
|
+
} else if (/^ssh:\/\//i.test(url)) {
|
|
60
|
+
// ssh://user@host[:port]/owner/repo → https://host/owner/repo
|
|
61
|
+
try {
|
|
62
|
+
const ssh = new URL(url);
|
|
63
|
+
const path = ssh.pathname.replace(/^\/+/, "");
|
|
64
|
+
if (ssh.hostname === "" || path === "") {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
url = `https://${ssh.hostname}/${path}`;
|
|
68
|
+
} catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
53
71
|
} else if (!/^https?:\/\//i.test(url)) {
|
|
54
72
|
return undefined;
|
|
55
73
|
}
|
|
@@ -67,7 +85,7 @@ export function httpsGitRepoUrlFromRemote(remote: string): string | undefined {
|
|
|
67
85
|
if (path === "" || !path.includes("/")) {
|
|
68
86
|
return undefined;
|
|
69
87
|
}
|
|
70
|
-
// Use hostname (not host) so ssh
|
|
88
|
+
// Use hostname (not host) so ssh://…@github.com:22/… does not keep :22.
|
|
71
89
|
return `https://${parsed.hostname}/${path}`;
|
|
72
90
|
}
|
|
73
91
|
|
|
@@ -454,7 +454,7 @@ function resolveHosting(
|
|
|
454
454
|
warn(`hosting.secretNames: ${nameError}`);
|
|
455
455
|
} else if (isReservedSecretName(name)) {
|
|
456
456
|
warn(
|
|
457
|
-
`hosting.secretNames: ${JSON.stringify(name)} is platform-
|
|
457
|
+
`hosting.secretNames: ${JSON.stringify(name)} is platform-managed (CURSOR_* / Cursor-hosted storage) and injected automatically; omit it from secretNames.`
|
|
458
458
|
);
|
|
459
459
|
}
|
|
460
460
|
}
|
|
@@ -103,4 +103,7 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
|
|
|
103
103
|
["evals", "evals.js"],
|
|
104
104
|
["ab", "ab.js"],
|
|
105
105
|
["storage", "storage.js"],
|
|
106
|
+
["storage/file-kv", "storage-backends/file-kv.js"],
|
|
107
|
+
["storage/postgres-kv", "storage-backends/postgres-kv.js"],
|
|
108
|
+
["storage/cursor-hosted", "storage-backends/cursor-hosted.js"],
|
|
106
109
|
];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author-facing durable JSON KV for {@link HostContext.kv}.
|
|
3
|
+
*
|
|
4
|
+
* When `defineStorage` is authored and exposes `get`, values live in that
|
|
5
|
+
* sink under {@link storageKeys.kv}. Otherwise they land as one JSON file
|
|
6
|
+
* per key under `--state-root/kv` (local dogfood / no durable plug-in).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { storageKeys } from "../storage.js";
|
|
13
|
+
import type { HostKvApi, JsonValue } from "../types.js";
|
|
14
|
+
import type { StorageCoordinator } from "./storage-coordinator.js";
|
|
15
|
+
|
|
16
|
+
export interface CreateHostKvApiOptions {
|
|
17
|
+
agentName: string;
|
|
18
|
+
stateRoot: string;
|
|
19
|
+
storage?: StorageCoordinator;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Build the host KV API for one agent process. */
|
|
23
|
+
export function createHostKvApi(options: CreateHostKvApiOptions): HostKvApi {
|
|
24
|
+
const storage = options.storage;
|
|
25
|
+
if (storage?.supportsAuthorKv === true) {
|
|
26
|
+
return {
|
|
27
|
+
get: (key) => storage.kvGet(normalizeAuthorKey(key)),
|
|
28
|
+
put: (key, value) => storage.kvPut(normalizeAuthorKey(key), value),
|
|
29
|
+
delete: (key) => storage.kvDelete(normalizeAuthorKey(key)),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return createFilesystemKvApi({
|
|
33
|
+
agentName: options.agentName,
|
|
34
|
+
stateRoot: options.stateRoot,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createFilesystemKvApi(options: {
|
|
39
|
+
agentName: string;
|
|
40
|
+
stateRoot: string;
|
|
41
|
+
}): HostKvApi {
|
|
42
|
+
const dir = join(options.stateRoot, "kv");
|
|
43
|
+
const filePath = (authorKey: string): string =>
|
|
44
|
+
join(
|
|
45
|
+
dir,
|
|
46
|
+
`${encodeURIComponent(storageKeys.kv(options.agentName, authorKey))}.json`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
async get(key): Promise<JsonValue | undefined> {
|
|
51
|
+
const authorKey = normalizeAuthorKey(key);
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(
|
|
54
|
+
await readFile(filePath(authorKey), "utf8")
|
|
55
|
+
) as JsonValue;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
async put(key, value): Promise<void> {
|
|
65
|
+
const authorKey = normalizeAuthorKey(key);
|
|
66
|
+
await mkdir(dir, { recursive: true });
|
|
67
|
+
const target = filePath(authorKey);
|
|
68
|
+
const tmp = join(dir, `.tmp-${randomUUID()}`);
|
|
69
|
+
await writeFile(tmp, JSON.stringify(value), "utf8");
|
|
70
|
+
await rename(tmp, target);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
async delete(key): Promise<void> {
|
|
74
|
+
const authorKey = normalizeAuthorKey(key);
|
|
75
|
+
await rm(filePath(authorKey), { force: true });
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function normalizeAuthorKey(key: string): string {
|
|
81
|
+
if (typeof key !== "string" || key.trim() === "") {
|
|
82
|
+
throw new Error("host.kv key must be a non-empty string");
|
|
83
|
+
}
|
|
84
|
+
return key;
|
|
85
|
+
}
|
package/src/internal/hosting.ts
CHANGED
|
@@ -18,6 +18,17 @@ export const MAX_SECRET_NAME_LENGTH = 64;
|
|
|
18
18
|
/** Secret names the platform injects; user writes are rejected. */
|
|
19
19
|
export const RESERVED_SECRET_NAME_PREFIX = "CURSOR_";
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Additional platform-managed env names for Cursor-hosted durable storage
|
|
23
|
+
* (Bugbot `agent_serve_*`). Mirrored from
|
|
24
|
+
* `@cursor/july/storage/cursor-hosted` so validate/secrets CLI stay in sync
|
|
25
|
+
* without importing the storage backend into the CLI graph.
|
|
26
|
+
*/
|
|
27
|
+
export const PLATFORM_HOSTED_STORAGE_SECRET_NAMES = [
|
|
28
|
+
"BUGBOTDB_URL",
|
|
29
|
+
"AGENT_SERVE_DEPLOYMENT_ID",
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
21
32
|
const SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
|
|
22
33
|
|
|
23
34
|
// Lowercase hostname with >=2 labels, an alphabetic TLD, and at most one
|
|
@@ -49,14 +60,23 @@ export function validateSecretName(name: string): string | undefined {
|
|
|
49
60
|
return undefined;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* True when the platform manages this name (`CURSOR_*` or hosted-storage
|
|
65
|
+
* env vars); user writes / deletes are rejected.
|
|
66
|
+
*/
|
|
53
67
|
export function isReservedSecretName(name: string): boolean {
|
|
54
|
-
|
|
68
|
+
if (name.startsWith(RESERVED_SECRET_NAME_PREFIX)) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
const upper = name.toUpperCase();
|
|
72
|
+
return (PLATFORM_HOSTED_STORAGE_SECRET_NAMES as readonly string[]).some(
|
|
73
|
+
(managed) => managed === upper
|
|
74
|
+
);
|
|
55
75
|
}
|
|
56
76
|
|
|
57
77
|
/**
|
|
58
78
|
* Human error for a secret name a user is trying to write or delete:
|
|
59
|
-
* grammar plus
|
|
79
|
+
* grammar plus platform-managed names (`CURSOR_*`, hosted storage).
|
|
60
80
|
*/
|
|
61
81
|
export function validateSettableSecretName(name: string): string | undefined {
|
|
62
82
|
const nameError = validateSecretName(name);
|
|
@@ -64,7 +84,7 @@ export function validateSettableSecretName(name: string): string | undefined {
|
|
|
64
84
|
return nameError;
|
|
65
85
|
}
|
|
66
86
|
if (isReservedSecretName(name)) {
|
|
67
|
-
return `Secret name ${JSON.stringify(name)} is platform-
|
|
87
|
+
return `Secret name ${JSON.stringify(name)} is platform-managed; the platform injects CURSOR_* and Cursor-hosted storage values automatically.`;
|
|
68
88
|
}
|
|
69
89
|
return undefined;
|
|
70
90
|
}
|
|
@@ -35,7 +35,9 @@ export type LogsProgress =
|
|
|
35
35
|
| DeploymentProgress
|
|
36
36
|
| "queued"
|
|
37
37
|
| "preparing"
|
|
38
|
+
| "creating"
|
|
38
39
|
| "building"
|
|
40
|
+
| "starting"
|
|
39
41
|
| "finalizing"
|
|
40
42
|
| "running"
|
|
41
43
|
| "failed"
|
|
@@ -46,7 +48,9 @@ export type LogsProgress =
|
|
|
46
48
|
const PROGRESS_MESSAGES: Readonly<Record<LogsProgress, string>> = {
|
|
47
49
|
queued: "Waiting to start…",
|
|
48
50
|
preparing: "Preparing runtime…",
|
|
49
|
-
|
|
51
|
+
creating: "Creating runtime…",
|
|
52
|
+
building: "Checking out source and installing dependencies…",
|
|
53
|
+
starting: "Starting agent and waiting for health…",
|
|
50
54
|
finalizing: "Finishing deployment…",
|
|
51
55
|
running: "Deployment running",
|
|
52
56
|
failed: "Deploy failed",
|
|
@@ -55,9 +59,15 @@ const PROGRESS_MESSAGES: Readonly<Record<LogsProgress, string>> = {
|
|
|
55
59
|
degraded: "Deployment degraded",
|
|
56
60
|
};
|
|
57
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Customer-facing line for the current deploy step. Prefer the live
|
|
64
|
+
* `statusMessage` from the API when present; otherwise the progress
|
|
65
|
+
* vocabulary. Failed/degraded always append sanitized `lastError`.
|
|
66
|
+
*/
|
|
58
67
|
export function progressMessage(
|
|
59
68
|
progress: LogsProgress,
|
|
60
|
-
lastError?: string | null
|
|
69
|
+
lastError?: string | null,
|
|
70
|
+
statusMessage?: string | null
|
|
61
71
|
): string {
|
|
62
72
|
if (progress === "failed") {
|
|
63
73
|
const detail =
|
|
@@ -73,6 +83,13 @@ export function progressMessage(
|
|
|
73
83
|
: `: ${sanitizeCustomerError(lastError)}`;
|
|
74
84
|
return `Deployment degraded${detail}`;
|
|
75
85
|
}
|
|
86
|
+
if (
|
|
87
|
+
statusMessage !== null &&
|
|
88
|
+
statusMessage !== undefined &&
|
|
89
|
+
statusMessage.trim() !== ""
|
|
90
|
+
) {
|
|
91
|
+
return statusMessage.trim();
|
|
92
|
+
}
|
|
76
93
|
return PROGRESS_MESSAGES[progress];
|
|
77
94
|
}
|
|
78
95
|
|
|
@@ -85,7 +102,38 @@ export function sanitizeCustomerError(message: string): string {
|
|
|
85
102
|
.replace(/\bcursorvm\.com\b/gi, "host")
|
|
86
103
|
.replace(/\bx-anyrun-[a-z0-9-]+\b/gi, "header")
|
|
87
104
|
.replace(/\bPROVISIONING\b/g, "building")
|
|
88
|
-
.replace(/\bPLANNED\b/g, "preparing")
|
|
105
|
+
.replace(/\bPLANNED\b/g, "preparing")
|
|
106
|
+
.replace(/\bgitCloneCheckout\b/gi, "git clone")
|
|
107
|
+
.replace(/\bgitFetchCheckout\b/gi, "git fetch")
|
|
108
|
+
.replace(/\bgitCheckout:clone\b/gi, "checkout")
|
|
109
|
+
.replace(/\bgitCheckout:fetch\b/gi, "checkout");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* One-line label for `agentkit deploy` polling (TTY spinner / non-TTY
|
|
114
|
+
* transitions). Uses statusMessage → progress → raw status.
|
|
115
|
+
*/
|
|
116
|
+
export function deployProgressLabel(detail: {
|
|
117
|
+
status: string;
|
|
118
|
+
progress?: DeploymentProgress;
|
|
119
|
+
statusMessage?: string | null;
|
|
120
|
+
}): string {
|
|
121
|
+
if (
|
|
122
|
+
detail.statusMessage !== null &&
|
|
123
|
+
detail.statusMessage !== undefined &&
|
|
124
|
+
detail.statusMessage.trim() !== ""
|
|
125
|
+
) {
|
|
126
|
+
return detail.statusMessage
|
|
127
|
+
.trim()
|
|
128
|
+
.replace(/…$/, "")
|
|
129
|
+
.replace(/\.\.\.$/, "");
|
|
130
|
+
}
|
|
131
|
+
if (detail.progress !== undefined) {
|
|
132
|
+
return PROGRESS_MESSAGES[detail.progress]
|
|
133
|
+
.replace(/…$/, "")
|
|
134
|
+
.replace(/\.\.\.$/, "");
|
|
135
|
+
}
|
|
136
|
+
return detail.status;
|
|
89
137
|
}
|
|
90
138
|
|
|
91
139
|
export async function fetchLogs(args: {
|
|
@@ -241,7 +289,7 @@ async function followProdLogs(args: {
|
|
|
241
289
|
);
|
|
242
290
|
});
|
|
243
291
|
|
|
244
|
-
let
|
|
292
|
+
let lastEmittedKey: string | undefined;
|
|
245
293
|
const slugHint = args.slug !== undefined && args.slug !== "" ? args.slug : "";
|
|
246
294
|
if (args.once !== true) {
|
|
247
295
|
const label = slugHint !== "" ? slugHint : "deployment";
|
|
@@ -260,33 +308,32 @@ async function followProdLogs(args: {
|
|
|
260
308
|
}
|
|
261
309
|
|
|
262
310
|
const progress = resolveProgress(detail);
|
|
311
|
+
const message = progressMessage(
|
|
312
|
+
progress,
|
|
313
|
+
detail.lastError,
|
|
314
|
+
detail.statusMessage
|
|
315
|
+
);
|
|
316
|
+
const emitKey = `${progress}\0${message}`;
|
|
263
317
|
|
|
264
318
|
if (progress === "failed") {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
lastProgress = progress;
|
|
319
|
+
if (emitKey !== lastEmittedKey) {
|
|
320
|
+
lastEmittedKey = emitKey;
|
|
268
321
|
emitProgress(args.write, args.json === true, progress, message);
|
|
269
322
|
}
|
|
270
323
|
throw new Error(`Deployment "${detail.slug}" failed.`);
|
|
271
324
|
}
|
|
272
325
|
if (progress === "stopped") {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
lastProgress = progress;
|
|
326
|
+
if (emitKey !== lastEmittedKey) {
|
|
327
|
+
lastEmittedKey = emitKey;
|
|
276
328
|
emitProgress(args.write, args.json === true, progress, message);
|
|
277
329
|
}
|
|
278
330
|
throw new Error(`Deployment "${detail.slug}" is stopped.`);
|
|
279
331
|
}
|
|
280
332
|
if (progress === "running" || progress === "degraded") {
|
|
281
333
|
// Hand off to runtime logs. Print degraded once; skip a "running" line.
|
|
282
|
-
if (progress === "degraded" &&
|
|
283
|
-
|
|
284
|
-
emitProgress(
|
|
285
|
-
args.write,
|
|
286
|
-
args.json === true,
|
|
287
|
-
progress,
|
|
288
|
-
progressMessage(progress, detail.lastError)
|
|
289
|
-
);
|
|
334
|
+
if (progress === "degraded" && emitKey !== lastEmittedKey) {
|
|
335
|
+
lastEmittedKey = emitKey;
|
|
336
|
+
emitProgress(args.write, args.json === true, progress, message);
|
|
290
337
|
}
|
|
291
338
|
const runtime = await resolveRuntime();
|
|
292
339
|
await followRuntimeLogs({
|
|
@@ -306,9 +353,8 @@ async function followProdLogs(args: {
|
|
|
306
353
|
return;
|
|
307
354
|
}
|
|
308
355
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
lastProgress = progress;
|
|
356
|
+
if (emitKey !== lastEmittedKey) {
|
|
357
|
+
lastEmittedKey = emitKey;
|
|
312
358
|
emitProgress(args.write, args.json === true, progress, message);
|
|
313
359
|
}
|
|
314
360
|
|
package/src/internal/server.ts
CHANGED
|
@@ -423,6 +423,17 @@ export async function startServer(
|
|
|
423
423
|
},
|
|
424
424
|
resolveApproval: (sessionId, callId, decision, auth) =>
|
|
425
425
|
engine.resolveApproval(sessionId, callId, decision, auth),
|
|
426
|
+
hasContinuationSession: (continuationToken) =>
|
|
427
|
+
engine.hasContinuationSession(channel.id, continuationToken),
|
|
428
|
+
isContinuationBusy: (continuationToken) =>
|
|
429
|
+
engine.isContinuationBusy(channel.id, continuationToken),
|
|
430
|
+
getContinuationLastBotMessageTs: (continuationToken) =>
|
|
431
|
+
engine.getContinuationLastBotMessageTs(
|
|
432
|
+
channel.id,
|
|
433
|
+
continuationToken
|
|
434
|
+
),
|
|
435
|
+
interruptContinuation: (continuationToken) =>
|
|
436
|
+
engine.interruptContinuation(channel.id, continuationToken),
|
|
426
437
|
logger,
|
|
427
438
|
};
|
|
428
439
|
try {
|
|
@@ -1624,6 +1635,26 @@ async function startCursorSlackRelay(input: {
|
|
|
1624
1635
|
envelope,
|
|
1625
1636
|
send: args.send,
|
|
1626
1637
|
host: args.host,
|
|
1638
|
+
hasContinuationSession: (continuationToken) =>
|
|
1639
|
+
target.runtime.engine.hasContinuationSession(
|
|
1640
|
+
target.channelId,
|
|
1641
|
+
continuationToken
|
|
1642
|
+
),
|
|
1643
|
+
isContinuationBusy: (continuationToken) =>
|
|
1644
|
+
target.runtime.engine.isContinuationBusy(
|
|
1645
|
+
target.channelId,
|
|
1646
|
+
continuationToken
|
|
1647
|
+
),
|
|
1648
|
+
getContinuationLastBotMessageTs: (continuationToken) =>
|
|
1649
|
+
target.runtime.engine.getContinuationLastBotMessageTs(
|
|
1650
|
+
target.channelId,
|
|
1651
|
+
continuationToken
|
|
1652
|
+
),
|
|
1653
|
+
interruptContinuation: (continuationToken) =>
|
|
1654
|
+
target.runtime.engine.interruptContinuation(
|
|
1655
|
+
target.channelId,
|
|
1656
|
+
continuationToken
|
|
1657
|
+
),
|
|
1627
1658
|
});
|
|
1628
1659
|
},
|
|
1629
1660
|
});
|