@cursor/july 0.1.105 → 0.1.107
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 +1 -8
- package/dist/channels/bitbucket/types.d.ts +2 -4
- package/dist/channels/bitbucket/types.d.ts.map +1 -1
- package/dist/channels/deployments/types.d.ts +5 -8
- package/dist/channels/deployments/types.d.ts.map +1 -1
- package/dist/channels/github/types.d.ts +2 -4
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/gitlab/types.d.ts +2 -5
- package/dist/channels/gitlab/types.d.ts.map +1 -1
- package/dist/channels/origin/types.d.ts +2 -3
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +3 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +1 -1
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +48 -11
- package/dist/channels/slack/types.d.ts +4 -3
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +3 -3
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{app.BVwaffdK.js → app.CtuckIiL.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.WuWTZ1x8.js → VPLocalSearchBox.Bkkhnu8K.js} +2 -2
- package/dist/docs/assets/chunks/{theme.BYdI_6sF.js → theme.DhpIe0Pa.js} +2 -2
- package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.js → guides_opentelemetry.md.SCRMskno.js} +3 -3
- package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.lean.js → guides_opentelemetry.md.SCRMskno.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.DBGcaB7m.js → reference_channels.md.D-qTqwcq.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.DBGcaB7m.lean.js → reference_channels.md.D-qTqwcq.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.js → reference_cli.md.Dm67hd2D.js} +1 -1
- package/dist/docs/assets/{skills_otel.md.CqhobH3B.js → skills_otel.md.B5Ddv1xH.js} +1 -1
- package/dist/docs/assets/{style.BRuM8477.css → style.DCD_zyg3.css} +1 -1
- package/dist/docs/building-with-agents.html +6 -6
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +6 -6
- package/dist/docs/guides/agent-to-agent.html +6 -6
- package/dist/docs/guides/cloud-agents.html +6 -6
- package/dist/docs/guides/convert-automation.html +6 -6
- package/dist/docs/guides/github.html +6 -6
- package/dist/docs/guides/grokbot-agents.html +6 -6
- package/dist/docs/guides/human-in-the-loop.html +6 -6
- package/dist/docs/guides/mcp-oauth.html +6 -6
- package/dist/docs/guides/opentelemetry.html +8 -8
- package/dist/docs/guides/opentelemetry.md +3 -4
- package/dist/docs/guides/slack.html +6 -6
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/index.html +6 -6
- package/dist/docs/llms-full.txt +22 -28
- package/dist/docs/quickstart.html +6 -6
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/artifacts.html +6 -6
- package/dist/docs/reference/channels.html +7 -7
- package/dist/docs/reference/channels.md +11 -19
- package/dist/docs/reference/cli.html +8 -8
- package/dist/docs/reference/cli.md +5 -2
- package/dist/docs/reference/connections.html +6 -6
- package/dist/docs/reference/extensions.html +6 -6
- package/dist/docs/reference/hooks.html +6 -6
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/instructions.html +6 -6
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/project-layout.html +6 -6
- package/dist/docs/reference/prompt.html +6 -6
- package/dist/docs/reference/result.html +6 -6
- package/dist/docs/reference/schedules.html +6 -6
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/skills.html +6 -6
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/tools.html +6 -6
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/skills/ab.html +6 -6
- package/dist/docs/skills/create-agent.html +6 -6
- package/dist/docs/skills/debug.html +5 -5
- package/dist/docs/skills/evals.html +6 -6
- package/dist/docs/skills/framework-map.html +5 -5
- package/dist/docs/skills/github.html +6 -6
- package/dist/docs/skills/hillclimb.html +6 -6
- package/dist/docs/skills/index.html +5 -5
- package/dist/docs/skills/mcp-auth.html +6 -6
- package/dist/docs/skills/otel.html +8 -8
- package/dist/docs/skills/otel.md +3 -3
- package/dist/docs/skills/setup-slack.html +6 -6
- package/dist/docs/storage.html +6 -6
- package/dist/docs/templates/agentic-owners.html +6 -6
- package/dist/docs/templates/agents-md.html +6 -6
- package/dist/docs/templates/code-wiki.html +6 -6
- package/dist/docs/templates/demo.html +6 -6
- package/dist/docs/templates/grokbot-agents.html +6 -6
- package/dist/docs/templates/pr-autofixer.html +6 -6
- package/dist/docs/templates/security-help.html +6 -6
- package/dist/docs/templates/security-reviewer.html +6 -6
- package/dist/docs/templates/triage.html +6 -6
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +23 -11
- package/dist/internal/cursor/backend-client.d.ts +25 -0
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +57 -2
- package/dist/internal/deploy-client.d.ts +8 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +14 -0
- package/dist/internal/deploy-manifest.d.ts +3 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +15 -12
- package/dist/internal/discovery/agent.d.ts.map +1 -1
- package/dist/internal/discovery/agent.js +1 -0
- package/dist/internal/discovery/info.d.ts.map +1 -1
- package/dist/internal/discovery/info.js +7 -3
- package/dist/internal/discovery/modules.d.ts +1 -1
- package/dist/internal/discovery/modules.d.ts.map +1 -1
- package/dist/internal/discovery/modules.js +1 -0
- package/dist/internal/discovery/project.d.ts.map +1 -1
- package/dist/internal/discovery/project.js +3 -0
- package/dist/internal/discovery/reminders.d.ts +7 -0
- package/dist/internal/discovery/reminders.d.ts.map +1 -0
- package/dist/internal/discovery/reminders.js +65 -0
- package/dist/internal/discovery/subagent.js +1 -0
- package/dist/internal/distribution.d.ts +5 -0
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +17 -0
- package/dist/internal/framework-storage-selection.d.ts +14 -3
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +36 -6
- package/dist/internal/guest-network.d.ts.map +1 -1
- package/dist/internal/guest-network.js +2 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +48 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +60 -0
- package/dist/internal/hosted-delivery.d.ts +10 -0
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +83 -18
- package/dist/internal/local-control-plane.d.ts +18 -2
- package/dist/internal/local-control-plane.d.ts.map +1 -1
- package/dist/internal/local-control-plane.js +199 -17
- package/dist/internal/reminder-control-plane-protocol.d.ts +187 -0
- package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -0
- package/dist/internal/reminder-control-plane-protocol.js +244 -0
- package/dist/internal/reminder-runner.d.ts +48 -6
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +336 -48
- package/dist/internal/reminder-schedule.d.ts +5 -2
- package/dist/internal/reminder-schedule.d.ts.map +1 -1
- package/dist/internal/reminder-schedule.js +8 -6
- package/dist/internal/reminder-store.d.ts +24 -7
- package/dist/internal/reminder-store.d.ts.map +1 -1
- package/dist/internal/reminder-store.js +6 -5
- package/dist/internal/request-error-status.d.ts +2 -0
- package/dist/internal/request-error-status.d.ts.map +1 -1
- package/dist/internal/request-error-status.js +22 -3
- package/dist/internal/scm/pr-url.d.ts +40 -0
- package/dist/internal/scm/pr-url.d.ts.map +1 -1
- package/dist/internal/scm/pr-url.js +93 -14
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +67 -27
- package/dist/internal/session-engine.d.ts +4 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +5 -0
- package/dist/playground/assets/{index-BaQzjaNK.js → index-Bq2HpEQB.js} +23 -23
- package/dist/playground/assets/index-CZKKNlmb.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/reminders.d.ts +24 -5
- package/dist/reminders.d.ts.map +1 -1
- package/dist/reminders.js +28 -5
- package/dist/types.d.ts +89 -20
- package/dist/types.d.ts.map +1 -1
- package/docs/guides/opentelemetry.md +3 -4
- package/docs/reference/channels.md +11 -19
- package/docs/reference/cli.md +5 -2
- package/package.json +3 -3
- package/skills/otel/SKILL.md +3 -3
- package/src/bin/agent-serve.ts +1 -9
- package/src/channels/bitbucket/types.ts +2 -4
- package/src/channels/deployments/types.ts +5 -8
- package/src/channels/github/types.ts +2 -4
- package/src/channels/gitlab/types.ts +2 -5
- package/src/channels/origin/types.ts +2 -3
- package/src/channels/slack/defaults.ts +3 -0
- package/src/channels/slack/dispatch.ts +1 -0
- package/src/channels/slack/live-delivery.ts +53 -12
- package/src/channels/slack/types.ts +4 -3
- package/src/index.ts +6 -3
- package/src/internal/cli-deploy.ts +30 -12
- package/src/internal/cursor/backend-client.ts +90 -2
- package/src/internal/deploy-client.ts +16 -0
- package/src/internal/deploy-manifest.ts +16 -11
- package/src/internal/discovery/agent.ts +1 -0
- package/src/internal/discovery/info.ts +6 -0
- package/src/internal/discovery/modules.ts +2 -4
- package/src/internal/discovery/project.ts +3 -0
- package/src/internal/discovery/reminders.ts +65 -0
- package/src/internal/discovery/subagent.ts +1 -0
- package/src/internal/distribution.ts +20 -0
- package/src/internal/framework-storage-selection.ts +43 -6
- package/src/internal/guest-network.ts +3 -0
- package/src/internal/hosted-delivery-protocol.ts +96 -0
- package/src/internal/hosted-delivery.ts +154 -27
- package/src/internal/local-control-plane.ts +281 -22
- package/src/internal/reminder-control-plane-protocol.ts +499 -0
- package/src/internal/reminder-runner.ts +421 -48
- package/src/internal/reminder-schedule.ts +11 -6
- package/src/internal/reminder-store.ts +27 -7
- package/src/internal/request-error-status.ts +27 -3
- package/src/internal/scm/pr-url.ts +167 -20
- package/src/internal/server.ts +69 -16
- package/src/internal/session-engine.ts +5 -0
- package/src/reminders.ts +35 -4
- package/src/types.ts +95 -20
- package/dist/docs/assets/chunks/@localSearchIndexroot.CJxMklAy.js +0 -1
- package/dist/playground/assets/index-CceqnLTX.css +0 -1
- /package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.lean.js → reference_cli.md.Dm67hd2D.lean.js} +0 -0
- /package/dist/docs/assets/{skills_otel.md.CqhobH3B.lean.js → skills_otel.md.B5Ddv1xH.lean.js} +0 -0
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
projectInfo,
|
|
48
48
|
runtimeArchitectureCompatibilityError,
|
|
49
49
|
} from "./discovery.js";
|
|
50
|
-
import { packageVersion } from "./distribution.js";
|
|
50
|
+
import { packageGitSha, packageVersion } from "./distribution.js";
|
|
51
51
|
|
|
52
52
|
export const DEPLOY_MANIFEST_VERSION: 1 = 1;
|
|
53
53
|
|
|
@@ -62,6 +62,10 @@ const agentDeployManifestV1Schema = z.object({
|
|
|
62
62
|
manifestVersion: z.literal(DEPLOY_MANIFEST_VERSION),
|
|
63
63
|
generatedAtMs: z.number().int().nonnegative(),
|
|
64
64
|
cliVersion: z.string().min(1),
|
|
65
|
+
cliGitSha: z
|
|
66
|
+
.string()
|
|
67
|
+
.regex(/^[0-9a-f]{40,64}$/)
|
|
68
|
+
.optional(),
|
|
65
69
|
declarations: z.object({
|
|
66
70
|
egressDomains: z.array(z.string().min(1)).max(64),
|
|
67
71
|
publicRoutePaths: z.array(z.string().min(1)).max(64),
|
|
@@ -115,6 +119,8 @@ export interface AgentDeployManifestV1 {
|
|
|
115
119
|
generatedAtMs: number;
|
|
116
120
|
/** `@cursor/july` version that produced the manifest. */
|
|
117
121
|
cliVersion: string;
|
|
122
|
+
/** Git commit for a checkout-built `@cursor/july`; absent for npm builds. */
|
|
123
|
+
cliGitSha?: string;
|
|
118
124
|
declarations: AgentDeployManifestDeclarations;
|
|
119
125
|
/**
|
|
120
126
|
* Full `projectInfo` payload (see `GET /v1/info`). Opaque to the wire
|
|
@@ -129,7 +135,7 @@ export interface AgentDeployManifestV1 {
|
|
|
129
135
|
*/
|
|
130
136
|
export function buildAgentDeployManifest(
|
|
131
137
|
project: AgentProject,
|
|
132
|
-
options?: { nowMs?: number; cliVersion?: string }
|
|
138
|
+
options?: { nowMs?: number; cliVersion?: string; cliGitSha?: string }
|
|
133
139
|
): AgentDeployManifestV1 {
|
|
134
140
|
const runtimeArchitectureError = runtimeArchitectureCompatibilityError(
|
|
135
141
|
project.agent
|
|
@@ -167,20 +173,19 @@ export function buildAgentDeployManifest(
|
|
|
167
173
|
manifestVersion: DEPLOY_MANIFEST_VERSION,
|
|
168
174
|
generatedAtMs: options?.nowMs ?? Date.now(),
|
|
169
175
|
cliVersion: options?.cliVersion ?? packageVersion(),
|
|
176
|
+
cliGitSha: options?.cliGitSha ?? packageGitSha(),
|
|
170
177
|
declarations: {
|
|
171
178
|
egressDomains: [...(project.agent.hosting?.egressDomains ?? [])],
|
|
172
179
|
publicRoutePaths,
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
180
|
+
// Deploy manifests describe Cursor-hosted deployments. When the agent
|
|
181
|
+
// authors no storage, framework-storage-selection.ts injects the
|
|
182
|
+
// platform Cursor-hosted mirror for both v1 and v2.
|
|
176
183
|
frameworkStorage:
|
|
177
|
-
project.
|
|
184
|
+
project.storage === undefined
|
|
178
185
|
? "cursor-hosted"
|
|
179
|
-
: project.storage
|
|
180
|
-
? "
|
|
181
|
-
:
|
|
182
|
-
? "cursor-hosted"
|
|
183
|
-
: "other",
|
|
186
|
+
: isCursorHostedStorage(project.storage)
|
|
187
|
+
? "cursor-hosted"
|
|
188
|
+
: "other",
|
|
184
189
|
...(project.agent.architecture === undefined
|
|
185
190
|
? {}
|
|
186
191
|
: { architecture: project.agent.architecture }),
|
|
@@ -151,6 +151,12 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
|
|
|
151
151
|
cron: schedule.cron,
|
|
152
152
|
kind: schedule.kind,
|
|
153
153
|
})),
|
|
154
|
+
reminders:
|
|
155
|
+
(project.reminders ?? []).length === 0
|
|
156
|
+
? undefined
|
|
157
|
+
: (project.reminders ?? []).map((reminder) => ({
|
|
158
|
+
name: reminder.name,
|
|
159
|
+
})),
|
|
154
160
|
hooks: project.hooks.map((hook) => hook.name),
|
|
155
161
|
abs: project.abs.map((experiment) => experiment.name),
|
|
156
162
|
...(project.abConfig === undefined && project.abs.length === 0
|
|
@@ -9,10 +9,7 @@ import { type DiscoveryContext, displayPath, errorMessage } from "./context.js";
|
|
|
9
9
|
import { isDirectory, isModuleFile, moduleStem, sortedEntries } from "./fs.js";
|
|
10
10
|
import { validateName } from "./names.js";
|
|
11
11
|
|
|
12
|
-
type ImportableKind = Exclude<
|
|
13
|
-
DefinitionKind,
|
|
14
|
-
"instructions" | "eval" | "reminder"
|
|
15
|
-
>;
|
|
12
|
+
type ImportableKind = Exclude<DefinitionKind, "instructions" | "eval">;
|
|
16
13
|
|
|
17
14
|
/** The module files of a slot directory whose filenames are valid names. */
|
|
18
15
|
export async function moduleEntries(
|
|
@@ -104,6 +101,7 @@ const DEFINE_HELPER_NAME: Record<ImportableKind, string> = {
|
|
|
104
101
|
channel: "defineChannel",
|
|
105
102
|
"http-channel": "httpChannel",
|
|
106
103
|
schedule: "defineSchedule",
|
|
104
|
+
reminder: "defineReminder",
|
|
107
105
|
hook: "defineHook",
|
|
108
106
|
ab: "defineAB",
|
|
109
107
|
storage: "defineStorage",
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "./fs.js";
|
|
32
32
|
import { loadHooks } from "./hooks.js";
|
|
33
33
|
import { NAME_PATTERN } from "./names.js";
|
|
34
|
+
import { loadReminders } from "./reminders.js";
|
|
34
35
|
import { loadSchedules } from "./schedules.js";
|
|
35
36
|
import {
|
|
36
37
|
appendArtifactTool,
|
|
@@ -236,6 +237,7 @@ export async function loadAgentProject(
|
|
|
236
237
|
}
|
|
237
238
|
const schedules = await loadSchedules(ctx, join(agentDir, "schedules"));
|
|
238
239
|
schedules.push(...projectSlots.schedules);
|
|
240
|
+
const reminders = await loadReminders(ctx, join(agentDir, "reminders"));
|
|
239
241
|
const hooks = await loadHooks(ctx, join(agentDir, "hooks"));
|
|
240
242
|
hooks.push(...projectSlots.hooks);
|
|
241
243
|
const abs = await loadABs(ctx, agentDir);
|
|
@@ -291,6 +293,7 @@ export async function loadAgentProject(
|
|
|
291
293
|
httpChannel: resolvedHttpChannel,
|
|
292
294
|
channels,
|
|
293
295
|
schedules,
|
|
296
|
+
reminders,
|
|
294
297
|
hooks,
|
|
295
298
|
abs,
|
|
296
299
|
abConfig,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent/reminders/*.ts`: named durable reminder fire handlers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { basename, extname, relative } from "node:path";
|
|
6
|
+
import type { DiscoveredReminder, ReminderDefinition } from "../../types.js";
|
|
7
|
+
import { getDefinitionKind } from "../brand.js";
|
|
8
|
+
import { type DiscoveryContext, displayPath } from "./context.js";
|
|
9
|
+
import { isDirectory, isModuleFile, toPosix, walkFiles } from "./fs.js";
|
|
10
|
+
import { importDefault } from "./modules.js";
|
|
11
|
+
import { NAME_PATTERN } from "./names.js";
|
|
12
|
+
|
|
13
|
+
export async function loadReminders(
|
|
14
|
+
ctx: DiscoveryContext,
|
|
15
|
+
remindersDir: string,
|
|
16
|
+
onDisable?: (name: string, path: string) => void
|
|
17
|
+
): Promise<DiscoveredReminder[]> {
|
|
18
|
+
if (!(await isDirectory(remindersDir))) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
const reminders: DiscoveredReminder[] = [];
|
|
22
|
+
for (const filePath of await walkFiles(remindersDir)) {
|
|
23
|
+
const rel = toPosix(relative(remindersDir, filePath));
|
|
24
|
+
if (!isModuleFile(basename(filePath))) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const name = rel.slice(0, -extname(rel).length);
|
|
28
|
+
if (!NAME_PATTERN.test(name) || name.includes("__")) {
|
|
29
|
+
ctx.diagnostics.push({
|
|
30
|
+
severity: "error",
|
|
31
|
+
path: displayPath(ctx, filePath),
|
|
32
|
+
message: name.includes("__")
|
|
33
|
+
? `Reminder name "${name}" may not contain "__"; it is reserved for extension contributions (\`<ns>__<name>\`).`
|
|
34
|
+
: `Reminder name "${name}" must match ${NAME_PATTERN}.`,
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const definition = await importDefault(
|
|
39
|
+
ctx,
|
|
40
|
+
filePath,
|
|
41
|
+
onDisable === undefined ? "reminder" : ["reminder", "disabled"]
|
|
42
|
+
);
|
|
43
|
+
if (definition === undefined) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (getDefinitionKind(definition) === "disabled") {
|
|
47
|
+
onDisable?.(name, filePath);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const reminder = definition as ReminderDefinition;
|
|
51
|
+
if (typeof reminder.run !== "function") {
|
|
52
|
+
ctx.diagnostics.push({
|
|
53
|
+
severity: "error",
|
|
54
|
+
path: displayPath(ctx, filePath),
|
|
55
|
+
message: "Reminder handlers require a `run` function.",
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
reminders.push({
|
|
60
|
+
name,
|
|
61
|
+
definition: reminder,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return reminders;
|
|
65
|
+
}
|
|
@@ -13,6 +13,8 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
13
13
|
|
|
14
14
|
/** Published npm package name (pre-launch codename for Agent SDK). */
|
|
15
15
|
export const PACKAGE_NAME = "@cursor/july";
|
|
16
|
+
const HOSTED_WORKTREE_SHA_FILENAME = ".cursor-hosted-worktree-sha";
|
|
17
|
+
const GIT_COMMIT_SHA_RE = /^[0-9a-f]{40,64}$/;
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Bracketed product tag for stderr / ServeOptions.logger lines
|
|
@@ -59,6 +61,24 @@ export function packageVersion(): string {
|
|
|
59
61
|
return packageManifest().version;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Git commit of a checkout-built framework distribution. Published npm
|
|
66
|
+
* packages do not carry this marker and return undefined.
|
|
67
|
+
*/
|
|
68
|
+
export function packageGitSha(): string | undefined {
|
|
69
|
+
try {
|
|
70
|
+
const sha = readFileSync(
|
|
71
|
+
join(packageRootDir(), "dist", HOSTED_WORKTREE_SHA_FILENAME),
|
|
72
|
+
"utf8"
|
|
73
|
+
)
|
|
74
|
+
.trim()
|
|
75
|
+
.toLowerCase();
|
|
76
|
+
return GIT_COMMIT_SHA_RE.test(sha) ? sha : undefined;
|
|
77
|
+
} catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
62
82
|
/** Facts `agent-sdk version` / `--version` print. */
|
|
63
83
|
export interface CliVersionInfo {
|
|
64
84
|
/** Published npm name (`@cursor/july`). */
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
* That selection is a hosting-mode question, not an authoring question.
|
|
14
14
|
* Architecture v2 moves it here: `agent/storage.ts` is rejected at
|
|
15
15
|
* discovery (error diagnostic, so serve and deploy fail early), and the
|
|
16
|
-
* platform picks the default
|
|
16
|
+
* platform picks the default. Architecture v1 with no authored file now
|
|
17
|
+
* uses the same hosted-vs-self-hosted split, so deleting `agent/storage.ts`
|
|
18
|
+
* (required to deploy the same tree onto v2) does not drop the Cursor-hosted
|
|
19
|
+
* session mirror on a still-v1 pod.
|
|
17
20
|
*
|
|
18
21
|
* - **Cursor-managed hosting** (the deployment-generation environment
|
|
19
22
|
* variable is set, same signal that registers `GET /v1/manifest`):
|
|
@@ -33,8 +36,10 @@
|
|
|
33
36
|
* - **Self-hosted**: no mirror. `--state-root` is the durable copy, which
|
|
34
37
|
* is correct when the operator owns the disk.
|
|
35
38
|
*
|
|
36
|
-
* v1
|
|
37
|
-
*
|
|
39
|
+
* v1 still honors an authored `agent/storage.ts` when present. Hosted v1
|
|
40
|
+
* pods with no authored file get the Cursor-hosted lazy mirror (gated on
|
|
41
|
+
* `AGENT_SERVE_DEPLOYMENT_ID`, the same signal the previous authored sinks
|
|
42
|
+
* used). Self-hosted v1 with no authored file stays disk-only.
|
|
38
43
|
*
|
|
39
44
|
* Local disk is not part of this decision. `<stateRoot>/sessions/<id>/`
|
|
40
45
|
* already holds `session.json` and `events.ndjson` unconditionally, through
|
|
@@ -44,6 +49,10 @@
|
|
|
44
49
|
|
|
45
50
|
import { cursorHostedFiles } from "../files-backends/cursor-hosted.js";
|
|
46
51
|
import { defineStorage, type StorageDefinition } from "../storage.js";
|
|
52
|
+
import {
|
|
53
|
+
AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR,
|
|
54
|
+
cursorHostedStorage,
|
|
55
|
+
} from "../storage-backends/cursor-hosted.js";
|
|
47
56
|
import { cursorHostedStorageV2 } from "../storage-backends/cursor-hosted-v2.js";
|
|
48
57
|
import type { AgentArchitecture } from "../types.js";
|
|
49
58
|
import { resolveApiKeySync } from "./cursor/credentials.js";
|
|
@@ -54,6 +63,13 @@ import {
|
|
|
54
63
|
} from "./framework-file-storage.js";
|
|
55
64
|
import { resolveAgentV2Hosting } from "./v2-hosting.js";
|
|
56
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Hosted v2 event-chunk flush debounce. Matches the session view's live poll
|
|
68
|
+
* cadence; a streaming turn still caps each chunk at the coordinator's batch
|
|
69
|
+
* limit, so a long turn writes a few dozen chunks rather than one per event.
|
|
70
|
+
*/
|
|
71
|
+
export const HOSTED_V2_EVENT_FLUSH_DEBOUNCE_MS = 2_000;
|
|
72
|
+
|
|
57
73
|
export interface FrameworkStorageSelectionInput {
|
|
58
74
|
/** `agent/storage.ts`, when the author wrote one (v1 only: discovery rejects it on v2). */
|
|
59
75
|
readonly authored: StorageDefinition | undefined;
|
|
@@ -73,8 +89,21 @@ export function selectFrameworkStorageDefinition(
|
|
|
73
89
|
input: FrameworkStorageSelectionInput
|
|
74
90
|
): StorageDefinition | undefined {
|
|
75
91
|
if (input.architecture !== "v2") {
|
|
76
|
-
|
|
77
|
-
|
|
92
|
+
if (input.authored !== undefined) {
|
|
93
|
+
return input.authored;
|
|
94
|
+
}
|
|
95
|
+
const env = input.env ?? process.env;
|
|
96
|
+
if ((env[AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR] ?? "").trim() !== "") {
|
|
97
|
+
// Hosted v1 pod with no authored sink: keep the Cursor-hosted
|
|
98
|
+
// mirror (lazy restore) so agents can delete `agent/storage.ts`
|
|
99
|
+
// without losing durability while they still run architecture v1.
|
|
100
|
+
return defineStorage({
|
|
101
|
+
name: "cursor-hosted (lazy restore)",
|
|
102
|
+
policy: { restore: "off" },
|
|
103
|
+
...cursorHostedStorage(),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
78
107
|
}
|
|
79
108
|
if (input.authored !== undefined) {
|
|
80
109
|
// Discovery rejects agent/storage.ts on v2 before an engine is built;
|
|
@@ -97,7 +126,15 @@ export function selectFrameworkStorageDefinition(
|
|
|
97
126
|
// backend it is per-key HTTP round trips before the listener even
|
|
98
127
|
// comes up). Follow-ups restore lazily by continuation or session id;
|
|
99
128
|
// GET /v1/sessions lists from the sink either way.
|
|
100
|
-
|
|
129
|
+
//
|
|
130
|
+
// Events flush on a quiet-period debounce rather than only at turn end so
|
|
131
|
+
// the read-only session view and dashboard trace (which have no resident
|
|
132
|
+
// engine to ask) see steps mid-turn. The turn-end record still lands
|
|
133
|
+
// before the execution reply: drainSessionDurability forces the flush.
|
|
134
|
+
const policy = {
|
|
135
|
+
restore: "off",
|
|
136
|
+
debounceMs: HOSTED_V2_EVENT_FLUSH_DEBOUNCE_MS,
|
|
137
|
+
} as const;
|
|
101
138
|
// Full chain (env → bind file → stored login): frozen engines listen
|
|
102
139
|
// unsigned and bind store ids + CURSOR_API_KEY at task time, after this
|
|
103
140
|
// definition is constructed.
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* with that message instead of throwing.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { HOSTED_GUEST_RETRY_TRANSIENT } from "./hosted-delivery-protocol.js";
|
|
23
|
+
|
|
22
24
|
export const GUEST_NETWORK_UNAVAILABLE = "guest_network_unavailable";
|
|
23
25
|
export const GUEST_CONNECT_STALLED = "guest_connect_stalled";
|
|
24
26
|
|
|
@@ -369,6 +371,7 @@ export async function guestNetworkReadinessResponse(
|
|
|
369
371
|
JSON.stringify({
|
|
370
372
|
ok: false,
|
|
371
373
|
error: GUEST_NETWORK_UNAVAILABLE,
|
|
374
|
+
retry: HOSTED_GUEST_RETRY_TRANSIENT,
|
|
372
375
|
message: error.message,
|
|
373
376
|
waitMs: error.waitMs,
|
|
374
377
|
probeAttempts: error.probeAttempts,
|
|
@@ -2,6 +2,43 @@ export const HOSTED_DELIVERY_PROTOCOL_VERSION = 2;
|
|
|
2
2
|
export const HOSTED_DELIVERY_HEADER = "x-agent-sdk-hosted-delivery";
|
|
3
3
|
export const HOSTED_ADMISSION_PATH = "/v1/internal/hosted-admission";
|
|
4
4
|
export const HOSTED_EXECUTION_PATH = "/v1/internal/hosted-execution";
|
|
5
|
+
export const HOSTED_GUEST_RETRY_TRANSIENT = "transient";
|
|
6
|
+
export const HOSTED_GUEST_RETRY_TERMINAL = "terminal";
|
|
7
|
+
|
|
8
|
+
export type HostedGuestRetryDisposition =
|
|
9
|
+
| typeof HOSTED_GUEST_RETRY_TRANSIENT
|
|
10
|
+
| typeof HOSTED_GUEST_RETRY_TERMINAL;
|
|
11
|
+
|
|
12
|
+
export type HostedGuestError = {
|
|
13
|
+
ok: false;
|
|
14
|
+
error: string;
|
|
15
|
+
retry: HostedGuestRetryDisposition;
|
|
16
|
+
message?: string;
|
|
17
|
+
turnStatus?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hosted delivery is the only HTTP surface whose failures drive Temporal
|
|
22
|
+
* retries. Keep its retry disposition explicit instead of making the shared
|
|
23
|
+
* HTTP error helper guess from a status code.
|
|
24
|
+
*/
|
|
25
|
+
export function hostedGuestErrorResponse(input: {
|
|
26
|
+
status: number;
|
|
27
|
+
error: string;
|
|
28
|
+
retry: HostedGuestRetryDisposition;
|
|
29
|
+
message?: string;
|
|
30
|
+
turnStatus?: string;
|
|
31
|
+
}): Response {
|
|
32
|
+
const body: HostedGuestError = {
|
|
33
|
+
ok: false,
|
|
34
|
+
error: input.error,
|
|
35
|
+
retry: input.retry,
|
|
36
|
+
message: input.message,
|
|
37
|
+
turnStatus: input.turnStatus,
|
|
38
|
+
};
|
|
39
|
+
return Response.json(body, { status: input.status });
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
/**
|
|
6
43
|
* Filename under the serve `--state-root` (not the per-slug SessionEngine
|
|
7
44
|
* dir). Hosted freeze uses `/workspace/.agent-serve`; the Temporal host
|
|
@@ -10,6 +47,25 @@ export const HOSTED_EXECUTION_PATH = "/v1/internal/hosted-execution";
|
|
|
10
47
|
*/
|
|
11
48
|
export const HOSTED_EXECUTION_DIAG_FILENAME = "hosted-execution.json";
|
|
12
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Reserved hosted-admission `channelKind` for durable reminder fires.
|
|
52
|
+
* Bypasses authored channel admission and invokes ReminderRunner.dispatch.
|
|
53
|
+
* Backend builds envelopes with this constant + {@link HOSTED_REMINDER_EVENT_TYPE}.
|
|
54
|
+
*/
|
|
55
|
+
export const HOSTED_REMINDER_CHANNEL_KIND = "agent-sdk:reminder";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Reserved hosted-admission `eventType` for durable reminder fires.
|
|
59
|
+
* Payload is {@link HostedReminderFirePayload}.
|
|
60
|
+
*/
|
|
61
|
+
export const HOSTED_REMINDER_EVENT_TYPE = "agent-sdk.reminder/fire";
|
|
62
|
+
|
|
63
|
+
/** Compact reminder-fire payload on the reserved hosted-admission path. */
|
|
64
|
+
export type HostedReminderFirePayload = {
|
|
65
|
+
reminderId: string;
|
|
66
|
+
fireCount: number;
|
|
67
|
+
};
|
|
68
|
+
|
|
13
69
|
export type HostedAdmissionManagedAutomation = {
|
|
14
70
|
automationUuid: string;
|
|
15
71
|
mcpServerNames: string[];
|
|
@@ -171,6 +227,46 @@ export function parseHostedExecution(
|
|
|
171
227
|
return body as HostedExecution;
|
|
172
228
|
}
|
|
173
229
|
|
|
230
|
+
/**
|
|
231
|
+
* True when the admission envelope is the reserved internal reminder fire
|
|
232
|
+
* path (not an authored channel event).
|
|
233
|
+
*/
|
|
234
|
+
export function isHostedReminderAdmission(delivery: HostedAdmission): boolean {
|
|
235
|
+
return (
|
|
236
|
+
delivery.channelKind === HOSTED_REMINDER_CHANNEL_KIND &&
|
|
237
|
+
delivery.eventType === HOSTED_REMINDER_EVENT_TYPE
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Parse `{ reminderId, fireCount }` from a reserved reminder admission
|
|
243
|
+
* payload. Rejects unknown keys and non-integer fireCount.
|
|
244
|
+
*/
|
|
245
|
+
export function parseHostedReminderFirePayload(
|
|
246
|
+
value: unknown
|
|
247
|
+
): HostedReminderFirePayload | undefined {
|
|
248
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
const body = value as Record<string, unknown>;
|
|
252
|
+
const keys = Object.keys(body);
|
|
253
|
+
if (
|
|
254
|
+
keys.length !== 2 ||
|
|
255
|
+
!Object.hasOwn(body, "reminderId") ||
|
|
256
|
+
!Object.hasOwn(body, "fireCount") ||
|
|
257
|
+
!boundedString(body.reminderId, 128) ||
|
|
258
|
+
typeof body.fireCount !== "number" ||
|
|
259
|
+
!Number.isInteger(body.fireCount) ||
|
|
260
|
+
body.fireCount < 0
|
|
261
|
+
) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
reminderId: body.reminderId,
|
|
266
|
+
fireCount: body.fireCount,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
174
270
|
export function parseHostedAdmissionOutcome(
|
|
175
271
|
value: unknown
|
|
176
272
|
): HostedAdmissionOutcome | undefined {
|