@cursor/july 0.1.8 → 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 +0 -0
- package/dist/channels/slack/post-update-delivery.d.ts +85 -0
- package/dist/channels/slack/post-update-delivery.d.ts.map +1 -0
- package/dist/channels/slack/post-update-delivery.js +318 -0
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.BP8mAVMW.js → app.Ciosf24M.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.1FXIZbz8.js → VPLocalSearchBox.BcRDly7n.js} +1 -1
- package/dist/docs/assets/chunks/{theme.Dm1R02v9.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.CwtWu5ix.js → example-agents_index.md.BPXjUtRB.js} +2 -2
- package/dist/docs/assets/{example-agents_index.md.CwtWu5ix.lean.js → example-agents_index.md.BPXjUtRB.lean.js} +1 -1
- 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/{storage.md.Cu3MwM2a.js → storage.md.DRTdnFvd.js} +7 -1
- package/dist/docs/assets/{storage.md.Cu3MwM2a.lean.js → storage.md.DRTdnFvd.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +5 -5
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +5 -5
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +5 -5
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +6 -6
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +11 -5
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +45 -18
- 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 +1 -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.d.ts +32 -0
- package/dist/internal/json-dir-store.d.ts.map +1 -0
- 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/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +29 -15
- 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-C0-QEG4O.js +86 -0
- 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/postgres-kv.d.ts +5 -0
- package/dist/storage-backends/postgres-kv.d.ts.map +1 -1
- package/dist/storage-backends/postgres-kv.js +5 -0
- 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 +1 -1
- package/docs/example-agents/security-reviewer.md +5 -5
- package/docs/storage.md +18 -4
- package/package.json +8 -1
- package/src/internal/cli-deploy.ts +58 -20
- 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 +1 -0
- package/src/internal/hosting.ts +24 -4
- package/src/internal/logs-client.ts +67 -21
- package/src/internal/session-engine.ts +28 -11
- package/src/internal/workspace.ts +48 -11
- package/src/storage-backends/cursor-hosted.ts +246 -0
- package/src/storage-backends/postgres-kv.ts +5 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DevOabKJ.js +0 -1
- package/dist/playground/assets/index-7GJIUFQj.css +0 -1
- package/dist/playground/assets/index-Bpr4Th4M.js +0 -319
- /package/dist/docs/assets/{deployment.md.BtfEsc9S.lean.js → deployment.md.DC5-ImcM.lean.js} +0 -0
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
/>
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
10
10
|
<title>agent-serve playground</title>
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-C0-QEG4O.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/index-z3JY9O2x.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-managed durable storage for hosted agents.
|
|
3
|
+
*
|
|
4
|
+
* Talks to the control-plane storage proxy
|
|
5
|
+
* (`POST /internal/agent-serve/storage/*`) using the engine's pod
|
|
6
|
+
* `CURSOR_API_KEY`. The server resolves `deployment_id` from that service
|
|
7
|
+
* account — engines never receive a Bugbot DSN and cannot address another
|
|
8
|
+
* deployment's rows.
|
|
9
|
+
*
|
|
10
|
+
* On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
|
|
11
|
+
* `https://api.cursor.com` (where the proxy is mounted). Locally, point
|
|
12
|
+
* `CURSOR_API_BASE_URL` at a backend that mounts Agent Serve routes and use
|
|
13
|
+
* a deployment SA key, or use `@cursor/july/storage/postgres-kv` /
|
|
14
|
+
* `file-kv` instead.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { defineStorage } from "@cursor/july/storage";
|
|
18
|
+
* import { cursorHostedStorage } from "@cursor/july/storage/cursor-hosted";
|
|
19
|
+
*
|
|
20
|
+
* export default defineStorage({
|
|
21
|
+
* ...cursorHostedStorage(),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
|
|
26
|
+
/**
|
|
27
|
+
* Reserved so user `secrets set` cannot smuggle a Bugbot DSN into the pod.
|
|
28
|
+
* Not injected by Cursor hosting (storage is HTTP-proxied).
|
|
29
|
+
*/
|
|
30
|
+
export declare const AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR: "BUGBOTDB_URL";
|
|
31
|
+
/**
|
|
32
|
+
* Diagnostic / self-host deployment id. Not the hosted-storage authz
|
|
33
|
+
* boundary — the proxy scopes rows from the authenticated service account.
|
|
34
|
+
*/
|
|
35
|
+
export declare const AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR: "AGENT_SERVE_DEPLOYMENT_ID";
|
|
36
|
+
/**
|
|
37
|
+
* Platform-managed secret / env names. User `secrets set` / DELETE cannot
|
|
38
|
+
* claim these.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CURSOR_HOSTED_STORAGE_ENV_VARS: readonly [
|
|
41
|
+
typeof AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR,
|
|
42
|
+
typeof AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR
|
|
43
|
+
];
|
|
44
|
+
export interface CursorHostedStorageOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Control-plane base URL (default: `CURSOR_API_BASE_URL`, else
|
|
47
|
+
* `https://api.cursor.com`).
|
|
48
|
+
*/
|
|
49
|
+
baseUrl?: string;
|
|
50
|
+
/** Bearer credential (default: `CURSOR_API_KEY`). */
|
|
51
|
+
apiKey?: string;
|
|
52
|
+
/** Injected for tests. */
|
|
53
|
+
fetch?: typeof fetch;
|
|
54
|
+
}
|
|
55
|
+
type CursorHostedStorageMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
|
|
56
|
+
evals: StorageEvalsTable;
|
|
57
|
+
abs: StorageABTable;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Cursor-hosted `defineStorage` methods (control-plane storage proxy →
|
|
61
|
+
* Bugbot `agent_serve_*` tables). Spread into `defineStorage({...})`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function cursorHostedStorage(options?: CursorHostedStorageOptions): CursorHostedStorageMethods;
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=cursor-hosted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-hosted.d.ts","sourceRoot":"","sources":["../../src/storage-backends/cursor-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAYvB;;;GAGG;AACH,eAAO,MAAM,+CAA+C,EAC1D,cAAuB,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,iCAAiC,EAC5C,2BAAoC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS;IACpD,OAAO,+CAA+C;IACtD,OAAO,iCAAiC;CAIzC,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,KAAK,0BAA0B,GAAG,QAAQ,CACxC,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AA8DF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,0BAA0B,CA0F5B"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-managed durable storage for hosted agents.
|
|
3
|
+
*
|
|
4
|
+
* Talks to the control-plane storage proxy
|
|
5
|
+
* (`POST /internal/agent-serve/storage/*`) using the engine's pod
|
|
6
|
+
* `CURSOR_API_KEY`. The server resolves `deployment_id` from that service
|
|
7
|
+
* account — engines never receive a Bugbot DSN and cannot address another
|
|
8
|
+
* deployment's rows.
|
|
9
|
+
*
|
|
10
|
+
* On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
|
|
11
|
+
* `https://api.cursor.com` (where the proxy is mounted). Locally, point
|
|
12
|
+
* `CURSOR_API_BASE_URL` at a backend that mounts Agent Serve routes and use
|
|
13
|
+
* a deployment SA key, or use `@cursor/july/storage/postgres-kv` /
|
|
14
|
+
* `file-kv` instead.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { defineStorage } from "@cursor/july/storage";
|
|
18
|
+
* import { cursorHostedStorage } from "@cursor/july/storage/cursor-hosted";
|
|
19
|
+
*
|
|
20
|
+
* export default defineStorage({
|
|
21
|
+
* ...cursorHostedStorage(),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Same default as {@link cursorExternalApiUrl} in the CLI credentials module,
|
|
36
|
+
* inlined here so this storage entrypoint does not import CLI/zod code.
|
|
37
|
+
* Hosted monorepo examples load this file from `packages/agent-serve/src`
|
|
38
|
+
* while `npm install` runs in the example package — a credentials import
|
|
39
|
+
* would resolve `zod` from the wrong `node_modules` tree and crash serve.
|
|
40
|
+
*/
|
|
41
|
+
const DEFAULT_CURSOR_EXTERNAL_API_URL = "https://api.cursor.com";
|
|
42
|
+
/**
|
|
43
|
+
* Reserved so user `secrets set` cannot smuggle a Bugbot DSN into the pod.
|
|
44
|
+
* Not injected by Cursor hosting (storage is HTTP-proxied).
|
|
45
|
+
*/
|
|
46
|
+
export const AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR = "BUGBOTDB_URL";
|
|
47
|
+
/**
|
|
48
|
+
* Diagnostic / self-host deployment id. Not the hosted-storage authz
|
|
49
|
+
* boundary — the proxy scopes rows from the authenticated service account.
|
|
50
|
+
*/
|
|
51
|
+
export const AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR = "AGENT_SERVE_DEPLOYMENT_ID";
|
|
52
|
+
/**
|
|
53
|
+
* Platform-managed secret / env names. User `secrets set` / DELETE cannot
|
|
54
|
+
* claim these.
|
|
55
|
+
*/
|
|
56
|
+
export const CURSOR_HOSTED_STORAGE_ENV_VARS = [
|
|
57
|
+
AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR,
|
|
58
|
+
AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR,
|
|
59
|
+
];
|
|
60
|
+
function resolveApiKey(options) {
|
|
61
|
+
var _a;
|
|
62
|
+
var _b;
|
|
63
|
+
const key = (_a = ((_b = options.apiKey) !== null && _b !== void 0 ? _b : process.env.CURSOR_API_KEY)) === null || _a === void 0 ? void 0 : _a.trim();
|
|
64
|
+
if (key === undefined || key === "") {
|
|
65
|
+
throw new Error("cursorHostedStorage requires CURSOR_API_KEY (deployment pod credential on Cursor hosting)");
|
|
66
|
+
}
|
|
67
|
+
return key;
|
|
68
|
+
}
|
|
69
|
+
function resolveBaseUrl(options) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const raw = ((_b = (_a = options.baseUrl) !== null && _a !== void 0 ? _a : process.env.CURSOR_API_BASE_URL) !== null && _b !== void 0 ? _b : DEFAULT_CURSOR_EXTERNAL_API_URL).trim();
|
|
72
|
+
return raw.endsWith("/") ? raw.slice(0, -1) : raw;
|
|
73
|
+
}
|
|
74
|
+
function storageRpc(options, path, body) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
var _a;
|
|
77
|
+
const baseUrl = resolveBaseUrl(options);
|
|
78
|
+
const apiKey = resolveApiKey(options);
|
|
79
|
+
const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch;
|
|
80
|
+
if (typeof fetchImpl !== "function") {
|
|
81
|
+
throw new Error("cursorHostedStorage requires fetch");
|
|
82
|
+
}
|
|
83
|
+
const response = yield fetchImpl(`${baseUrl}${path}`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: {
|
|
86
|
+
Authorization: `Bearer ${apiKey}`,
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify(body),
|
|
90
|
+
});
|
|
91
|
+
const text = yield response.text();
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = text.length === 0 ? {} : JSON.parse(text);
|
|
95
|
+
}
|
|
96
|
+
catch (_b) {
|
|
97
|
+
throw new Error(`cursorHostedStorage ${path} returned non-JSON (${response.status})`);
|
|
98
|
+
}
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const error = parsed !== null &&
|
|
101
|
+
typeof parsed === "object" &&
|
|
102
|
+
"error" in parsed &&
|
|
103
|
+
typeof parsed.error === "string"
|
|
104
|
+
? parsed.error
|
|
105
|
+
: `HTTP ${response.status}`;
|
|
106
|
+
throw new Error(`cursorHostedStorage ${path}: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
return parsed;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Cursor-hosted `defineStorage` methods (control-plane storage proxy →
|
|
113
|
+
* Bugbot `agent_serve_*` tables). Spread into `defineStorage({...})`.
|
|
114
|
+
*/
|
|
115
|
+
export function cursorHostedStorage(options = {}) {
|
|
116
|
+
return {
|
|
117
|
+
put(key, value) {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
yield storageRpc(options, "/internal/agent-serve/storage/kv/put", {
|
|
120
|
+
key,
|
|
121
|
+
value,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
get(key) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
var _a;
|
|
128
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/get", { key });
|
|
129
|
+
if (!result.found) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return (_a = result.value) !== null && _a !== void 0 ? _a : undefined;
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
delete(key) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
yield storageRpc(options, "/internal/agent-serve/storage/kv/delete", {
|
|
138
|
+
key,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
list(prefix) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/list", { prefix });
|
|
145
|
+
return result.entries;
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
evals: {
|
|
149
|
+
put(run, ctx) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
yield storageRpc(options, "/internal/agent-serve/storage/evals/put", {
|
|
152
|
+
agentName: ctx.agentName,
|
|
153
|
+
run,
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
delete(runId, ctx) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
yield storageRpc(options, "/internal/agent-serve/storage/evals/delete", {
|
|
160
|
+
agentName: ctx.agentName,
|
|
161
|
+
runId,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
list(ctx) {
|
|
166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/evals/list", { agentName: ctx.agentName });
|
|
168
|
+
return result.runs;
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
abs: {
|
|
173
|
+
putSample(sample, ctx) {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
175
|
+
yield storageRpc(options, "/internal/agent-serve/storage/abs/put-sample", {
|
|
176
|
+
agentName: ctx.agentName,
|
|
177
|
+
sample,
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
putSnapshot(snapshot, ctx) {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
yield storageRpc(options, "/internal/agent-serve/storage/abs/put-snapshot", {
|
|
184
|
+
agentName: ctx.agentName,
|
|
185
|
+
snapshot,
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
getSnapshot(ctx) {
|
|
190
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
191
|
+
var _a;
|
|
192
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/abs/get-snapshot", {
|
|
193
|
+
agentName: ctx.agentName,
|
|
194
|
+
});
|
|
195
|
+
if (!result.found) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return (_a = result.snapshot) !== null && _a !== void 0 ? _a : undefined;
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* agent_serve_ab(deployment_id, agent, kind, ref, value JSONB, updated_at)
|
|
10
10
|
* PRIMARY KEY (deployment_id, agent, kind, ref)
|
|
11
11
|
*
|
|
12
|
+
* For Cursor-managed hosting prefer `cursorHostedStorage` from
|
|
13
|
+
* `@cursor/july/storage/cursor-hosted` — same tables via a control-plane
|
|
14
|
+
* HTTP proxy (no pod-visible DSN). Use this helper when you supply
|
|
15
|
+
* `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` yourself (self-host).
|
|
16
|
+
*
|
|
12
17
|
* `postgresStorage` implements the whole `defineStorage` surface as plain
|
|
13
18
|
* SQL: the four KV methods against the last-write-wins `agent_serve_kv`
|
|
14
19
|
* table (sessions, event chunks, continuations, reminders), the `evals`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-kv.d.ts","sourceRoot":"","sources":["../../src/storage-backends/postgres-kv.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"postgres-kv.d.ts","sourceRoot":"","sources":["../../src/storage-backends/postgres-kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAC1B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,MAAM,uBAAuB,GAAG,KAAK,MAAM,CAAC,EAAE;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,GAAG;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAClD,KAAK,iBAAiB,CAAC;AAExB,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,IAAI,EAAE,uBAAuB,CAAC;IAC9B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,sBAAsB,GAAG,QAAQ,CACpC,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAYpE;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,CA4HxB"}
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* agent_serve_ab(deployment_id, agent, kind, ref, value JSONB, updated_at)
|
|
10
10
|
* PRIMARY KEY (deployment_id, agent, kind, ref)
|
|
11
11
|
*
|
|
12
|
+
* For Cursor-managed hosting prefer `cursorHostedStorage` from
|
|
13
|
+
* `@cursor/july/storage/cursor-hosted` — same tables via a control-plane
|
|
14
|
+
* HTTP proxy (no pod-visible DSN). Use this helper when you supply
|
|
15
|
+
* `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` yourself (self-host).
|
|
16
|
+
*
|
|
12
17
|
* `postgresStorage` implements the whole `defineStorage` surface as plain
|
|
13
18
|
* SQL: the four KV methods against the last-write-wins `agent_serve_kv`
|
|
14
19
|
* table (sessions, event chunks, continuations, reminders), the `evals`
|
package/docs/deployment.md
CHANGED
|
@@ -127,9 +127,13 @@ shell arguments.
|
|
|
127
127
|
### Choose durable storage
|
|
128
128
|
|
|
129
129
|
Hosted filesystem state can reset during a deploy or runtime
|
|
130
|
-
replacement.
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
replacement. Prefer
|
|
131
|
+
[`cursorHostedStorage`](./storage.md) (`@cursor/july/storage/cursor-hosted`)
|
|
132
|
+
so durable records land in Cursor's Bugbot `agent_serve_*` tables through
|
|
133
|
+
a control-plane HTTP proxy (pod credential auth — no database URL in the
|
|
134
|
+
engine). Do not put `BUGBOTDB_URL` or `AGENT_SERVE_DEPLOYMENT_ID` in
|
|
135
|
+
`hosting.secretNames`. Self-host with your own `defineStorage` backend or
|
|
136
|
+
a persistent `--state-root` when the complete filesystem must survive.
|
|
133
137
|
|
|
134
138
|
### Use the hosted agent
|
|
135
139
|
|
|
@@ -69,7 +69,7 @@ approving the PR.
|
|
|
69
69
|
| Server tools | [`agent/tools/`](../../examples/approval-buddy/agent/tools/) | Prepare evidence, approve, list buddies, and search GIFs. |
|
|
70
70
|
| Deterministic policy | [`agent/lib/approve.ts`](../../examples/approval-buddy/agent/lib/approve.ts), [`agent/lib/buddies.ts`](../../examples/approval-buddy/agent/lib/buddies.ts) | Own the roster and live eligibility checks. |
|
|
71
71
|
| Review subagents | [`agent/subagents/`](../../examples/approval-buddy/agent/subagents/) | Run deep audit and code-quality passes over the same evidence. |
|
|
72
|
-
| Storage | [`agent/storage.ts`](../../examples/approval-buddy/agent/storage.ts) | Persist sessions and events
|
|
72
|
+
| Storage | [`agent/storage.ts`](../../examples/approval-buddy/agent/storage.ts) | Persist sessions and events with `cursorHostedStorage` (Bugbot `agent_serve_*`). |
|
|
73
73
|
| Evals and unit tests | [`evals/`](../../examples/approval-buddy/evals/), [`agent/lib/`](../../examples/approval-buddy/agent/lib/) | Protect routing, output contracts, policy, and GitHub behavior. |
|
|
74
74
|
|
|
75
75
|
There are no authored skills, MCP connections, schedules, reminders, hooks,
|
|
@@ -72,7 +72,7 @@ Several examples need more:
|
|
|
72
72
|
- GitHub examples require access to the target repository. Codebase wiki and
|
|
73
73
|
Codeowners review call the host `gh` CLI for PR data; the codeowners
|
|
74
74
|
fixtures run without network.
|
|
75
|
-
-
|
|
75
|
+
- Example agents use `cursorHostedStorage` (`agent/storage.ts`) for Cursor-hosted session storage (control-plane proxy).
|
|
76
76
|
- Remote PR coordinator starts remote agent sessions and needs access to its
|
|
77
77
|
workflow backend.
|
|
78
78
|
|
|
@@ -71,7 +71,7 @@ status from the finding count even when the review posting result says
|
|
|
71
71
|
| Progress channel | [`agent/channels/asr-progress.ts`](../../examples/security-reviewer/agent/channels/asr-progress.ts) | Serve live reviewer and triage state by `runId`. |
|
|
72
72
|
| Playground renderer | [`agent/playground/tools/run_reviewers.tsx`](../../examples/security-reviewer/agent/playground/tools/run_reviewers.tsx) | Replace the generic tool chip with live module rows. |
|
|
73
73
|
| SDK review pipeline | [`agent/lib/asr/`](../../examples/security-reviewer/agent/lib/asr/), [`review-stages.ts`](../../examples/security-reviewer/agent/lib/review-stages.ts) | Select modules, call model workers, triage, deduplicate, and write artifacts. |
|
|
74
|
-
| Storage | [`agent/storage.ts`](../../examples/security-reviewer/agent/storage.ts) | Persist framework sessions
|
|
74
|
+
| Storage | [`agent/storage.ts`](../../examples/security-reviewer/agent/storage.ts) | Persist framework sessions with `cursorHostedStorage` (lazy restore). |
|
|
75
75
|
| A/B | [`agent/ab.ts`](../../examples/security-reviewer/agent/ab.ts), [`agent/ab.config.ts`](../../examples/security-reviewer/agent/ab.config.ts) | Compare all-severity versus high-only GitHub comments. |
|
|
76
76
|
| Eval | [`evals/`](../../examples/security-reviewer/evals/) | Check stage-tool presence against a pinned sample. |
|
|
77
77
|
|
|
@@ -190,10 +190,10 @@ findings, accounting, and audit events.
|
|
|
190
190
|
|
|
191
191
|
## Separate session storage from review artifacts
|
|
192
192
|
|
|
193
|
-
`defineStorage` sends agentkit session and event records
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
session.
|
|
193
|
+
`defineStorage` + `cursorHostedStorage` sends agentkit session and event records
|
|
194
|
+
to Cursor-hosted Bugbot storage through the control-plane proxy. Security
|
|
195
|
+
Reviewer sets `restore: "off"` so startup doesn't load old review sessions in
|
|
196
|
+
bulk. A continuation lookup can still fetch a needed session.
|
|
197
197
|
|
|
198
198
|
The staged review files are separate from session storage. Session-store
|
|
199
199
|
durability doesn't preserve those files. All stages for one `runId` must see
|
package/docs/storage.md
CHANGED
|
@@ -113,13 +113,27 @@ propagate errors — unlike session mirrors, which are at-most-once.
|
|
|
113
113
|
|
|
114
114
|
Without `agent/storage.ts`, `host.kv` falls back to files under
|
|
115
115
|
`--state-root/kv`. That is fine for local dogfood; it does **not**
|
|
116
|
-
survive replacing the host. For
|
|
117
|
-
`@cursor/july/storage/
|
|
118
|
-
|
|
116
|
+
survive replacing the host. For Cursor-managed hosting, prefer
|
|
117
|
+
`@cursor/july/storage/cursor-hosted` so sessions and author KV share the
|
|
118
|
+
platform Bugbot tables through a control-plane HTTP proxy (authenticated
|
|
119
|
+
as the deployment pod credential — engines never receive a database URL).
|
|
120
|
+
For self-hosted Postgres you own, use `@cursor/july/storage/postgres-kv`
|
|
121
|
+
and supply `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` yourself.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
// agent/storage.ts — Cursor-managed hosting
|
|
125
|
+
import { defineStorage } from "@cursor/july/storage";
|
|
126
|
+
import { cursorHostedStorage } from "@cursor/july/storage/cursor-hosted";
|
|
127
|
+
|
|
128
|
+
export default defineStorage({
|
|
129
|
+
...cursorHostedStorage(),
|
|
130
|
+
});
|
|
131
|
+
```
|
|
119
132
|
|
|
120
133
|
Built-in helpers:
|
|
121
134
|
|
|
122
135
|
| Import | Backend |
|
|
123
136
|
| --- | --- |
|
|
124
137
|
| `@cursor/july/storage/file-kv` | File-per-key under `.agent-serve/kv` |
|
|
125
|
-
| `@cursor/july/storage/
|
|
138
|
+
| `@cursor/july/storage/cursor-hosted` | Platform Bugbot `agent_serve_*` via control-plane proxy |
|
|
139
|
+
| `@cursor/july/storage/postgres-kv` | Same tables; you supply `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -138,6 +138,13 @@
|
|
|
138
138
|
"import": "./dist/storage-backends/postgres-kv.js",
|
|
139
139
|
"default": "./dist/storage-backends/postgres-kv.js"
|
|
140
140
|
},
|
|
141
|
+
"./storage/cursor-hosted": {
|
|
142
|
+
"anysphere-source": "./src/storage-backends/cursor-hosted.ts",
|
|
143
|
+
"bun": "./src/storage-backends/cursor-hosted.ts",
|
|
144
|
+
"types": "./dist/storage-backends/cursor-hosted.d.ts",
|
|
145
|
+
"import": "./dist/storage-backends/cursor-hosted.js",
|
|
146
|
+
"default": "./dist/storage-backends/cursor-hosted.js"
|
|
147
|
+
},
|
|
141
148
|
"./package.json": {
|
|
142
149
|
"anysphere-source": "./package.json",
|
|
143
150
|
"bun": "./package.json",
|
|
@@ -40,9 +40,11 @@ import {
|
|
|
40
40
|
} from "./discovery.js";
|
|
41
41
|
import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
|
|
42
42
|
import {
|
|
43
|
+
isReservedSecretName,
|
|
43
44
|
isValidCursorEventRepo,
|
|
44
45
|
validateSettableSecretName,
|
|
45
46
|
} from "./hosting.js";
|
|
47
|
+
import { deployProgressLabel, sanitizeCustomerError } from "./logs-client.js";
|
|
46
48
|
import { stderrPalette } from "./terminal-style.js";
|
|
47
49
|
|
|
48
50
|
const DEFAULT_POLL_INTERVAL_MS = 3_000;
|
|
@@ -554,6 +556,24 @@ async function deployOne(
|
|
|
554
556
|
);
|
|
555
557
|
return 1;
|
|
556
558
|
}
|
|
559
|
+
// Repo-backed fields without a resolvable https origin become a static
|
|
560
|
+
// deploy body the control plane rejects. Fail here with a fix hint —
|
|
561
|
+
// common when origin is an unrecognized SSH shape (pass --repo).
|
|
562
|
+
if (
|
|
563
|
+
gitRepoUrl === undefined &&
|
|
564
|
+
(gitRef !== undefined ||
|
|
565
|
+
agentPath !== undefined ||
|
|
566
|
+
(options.cursorEventsRepos !== undefined &&
|
|
567
|
+
options.cursorEventsRepos.length > 0) ||
|
|
568
|
+
(options.allowDomains !== undefined && options.allowDomains.length > 0))
|
|
569
|
+
) {
|
|
570
|
+
ctx.err(
|
|
571
|
+
`Could not resolve an https:// git repository URL for this deploy.\n` +
|
|
572
|
+
` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n` +
|
|
573
|
+
` Or omit --ref/--path/--cursor-events-repo/--allow-domain for a static engine.\n`
|
|
574
|
+
);
|
|
575
|
+
return 1;
|
|
576
|
+
}
|
|
557
577
|
for (const repo of options.cursorEventsRepos ?? []) {
|
|
558
578
|
if (!isValidCursorEventRepo(repo)) {
|
|
559
579
|
ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
|
|
@@ -659,13 +679,11 @@ async function deployOne(
|
|
|
659
679
|
}
|
|
660
680
|
|
|
661
681
|
if (detail.status !== "running") {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}\n`
|
|
668
|
-
);
|
|
682
|
+
const errorDetail =
|
|
683
|
+
detail.lastError === null || detail.lastError === undefined
|
|
684
|
+
? ""
|
|
685
|
+
: `: ${sanitizeCustomerError(detail.lastError)}`;
|
|
686
|
+
ctx.err(`Deployment ${slug} ended ${detail.status}${errorDetail}\n`);
|
|
669
687
|
return 1;
|
|
670
688
|
}
|
|
671
689
|
ctx.out(
|
|
@@ -709,7 +727,11 @@ function warnMissingSecrets(
|
|
|
709
727
|
return;
|
|
710
728
|
}
|
|
711
729
|
const setNames = new Set(set ?? []);
|
|
712
|
-
|
|
730
|
+
// Platform-managed names (CURSOR_*, hosted storage) are injected by the
|
|
731
|
+
// control plane and never appear in secrets list — do not warn on them.
|
|
732
|
+
const missing = declared.filter(
|
|
733
|
+
(name) => !setNames.has(name) && !isReservedSecretName(name)
|
|
734
|
+
);
|
|
713
735
|
if (missing.length === 0) {
|
|
714
736
|
return;
|
|
715
737
|
}
|
|
@@ -793,11 +815,23 @@ export async function cmdDeploymentStatus(
|
|
|
793
815
|
const lines = [
|
|
794
816
|
`${detail.slug} (team ${detail.teamId})`,
|
|
795
817
|
` status: ${detail.status}`,
|
|
818
|
+
];
|
|
819
|
+
if (detail.progress !== undefined) {
|
|
820
|
+
lines.push(` progress: ${detail.progress}`);
|
|
821
|
+
}
|
|
822
|
+
if (
|
|
823
|
+
detail.statusMessage !== null &&
|
|
824
|
+
detail.statusMessage !== undefined &&
|
|
825
|
+
detail.statusMessage.trim() !== ""
|
|
826
|
+
) {
|
|
827
|
+
lines.push(` step: ${detail.statusMessage}`);
|
|
828
|
+
}
|
|
829
|
+
lines.push(
|
|
796
830
|
` generation: ${detail.generation}`,
|
|
797
831
|
` kind: ${detail.deploymentKind}`,
|
|
798
832
|
` alias: ${aliasUrl}`,
|
|
799
|
-
` playground: ${aliasUrl}/playground
|
|
800
|
-
|
|
833
|
+
` playground: ${aliasUrl}/playground`
|
|
834
|
+
);
|
|
801
835
|
if (detail.gitRepoUrl !== null && detail.gitRepoUrl !== undefined) {
|
|
802
836
|
lines.push(` repo: ${detail.gitRepoUrl} @ ${detail.gitRef ?? ""}`);
|
|
803
837
|
}
|
|
@@ -835,7 +869,7 @@ export async function cmdDeploymentStatus(
|
|
|
835
869
|
);
|
|
836
870
|
}
|
|
837
871
|
if (detail.lastError !== null && detail.lastError !== undefined) {
|
|
838
|
-
lines.push(` last error: ${detail.lastError}`);
|
|
872
|
+
lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
|
|
839
873
|
}
|
|
840
874
|
if (detail.desiredUpdatedAt !== undefined) {
|
|
841
875
|
lines.push(` updated: ${detail.desiredUpdatedAt}`);
|
|
@@ -1229,7 +1263,9 @@ function createLineReader(
|
|
|
1229
1263
|
/**
|
|
1230
1264
|
* Poll deployment status every `pollIntervalMs` until it lands in
|
|
1231
1265
|
* `terminal` (single-line progress on a TTY, one line per transition
|
|
1232
|
-
* otherwise).
|
|
1266
|
+
* otherwise). Prefers customer `statusMessage` / `progress` over raw
|
|
1267
|
+
* status so create → checkout → start is visible. Throws DeployApiError
|
|
1268
|
+
* on request failures or timeout.
|
|
1233
1269
|
*/
|
|
1234
1270
|
async function pollUntil(
|
|
1235
1271
|
ctx: DeployCliContext,
|
|
@@ -1238,21 +1274,22 @@ async function pollUntil(
|
|
|
1238
1274
|
): Promise<DeploymentDetail> {
|
|
1239
1275
|
const startedAt = Date.now();
|
|
1240
1276
|
const tty = process.stderr.isTTY === true;
|
|
1241
|
-
let
|
|
1277
|
+
let lastLabel: string | undefined;
|
|
1242
1278
|
let sawProgress = false;
|
|
1243
1279
|
|
|
1244
|
-
const report = (
|
|
1280
|
+
const report = (detail: DeploymentDetail): void => {
|
|
1245
1281
|
if (ctx.json) {
|
|
1246
1282
|
return;
|
|
1247
1283
|
}
|
|
1284
|
+
const label = deployProgressLabel(detail);
|
|
1248
1285
|
const elapsed = Math.round((Date.now() - startedAt) / 1000);
|
|
1249
1286
|
if (tty) {
|
|
1250
|
-
ctx.err(`\r\x1b[2K${slug}: ${
|
|
1287
|
+
ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
|
|
1251
1288
|
sawProgress = true;
|
|
1252
|
-
} else if (
|
|
1253
|
-
ctx.err(`${slug}: ${
|
|
1289
|
+
} else if (label !== lastLabel) {
|
|
1290
|
+
ctx.err(`${slug}: ${label}\n`);
|
|
1254
1291
|
}
|
|
1255
|
-
|
|
1292
|
+
lastLabel = label;
|
|
1256
1293
|
};
|
|
1257
1294
|
const finishProgressLine = (): void => {
|
|
1258
1295
|
if (tty && sawProgress) {
|
|
@@ -1267,15 +1304,16 @@ async function pollUntil(
|
|
|
1267
1304
|
finishProgressLine();
|
|
1268
1305
|
throw error;
|
|
1269
1306
|
});
|
|
1270
|
-
report(detail
|
|
1307
|
+
report(detail);
|
|
1271
1308
|
if (terminal.has(detail.status)) {
|
|
1272
1309
|
finishProgressLine();
|
|
1273
1310
|
return detail;
|
|
1274
1311
|
}
|
|
1275
1312
|
if (Date.now() - startedAt >= ctx.timeoutMs) {
|
|
1276
1313
|
finishProgressLine();
|
|
1314
|
+
const last = deployProgressLabel(detail);
|
|
1277
1315
|
throw new DeployApiError(
|
|
1278
|
-
`Timed out after ${Math.round(ctx.timeoutMs / 1000)}s waiting for ${slug} (last
|
|
1316
|
+
`Timed out after ${Math.round(ctx.timeoutMs / 1000)}s waiting for ${slug} (last: ${last}). It may still converge — check \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.`,
|
|
1279
1317
|
0
|
|
1280
1318
|
);
|
|
1281
1319
|
}
|
|
@@ -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(),
|