@cursor/july 0.1.32 → 0.1.33
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/docs/404.html +1 -1
- package/dist/docs/ab.html +2 -2
- package/dist/docs/assets/{app.C2aVczmo.js → app.CgZqLyWL.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B1uHGxBZ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DLEzetbD.js → VPLocalSearchBox.C4KigoQn.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BkOH1oMp.js → theme.C_Ty4yT7.js} +2 -2
- package/dist/docs/building-with-agents.html +2 -2
- package/dist/docs/concepts.html +2 -2
- package/dist/docs/deployment.html +2 -2
- package/dist/docs/evals.html +2 -2
- package/dist/docs/example-agents/approval-buddy.html +2 -2
- package/dist/docs/example-agents/benny.html +2 -2
- package/dist/docs/example-agents/bugbot.html +2 -2
- package/dist/docs/example-agents/codebase-wiki.html +2 -2
- package/dist/docs/example-agents/codeowners-review.html +2 -2
- package/dist/docs/example-agents/concierge.html +2 -2
- package/dist/docs/example-agents/fsd.html +2 -2
- package/dist/docs/example-agents/index.html +2 -2
- package/dist/docs/example-agents/knowledge-base.html +2 -2
- package/dist/docs/example-agents/oncall.html +2 -2
- package/dist/docs/example-agents/security-reviewer.html +2 -2
- package/dist/docs/example-agents/slack-agent.html +2 -2
- package/dist/docs/example-agents/weather-agent.html +2 -2
- package/dist/docs/guides/agent-to-agent.html +2 -2
- package/dist/docs/guides/cloud-runtime.html +2 -2
- package/dist/docs/guides/github.html +2 -2
- package/dist/docs/guides/human-in-the-loop.html +2 -2
- package/dist/docs/guides/mcp-oauth.html +2 -2
- package/dist/docs/guides/slack.html +2 -2
- package/dist/docs/guides/webhooks.html +2 -2
- package/dist/docs/hillclimbing.html +2 -2
- package/dist/docs/index.html +2 -2
- package/dist/docs/quickstart.html +2 -2
- package/dist/docs/reference/agent-config.html +2 -2
- package/dist/docs/reference/channels.html +2 -2
- package/dist/docs/reference/cli.html +2 -2
- package/dist/docs/reference/connections.html +2 -2
- package/dist/docs/reference/hooks.html +2 -2
- package/dist/docs/reference/http-api.html +2 -2
- package/dist/docs/reference/instructions.html +2 -2
- package/dist/docs/reference/playground.html +2 -2
- package/dist/docs/reference/project-layout.html +2 -2
- package/dist/docs/reference/prompt.html +2 -2
- package/dist/docs/reference/schedules.html +2 -2
- package/dist/docs/reference/sessions.html +2 -2
- package/dist/docs/reference/skills.html +2 -2
- package/dist/docs/reference/subagents.html +2 -2
- package/dist/docs/reference/tools.html +2 -2
- package/dist/docs/scaffolding-agents.html +2 -2
- package/dist/docs/storage.html +2 -2
- package/dist/docs/troubleshooting.html +2 -2
- package/dist/files-backends/agent-store-presigned-url.d.ts +11 -3
- package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -1
- package/dist/files-backends/agent-store-presigned-url.js +19 -810
- package/dist/internal/cursor-relay-core.d.ts +12 -0
- package/dist/internal/cursor-relay-core.d.ts.map +1 -1
- package/dist/internal/cursor-relay-core.js +42 -8
- package/dist/internal/review-comments.d.ts +9 -1
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +76 -0
- package/dist/internal/server.js +8 -1
- package/dist/playground/assets/index-BRhBbnd4.css +1 -0
- package/dist/playground/assets/index-CVlCAcUx.js +85 -0
- package/dist/playground/index.html +2 -2
- package/package.json +1 -22
- package/src/files-backends/agent-store-presigned-url.ts +7 -5
- package/src/internal/cursor-relay-core.ts +62 -3
- package/src/internal/review-comments.ts +102 -2
- package/src/internal/server.ts +9 -1
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.xgMnlUSO.js +0 -1
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/multi-tenant.d.ts +0 -80
- package/dist/multi-tenant.d.ts.map +0 -1
- package/dist/multi-tenant.js +0 -69
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-50PKeJlG.css +0 -1
- package/dist/playground/assets/index-C0f2Wl1q.js +0 -85
|
@@ -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-CVlCAcUx.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BRhBbnd4.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
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": {
|
|
@@ -39,147 +39,126 @@
|
|
|
39
39
|
"exports": {
|
|
40
40
|
".": {
|
|
41
41
|
"anysphere-source": "./src/index.ts",
|
|
42
|
-
"bun": "./src/index.ts",
|
|
43
42
|
"types": "./dist/index.d.ts",
|
|
44
43
|
"import": "./dist/index.js",
|
|
45
44
|
"default": "./dist/index.js"
|
|
46
45
|
},
|
|
47
46
|
"./tools": {
|
|
48
47
|
"anysphere-source": "./src/tools.ts",
|
|
49
|
-
"bun": "./src/tools.ts",
|
|
50
48
|
"types": "./dist/tools.d.ts",
|
|
51
49
|
"import": "./dist/tools.js",
|
|
52
50
|
"default": "./dist/tools.js"
|
|
53
51
|
},
|
|
54
52
|
"./channels": {
|
|
55
53
|
"anysphere-source": "./src/channels.ts",
|
|
56
|
-
"bun": "./src/channels.ts",
|
|
57
54
|
"types": "./dist/channels.d.ts",
|
|
58
55
|
"import": "./dist/channels.js",
|
|
59
56
|
"default": "./dist/channels.js"
|
|
60
57
|
},
|
|
61
58
|
"./channels/slack": {
|
|
62
59
|
"anysphere-source": "./src/channels/slack/index.ts",
|
|
63
|
-
"bun": "./src/channels/slack/index.ts",
|
|
64
60
|
"types": "./dist/channels/slack/index.d.ts",
|
|
65
61
|
"import": "./dist/channels/slack/index.js",
|
|
66
62
|
"default": "./dist/channels/slack/index.js"
|
|
67
63
|
},
|
|
68
64
|
"./channels/github": {
|
|
69
65
|
"anysphere-source": "./src/channels/github/index.ts",
|
|
70
|
-
"bun": "./src/channels/github/index.ts",
|
|
71
66
|
"types": "./dist/channels/github/index.d.ts",
|
|
72
67
|
"import": "./dist/channels/github/index.js",
|
|
73
68
|
"default": "./dist/channels/github/index.js"
|
|
74
69
|
},
|
|
75
70
|
"./skills": {
|
|
76
71
|
"anysphere-source": "./src/skills.ts",
|
|
77
|
-
"bun": "./src/skills.ts",
|
|
78
72
|
"types": "./dist/skills.d.ts",
|
|
79
73
|
"import": "./dist/skills.js",
|
|
80
74
|
"default": "./dist/skills.js"
|
|
81
75
|
},
|
|
82
76
|
"./schedules": {
|
|
83
77
|
"anysphere-source": "./src/schedules.ts",
|
|
84
|
-
"bun": "./src/schedules.ts",
|
|
85
78
|
"types": "./dist/schedules.d.ts",
|
|
86
79
|
"import": "./dist/schedules.js",
|
|
87
80
|
"default": "./dist/schedules.js"
|
|
88
81
|
},
|
|
89
82
|
"./reminders": {
|
|
90
83
|
"anysphere-source": "./src/reminders.ts",
|
|
91
|
-
"bun": "./src/reminders.ts",
|
|
92
84
|
"types": "./dist/reminders.d.ts",
|
|
93
85
|
"import": "./dist/reminders.js",
|
|
94
86
|
"default": "./dist/reminders.js"
|
|
95
87
|
},
|
|
96
88
|
"./connections": {
|
|
97
89
|
"anysphere-source": "./src/connections.ts",
|
|
98
|
-
"bun": "./src/connections.ts",
|
|
99
90
|
"types": "./dist/connections.d.ts",
|
|
100
91
|
"import": "./dist/connections.js",
|
|
101
92
|
"default": "./dist/connections.js"
|
|
102
93
|
},
|
|
103
94
|
"./hooks": {
|
|
104
95
|
"anysphere-source": "./src/hooks.ts",
|
|
105
|
-
"bun": "./src/hooks.ts",
|
|
106
96
|
"types": "./dist/hooks.d.ts",
|
|
107
97
|
"import": "./dist/hooks.js",
|
|
108
98
|
"default": "./dist/hooks.js"
|
|
109
99
|
},
|
|
110
100
|
"./memory": {
|
|
111
101
|
"anysphere-source": "./src/memory.ts",
|
|
112
|
-
"bun": "./src/memory.ts",
|
|
113
102
|
"types": "./dist/memory.d.ts",
|
|
114
103
|
"import": "./dist/memory.js",
|
|
115
104
|
"default": "./dist/memory.js"
|
|
116
105
|
},
|
|
117
106
|
"./prompt": {
|
|
118
107
|
"anysphere-source": "./src/prompt.ts",
|
|
119
|
-
"bun": "./src/prompt.ts",
|
|
120
108
|
"types": "./dist/prompt.d.ts",
|
|
121
109
|
"import": "./dist/prompt.js",
|
|
122
110
|
"default": "./dist/prompt.js"
|
|
123
111
|
},
|
|
124
112
|
"./evals": {
|
|
125
113
|
"anysphere-source": "./src/evals.ts",
|
|
126
|
-
"bun": "./src/evals.ts",
|
|
127
114
|
"types": "./dist/evals.d.ts",
|
|
128
115
|
"import": "./dist/evals.js",
|
|
129
116
|
"default": "./dist/evals.js"
|
|
130
117
|
},
|
|
131
118
|
"./evals/reporters": {
|
|
132
119
|
"anysphere-source": "./src/evals/reporters.ts",
|
|
133
|
-
"bun": "./src/evals/reporters.ts",
|
|
134
120
|
"types": "./dist/evals/reporters.d.ts",
|
|
135
121
|
"import": "./dist/evals/reporters.js",
|
|
136
122
|
"default": "./dist/evals/reporters.js"
|
|
137
123
|
},
|
|
138
124
|
"./evals/loaders": {
|
|
139
125
|
"anysphere-source": "./src/evals/loaders.ts",
|
|
140
|
-
"bun": "./src/evals/loaders.ts",
|
|
141
126
|
"types": "./dist/evals/loaders.d.ts",
|
|
142
127
|
"import": "./dist/evals/loaders.js",
|
|
143
128
|
"default": "./dist/evals/loaders.js"
|
|
144
129
|
},
|
|
145
130
|
"./ab": {
|
|
146
131
|
"anysphere-source": "./src/ab.ts",
|
|
147
|
-
"bun": "./src/ab.ts",
|
|
148
132
|
"types": "./dist/ab.d.ts",
|
|
149
133
|
"import": "./dist/ab.js",
|
|
150
134
|
"default": "./dist/ab.js"
|
|
151
135
|
},
|
|
152
136
|
"./artifacts": {
|
|
153
137
|
"anysphere-source": "./src/artifacts.ts",
|
|
154
|
-
"bun": "./src/artifacts.ts",
|
|
155
138
|
"types": "./dist/artifacts.d.ts",
|
|
156
139
|
"import": "./dist/artifacts.js",
|
|
157
140
|
"default": "./dist/artifacts.js"
|
|
158
141
|
},
|
|
159
142
|
"./storage": {
|
|
160
143
|
"anysphere-source": "./src/storage.ts",
|
|
161
|
-
"bun": "./src/storage.ts",
|
|
162
144
|
"types": "./dist/storage.d.ts",
|
|
163
145
|
"import": "./dist/storage.js",
|
|
164
146
|
"default": "./dist/storage.js"
|
|
165
147
|
},
|
|
166
148
|
"./storage/file-kv": {
|
|
167
149
|
"anysphere-source": "./src/storage-backends/file-kv.ts",
|
|
168
|
-
"bun": "./src/storage-backends/file-kv.ts",
|
|
169
150
|
"types": "./dist/storage-backends/file-kv.d.ts",
|
|
170
151
|
"import": "./dist/storage-backends/file-kv.js",
|
|
171
152
|
"default": "./dist/storage-backends/file-kv.js"
|
|
172
153
|
},
|
|
173
154
|
"./storage/postgres-kv": {
|
|
174
155
|
"anysphere-source": "./src/storage-backends/postgres-kv.ts",
|
|
175
|
-
"bun": "./src/storage-backends/postgres-kv.ts",
|
|
176
156
|
"types": "./dist/storage-backends/postgres-kv.d.ts",
|
|
177
157
|
"import": "./dist/storage-backends/postgres-kv.js",
|
|
178
158
|
"default": "./dist/storage-backends/postgres-kv.js"
|
|
179
159
|
},
|
|
180
160
|
"./storage/cursor-hosted": {
|
|
181
161
|
"anysphere-source": "./src/storage-backends/cursor-hosted.ts",
|
|
182
|
-
"bun": "./src/storage-backends/cursor-hosted.ts",
|
|
183
162
|
"types": "./dist/storage-backends/cursor-hosted.d.ts",
|
|
184
163
|
"import": "./dist/storage-backends/cursor-hosted.js",
|
|
185
164
|
"default": "./dist/storage-backends/cursor-hosted.js"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Re-export
|
|
2
|
+
* Re-export bundled into dist by `scripts/bundle-publish-shims.mjs`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Imports the `presigned-url` entry point rather than the package root: the
|
|
5
|
+
* root is a barrel over the whole library, and bundling through it inlines
|
|
6
|
+
* every module the barrel can reach (sync engine, local sqlite index, secure
|
|
7
|
+
* open) into the published tarball. This module has no imports of its own, so
|
|
8
|
+
* the bundle stays limited to the validator.
|
|
7
9
|
*/
|
|
8
|
-
export { createAgentStorePresignedUrlValidatorForBackend } from "@anysphere/agent-store-sync";
|
|
10
|
+
export { createAgentStorePresignedUrlValidatorForBackend } from "@anysphere/agent-store-sync/presigned-url";
|
|
@@ -151,6 +151,42 @@ export interface CursorRelayCoreOptions<TEvent extends { offset: string }> {
|
|
|
151
151
|
fetchImpl?: typeof fetch;
|
|
152
152
|
/** Test seam: override long-poll wait (default 25s). */
|
|
153
153
|
pollWaitMs?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Desired-revision generation for hosted engines. Sent as
|
|
156
|
+
* `x-agent-serve-generation` so the control plane can fence zombies after
|
|
157
|
+
* a redeploy. Defaults to `process.env.AGENT_SERVE_GENERATION` when set.
|
|
158
|
+
*/
|
|
159
|
+
deploymentGeneration?: number;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Must match server-shared `AGENT_SERVE_GENERATION_HEADER`. */
|
|
163
|
+
export const AGENT_SERVE_GENERATION_HEADER = "x-agent-serve-generation";
|
|
164
|
+
|
|
165
|
+
/** Must match server-shared `AGENT_SERVE_GENERATION_ENV_VAR`. */
|
|
166
|
+
export const AGENT_SERVE_GENERATION_ENV_VAR = "AGENT_SERVE_GENERATION";
|
|
167
|
+
|
|
168
|
+
export function resolveAgentServeDeploymentGeneration(
|
|
169
|
+
explicit?: number
|
|
170
|
+
): number | undefined {
|
|
171
|
+
if (
|
|
172
|
+
explicit !== undefined &&
|
|
173
|
+
Number.isSafeInteger(explicit) &&
|
|
174
|
+
explicit > 0
|
|
175
|
+
) {
|
|
176
|
+
return explicit;
|
|
177
|
+
}
|
|
178
|
+
const raw = process.env[AGENT_SERVE_GENERATION_ENV_VAR]?.trim();
|
|
179
|
+
if (raw === undefined || raw.length === 0) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
if (!/^\d+$/.test(raw)) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const parsed = Number(raw);
|
|
186
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
return parsed;
|
|
154
190
|
}
|
|
155
191
|
|
|
156
192
|
export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
@@ -160,6 +196,7 @@ export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
|
160
196
|
private consumePromise: Promise<void> | undefined;
|
|
161
197
|
private readonly offsetStore: RelayOffsetStore;
|
|
162
198
|
private readonly fetchImpl: typeof fetch;
|
|
199
|
+
private readonly deploymentGeneration: number | undefined;
|
|
163
200
|
private consumerId = "";
|
|
164
201
|
/** undefined until the first registration, so a clean first success logs. */
|
|
165
202
|
private lastRegistrationLog: string | undefined;
|
|
@@ -175,6 +212,9 @@ export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
|
175
212
|
constructor(private readonly options: CursorRelayCoreOptions<TEvent>) {
|
|
176
213
|
this.offsetStore = new RelayOffsetStore(options.stateDir);
|
|
177
214
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
215
|
+
this.deploymentGeneration = resolveAgentServeDeploymentGeneration(
|
|
216
|
+
options.deploymentGeneration
|
|
217
|
+
);
|
|
178
218
|
}
|
|
179
219
|
|
|
180
220
|
start(): void {
|
|
@@ -285,6 +325,13 @@ export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
|
285
325
|
headers: {
|
|
286
326
|
authorization: `Bearer ${this.options.apiKey}`,
|
|
287
327
|
"content-type": "application/json",
|
|
328
|
+
...(this.deploymentGeneration === undefined
|
|
329
|
+
? {}
|
|
330
|
+
: {
|
|
331
|
+
[AGENT_SERVE_GENERATION_HEADER]: String(
|
|
332
|
+
this.deploymentGeneration
|
|
333
|
+
),
|
|
334
|
+
}),
|
|
288
335
|
},
|
|
289
336
|
body: JSON.stringify(adapter.buildDeregistrationBody(this.consumerId)),
|
|
290
337
|
signal: controller.signal,
|
|
@@ -322,6 +369,13 @@ export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
|
322
369
|
headers: {
|
|
323
370
|
authorization: `Bearer ${this.options.apiKey}`,
|
|
324
371
|
...(body === undefined ? {} : { "content-type": "application/json" }),
|
|
372
|
+
...(this.deploymentGeneration === undefined
|
|
373
|
+
? {}
|
|
374
|
+
: {
|
|
375
|
+
[AGENT_SERVE_GENERATION_HEADER]: String(
|
|
376
|
+
this.deploymentGeneration
|
|
377
|
+
),
|
|
378
|
+
}),
|
|
325
379
|
},
|
|
326
380
|
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
327
381
|
...(this.abort === undefined ? {} : { signal: this.abort.signal }),
|
|
@@ -514,14 +568,19 @@ export class CursorRelayCore<TEvent extends { offset: string }> {
|
|
|
514
568
|
response: Response,
|
|
515
569
|
backoffMs: number
|
|
516
570
|
): Promise<number> {
|
|
517
|
-
|
|
518
|
-
|
|
571
|
+
// 409 = generation fence (stale resident after redeploy). Same long
|
|
572
|
+
// backoff as auth: retrying every second cannot heal a wrong generation.
|
|
573
|
+
const isAuthOrFenceFailure =
|
|
574
|
+
response.status === 401 ||
|
|
575
|
+
response.status === 403 ||
|
|
576
|
+
response.status === 409;
|
|
577
|
+
const sleepMs = isAuthOrFenceFailure ? AUTH_FAILURE_BACKOFF_MS : backoffMs;
|
|
519
578
|
const text = await response.text().catch(() => "");
|
|
520
579
|
this.log(
|
|
521
580
|
`poll failed: ${response.status} ${text.slice(0, 300)} (retrying in ${Math.round(sleepMs / 1000)}s)`
|
|
522
581
|
);
|
|
523
582
|
await this.sleep(sleepMs);
|
|
524
|
-
return
|
|
583
|
+
return isAuthOrFenceFailure
|
|
525
584
|
? AUTH_FAILURE_BACKOFF_MS
|
|
526
585
|
: Math.min(backoffMs * 2, MAX_BACKOFF_MS);
|
|
527
586
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import type { HostGitHubClient } from "../types.js";
|
|
2
3
|
|
|
3
|
-
export type ReviewCommentPublisher = "local_gh";
|
|
4
|
+
export type ReviewCommentPublisher = "local_gh" | "host_github";
|
|
4
5
|
|
|
5
6
|
export type ReviewCommentPostResult = {
|
|
6
7
|
posted: boolean;
|
|
@@ -84,6 +85,80 @@ export function createLocalGhReviewPublisher(): ReviewCommentPublisherImplementa
|
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Posts a PR review through the host GitHub client (Cursor account lease,
|
|
90
|
+
* App installation token, or PAT). Prefer this on Cursor-deployed agents —
|
|
91
|
+
* no separate GitHub write secret is required when `githubChannel({
|
|
92
|
+
* cursorAccount })` is bound.
|
|
93
|
+
*/
|
|
94
|
+
export function createHostGithubReviewPublisher(
|
|
95
|
+
github: HostGitHubClient
|
|
96
|
+
): ReviewCommentPublisherImplementation {
|
|
97
|
+
return {
|
|
98
|
+
async postReview(args) {
|
|
99
|
+
return postReviewViaHostGithub(github, args);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function postReviewViaHostGithub(
|
|
105
|
+
github: HostGitHubClient,
|
|
106
|
+
args: ReviewCommentPostArgs
|
|
107
|
+
): Promise<ReviewCommentPostResult> {
|
|
108
|
+
const prepared = prepareReviewCommentsRequest(args);
|
|
109
|
+
if (prepared.kind === "skipped") {
|
|
110
|
+
return {
|
|
111
|
+
...prepared.result,
|
|
112
|
+
publisher: "host_github",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const { request } = prepared;
|
|
117
|
+
const [owner, repo] = request.repo.split("/", 2);
|
|
118
|
+
if (owner === undefined || repo === undefined || repo === "") {
|
|
119
|
+
return skippedHost("unparseable owner/repo from PR URL");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
args.signal?.throwIfAborted();
|
|
124
|
+
const octokit = await github.getOctokit();
|
|
125
|
+
args.signal?.throwIfAborted();
|
|
126
|
+
const response = await octokit.rest.pulls.createReview({
|
|
127
|
+
owner,
|
|
128
|
+
repo,
|
|
129
|
+
pull_number: request.prNumber,
|
|
130
|
+
commit_id: request.headSha,
|
|
131
|
+
body: request.message,
|
|
132
|
+
event: "COMMENT",
|
|
133
|
+
comments: request.comments.map(toGithubPullRequestReviewComment),
|
|
134
|
+
});
|
|
135
|
+
const htmlUrl =
|
|
136
|
+
typeof response.data.html_url === "string"
|
|
137
|
+
? response.data.html_url
|
|
138
|
+
: undefined;
|
|
139
|
+
const inlineCommentCount = request.comments.length;
|
|
140
|
+
return {
|
|
141
|
+
posted: true,
|
|
142
|
+
publisher: "host_github",
|
|
143
|
+
mode:
|
|
144
|
+
inlineCommentCount > 0
|
|
145
|
+
? "review_with_inline_comments"
|
|
146
|
+
: "review_body_only",
|
|
147
|
+
inlineCommentCount,
|
|
148
|
+
detail: htmlUrl
|
|
149
|
+
? `posted via host GitHub: ${htmlUrl}`
|
|
150
|
+
: `posted via host GitHub with ${inlineCommentCount} inline comment(s)`,
|
|
151
|
+
};
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (args.signal?.aborted) {
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
return skippedHost(
|
|
157
|
+
`host GitHub review post failed: ${error instanceof Error ? error.message : String(error)}`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
87
162
|
async function postReviewViaLocalGh(
|
|
88
163
|
args: ReviewCommentPostArgs
|
|
89
164
|
): Promise<ReviewCommentPostResult> {
|
|
@@ -129,10 +204,25 @@ async function postReviewViaLocalGh(
|
|
|
129
204
|
}
|
|
130
205
|
}
|
|
131
206
|
|
|
207
|
+
type GithubPullRequestReviewComment = {
|
|
208
|
+
path: string;
|
|
209
|
+
body: string;
|
|
210
|
+
line: number;
|
|
211
|
+
side: "RIGHT";
|
|
212
|
+
start_line?: number;
|
|
213
|
+
start_side?: "RIGHT";
|
|
214
|
+
};
|
|
215
|
+
|
|
132
216
|
function toGithubReviewComment(
|
|
133
217
|
comment: ReviewInlineComment
|
|
134
218
|
): Record<string, string | number> {
|
|
135
|
-
|
|
219
|
+
return toGithubPullRequestReviewComment(comment);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function toGithubPullRequestReviewComment(
|
|
223
|
+
comment: ReviewInlineComment
|
|
224
|
+
): GithubPullRequestReviewComment {
|
|
225
|
+
const body: GithubPullRequestReviewComment = {
|
|
136
226
|
path: comment.file,
|
|
137
227
|
body: comment.body,
|
|
138
228
|
line: comment.line,
|
|
@@ -159,6 +249,16 @@ function skipped(detail: string): ReviewCommentPostResult {
|
|
|
159
249
|
};
|
|
160
250
|
}
|
|
161
251
|
|
|
252
|
+
function skippedHost(detail: string): ReviewCommentPostResult {
|
|
253
|
+
return {
|
|
254
|
+
posted: false,
|
|
255
|
+
publisher: "host_github",
|
|
256
|
+
mode: "skipped",
|
|
257
|
+
inlineCommentCount: 0,
|
|
258
|
+
detail,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
162
262
|
function parseGithubPrUrl(
|
|
163
263
|
prUrl: string
|
|
164
264
|
):
|
package/src/internal/server.ts
CHANGED
|
@@ -959,7 +959,15 @@ function mountAgentRoutes(
|
|
|
959
959
|
method: "GET",
|
|
960
960
|
pattern: `${base}/v1/health`,
|
|
961
961
|
auth: "none",
|
|
962
|
-
|
|
962
|
+
// Temporal consumes this response before promoting a newly deployed pod.
|
|
963
|
+
// Include the framework build there so deploy observability gets the
|
|
964
|
+
// version from the process that will serve turns, with no second request.
|
|
965
|
+
handler: () =>
|
|
966
|
+
jsonResponse({
|
|
967
|
+
ok: true,
|
|
968
|
+
name: project.name,
|
|
969
|
+
version: packageVersion(),
|
|
970
|
+
}),
|
|
963
971
|
});
|
|
964
972
|
|
|
965
973
|
// Bootstrap the SPA can't derive from its own URL (agent name, dev mode, and
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Live-reply delivery strategies for the Slack default handlers.
|
|
3
|
-
*
|
|
4
|
-
* A single strategy owns how an in-progress reply is opened, updated,
|
|
5
|
-
* finalized, and cleaned up so the handlers in `defaults.ts` don't fork on the
|
|
6
|
-
* delivery mode at every event:
|
|
7
|
-
*
|
|
8
|
-
* - `stream`: Slack chat.startStream / appendStream / stopStream.
|
|
9
|
-
* - `post-update`: a chat.postMessage skeleton edited with chat.update. This is
|
|
10
|
-
* the only path that preserves Cursor-account identity pinning (which only
|
|
11
|
-
* covers postMessage).
|
|
12
|
-
*
|
|
13
|
-
* `buildDefaultEvents` selects one via {@link selectLiveDeliveryStrategy} up
|
|
14
|
-
* front and calls into it. All calls keep the same soft-fail / log behavior as
|
|
15
|
-
* the inlined logic they replaced.
|
|
16
|
-
*/
|
|
17
|
-
import type { ChannelEventContext } from "../../types.js";
|
|
18
|
-
import type { SlackLog } from "./log.js";
|
|
19
|
-
import type { SlackBotToken, SlackChannelState } from "./types.js";
|
|
20
|
-
type SlackChannel = ChannelEventContext<SlackChannelState>;
|
|
21
|
-
export interface LiveDeliveryDeps {
|
|
22
|
-
botToken: SlackBotToken | undefined;
|
|
23
|
-
getLog: () => SlackLog;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* How the default handlers deliver an in-progress reply. Methods write live
|
|
27
|
-
* delivery state (`streamTs`, `streamChannelId`, `lastPostedText`,
|
|
28
|
-
* `lastPostUpdateAtMs`, `streamingUnavailable`) on `channel.state` directly.
|
|
29
|
-
*/
|
|
30
|
-
export interface LiveDeliveryStrategy {
|
|
31
|
-
/** True when tool-call thinking steps can be appended to the live message. */
|
|
32
|
-
readonly inlineToolSteps: boolean;
|
|
33
|
-
/** Open the live message (skeleton post / stream start). */
|
|
34
|
-
start(args: {
|
|
35
|
-
channel: SlackChannel;
|
|
36
|
-
channelId: string;
|
|
37
|
-
threadTs: string;
|
|
38
|
-
sessionId: string;
|
|
39
|
-
}): Promise<void>;
|
|
40
|
-
/** Push the latest cumulative text to the live message (throttled). */
|
|
41
|
-
append(args: {
|
|
42
|
-
channel: SlackChannel;
|
|
43
|
-
channelId: string;
|
|
44
|
-
streamTs: string;
|
|
45
|
-
text: string;
|
|
46
|
-
sessionId: string;
|
|
47
|
-
}): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Flush the final reply text. `delivered` is false only when the caller must
|
|
50
|
-
* post the full reply as a fresh message (finalize failed on partial text).
|
|
51
|
-
*/
|
|
52
|
-
finalize(args: {
|
|
53
|
-
channel: SlackChannel;
|
|
54
|
-
channelId: string;
|
|
55
|
-
streamTs: string;
|
|
56
|
-
text: string;
|
|
57
|
-
sessionId: string;
|
|
58
|
-
}): Promise<{
|
|
59
|
-
delivered: boolean;
|
|
60
|
-
}>;
|
|
61
|
-
/** Close the live message when the turn produced no final text. */
|
|
62
|
-
finalizeEmpty(args: {
|
|
63
|
-
channel: SlackChannel;
|
|
64
|
-
channelId: string;
|
|
65
|
-
streamTs: string;
|
|
66
|
-
}): Promise<void>;
|
|
67
|
-
/** Best-effort remove a live message left open after the turn ended. */
|
|
68
|
-
cleanupOrphan(args: {
|
|
69
|
-
channel: SlackChannel;
|
|
70
|
-
}): Promise<void>;
|
|
71
|
-
/** Deliver the error text into the live message; `delivered` gates a fallback post. */
|
|
72
|
-
fail(args: {
|
|
73
|
-
channel: SlackChannel;
|
|
74
|
-
channelId: string;
|
|
75
|
-
streamTs: string;
|
|
76
|
-
errorText: string;
|
|
77
|
-
sessionId: string;
|
|
78
|
-
}): Promise<{
|
|
79
|
-
delivered: boolean;
|
|
80
|
-
}>;
|
|
81
|
-
}
|
|
82
|
-
/** Pick the live-reply delivery strategy for a `buildDefaultEvents` instance. */
|
|
83
|
-
export declare function selectLiveDeliveryStrategy(deps: LiveDeliveryDeps, usePostUpdate: boolean): LiveDeliveryStrategy;
|
|
84
|
-
export {};
|
|
85
|
-
//# sourceMappingURL=post-update-delivery.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"post-update-delivery.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/post-update-delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAW1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE,KAAK,YAAY,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,MAAM,QAAQ,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,4DAA4D;IAC5D,KAAK,CAAC,IAAI,EAAE;QACV,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,uEAAuE;IACvE,MAAM,CAAC,IAAI,EAAE;QACX,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACpC,mEAAmE;IACnE,aAAa,CAAC,IAAI,EAAE;QAClB,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,wEAAwE;IACxE,aAAa,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,uFAAuF;IACvF,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrC;AA6RD,iFAAiF;AACjF,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,gBAAgB,EACtB,aAAa,EAAE,OAAO,GACrB,oBAAoB,CAItB"}
|