@cursor/july 0.1.99 → 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/AGENTS.md +4 -2
- 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/github/defaults.d.ts.map +1 -1
- package/dist/channels/github/defaults.js +28 -3
- package/dist/channels/github/progress.d.ts +7 -0
- package/dist/channels/github/progress.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 +16 -7
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +31 -14
- 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/constants.d.ts +6 -0
- package/dist/channels/slack/constants.d.ts.map +1 -1
- package/dist/channels/slack/constants.js +6 -0
- package/dist/channels/slack/defaults.d.ts +9 -4
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +154 -76
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +3 -3
- package/dist/channels/slack/inbound.d.ts +9 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +14 -0
- package/dist/channels/slack/index.d.ts +2 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +2 -0
- package/dist/channels/slack/live-delivery.d.ts +5 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +116 -21
- package/dist/channels/slack/reasoning-card.d.ts +38 -0
- package/dist/channels/slack/reasoning-card.d.ts.map +1 -0
- package/dist/channels/slack/reasoning-card.js +104 -0
- package/dist/channels/slack/redact.d.ts +2 -0
- package/dist/channels/slack/redact.d.ts.map +1 -0
- package/dist/channels/slack/redact.js +5 -0
- package/dist/channels/slack/reply-options.d.ts +40 -0
- package/dist/channels/slack/reply-options.d.ts.map +1 -0
- package/dist/channels/slack/reply-options.js +150 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +8 -4
- package/dist/channels/slack/stream.d.ts +22 -10
- package/dist/channels/slack/stream.d.ts.map +1 -1
- package/dist/channels/slack/stream.js +9 -16
- package/dist/channels/slack/tool-cards.d.ts +22 -0
- package/dist/channels/slack/tool-cards.d.ts.map +1 -0
- package/dist/channels/slack/tool-cards.js +178 -0
- package/dist/channels/slack/types.d.ts +145 -6
- package/dist/channels/slack/types.d.ts.map +1 -1
- 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 +6 -6
- package/dist/docs/ab.md +1 -1
- package/dist/docs/assets/{ab.md.DJo5r4R-.js → ab.md.mlVgqvSk.js} +1 -1
- package/dist/docs/assets/{app.BplEAZ3S.js → app.BASO9Kih.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.js → building-with-agents.md.CUSWxlP_.js} +2 -2
- package/dist/docs/assets/chunks/@localSearchIndexroot.DbFXINq2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CHXyv4wP.js → VPLocalSearchBox.DwkqxoE0.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BTcsZmjQ.js → theme.CCil_13e.js} +2 -2
- package/dist/docs/assets/{evals.md.lfJoEVc8.js → evals.md.CPzDAwoH.js} +1 -1
- package/dist/docs/assets/{guides_github.md.Cnh2mL4a.js → guides_github.md.BtPr9GaP.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.js → guides_mcp-oauth.md.Dp6cDP7f.js} +1 -1
- package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.js → guides_opentelemetry.md.BVTXDCRg.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.VDXQV3ja.js → guides_slack.md.9oHPye9o.js} +19 -3
- package/dist/docs/assets/{guides_slack.md.VDXQV3ja.lean.js → guides_slack.md.9oHPye9o.lean.js} +1 -1
- package/dist/docs/assets/hillclimbing.md.CpTGTCle.js +4 -0
- package/dist/docs/assets/{index.md.CVeRUOeZ.js → index.md.Bb4k8kUm.js} +1 -1
- package/dist/docs/assets/{quickstart.md.Nj_LjW_a.js → quickstart.md.DdQOF7Y8.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.Di6jJAXF.js} +13 -3
- package/dist/docs/assets/{reference_connections.md.DxldvyIB.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/assets/scaffolding-agents.md.em43xlY1.js +1 -0
- package/dist/docs/assets/skills_ab.md.CsFNatVx.js +26 -0
- package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +1 -0
- package/dist/docs/assets/skills_create-agent.md.BVoWPcan.js +8 -0
- package/dist/docs/assets/skills_create-agent.md.BVoWPcan.lean.js +1 -0
- package/dist/docs/assets/skills_debug.md.CDbPhHfg.js +1 -0
- package/dist/docs/assets/skills_debug.md.CDbPhHfg.lean.js +1 -0
- package/dist/docs/assets/skills_evals.md.723kpUmA.js +25 -0
- package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +1 -0
- package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +1 -0
- package/dist/docs/assets/skills_framework-map.md.BTi817yv.lean.js +1 -0
- package/dist/docs/assets/skills_github.md.D0JahM8c.js +16 -0
- package/dist/docs/assets/skills_github.md.D0JahM8c.lean.js +1 -0
- package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.js +7 -0
- package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.lean.js +1 -0
- package/dist/docs/assets/skills_index.md.DKwIxzGg.js +1 -0
- package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +1 -0
- package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.js +18 -0
- package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.lean.js +1 -0
- package/dist/docs/assets/skills_otel.md.CgiZryR3.js +8 -0
- package/dist/docs/assets/skills_otel.md.CgiZryR3.lean.js +1 -0
- package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.js +20 -0
- package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.lean.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.js → troubleshooting.md.Cus_YZga.js} +1 -1
- package/dist/docs/building-with-agents.html +6 -6
- package/dist/docs/building-with-agents.md +14 -11
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +6 -6
- package/dist/docs/evals.md +1 -1
- 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 +5 -5
- package/dist/docs/guides/github.md +1 -1
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +5 -5
- package/dist/docs/guides/mcp-oauth.md +1 -1
- package/dist/docs/guides/opentelemetry.html +7 -7
- package/dist/docs/guides/opentelemetry.md +2 -2
- package/dist/docs/guides/slack.html +22 -6
- package/dist/docs/guides/slack.md +80 -1
- package/dist/docs/guides/webhooks.html +5 -5
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/hillclimbing.md +5 -5
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +1 -1
- package/dist/docs/llms-full.txt +1073 -31
- package/dist/docs/llms.txt +14 -0
- package/dist/docs/quickstart.html +5 -5
- package/dist/docs/quickstart.md +1 -1
- 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 +17 -7
- package/dist/docs/reference/connections.md +32 -1
- 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 +5 -5
- package/dist/docs/scaffolding-agents.md +3 -3
- package/dist/docs/skills/ab.html +52 -0
- package/dist/docs/skills/ab.md +50 -0
- package/dist/docs/skills/create-agent.html +34 -0
- package/dist/docs/skills/create-agent.md +160 -0
- package/dist/docs/skills/debug.html +27 -0
- package/dist/docs/skills/debug.md +36 -0
- package/dist/docs/skills/evals.html +51 -0
- package/dist/docs/skills/evals.md +99 -0
- package/dist/docs/skills/framework-map.html +27 -0
- package/dist/docs/skills/framework-map.md +95 -0
- package/dist/docs/skills/github.html +42 -0
- package/dist/docs/skills/github.md +93 -0
- package/dist/docs/skills/hillclimb.html +33 -0
- package/dist/docs/skills/hillclimb.md +55 -0
- package/dist/docs/skills/index.html +27 -0
- package/dist/docs/skills/index.md +21 -0
- package/dist/docs/skills/mcp-auth.html +44 -0
- package/dist/docs/skills/mcp-auth.md +76 -0
- package/dist/docs/skills/otel.html +34 -0
- package/dist/docs/skills/otel.md +48 -0
- package/dist/docs/skills/setup-slack.html +46 -0
- package/dist/docs/skills/setup-slack.md +141 -0
- 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 +5 -5
- package/dist/docs/troubleshooting.md +1 -1
- 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/files-backends/cursor-hosted.d.ts +6 -0
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +6 -9
- 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 +66 -21
- package/dist/internal/continuation-identity.d.ts.map +1 -1
- package/dist/internal/continuation-identity.js +3 -1
- package/dist/internal/conversation-mirror.d.ts.map +1 -1
- package/dist/internal/conversation-mirror.js +3 -4
- 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/hosted-store-secrets.d.ts +15 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -0
- package/dist/internal/cursor/hosted-store-secrets.js +48 -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 +29 -6
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +61 -19
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +426 -121
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +5 -0
- package/dist/internal/framework-file-storage.d.ts +15 -8
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +70 -10
- package/dist/internal/framework-storage-selection.d.ts +12 -12
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +33 -39
- 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 +5 -4
- package/dist/internal/session-run-log.d.ts.map +1 -1
- package/dist/internal/session-run-log.js +8 -8
- 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/storage-coordinator.d.ts +0 -6
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +1 -9
- 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-jzNbJENa.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-backends/cursor-hosted-v2.d.ts +83 -0
- package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -0
- package/dist/storage-backends/cursor-hosted-v2.js +164 -0
- package/dist/storage-backends/cursor-hosted.d.ts +6 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +6 -1
- 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 +123 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +29 -1
- package/docs/README.md +1 -1
- package/docs/ab.md +1 -1
- package/docs/building-with-agents.md +14 -11
- package/docs/evals.md +1 -1
- package/docs/guides/github.md +1 -1
- package/docs/guides/mcp-oauth.md +1 -1
- package/docs/guides/opentelemetry.md +2 -2
- package/docs/guides/slack.md +80 -1
- package/docs/hillclimbing.md +5 -5
- package/docs/quickstart.md +1 -1
- package/docs/reference/connections.md +32 -1
- package/docs/reference/http-api.md +1 -1
- package/docs/scaffolding-agents.md +3 -3
- package/docs/skills/index.md +26 -0
- package/docs/troubleshooting.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/github/defaults.ts +36 -3
- package/src/channels/github/progress.ts +7 -0
- 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 +37 -18
- package/src/channels/slack/code-fences.ts +183 -0
- package/src/channels/slack/constants.ts +6 -0
- package/src/channels/slack/defaults.ts +173 -92
- package/src/channels/slack/dispatch.ts +8 -1
- package/src/channels/slack/inbound.ts +17 -0
- package/src/channels/slack/index.ts +2 -0
- package/src/channels/slack/live-delivery.ts +142 -28
- package/src/channels/slack/reasoning-card.ts +140 -0
- package/src/channels/slack/redact.ts +6 -0
- package/src/channels/slack/reply-options.ts +229 -0
- package/src/channels/slack/slack-channel.ts +7 -2
- package/src/channels/slack/stream.ts +31 -24
- package/src/channels/slack/tool-cards.ts +221 -0
- package/src/channels/slack/types.ts +159 -6
- 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/files-backends/cursor-hosted.ts +15 -5
- 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 +88 -25
- package/src/internal/continuation-identity.ts +3 -1
- package/src/internal/conversation-mirror.ts +3 -8
- package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
- package/src/internal/cursor/hosted-store-secrets.ts +72 -0
- package/src/internal/cursor-deployment-relay.ts +65 -8
- package/src/internal/deploy-client.ts +83 -28
- package/src/internal/discovery.ts +479 -114
- package/src/internal/distribution.ts +5 -0
- package/src/internal/framework-file-storage.ts +80 -10
- package/src/internal/framework-storage-selection.ts +31 -44
- 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 +8 -12
- package/src/internal/start-log-store.ts +177 -0
- package/src/internal/storage-coordinator.ts +1 -11
- package/src/internal/tool-policy.ts +39 -9
- package/src/storage-backends/cursor-hosted-v2.ts +219 -0
- package/src/storage-backends/cursor-hosted.ts +6 -1
- package/src/storage-protocol.ts +37 -0
- package/src/storage.ts +1 -0
- package/src/types.ts +177 -14
- package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +0 -1
- package/dist/docs/assets/hillclimbing.md.DhESf3OO.js +0 -4
- package/dist/docs/assets/scaffolding-agents.md.D7UUkWw0.js +0 -1
- package/dist/internal/null-kv-storage.d.ts +0 -48
- package/dist/internal/null-kv-storage.d.ts.map +0 -1
- package/dist/internal/null-kv-storage.js +0 -58
- package/dist/playground/assets/index-D7rGZNjy.css +0 -1
- package/src/internal/null-kv-storage.ts +0 -74
- /package/dist/docs/assets/{ab.md.DJo5r4R-.lean.js → ab.md.mlVgqvSk.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.lean.js → building-with-agents.md.CUSWxlP_.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.lfJoEVc8.lean.js → evals.md.CPzDAwoH.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.Cnh2mL4a.lean.js → guides_github.md.BtPr9GaP.lean.js} +0 -0
- /package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.lean.js → guides_mcp-oauth.md.Dp6cDP7f.lean.js} +0 -0
- /package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.lean.js → guides_opentelemetry.md.BVTXDCRg.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.DhESf3OO.lean.js → hillclimbing.md.CpTGTCle.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.CVeRUOeZ.lean.js → index.md.Bb4k8kUm.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.Nj_LjW_a.lean.js → quickstart.md.DdQOF7Y8.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
- /package/dist/docs/assets/{scaffolding-agents.md.D7UUkWw0.lean.js → scaffolding-agents.md.em43xlY1.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.lean.js → troubleshooting.md.Cus_YZga.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 (${
|
|
@@ -167,11 +201,8 @@ function decodeDocument(key: string, bytes: Uint8Array): JsonValue {
|
|
|
167
201
|
* Split one storage core by key kind: framework session state to `files`,
|
|
168
202
|
* everything else to `kv`. Spread over the KV backend when building the
|
|
169
203
|
* full definition so its `evals` / `abs` groups (and the cursor-hosted
|
|
170
|
-
* marker) ride along untouched
|
|
171
|
-
*
|
|
172
|
-
* `continuation/` key would read and write a different store than the
|
|
173
|
-
* routed plain core — silent split-brain. Nothing in the package CASes
|
|
174
|
-
* those kinds today.
|
|
204
|
+
* marker) ride along untouched; wrap the KV `cas` group with
|
|
205
|
+
* {@link frameworkGuardedCas} rather than spreading it as-is.
|
|
175
206
|
*/
|
|
176
207
|
export function composeFrameworkStorage(input: {
|
|
177
208
|
kv: FileSinkStorageCore;
|
|
@@ -192,3 +223,42 @@ export function composeFrameworkStorage(input: {
|
|
|
192
223
|
listNewest: undefined,
|
|
193
224
|
};
|
|
194
225
|
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The KV backend's conditional writes, refusing framework-file keys.
|
|
229
|
+
*
|
|
230
|
+
* CAS runs on the KV proxy (a database row version); the plain core routes
|
|
231
|
+
* framework session state to the file store. A future coordination path
|
|
232
|
+
* that CASes a `session/` or `continuation/` key would otherwise read and
|
|
233
|
+
* write a different store than the plain path — silent split-brain. Fail
|
|
234
|
+
* loudly instead; nothing in the package CASes those kinds today.
|
|
235
|
+
*/
|
|
236
|
+
export function frameworkGuardedCas(
|
|
237
|
+
cas: NonNullable<StorageConfig["cas"]>
|
|
238
|
+
): NonNullable<StorageConfig["cas"]> {
|
|
239
|
+
const refuse = (key: string): void => {
|
|
240
|
+
if (isFrameworkFileKey(key)) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`framework file storage: conditional writes are KV-only, but "${key}" routes to the framework file store`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
return {
|
|
247
|
+
getWithVersion: (key, ctx) => {
|
|
248
|
+
refuse(key);
|
|
249
|
+
return cas.getWithVersion(key, ctx);
|
|
250
|
+
},
|
|
251
|
+
putIfAbsent: (key, value, ctx) => {
|
|
252
|
+
refuse(key);
|
|
253
|
+
return cas.putIfAbsent(key, value, ctx);
|
|
254
|
+
},
|
|
255
|
+
putIfVersion: (key, value, expectedVersion, ctx) => {
|
|
256
|
+
refuse(key);
|
|
257
|
+
return cas.putIfVersion(key, value, expectedVersion, ctx);
|
|
258
|
+
},
|
|
259
|
+
listKeys: (prefix, ctx) => {
|
|
260
|
+
refuse(prefix);
|
|
261
|
+
return cas.listKeys(prefix, ctx);
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -18,18 +18,18 @@
|
|
|
18
18
|
* - **Cursor-managed hosting** (the deployment-generation environment
|
|
19
19
|
* variable is set, same signal that registers `GET /v1/manifest`):
|
|
20
20
|
* the deployment's **framework-level file store**
|
|
21
|
-
* (`AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID
|
|
22
|
-
* transcripts, and the continuation index —
|
|
23
|
-
* storage, apart from the author-facing user
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
21
|
+
* (`AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID`, bound at task time) holds
|
|
22
|
+
* session records, event transcripts, and the continuation index —
|
|
23
|
+
* file-shaped state on file storage, apart from the author-facing user
|
|
24
|
+
* store. Author `host.kv`, eval runs, A/B samples, and conditional writes
|
|
25
|
+
* ride the AgentSDK v2 KV proxy (cursor-hosted-v2.ts), which resolves the
|
|
26
|
+
* pod service account to the factorydb deployment row (the v1 Bugbot
|
|
27
|
+
* proxy cannot resolve v2 pods at all). Framework session state never
|
|
28
|
+
* routes to the KV proxy — the composite splits by key kind — so
|
|
29
|
+
* transcripts stay off the author-reachable KV namespace. The API key
|
|
30
|
+
* resolves through the full credential chain on every call because hosted
|
|
31
|
+
* freeze snapshots listen unsigned and the binder drops the key file
|
|
32
|
+
* after restore.
|
|
33
33
|
* - **Self-hosted**: no mirror. `--state-root` is the durable copy, which
|
|
34
34
|
* is correct when the operator owns the disk.
|
|
35
35
|
*
|
|
@@ -47,17 +47,15 @@ import {
|
|
|
47
47
|
cursorHostedFiles,
|
|
48
48
|
} from "../files-backends/cursor-hosted.js";
|
|
49
49
|
import { defineStorage, type StorageDefinition } from "../storage.js";
|
|
50
|
-
import {
|
|
50
|
+
import { cursorHostedStorageV2 } from "../storage-backends/cursor-hosted-v2.js";
|
|
51
51
|
import type { AgentArchitecture } from "../types.js";
|
|
52
52
|
import { resolveApiKeySync } from "./cursor/credentials.js";
|
|
53
53
|
import { AGENT_SERVE_GENERATION_ENV_VAR } from "./cursor-relay-core.js";
|
|
54
54
|
import {
|
|
55
55
|
composeFrameworkStorage,
|
|
56
56
|
fileSinkStorageCore,
|
|
57
|
+
frameworkGuardedCas,
|
|
57
58
|
} from "./framework-file-storage.js";
|
|
58
|
-
import { nullKvStorage } from "./null-kv-storage.js";
|
|
59
|
-
|
|
60
|
-
const cursorHostedMarker = { [CURSOR_HOSTED_STORAGE]: true } as const;
|
|
61
59
|
|
|
62
60
|
export interface FrameworkStorageSelectionInput {
|
|
63
61
|
/** `agent/storage.ts`, when the author wrote one (v1 only: discovery rejects it on v2). */
|
|
@@ -100,44 +98,33 @@ export function selectFrameworkStorageDefinition(
|
|
|
100
98
|
// comes up). Follow-ups restore lazily by continuation or session id;
|
|
101
99
|
// GET /v1/sessions lists from the sink either way.
|
|
102
100
|
const policy = { restore: "off" } as const;
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (frameworkStoreId === undefined) {
|
|
107
|
-
// Nothing to mirror to: the KV proxy rejects v2 service accounts, so a
|
|
108
|
-
// definition over it would fail every delivery that reads it. The state
|
|
109
|
-
// root is the durable copy, as when self-hosted.
|
|
110
|
-
return undefined;
|
|
111
|
-
}
|
|
112
|
-
// Full chain (env → key file → stored login): frozen engines listen
|
|
113
|
-
// unsigned and bind CURSOR_API_KEY_FILE at task time, after this
|
|
101
|
+
const envSnapshot = env as NodeJS.ProcessEnv;
|
|
102
|
+
// Full chain (env → bind file → stored login): frozen engines listen
|
|
103
|
+
// unsigned and bind store ids + CURSOR_API_KEY at task time, after this
|
|
114
104
|
// definition is constructed.
|
|
115
105
|
const resolveApiKey = (): string | undefined => resolveApiKeySync()?.apiKey;
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
// deployments also means restoring the guard its `cas` group needs: a
|
|
124
|
-
// conditional write over a `session/` or `continuation/` key would run on
|
|
125
|
-
// the KV database while the plain core routes that key to the file store.
|
|
126
|
-
const kv = nullKvStorage();
|
|
106
|
+
// v2 pods carry a factorydb-bound service account, which the v1 Bugbot
|
|
107
|
+
// storage proxy cannot resolve; author KV, CAS coordination, and the
|
|
108
|
+
// eval/A-B tables speak the AgentSDK v2 KV proxy instead. It also carries
|
|
109
|
+
// the cursor-hosted marker, so GET /v1/sessions prefers the durable list
|
|
110
|
+
// (session records are on the framework store, which the composed core
|
|
111
|
+
// lists).
|
|
112
|
+
const kv = cursorHostedStorageV2({ resolveApiKey });
|
|
127
113
|
return defineStorage({
|
|
128
114
|
name: "cursor-hosted (framework files)",
|
|
129
115
|
policy,
|
|
130
|
-
// GET /v1/sessions still prefers the durable list: session records live
|
|
131
|
-
// on the framework store, which the composed core lists. Spread rather
|
|
132
|
-
// than named, the way cursorHostedStorage carries it: the marker is a
|
|
133
|
-
// platform stamp, not part of the authored config surface.
|
|
134
|
-
...cursorHostedMarker,
|
|
135
116
|
...kv,
|
|
136
117
|
...composeFrameworkStorage({
|
|
137
118
|
kv,
|
|
138
119
|
files: fileSinkStorageCore(
|
|
139
|
-
cursorHostedFiles({
|
|
120
|
+
cursorHostedFiles({
|
|
121
|
+
resolveStoreSourceId: () => cursorFrameworkStoreSourceId(envSnapshot),
|
|
122
|
+
resolveApiKey,
|
|
123
|
+
})
|
|
140
124
|
),
|
|
141
125
|
}),
|
|
126
|
+
// CAS stays on the KV proxy but must refuse framework-file keys, or a
|
|
127
|
+
// future coordination path would split-brain against the plain core.
|
|
128
|
+
cas: frameworkGuardedCas(kv.cas),
|
|
142
129
|
});
|
|
143
130
|
}
|
|
@@ -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
|
+
}
|