@cursor/july 0.1.100 → 0.1.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agent-serve.js +3 -2
- package/dist/channels/deployments/deployments-channel.d.ts +41 -5
- package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
- package/dist/channels/deployments/deployments-channel.js +88 -8
- package/dist/channels/deployments/types.d.ts +4 -3
- package/dist/channels/deployments/types.d.ts.map +1 -1
- package/dist/channels/origin/defaults.d.ts +43 -0
- package/dist/channels/origin/defaults.d.ts.map +1 -0
- package/dist/channels/origin/defaults.js +111 -0
- package/dist/channels/origin/index.d.ts +2 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +2 -0
- package/dist/channels/origin/origin-channel.d.ts +2 -1
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +24 -3
- package/dist/channels/origin/state.d.ts +32 -0
- package/dist/channels/origin/state.d.ts.map +1 -0
- package/dist/channels/origin/state.js +23 -0
- package/dist/channels/origin/types.d.ts +23 -1
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +2 -1
- package/dist/channels/slack/code-fences.d.ts +17 -0
- package/dist/channels/slack/code-fences.d.ts.map +1 -0
- package/dist/channels/slack/code-fences.js +168 -0
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +11 -4
- package/dist/connections.d.ts +18 -2
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +18 -2
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.DZ1e0Ycq.js → app.BASO9Kih.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DbFXINq2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.l8omwc6D.js → VPLocalSearchBox.DwkqxoE0.js} +1 -1
- package/dist/docs/assets/chunks/{theme.JVcD6gel.js → theme.CCil_13e.js} +2 -2
- package/dist/docs/assets/{reference_connections.md.BiGoBAk2.js → reference_connections.md.Di6jJAXF.js} +12 -2
- package/dist/docs/assets/{reference_connections.md.BiGoBAk2.lean.js → reference_connections.md.Di6jJAXF.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.js → reference_http-api.md.oySXBO8o.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +4 -4
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +4 -4
- package/dist/docs/llms-full.txt +32 -1
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +16 -6
- package/dist/docs/reference/connections.md +31 -0
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +1 -1
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/skills/ab.html +4 -4
- package/dist/docs/skills/create-agent.html +4 -4
- package/dist/docs/skills/debug.html +4 -4
- package/dist/docs/skills/evals.html +4 -4
- package/dist/docs/skills/framework-map.html +4 -4
- package/dist/docs/skills/github.html +4 -4
- package/dist/docs/skills/hillclimb.html +4 -4
- package/dist/docs/skills/index.html +4 -4
- package/dist/docs/skills/mcp-auth.html +4 -4
- package/dist/docs/skills/otel.html +4 -4
- package/dist/docs/skills/setup-slack.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +4 -4
- package/dist/docs/templates/code-wiki.html +4 -4
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +4 -4
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/extensions/cursor-cloud-agents/extension.d.ts +55 -0
- package/dist/extensions/cursor-cloud-agents/extension.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/extension.js +64 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts +30 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/cloud.js +45 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts +25 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/fleet.js +85 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts +15 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/lib/repos.js +55 -0
- package/dist/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/follow_up.js +37 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/launch.js +83 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/list.js +36 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.d.ts +4 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.d.ts.map +1 -0
- package/dist/extensions/cursor-cloud-agents/tools/status.js +41 -0
- package/dist/extensions.d.ts +49 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +75 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/internal/advertise-tools.d.ts +4 -1
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +20 -1
- package/dist/internal/as-of.d.ts +18 -0
- package/dist/internal/as-of.d.ts.map +1 -1
- package/dist/internal/as-of.js +131 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +64 -19
- package/dist/internal/continuation-identity.d.ts.map +1 -1
- package/dist/internal/continuation-identity.js +3 -1
- package/dist/internal/cursor/hosted-deployment-secrets.d.ts +16 -0
- package/dist/internal/cursor/hosted-deployment-secrets.d.ts.map +1 -0
- package/dist/internal/cursor/hosted-deployment-secrets.js +61 -0
- package/dist/internal/cursor-deployment-relay.d.ts +15 -1
- package/dist/internal/cursor-deployment-relay.d.ts.map +1 -1
- package/dist/internal/cursor-deployment-relay.js +46 -7
- package/dist/internal/deploy-client.d.ts +23 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +54 -12
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +415 -120
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +5 -0
- package/dist/internal/framework-file-storage.d.ts +3 -3
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +34 -5
- package/dist/internal/hosted-delivery.d.ts +3 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +19 -32
- package/dist/internal/hosted-execution-diag.d.ts +5 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
- package/dist/internal/hosted-execution-diag.js +5 -0
- package/dist/internal/hosted-execution-flush.d.ts +46 -0
- package/dist/internal/hosted-execution-flush.d.ts.map +1 -0
- package/dist/internal/hosted-execution-flush.js +81 -0
- package/dist/internal/mcp-endpoint.js +1 -0
- package/dist/internal/mcp-host.d.ts +2 -1
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +35 -15
- package/dist/internal/review-comments.d.ts +1 -1
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +4 -4
- package/dist/internal/server.d.ts +3 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +79 -104
- package/dist/internal/session-engine.d.ts +9 -7
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +45 -34
- package/dist/internal/session-run-log.d.ts +2 -1
- package/dist/internal/session-run-log.d.ts.map +1 -1
- package/dist/internal/session-run-log.js +2 -1
- package/dist/internal/start-log-store.d.ts +60 -0
- package/dist/internal/start-log-store.d.ts.map +1 -0
- package/dist/internal/start-log-store.js +151 -0
- package/dist/internal/tool-policy.d.ts +8 -0
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +19 -7
- package/dist/playground/assets/{index-DVs98vPL.js → index-BnNN1-EK.js} +45 -45
- package/dist/playground/assets/index-DBQCwFp0.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-protocol.d.ts +24 -0
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +33 -0
- package/dist/storage.d.ts +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +118 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +29 -1
- package/docs/reference/connections.md +31 -0
- package/docs/reference/http-api.md +1 -1
- package/package.json +18 -4
- package/src/bin/agent-serve.ts +11 -2
- package/src/channels/deployments/deployments-channel.ts +117 -8
- package/src/channels/deployments/types.ts +4 -3
- package/src/channels/origin/defaults.ts +143 -0
- package/src/channels/origin/index.ts +2 -0
- package/src/channels/origin/origin-channel.ts +37 -1
- package/src/channels/origin/state.ts +54 -0
- package/src/channels/origin/types.ts +24 -0
- package/src/channels/slack/api.ts +2 -1
- package/src/channels/slack/code-fences.ts +183 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +16 -13
- package/src/connections.ts +18 -1
- package/src/extensions/cursor-cloud-agents/extension.ts +118 -0
- package/src/extensions/cursor-cloud-agents/lib/cloud.ts +79 -0
- package/src/extensions/cursor-cloud-agents/lib/fleet.ts +109 -0
- package/src/extensions/cursor-cloud-agents/lib/repos.ts +81 -0
- package/src/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
- package/src/extensions/cursor-cloud-agents/tools/follow_up.ts +29 -0
- package/src/extensions/cursor-cloud-agents/tools/launch.ts +84 -0
- package/src/extensions/cursor-cloud-agents/tools/list.ts +31 -0
- package/src/extensions/cursor-cloud-agents/tools/status.ts +39 -0
- package/src/extensions.ts +98 -0
- package/src/index.ts +2 -0
- package/src/internal/advertise-tools.ts +37 -12
- package/src/internal/as-of.ts +163 -0
- package/src/internal/cli-deploy.ts +86 -23
- package/src/internal/continuation-identity.ts +3 -1
- package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
- package/src/internal/cursor-deployment-relay.ts +65 -8
- package/src/internal/deploy-client.ts +73 -18
- package/src/internal/discovery.ts +470 -113
- package/src/internal/distribution.ts +5 -0
- package/src/internal/framework-file-storage.ts +39 -5
- package/src/internal/hosted-delivery.ts +38 -63
- package/src/internal/hosted-execution-diag.ts +6 -0
- package/src/internal/hosted-execution-flush.ts +142 -0
- package/src/internal/mcp-endpoint.ts +1 -0
- package/src/internal/mcp-host.ts +40 -14
- package/src/internal/review-comments.ts +5 -2
- package/src/internal/server.ts +81 -100
- package/src/internal/session-engine.ts +56 -28
- package/src/internal/session-run-log.ts +2 -1
- package/src/internal/start-log-store.ts +177 -0
- package/src/internal/tool-policy.ts +39 -9
- package/src/storage-protocol.ts +37 -0
- package/src/storage.ts +1 -0
- package/src/types.ts +172 -14
- package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +0 -1
- package/dist/playground/assets/index-BszoQDc6.css +0 -1
- /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
|
@@ -131,6 +131,11 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
|
|
|
131
131
|
["channels/origin", "channels/origin/index.js"],
|
|
132
132
|
["channels/deployments", "channels/deployments/index.js"],
|
|
133
133
|
["skills", "skills.js"],
|
|
134
|
+
["extensions", "extensions.js"],
|
|
135
|
+
[
|
|
136
|
+
"extensions/cursor-cloud-agents",
|
|
137
|
+
"extensions/cursor-cloud-agents/extension.js",
|
|
138
|
+
],
|
|
134
139
|
["schedules", "schedules.js"],
|
|
135
140
|
["reminders", "reminders.js"],
|
|
136
141
|
["connections", "connections.js"],
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* {@link storageKeys} scheme was designed for exactly this: keys are a
|
|
16
16
|
* stable versioned contract that sinks may route on, so
|
|
17
17
|
* {@link composeFrameworkStorage} splits one {@link StorageConfig} by key
|
|
18
|
-
* kind — `session` / `session-events` / `session-runs` / `
|
|
19
|
-
* go to the framework file store (file-shaped; the store
|
|
20
|
-
* up to 64 MiB per
|
|
18
|
+
* kind — `session` / `session-events` / `session-runs` / `logs` /
|
|
19
|
+
* `continuation` go to the framework file store (file-shaped; the store
|
|
20
|
+
* accepts values up to 64 MiB per
|
|
21
21
|
* object without chunking, versus the KV proxy's 1 MiB row cap), while
|
|
22
22
|
* author `kv`, eval runs, A/B samples, and conditional writes stay on the
|
|
23
23
|
* control-plane KV proxy (the dashboard reads them there, and CAS needs a
|
|
@@ -42,6 +42,7 @@ const FRAMEWORK_FILE_KINDS: ReadonlySet<string> = new Set([
|
|
|
42
42
|
"session",
|
|
43
43
|
"session-events",
|
|
44
44
|
"session-runs",
|
|
45
|
+
"logs",
|
|
45
46
|
"continuation",
|
|
46
47
|
]);
|
|
47
48
|
|
|
@@ -105,7 +106,7 @@ export function fileSinkStorageCore(sink: FileSink): FileSinkStorageCore {
|
|
|
105
106
|
`framework file storage: key "${key}" has a path segment the store cannot represent`
|
|
106
107
|
);
|
|
107
108
|
}
|
|
108
|
-
await sink.put(key,
|
|
109
|
+
await sink.put(key, encodeDocument(key, value));
|
|
109
110
|
},
|
|
110
111
|
async get(key): Promise<JsonValue | undefined> {
|
|
111
112
|
if (isUnrepresentableFileKey(key)) {
|
|
@@ -151,9 +152,42 @@ export function fileSinkStorageCore(sink: FileSink): FileSinkStorageCore {
|
|
|
151
152
|
};
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
function frameworkFileKind(key: string): string | undefined {
|
|
156
|
+
if (!key.startsWith(`${STORAGE_KEY_ROOT}/`)) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
const rest = key.slice(STORAGE_KEY_ROOT.length + 1);
|
|
160
|
+
const agentEnd = rest.indexOf("/");
|
|
161
|
+
if (agentEnd === -1) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
const afterAgent = rest.slice(agentEnd + 1);
|
|
165
|
+
const kindEnd = afterAgent.indexOf("/");
|
|
166
|
+
return kindEnd === -1 ? afterAgent : afterAgent.slice(0, kindEnd);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function isLogKey(key: string): boolean {
|
|
170
|
+
return frameworkFileKind(key) === "logs";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function encodeDocument(key: string, value: JsonValue): Uint8Array {
|
|
174
|
+
// start.log is raw UTF-8, not a JSON document. Stringify would quote
|
|
175
|
+
// every line and store a JSON string literal instead of the tee.
|
|
176
|
+
if (isLogKey(key)) {
|
|
177
|
+
return new TextEncoder().encode(
|
|
178
|
+
typeof value === "string" ? value : JSON.stringify(value)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return new TextEncoder().encode(JSON.stringify(value));
|
|
182
|
+
}
|
|
183
|
+
|
|
154
184
|
function decodeDocument(key: string, bytes: Uint8Array): JsonValue {
|
|
185
|
+
const text = new TextDecoder().decode(bytes);
|
|
186
|
+
if (isLogKey(key)) {
|
|
187
|
+
return text;
|
|
188
|
+
}
|
|
155
189
|
try {
|
|
156
|
-
return JSON.parse(
|
|
190
|
+
return JSON.parse(text) as JsonValue;
|
|
157
191
|
} catch (error) {
|
|
158
192
|
throw new Error(
|
|
159
193
|
`framework file storage: stored document at "${key}" is not JSON (${
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
ChannelHandlerArgs,
|
|
5
5
|
SendMessageOptions,
|
|
6
6
|
} from "../types.js";
|
|
7
|
+
import { refreshBoundDeploymentSecrets } from "./cursor/hosted-deployment-secrets.js";
|
|
7
8
|
import {
|
|
8
9
|
createDeferredChannelSession,
|
|
9
10
|
DeferredChannelSessionError,
|
|
@@ -28,19 +29,17 @@ import {
|
|
|
28
29
|
import {
|
|
29
30
|
abortReasonFromTurnStatus,
|
|
30
31
|
HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
|
|
31
|
-
hostedErrorStackSnippet,
|
|
32
32
|
hostedExecutionDiagId,
|
|
33
|
-
writeHostedExecutionDiag,
|
|
34
33
|
} from "./hosted-execution-diag.js";
|
|
34
|
+
import {
|
|
35
|
+
flushHostedExecutionRecord,
|
|
36
|
+
type HostedExecutionFlushSinks,
|
|
37
|
+
} from "./hosted-execution-flush.js";
|
|
35
38
|
import { recordHostedManagedAutomation } from "./hosted-managed-automation.js";
|
|
36
39
|
import { errorResponse, readJsonObject } from "./http-channel.js";
|
|
37
40
|
import type { LogRingEntry } from "./log-ring.js";
|
|
38
41
|
import type { Router } from "./router.js";
|
|
39
|
-
import {
|
|
40
|
-
type SessionRunExecutionWrite,
|
|
41
|
-
serializeSessionRunError,
|
|
42
|
-
snapshotSessionRunLogs,
|
|
43
|
-
} from "./session-run-log.js";
|
|
42
|
+
import type { SessionRunExecutionWrite } from "./session-run-log.js";
|
|
44
43
|
|
|
45
44
|
type DispatchInput = {
|
|
46
45
|
delivery: HostedAdmission;
|
|
@@ -279,6 +278,8 @@ export function registerHostedDeliveryRoute(input: {
|
|
|
279
278
|
* store; this path still awaits so a parked pod cannot shed the write.
|
|
280
279
|
*/
|
|
281
280
|
persistSessionRun?(write: SessionRunExecutionWrite): Promise<void>;
|
|
281
|
+
/** Snapshot the local `start.log` tee onto `logs/{ses_…}`. */
|
|
282
|
+
flushStartLog?(startLogId: string): Promise<void>;
|
|
282
283
|
/** Snapshot of the process log ring at persist time. */
|
|
283
284
|
snapshotLogs?(): LogRingEntry[];
|
|
284
285
|
}): void {
|
|
@@ -318,6 +319,7 @@ export function registerHostedDeliveryRoute(input: {
|
|
|
318
319
|
pattern: `${input.base}${HOSTED_ADMISSION_PATH}`,
|
|
319
320
|
auth: [auth],
|
|
320
321
|
handler: async (request) => {
|
|
322
|
+
refreshBoundDeploymentSecrets();
|
|
321
323
|
const startedAt = performance.now();
|
|
322
324
|
const finish = (response: Response) =>
|
|
323
325
|
withServerTiming(response, performance.now() - startedAt);
|
|
@@ -373,6 +375,7 @@ export function registerHostedDeliveryRoute(input: {
|
|
|
373
375
|
pattern: `${input.base}${HOSTED_EXECUTION_PATH}`,
|
|
374
376
|
auth: [auth],
|
|
375
377
|
handler: async (request) => {
|
|
378
|
+
refreshBoundDeploymentSecrets();
|
|
376
379
|
const startedAt = performance.now();
|
|
377
380
|
const finish = (response: Response) =>
|
|
378
381
|
withServerTiming(response, performance.now() - startedAt);
|
|
@@ -414,6 +417,20 @@ export function registerHostedDeliveryRoute(input: {
|
|
|
414
417
|
admitted.execution ??= (async (): Promise<ExecutionReply> => {
|
|
415
418
|
const startedAt = performance.now();
|
|
416
419
|
const executionId = hostedExecutionDiagId(execution.admissionToken);
|
|
420
|
+
const sinks: HostedExecutionFlushSinks = {
|
|
421
|
+
...(input.stateRoot === undefined
|
|
422
|
+
? {}
|
|
423
|
+
: { stateRoot: input.stateRoot }),
|
|
424
|
+
...(input.persistSessionRun === undefined
|
|
425
|
+
? {}
|
|
426
|
+
: { persistSessionRun: input.persistSessionRun }),
|
|
427
|
+
...(input.flushStartLog === undefined
|
|
428
|
+
? {}
|
|
429
|
+
: { flushStartLog: input.flushStartLog }),
|
|
430
|
+
...(input.snapshotLogs === undefined
|
|
431
|
+
? {}
|
|
432
|
+
: { snapshotLogs: input.snapshotLogs }),
|
|
433
|
+
};
|
|
417
434
|
const writeDiag = async (fields: {
|
|
418
435
|
sessionId: string;
|
|
419
436
|
turnStatus: string;
|
|
@@ -423,62 +440,20 @@ export function registerHostedDeliveryRoute(input: {
|
|
|
423
440
|
| "execute_throw";
|
|
424
441
|
error?: unknown;
|
|
425
442
|
}): Promise<void> => {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
fields.
|
|
436
|
-
?
|
|
437
|
-
:
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
v: 1,
|
|
441
|
-
executionId,
|
|
442
|
-
writtenAt: new Date().toISOString(),
|
|
443
|
-
sessionPublicId: execution.sessionPublicId,
|
|
444
|
-
sessionId: fields.sessionId,
|
|
445
|
-
turnStatus: fields.turnStatus,
|
|
446
|
-
durationMs,
|
|
447
|
-
...(message === undefined ? {} : { message }),
|
|
448
|
-
...(stack === undefined || stack.length === 0 ? {} : { stack }),
|
|
449
|
-
...(message !== undefined && /abort/i.test(message)
|
|
450
|
-
? { signalAborted: true }
|
|
451
|
-
: {}),
|
|
452
|
-
...(fields.abortReason === undefined
|
|
453
|
-
? {}
|
|
454
|
-
: { abortReason: fields.abortReason }),
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
if (input.persistSessionRun === undefined) {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
const error =
|
|
461
|
-
fields.error === undefined
|
|
462
|
-
? undefined
|
|
463
|
-
: serializeSessionRunError(fields.error);
|
|
464
|
-
try {
|
|
465
|
-
await input.persistSessionRun({
|
|
466
|
-
executionId,
|
|
467
|
-
writtenAt: new Date().toISOString(),
|
|
468
|
-
sessionPublicId: execution.sessionPublicId,
|
|
469
|
-
sessionId: fields.sessionId,
|
|
470
|
-
turnStatus: fields.turnStatus,
|
|
471
|
-
durationMs,
|
|
472
|
-
...(fields.abortReason === undefined
|
|
473
|
-
? {}
|
|
474
|
-
: { abortReason: fields.abortReason }),
|
|
475
|
-
...(message === undefined ? {} : { message }),
|
|
476
|
-
...(error === undefined ? {} : { error }),
|
|
477
|
-
logs: snapshotSessionRunLogs(input.snapshotLogs?.() ?? []),
|
|
478
|
-
});
|
|
479
|
-
} catch {
|
|
480
|
-
// Soft-fail: a store outage must not change the HTTP reply.
|
|
481
|
-
}
|
|
443
|
+
await flushHostedExecutionRecord(sinks, {
|
|
444
|
+
executionId,
|
|
445
|
+
sessionPublicId: execution.sessionPublicId,
|
|
446
|
+
sessionId: fields.sessionId,
|
|
447
|
+
turnStatus: fields.turnStatus,
|
|
448
|
+
durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
|
|
449
|
+
...(fields.message === undefined
|
|
450
|
+
? {}
|
|
451
|
+
: { message: fields.message }),
|
|
452
|
+
...(fields.abortReason === undefined
|
|
453
|
+
? {}
|
|
454
|
+
: { abortReason: fields.abortReason }),
|
|
455
|
+
...(fields.error === undefined ? {} : { error: fields.error }),
|
|
456
|
+
});
|
|
482
457
|
};
|
|
483
458
|
// Claim the file before the turn runs. The host reads it after its
|
|
484
459
|
// own POST returns, which for a 9-minute timeout is while this turn
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guest-local TAS diag (`hosted-execution.json`). Flushed with the durable
|
|
3
|
+
* session-run document and the `start.log` tee by
|
|
4
|
+
* `hosted-execution-flush.ts`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
8
|
import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
9
|
import { join } from "node:path";
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One hosted-execution flush. Two artifacts, same moments:
|
|
3
|
+
*
|
|
4
|
+
* - Guest-local `hosted-execution.json` — TAS failed-execute diag.
|
|
5
|
+
* - Durable `session-runs/{ses_…}` plus the `start.log` tee — dashboard.
|
|
6
|
+
*
|
|
7
|
+
* Claim (`running`) → terminal → process-death. Process-death upgrades the
|
|
8
|
+
* durable document and re-snapshots the tee; the local json stays `running`
|
|
9
|
+
* so TAS does not treat a previous delivery's terminal record as this one.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
type HostedExecutionDiagAbortReason,
|
|
14
|
+
hostedErrorStackSnippet,
|
|
15
|
+
writeHostedExecutionDiag,
|
|
16
|
+
} from "./hosted-execution-diag.js";
|
|
17
|
+
import type { LogRingEntry } from "./log-ring.js";
|
|
18
|
+
import {
|
|
19
|
+
type SessionRunAbortReason,
|
|
20
|
+
type SessionRunExecutionWrite,
|
|
21
|
+
serializeSessionRunError,
|
|
22
|
+
snapshotSessionRunLogs,
|
|
23
|
+
} from "./session-run-log.js";
|
|
24
|
+
|
|
25
|
+
const MAX_ERROR_MESSAGE_LENGTH = 1024;
|
|
26
|
+
|
|
27
|
+
function boundedMessage(text: string): string {
|
|
28
|
+
return text.length > MAX_ERROR_MESSAGE_LENGTH
|
|
29
|
+
? `${text.slice(0, MAX_ERROR_MESSAGE_LENGTH)}…`
|
|
30
|
+
: text;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type HostedExecutionFlushSinks = {
|
|
34
|
+
/** Serve `--state-root`. Omit to skip the guest-local TAS diag. */
|
|
35
|
+
stateRoot?: string;
|
|
36
|
+
persistSessionRun?(write: SessionRunExecutionWrite): Promise<void>;
|
|
37
|
+
flushStartLog?(startLogId: string): Promise<void>;
|
|
38
|
+
snapshotLogs?(): LogRingEntry[];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type HostedExecutionFlushFields = {
|
|
42
|
+
executionId: string;
|
|
43
|
+
sessionPublicId: string;
|
|
44
|
+
sessionId: string;
|
|
45
|
+
turnStatus: string;
|
|
46
|
+
durationMs: number;
|
|
47
|
+
message?: string;
|
|
48
|
+
abortReason?: HostedExecutionDiagAbortReason;
|
|
49
|
+
error?: unknown;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Write the local TAS diag and the durable session-run + tee together.
|
|
54
|
+
* Soft-fail per sink so a store outage does not change hosted HTTP.
|
|
55
|
+
*/
|
|
56
|
+
export async function flushHostedExecutionRecord(
|
|
57
|
+
sinks: HostedExecutionFlushSinks,
|
|
58
|
+
fields: HostedExecutionFlushFields
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
const writtenAt = new Date().toISOString();
|
|
61
|
+
const message =
|
|
62
|
+
fields.message === undefined ? undefined : boundedMessage(fields.message);
|
|
63
|
+
const stack =
|
|
64
|
+
fields.error === undefined
|
|
65
|
+
? undefined
|
|
66
|
+
: hostedErrorStackSnippet(fields.error);
|
|
67
|
+
if (sinks.stateRoot !== undefined) {
|
|
68
|
+
await writeHostedExecutionDiag(sinks.stateRoot, {
|
|
69
|
+
v: 1,
|
|
70
|
+
executionId: fields.executionId,
|
|
71
|
+
writtenAt,
|
|
72
|
+
sessionPublicId: fields.sessionPublicId,
|
|
73
|
+
sessionId: fields.sessionId,
|
|
74
|
+
turnStatus: fields.turnStatus,
|
|
75
|
+
durationMs: fields.durationMs,
|
|
76
|
+
...(message === undefined ? {} : { message }),
|
|
77
|
+
...(stack === undefined || stack.length === 0 ? {} : { stack }),
|
|
78
|
+
...(message !== undefined && /abort/i.test(message)
|
|
79
|
+
? { signalAborted: true }
|
|
80
|
+
: {}),
|
|
81
|
+
...(fields.abortReason === undefined
|
|
82
|
+
? {}
|
|
83
|
+
: { abortReason: fields.abortReason }),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (sinks.persistSessionRun !== undefined) {
|
|
87
|
+
const error =
|
|
88
|
+
fields.error === undefined
|
|
89
|
+
? undefined
|
|
90
|
+
: serializeSessionRunError(fields.error);
|
|
91
|
+
try {
|
|
92
|
+
await sinks.persistSessionRun({
|
|
93
|
+
executionId: fields.executionId,
|
|
94
|
+
writtenAt,
|
|
95
|
+
sessionPublicId: fields.sessionPublicId,
|
|
96
|
+
sessionId: fields.sessionId,
|
|
97
|
+
turnStatus: fields.turnStatus,
|
|
98
|
+
durationMs: fields.durationMs,
|
|
99
|
+
...(fields.abortReason === undefined
|
|
100
|
+
? {}
|
|
101
|
+
: { abortReason: fields.abortReason }),
|
|
102
|
+
...(message === undefined ? {} : { message }),
|
|
103
|
+
...(error === undefined ? {} : { error }),
|
|
104
|
+
logs: snapshotSessionRunLogs(sinks.snapshotLogs?.() ?? []),
|
|
105
|
+
});
|
|
106
|
+
} catch {
|
|
107
|
+
// Soft-fail: a store outage must not change the HTTP reply.
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (sinks.flushStartLog !== undefined) {
|
|
111
|
+
try {
|
|
112
|
+
await sinks.flushStartLog(fields.sessionPublicId);
|
|
113
|
+
} catch {
|
|
114
|
+
// Soft-fail: same posture as the session-run persist.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Durable-only crash flush. Leaves `hosted-execution.json` at `running`.
|
|
121
|
+
*/
|
|
122
|
+
export async function flushHostedExecutionProcessDeath(args: {
|
|
123
|
+
flushProcessDeath: (
|
|
124
|
+
reason: Extract<
|
|
125
|
+
SessionRunAbortReason,
|
|
126
|
+
"process_exit" | "uncaught_exception" | "unhandled_rejection"
|
|
127
|
+
>,
|
|
128
|
+
error?: unknown
|
|
129
|
+
) => Promise<void>;
|
|
130
|
+
flushStartLog?: (startLogId: string) => Promise<void>;
|
|
131
|
+
startLogId?: string;
|
|
132
|
+
reason: Extract<
|
|
133
|
+
SessionRunAbortReason,
|
|
134
|
+
"process_exit" | "uncaught_exception" | "unhandled_rejection"
|
|
135
|
+
>;
|
|
136
|
+
error?: unknown;
|
|
137
|
+
}): Promise<void> {
|
|
138
|
+
await args.flushProcessDeath(args.reason, args.error);
|
|
139
|
+
if (args.startLogId !== undefined && args.flushStartLog !== undefined) {
|
|
140
|
+
await args.flushStartLog(args.startLogId);
|
|
141
|
+
}
|
|
142
|
+
}
|
package/src/internal/mcp-host.ts
CHANGED
|
@@ -15,13 +15,14 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
15
15
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
16
16
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
17
17
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
import {
|
|
19
|
+
connectionAllowsTool,
|
|
20
|
+
type DiscoveredConnection,
|
|
21
|
+
type HostMcpCallResult,
|
|
22
|
+
type HostMcpRegistry,
|
|
23
|
+
type HostMcpToolInfo,
|
|
24
|
+
type JsonObject,
|
|
25
|
+
type McpToolAnnotations,
|
|
25
26
|
} from "../types.js";
|
|
26
27
|
import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
|
|
27
28
|
import { createHostMcpOAuthProvider } from "./mcp-oauth.js";
|
|
@@ -113,9 +114,12 @@ export class McpHost implements HostMcpRegistry {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
async listTools(connectionName: string): Promise<HostMcpToolInfo[]> {
|
|
117
|
+
const connection = this.requireConnection(connectionName);
|
|
116
118
|
return this.withClient(connectionName, async (client) => {
|
|
117
119
|
const listed = await client.listTools();
|
|
118
|
-
return listed.tools
|
|
120
|
+
return listed.tools
|
|
121
|
+
.map(toToolInfo)
|
|
122
|
+
.filter((tool) => connectionAllowsTool(connection, tool.name));
|
|
119
123
|
});
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -144,10 +148,13 @@ export class McpHost implements HostMcpRegistry {
|
|
|
144
148
|
listTools: () =>
|
|
145
149
|
withFreshClient(async (client) => {
|
|
146
150
|
const listed = await client.listTools();
|
|
147
|
-
return listed.tools
|
|
151
|
+
return listed.tools
|
|
152
|
+
.map(toToolInfo)
|
|
153
|
+
.filter((tool) => connectionAllowsTool(connection, tool.name));
|
|
148
154
|
}),
|
|
149
|
-
callTool: (toolName, args = {}) =>
|
|
150
|
-
|
|
155
|
+
callTool: (toolName, args = {}) => {
|
|
156
|
+
assertConnectionAllowsTool(connection, toolName);
|
|
157
|
+
return withFreshClient(async (client) => {
|
|
151
158
|
const result = await client.callTool({
|
|
152
159
|
name: toolName,
|
|
153
160
|
arguments: args,
|
|
@@ -156,7 +163,8 @@ export class McpHost implements HostMcpRegistry {
|
|
|
156
163
|
connection.name,
|
|
157
164
|
normalizeCallResult(result)
|
|
158
165
|
);
|
|
159
|
-
})
|
|
166
|
+
});
|
|
167
|
+
},
|
|
160
168
|
};
|
|
161
169
|
}
|
|
162
170
|
|
|
@@ -165,6 +173,8 @@ export class McpHost implements HostMcpRegistry {
|
|
|
165
173
|
toolName: string,
|
|
166
174
|
args: Record<string, unknown> = {}
|
|
167
175
|
): Promise<HostMcpCallResult> {
|
|
176
|
+
const connection = this.requireConnection(connectionName);
|
|
177
|
+
assertConnectionAllowsTool(connection, toolName);
|
|
168
178
|
return this.withClient(connectionName, async (client) => {
|
|
169
179
|
const result = await client.callTool({
|
|
170
180
|
name: toolName,
|
|
@@ -254,7 +264,7 @@ export class McpHost implements HostMcpRegistry {
|
|
|
254
264
|
await opened.close();
|
|
255
265
|
}
|
|
256
266
|
|
|
257
|
-
private
|
|
267
|
+
private requireConnection(name: string): DiscoveredConnection {
|
|
258
268
|
const connection = this.byName.get(name);
|
|
259
269
|
if (connection === undefined) {
|
|
260
270
|
const known = this.names().join(", ") || "(none)";
|
|
@@ -262,8 +272,24 @@ export class McpHost implements HostMcpRegistry {
|
|
|
262
272
|
`Unknown MCP connection "${name}". Authored MCP connections: ${known}.`
|
|
263
273
|
);
|
|
264
274
|
}
|
|
265
|
-
return
|
|
275
|
+
return connection;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private async connect(name: string): Promise<OpenedConnection> {
|
|
279
|
+
return openConnection(this.requireConnection(name), this.oauthRedirectUrl);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function assertConnectionAllowsTool(
|
|
284
|
+
connection: DiscoveredConnection,
|
|
285
|
+
toolName: string
|
|
286
|
+
): void {
|
|
287
|
+
if (connectionAllowsTool(connection, toolName)) {
|
|
288
|
+
return;
|
|
266
289
|
}
|
|
290
|
+
throw new Error(
|
|
291
|
+
`MCP connection "${connection.name}" does not allow tool "${toolName}".`
|
|
292
|
+
);
|
|
267
293
|
}
|
|
268
294
|
|
|
269
295
|
/** Exported for unit tests. */
|
|
@@ -639,7 +639,9 @@ type OriginThreadJson = {
|
|
|
639
639
|
*/
|
|
640
640
|
type OriginActorJson = {
|
|
641
641
|
user?: { id?: string; email?: string };
|
|
642
|
-
|
|
642
|
+
// Apps have no slug (they are id + display name); `slug` is being retired
|
|
643
|
+
// from the public actor and is never read here.
|
|
644
|
+
app?: { id?: string; displayName?: string };
|
|
643
645
|
serviceAccount?: { id?: string };
|
|
644
646
|
};
|
|
645
647
|
|
|
@@ -685,7 +687,8 @@ export function listedCommentFromOriginComment(
|
|
|
685
687
|
: startLine;
|
|
686
688
|
const commitSha = thread.version?.headSha;
|
|
687
689
|
const author = comment.author;
|
|
688
|
-
const authorLogin =
|
|
690
|
+
const authorLogin =
|
|
691
|
+
author?.app?.displayName ?? author?.app?.id ?? author?.user?.email;
|
|
689
692
|
// App and service-account actors are machine identities; only a `user`
|
|
690
693
|
// actor is a human PR participant.
|
|
691
694
|
const authorIsBot =
|