@cursor/july 0.1.30 → 0.1.32
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 +1 -1
- package/README.md +10 -5
- package/dist/bin/agent-serve.js +4 -4
- package/dist/channels/github/index.d.ts +1 -1
- package/dist/channels/github/index.js +1 -1
- package/dist/channels/slack/bot-mentions.d.ts +1 -1
- package/dist/channels/slack/bot-mentions.d.ts.map +1 -1
- package/dist/channels/slack/bot-mentions.js +1 -1
- package/dist/channels/slack/eval-directive.js +1 -1
- package/dist/channels/slack/external-policy.d.ts +1 -1
- package/dist/channels/slack/external-policy.js +1 -1
- package/dist/channels/slack/log.d.ts +1 -1
- package/dist/channels/slack/log.js +1 -1
- package/dist/channels/slack/post-update-delivery.d.ts +85 -0
- package/dist/channels/slack/post-update-delivery.d.ts.map +1 -0
- package/dist/channels/slack/setup.js +1 -1
- package/dist/channels/slack/socket-mode.js +1 -1
- package/dist/docs/404.html +3 -3
- package/dist/docs/ab.html +11 -11
- package/dist/docs/assets/{ab.md.BMCZ6Hd7.js → ab.md.DAQoJ-up.js} +6 -6
- package/dist/docs/assets/{ab.md.BMCZ6Hd7.lean.js → ab.md.DAQoJ-up.lean.js} +1 -1
- package/dist/docs/assets/{app.Cm4lsMc4.js → app.C2aVczmo.js} +1 -1
- package/dist/docs/assets/building-with-agents.md.CnHqvYDd.js +13 -0
- package/dist/docs/assets/{building-with-agents.md.CJCtZCyi.lean.js → building-with-agents.md.CnHqvYDd.lean.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.xgMnlUSO.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CYUFXspH.js → VPLocalSearchBox.DLEzetbD.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CTjkX9vc.js → theme.BkOH1oMp.js} +2 -2
- package/dist/docs/assets/concepts.md.DFaQEFkA.js +4 -0
- package/dist/docs/assets/concepts.md.DFaQEFkA.lean.js +1 -0
- package/dist/docs/assets/deployment.md.9MYBuKM1.js +55 -0
- package/dist/docs/assets/deployment.md.9MYBuKM1.lean.js +1 -0
- package/dist/docs/assets/{evals.md.DYOjkRCX.js → evals.md.BIUoVZ6X.js} +13 -13
- package/dist/docs/assets/evals.md.BIUoVZ6X.lean.js +1 -0
- package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.js → example-agents_approval-buddy.md.BhEfleVx.js} +4 -4
- package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.lean.js → example-agents_approval-buddy.md.BhEfleVx.lean.js} +1 -1
- package/dist/docs/assets/example-agents_benny.md.2Et1qa8f.js +7 -0
- package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.js → example-agents_bugbot.md.ByUexi5i.js} +5 -5
- package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.js → example-agents_codebase-wiki.md.B4y-7ZVW.js} +6 -6
- package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.lean.js → example-agents_codebase-wiki.md.B4y-7ZVW.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.js → example-agents_codeowners-review.md.D6ay4nvf.js} +6 -6
- package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.lean.js → example-agents_codeowners-review.md.D6ay4nvf.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.js → example-agents_concierge.md.lL8rhYlj.js} +7 -7
- package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.js → example-agents_fsd.md.DfNKQTHz.js} +5 -5
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +2 -0
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.lean.js +1 -0
- package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.js → example-agents_knowledge-base.md.CzyZ2DCr.js} +5 -5
- package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.lean.js → example-agents_knowledge-base.md.CzyZ2DCr.lean.js} +1 -1
- package/dist/docs/assets/example-agents_oncall.md.wFFXXEyW.js +10 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.js → example-agents_security-reviewer.md.Dkf1gyo6.js} +8 -8
- package/dist/docs/assets/example-agents_slack-agent.md.DvgvT4nn.js +5 -0
- package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.js +24 -0
- package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.lean.js +1 -0
- package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.js → guides_agent-to-agent.md.Bmbxy-FA.js} +4 -4
- package/dist/docs/assets/guides_cloud-runtime.md.BZ2GA7Es.js +9 -0
- package/dist/docs/assets/{guides_github.md.DOOCpqsW.js → guides_github.md.R2QlpR75.js} +5 -5
- package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.js → guides_human-in-the-loop.md.BWvT7UqY.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.Dd8EgSem.js → guides_mcp-oauth.md.C7G7IykG.js} +5 -5
- package/dist/docs/assets/guides_mcp-oauth.md.C7G7IykG.lean.js +1 -0
- package/dist/docs/assets/guides_slack.md.zriQpU_9.js +47 -0
- package/dist/docs/assets/guides_slack.md.zriQpU_9.lean.js +1 -0
- package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.js → guides_webhooks.md.DiAwSR42.js} +1 -1
- package/dist/docs/assets/{hillclimbing.md.DHNast08.js → hillclimbing.md.D9Y1_bYh.js} +1 -1
- package/dist/docs/assets/index.md.CZqbBJPB.js +20 -0
- package/dist/docs/assets/index.md.CZqbBJPB.lean.js +1 -0
- package/dist/docs/assets/{quickstart.md.BU6Iwi_9.js → quickstart.md.TnEXYgYW.js} +12 -12
- package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.js → reference_agent-config.md.kuN6-OxK.js} +1 -1
- package/dist/docs/assets/reference_cli.md.sD-IUWjg.js +73 -0
- package/dist/docs/assets/{reference_cli.md.ccoKOoXt.lean.js → reference_cli.md.sD-IUWjg.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.B9Q3TOve.js → reference_connections.md.DGqAsFXb.js} +3 -3
- package/dist/docs/assets/reference_http-api.md.CfVM_ICa.js +11 -0
- package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.js → reference_project-layout.md.D8E6ZmHJ.js} +4 -4
- package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.lean.js → reference_project-layout.md.D8E6ZmHJ.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.js → reference_schedules.md.gmfYzf_I.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.js → reference_sessions.md.C_ouF_uf.js} +3 -3
- package/dist/docs/assets/{reference_tools.md.BRSDnTbN.js → reference_tools.md.BswAQM41.js} +3 -3
- package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.js → scaffolding-agents.md.Bsr9Pwzu.js} +1 -1
- package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.lean.js → scaffolding-agents.md.Bsr9Pwzu.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.DRTdnFvd.js → storage.md.xZoiGM58.js} +3 -3
- package/dist/docs/assets/storage.md.xZoiGM58.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.CmQkmnzC.lean.js → troubleshooting.md.B5RVX_tL.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +12 -12
- package/dist/docs/concepts.html +6 -6
- package/dist/docs/deployment.html +32 -32
- package/dist/docs/evals.html +19 -19
- package/dist/docs/example-agents/approval-buddy.html +9 -9
- package/dist/docs/example-agents/benny.html +11 -11
- package/dist/docs/example-agents/bugbot.html +10 -10
- package/dist/docs/example-agents/codebase-wiki.html +11 -11
- package/dist/docs/example-agents/codeowners-review.html +11 -11
- package/dist/docs/example-agents/concierge.html +12 -12
- package/dist/docs/example-agents/fsd.html +10 -10
- package/dist/docs/example-agents/index.html +7 -7
- package/dist/docs/example-agents/knowledge-base.html +10 -10
- package/dist/docs/example-agents/oncall.html +10 -10
- package/dist/docs/example-agents/security-reviewer.html +13 -13
- package/dist/docs/example-agents/slack-agent.html +10 -10
- package/dist/docs/example-agents/weather-agent.html +16 -16
- package/dist/docs/guides/agent-to-agent.html +9 -9
- package/dist/docs/guides/cloud-runtime.html +7 -7
- package/dist/docs/guides/github.html +10 -10
- package/dist/docs/guides/human-in-the-loop.html +7 -7
- package/dist/docs/guides/mcp-oauth.html +11 -11
- package/dist/docs/guides/slack.html +22 -17
- package/dist/docs/guides/webhooks.html +7 -7
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +7 -7
- package/dist/docs/index.html +9 -9
- package/dist/docs/quickstart.html +17 -17
- package/dist/docs/reference/agent-config.html +7 -7
- package/dist/docs/reference/channels.html +5 -5
- package/dist/docs/reference/cli.html +56 -48
- package/dist/docs/reference/connections.html +9 -9
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +7 -7
- package/dist/docs/reference/instructions.html +5 -5
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/project-layout.html +9 -9
- package/dist/docs/reference/prompt.html +5 -5
- package/dist/docs/reference/schedules.html +7 -7
- package/dist/docs/reference/sessions.html +8 -8
- package/dist/docs/reference/skills.html +5 -5
- package/dist/docs/reference/subagents.html +5 -5
- package/dist/docs/reference/tools.html +9 -9
- package/dist/docs/scaffolding-agents.html +6 -6
- package/dist/docs/storage.html +9 -9
- package/dist/docs/troubleshooting.html +6 -6
- package/dist/evals/reporters.d.ts +1 -1
- package/dist/evals/reporters.js +1 -1
- package/dist/evals.d.ts +2 -2
- package/dist/files-backends/agent-store-presigned-url.d.ts +3 -0
- package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -0
- package/dist/files-backends/agent-store-presigned-url.js +1023 -0
- package/dist/files-backends/cursor-hosted.d.ts +87 -0
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -0
- package/dist/files-backends/cursor-hosted.js +563 -0
- package/dist/files-backends/local-fs.d.ts +33 -0
- package/dist/files-backends/local-fs.d.ts.map +1 -0
- package/dist/files-backends/local-fs.js +199 -0
- package/dist/files.d.ts +139 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +89 -0
- package/dist/internal/ab-collector.js +2 -2
- package/dist/internal/ab-fold.js +1 -1
- package/dist/internal/cli-ax.d.ts +2 -2
- package/dist/internal/cli-ax.js +2 -2
- package/dist/internal/cli-deploy.d.ts +1 -1
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +7 -2
- package/dist/internal/cli-docs.d.ts +1 -1
- package/dist/internal/cli-docs.js +1 -1
- package/dist/internal/cli-github.js +13 -13
- package/dist/internal/cli-mcp-oauth.d.ts +1 -1
- package/dist/internal/cli-mcp-oauth.js +2 -2
- package/dist/internal/cli-mcp.d.ts +3 -3
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/cli-skills.js +1 -1
- package/dist/internal/cloud-turn-cost.d.ts +9 -1
- package/dist/internal/cloud-turn-cost.d.ts.map +1 -1
- package/dist/internal/cloud-turn-cost.js +14 -4
- package/dist/internal/cursor/account-mcp.js +5 -5
- package/dist/internal/cursor/backend-client.js +1 -1
- package/dist/internal/cursor/github-credentials.js +3 -3
- package/dist/internal/cursor-account-mcp-auth.d.ts +1 -1
- package/dist/internal/cursor-account-mcp-auth.js +1 -1
- package/dist/internal/cursor-event-relay.js +1 -1
- package/dist/internal/cursor-relay-core.d.ts +1 -1
- package/dist/internal/cursor-relay-core.d.ts.map +1 -1
- package/dist/internal/cursor-slack-relay.js +1 -1
- package/dist/internal/deploy-client.d.ts +6 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -2
- package/dist/internal/deploy-source.d.ts +2 -2
- package/dist/internal/deploy-source.js +2 -2
- package/dist/internal/discovery.js +2 -2
- package/dist/internal/distribution.d.ts +5 -5
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +6 -6
- package/dist/internal/docs-site.js +5 -5
- package/dist/internal/eval-run-store.js +8 -8
- package/dist/internal/evals-client.d.ts +1 -1
- package/dist/internal/evals-client.js +1 -1
- package/dist/internal/github-fanout.js +2 -2
- package/dist/internal/host-files.d.ts +29 -0
- package/dist/internal/host-files.d.ts.map +1 -0
- package/dist/internal/host-files.js +283 -0
- package/dist/internal/host-platforms.js +5 -5
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +1 -1
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +26 -0
- package/dist/internal/install-cursor-skills.d.ts +1 -1
- package/dist/internal/install-cursor-skills.d.ts.map +1 -1
- package/dist/internal/install-cursor-skills.js +33 -4
- package/dist/internal/json-dir-store.d.ts +32 -0
- package/dist/internal/json-dir-store.d.ts.map +1 -0
- package/dist/internal/local-control-plane.js +2 -2
- package/dist/internal/logs-client.d.ts +2 -2
- package/dist/internal/logs-client.js +2 -2
- package/dist/internal/mcp-endpoint.js +1 -1
- package/dist/internal/mcp-oauth.js +2 -2
- package/dist/internal/persistence-coordinator.d.ts +127 -0
- package/dist/internal/persistence-coordinator.d.ts.map +1 -0
- package/dist/internal/platform-schedule-sync.js +2 -2
- package/dist/internal/playground/toolchain.js +6 -6
- package/dist/internal/reminder-runner.js +13 -13
- package/dist/internal/resolved-connections.js +6 -6
- package/dist/internal/schedule-runner.js +1 -1
- package/dist/internal/sdk-runner.js +5 -5
- package/dist/internal/server.js +16 -16
- package/dist/internal/session-cost.d.ts +3 -2
- package/dist/internal/session-cost.d.ts.map +1 -1
- package/dist/internal/session-cost.js +7 -6
- package/dist/internal/session-engine.d.ts +31 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +119 -31
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/storage-coordinator.js +7 -7
- package/dist/internal/trajectory.js +2 -2
- package/dist/internal/turn-cost.d.ts +27 -0
- package/dist/internal/turn-cost.d.ts.map +1 -0
- package/dist/internal/turn-cost.js +83 -0
- package/dist/internal/update-check.d.ts +3 -3
- package/dist/internal/update-check.d.ts.map +1 -1
- package/dist/internal/update-check.js +5 -5
- package/dist/memory.d.ts +1 -1
- package/dist/memory.js +1 -1
- package/dist/multi-tenant.d.ts +80 -0
- package/dist/multi-tenant.d.ts.map +1 -0
- package/dist/multi-tenant.js +69 -0
- package/dist/persistence.d.ts +184 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/playground/assets/index-50PKeJlG.css +1 -0
- package/dist/playground/assets/index-C0f2Wl1q.js +85 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +120 -16
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +23 -23
- package/docs/ab.md +12 -12
- package/docs/building-with-agents.md +9 -9
- package/docs/concepts.md +11 -11
- package/docs/deployment.md +55 -43
- package/docs/evals.md +20 -20
- package/docs/example-agents/approval-buddy.md +9 -9
- package/docs/example-agents/benny.md +13 -13
- package/docs/example-agents/bugbot.md +6 -6
- package/docs/example-agents/codebase-wiki.md +8 -8
- package/docs/example-agents/codeowners-review.md +8 -8
- package/docs/example-agents/concierge.md +10 -10
- package/docs/example-agents/fsd.md +7 -7
- package/docs/example-agents/index.md +8 -8
- package/docs/example-agents/knowledge-base.md +9 -9
- package/docs/example-agents/oncall.md +7 -7
- package/docs/example-agents/security-reviewer.md +12 -12
- package/docs/example-agents/slack-agent.md +10 -10
- package/docs/example-agents/weather-agent.md +30 -26
- package/docs/guides/agent-to-agent.md +4 -4
- package/docs/guides/cloud-runtime.md +3 -3
- package/docs/guides/github.md +6 -6
- package/docs/guides/human-in-the-loop.md +1 -1
- package/docs/guides/mcp-oauth.md +9 -9
- package/docs/guides/slack.md +94 -21
- package/docs/guides/webhooks.md +1 -1
- package/docs/hillclimbing.md +3 -3
- package/docs/quickstart.md +18 -18
- package/docs/reference/agent-config.md +1 -1
- package/docs/reference/cli.md +110 -79
- package/docs/reference/connections.md +3 -3
- package/docs/reference/http-api.md +2 -2
- package/docs/reference/project-layout.md +7 -7
- package/docs/reference/schedules.md +1 -1
- package/docs/reference/sessions.md +7 -7
- package/docs/reference/tools.md +3 -3
- package/docs/scaffolding-agents.md +2 -2
- package/docs/storage.md +5 -5
- package/docs/troubleshooting.md +11 -10
- package/package.json +5 -2
- package/skills/ab/SKILL.md +5 -5
- package/skills/create-agent/SKILL.md +17 -17
- package/skills/debug/SKILL.md +10 -10
- package/skills/evals/SKILL.md +13 -13
- package/skills/framework-map/SKILL.md +3 -3
- package/skills/github/SKILL.md +11 -11
- package/skills/hillclimb/SKILL.md +9 -9
- package/skills/mcp-auth/SKILL.md +11 -11
- package/skills/setup-slack/SKILL.md +28 -28
- package/src/bin/agent-serve.ts +4 -4
- package/src/channels/github/index.ts +1 -1
- package/src/channels/slack/bot-mentions.ts +1 -1
- package/src/channels/slack/eval-directive.ts +1 -1
- package/src/channels/slack/external-policy.ts +1 -1
- package/src/channels/slack/log.ts +1 -1
- package/src/channels/slack/setup.ts +1 -1
- package/src/channels/slack/socket-mode.ts +1 -1
- package/src/evals/reporters.ts +1 -1
- package/src/evals.ts +2 -2
- package/src/files-backends/agent-store-presigned-url.ts +8 -0
- package/src/files-backends/cursor-hosted.ts +724 -0
- package/src/files-backends/local-fs.ts +178 -0
- package/src/files.ts +195 -0
- package/src/internal/ab-collector.ts +2 -2
- package/src/internal/ab-fold.ts +1 -1
- package/src/internal/cli-ax.ts +2 -2
- package/src/internal/cli-deploy.ts +7 -2
- package/src/internal/cli-docs.ts +1 -1
- package/src/internal/cli-github.ts +13 -13
- package/src/internal/cli-mcp-oauth.ts +2 -2
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/cli-skills.ts +1 -1
- package/src/internal/cloud-turn-cost.ts +20 -4
- package/src/internal/cursor/account-mcp.ts +5 -5
- package/src/internal/cursor/backend-client.ts +1 -1
- package/src/internal/cursor/github-credentials.ts +3 -3
- package/src/internal/cursor-account-mcp-auth.ts +1 -1
- package/src/internal/cursor-event-relay.ts +1 -1
- package/src/internal/cursor-relay-core.ts +1 -1
- package/src/internal/cursor-slack-relay.ts +1 -1
- package/src/internal/deploy-client.ts +8 -2
- package/src/internal/deploy-source.ts +2 -2
- package/src/internal/discovery.ts +2 -2
- package/src/internal/distribution.ts +6 -6
- package/src/internal/docs-site.ts +5 -5
- package/src/internal/eval-run-store.ts +8 -8
- package/src/internal/evals-client.ts +1 -1
- package/src/internal/github-fanout.ts +2 -2
- package/src/internal/host-files.ts +372 -0
- package/src/internal/host-platforms.ts +5 -5
- package/src/internal/hosting.ts +1 -1
- package/src/internal/http-channel.ts +30 -0
- package/src/internal/install-cursor-skills.ts +31 -3
- package/src/internal/local-control-plane.ts +2 -2
- package/src/internal/logs-client.ts +2 -2
- package/src/internal/mcp-endpoint.ts +1 -1
- package/src/internal/mcp-oauth.ts +2 -2
- package/src/internal/platform-schedule-sync.ts +2 -2
- package/src/internal/playground/toolchain.ts +6 -6
- package/src/internal/reminder-runner.ts +13 -13
- package/src/internal/resolved-connections.ts +6 -6
- package/src/internal/schedule-runner.ts +1 -1
- package/src/internal/sdk-runner.ts +5 -5
- package/src/internal/server.ts +16 -16
- package/src/internal/session-cost.ts +7 -6
- package/src/internal/session-engine.ts +141 -28
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/storage-coordinator.ts +7 -7
- package/src/internal/trajectory.ts +2 -2
- package/src/internal/turn-cost.ts +110 -0
- package/src/internal/update-check.ts +6 -6
- package/src/memory.ts +1 -1
- package/src/storage.ts +1 -1
- package/src/types.ts +148 -16
- package/dist/docs/assets/building-with-agents.md.CJCtZCyi.js +0 -13
- package/dist/docs/assets/chunks/@localSearchIndexroot.CbQshWFK.js +0 -1
- package/dist/docs/assets/concepts.md.Cfb9b-k1.js +0 -4
- package/dist/docs/assets/concepts.md.Cfb9b-k1.lean.js +0 -1
- package/dist/docs/assets/deployment.md.TecHo0_2.js +0 -55
- package/dist/docs/assets/deployment.md.TecHo0_2.lean.js +0 -1
- package/dist/docs/assets/evals.md.DYOjkRCX.lean.js +0 -1
- package/dist/docs/assets/example-agents_benny.md.B0gjhI-p.js +0 -7
- package/dist/docs/assets/example-agents_index.md.D2PEVSXl.js +0 -2
- package/dist/docs/assets/example-agents_index.md.D2PEVSXl.lean.js +0 -1
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +0 -10
- package/dist/docs/assets/example-agents_slack-agent.md.buLbgvBf.js +0 -5
- package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.js +0 -24
- package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.lean.js +0 -1
- package/dist/docs/assets/guides_cloud-runtime.md.gVzabdQL.js +0 -9
- package/dist/docs/assets/guides_mcp-oauth.md.Dd8EgSem.lean.js +0 -1
- package/dist/docs/assets/guides_slack.md.CjmJSvZS.js +0 -42
- package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +0 -1
- package/dist/docs/assets/index.md.CH_s5uZe.js +0 -20
- package/dist/docs/assets/index.md.CH_s5uZe.lean.js +0 -1
- package/dist/docs/assets/reference_cli.md.ccoKOoXt.js +0 -65
- package/dist/docs/assets/reference_http-api.md.BncLd3PZ.js +0 -11
- package/dist/docs/assets/storage.md.DRTdnFvd.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.CmQkmnzC.js +0 -1
- package/dist/internal/model-pricing.d.ts +0 -49
- package/dist/internal/model-pricing.d.ts.map +0 -1
- package/dist/internal/model-pricing.js +0 -377
- package/dist/playground/assets/index-CquRB-l0.js +0 -85
- package/dist/playground/assets/index-Dj0bWpkn.css +0 -1
- package/src/internal/model-pricing.ts +0 -426
- /package/dist/docs/assets/{example-agents_benny.md.B0gjhI-p.lean.js → example-agents_benny.md.2Et1qa8f.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.lean.js → example-agents_bugbot.md.ByUexi5i.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.lean.js → example-agents_concierge.md.lL8rhYlj.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.lean.js → example-agents_fsd.md.DfNKQTHz.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_oncall.md.BG_sUMly.lean.js → example-agents_oncall.md.wFFXXEyW.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.lean.js → example-agents_security-reviewer.md.Dkf1gyo6.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_slack-agent.md.buLbgvBf.lean.js → example-agents_slack-agent.md.DvgvT4nn.lean.js} +0 -0
- /package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.lean.js → guides_agent-to-agent.md.Bmbxy-FA.lean.js} +0 -0
- /package/dist/docs/assets/{guides_cloud-runtime.md.gVzabdQL.lean.js → guides_cloud-runtime.md.BZ2GA7Es.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.DOOCpqsW.lean.js → guides_github.md.R2QlpR75.lean.js} +0 -0
- /package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.lean.js → guides_human-in-the-loop.md.BWvT7UqY.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.lean.js → guides_webhooks.md.DiAwSR42.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.DHNast08.lean.js → hillclimbing.md.D9Y1_bYh.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.BU6Iwi_9.lean.js → quickstart.md.TnEXYgYW.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.lean.js → reference_agent-config.md.kuN6-OxK.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.B9Q3TOve.lean.js → reference_connections.md.DGqAsFXb.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.BncLd3PZ.lean.js → reference_http-api.md.CfVM_ICa.lean.js} +0 -0
- /package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.lean.js → reference_schedules.md.gmfYzf_I.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.lean.js → reference_sessions.md.C_ouF_uf.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.BRSDnTbN.lean.js → reference_tools.md.BswAQM41.lean.js} +0 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author-facing durable file storage for {@link HostContext.files}.
|
|
3
|
+
*
|
|
4
|
+
* On Cursor-managed hosting the bytes live in the deployment's durable
|
|
5
|
+
* store; otherwise they land under `--state-root/files` on local disk, which
|
|
6
|
+
* is what makes `host.files` work self-hosted with no storage service at all.
|
|
7
|
+
*
|
|
8
|
+
* Everything that decides *which* bytes an author may reach lives here rather
|
|
9
|
+
* than in the sink: scope selection, path validation, and key minting through
|
|
10
|
+
* {@link fileKeys}. A sink only ever sees a fully-qualified opaque key, so an
|
|
11
|
+
* authored sink — including one a customer wrote against their own Dropbox —
|
|
12
|
+
* cannot be steered into another deployment's or another session's files.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { join, normalize, sep } from "node:path";
|
|
16
|
+
import {
|
|
17
|
+
FilePathRejectedError,
|
|
18
|
+
FileSessionRequiredError,
|
|
19
|
+
type FileSink,
|
|
20
|
+
type FileSinkEntry,
|
|
21
|
+
FileTooLargeError,
|
|
22
|
+
fileKeys,
|
|
23
|
+
} from "../files.js";
|
|
24
|
+
import {
|
|
25
|
+
cursorHostedFiles,
|
|
26
|
+
isCursorHostedFilesAvailable,
|
|
27
|
+
} from "../files-backends/cursor-hosted.js";
|
|
28
|
+
import { localFiles } from "../files-backends/local-fs.js";
|
|
29
|
+
import type {
|
|
30
|
+
HostFileEntry,
|
|
31
|
+
HostFileStat,
|
|
32
|
+
HostFilesApi,
|
|
33
|
+
HostFilesCapabilities,
|
|
34
|
+
HostFilesScope,
|
|
35
|
+
} from "../types.js";
|
|
36
|
+
|
|
37
|
+
export interface CreateHostFilesApiOptions {
|
|
38
|
+
agentName: string;
|
|
39
|
+
/** Local disk root for the default sink. Required unless `sink` is supplied. */
|
|
40
|
+
stateRoot?: string;
|
|
41
|
+
/** Explicit sink override (tests). Omitted → hosted store or local disk. */
|
|
42
|
+
sink?: FileSink;
|
|
43
|
+
/** Session bound for `scope: "session"` calls; prefer {@link HostFilesApi.forSession}. */
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
/** Environment consulted when choosing the default sink (tests). */
|
|
46
|
+
env?: NodeJS.ProcessEnv;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Build the host file API for one agent process. */
|
|
50
|
+
export function createHostFilesApi(
|
|
51
|
+
options: CreateHostFilesApiOptions
|
|
52
|
+
): HostFilesApi {
|
|
53
|
+
const sink = options.sink ?? createDefaultSink(options);
|
|
54
|
+
return createBoundHostFilesApi({
|
|
55
|
+
agentName: options.agentName,
|
|
56
|
+
sink,
|
|
57
|
+
...(options.sessionId === undefined
|
|
58
|
+
? {}
|
|
59
|
+
: { sessionId: options.sessionId }),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Pick the default sink.
|
|
65
|
+
*
|
|
66
|
+
* On Cursor-managed hosting the durable store is the only correct answer —
|
|
67
|
+
* falling back to pod-local disk there would accept writes that vanish with
|
|
68
|
+
* the pod, which is the failure this surface exists to remove. Off hosting,
|
|
69
|
+
* local disk keeps `serve --dev`, replay, fixtures, and evals working with no
|
|
70
|
+
* storage service. This is the gate all six hosted agents write by hand in
|
|
71
|
+
* their `agent/storage.ts`; resolving it here means authors do not repeat it.
|
|
72
|
+
*/
|
|
73
|
+
function createDefaultSink(options: CreateHostFilesApiOptions): FileSink {
|
|
74
|
+
if (isCursorHostedFilesAvailable(options.env ?? process.env)) {
|
|
75
|
+
return cursorHostedFiles();
|
|
76
|
+
}
|
|
77
|
+
if (options.stateRoot === undefined) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
"createHostFilesApi needs a stateRoot for the default local-disk sink, or an explicit sink"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return localFiles({
|
|
83
|
+
filesRoot: join(options.stateRoot, "files"),
|
|
84
|
+
stripKeyPrefix: localKeyPrefix(options.agentName),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** On-disk layout drops the framework key prefix so paths stay navigable. */
|
|
89
|
+
function localKeyPrefix(agentName: string): string {
|
|
90
|
+
return fileKeys.deploymentPrefix(agentName).replace(/deployment\/$/, "");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface BoundState {
|
|
94
|
+
agentName: string;
|
|
95
|
+
sink: FileSink;
|
|
96
|
+
sessionId?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function createBoundHostFilesApi(state: BoundState): HostFilesApi {
|
|
100
|
+
const sinkCaps = state.sink.capabilities ?? {};
|
|
101
|
+
const capabilities: HostFilesCapabilities = {
|
|
102
|
+
conflictDetection: sinkCaps.etags === true,
|
|
103
|
+
materialized:
|
|
104
|
+
sinkCaps.materialized === true &&
|
|
105
|
+
typeof state.sink.materializedPath === "function",
|
|
106
|
+
...(sinkCaps.maxBytes === undefined ? {} : { maxBytes: sinkCaps.maxBytes }),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const keyFor = (path: string, scope: HostFilesScope | undefined): string =>
|
|
110
|
+
mintKey(state, path, scope);
|
|
111
|
+
|
|
112
|
+
const api: HostFilesApi = {
|
|
113
|
+
capabilities,
|
|
114
|
+
|
|
115
|
+
forSession(sessionId: string): HostFilesApi {
|
|
116
|
+
const trimmed = sessionId.trim();
|
|
117
|
+
if (trimmed === "") {
|
|
118
|
+
throw new FileSessionRequiredError(
|
|
119
|
+
"host.files.forSession requires a non-empty session id"
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return createBoundHostFilesApi({ ...state, sessionId: trimmed });
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async read(path, options): Promise<string | undefined> {
|
|
126
|
+
const bytes = await api.readBytes(path, options);
|
|
127
|
+
return bytes === undefined
|
|
128
|
+
? undefined
|
|
129
|
+
: Buffer.from(bytes).toString(options?.encoding ?? "utf8");
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
async readBytes(path, options): Promise<Uint8Array | undefined> {
|
|
133
|
+
const found = await state.sink.get(keyFor(path, options?.scope));
|
|
134
|
+
if (found === undefined) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
return found instanceof Uint8Array ? found : found.body;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
async write(path, data, options): Promise<void> {
|
|
141
|
+
const key = keyFor(path, options?.scope);
|
|
142
|
+
const body =
|
|
143
|
+
typeof data === "string"
|
|
144
|
+
? Buffer.from(data, "utf8")
|
|
145
|
+
: Buffer.from(data);
|
|
146
|
+
const maxBytes = capabilities.maxBytes;
|
|
147
|
+
if (maxBytes !== undefined && body.byteLength > maxBytes) {
|
|
148
|
+
throw new FileTooLargeError(key, body.byteLength, maxBytes);
|
|
149
|
+
}
|
|
150
|
+
await state.sink.put(
|
|
151
|
+
key,
|
|
152
|
+
body,
|
|
153
|
+
options?.ifMatch === undefined
|
|
154
|
+
? undefined
|
|
155
|
+
: { ifMatch: options.ifMatch }
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
async remove(path, options): Promise<void> {
|
|
160
|
+
await state.sink.delete(keyFor(path, options?.scope));
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
async exists(path, options): Promise<boolean> {
|
|
164
|
+
return (await api.stat(path, options)) !== undefined;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
async stat(path, options): Promise<HostFileStat | undefined> {
|
|
168
|
+
const key = keyFor(path, options?.scope);
|
|
169
|
+
const entry = await statKey(state.sink, key);
|
|
170
|
+
if (entry === undefined) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
size: entry.size,
|
|
175
|
+
...(entry.mtimeMs === undefined ? {} : { mtimeMs: entry.mtimeMs }),
|
|
176
|
+
...(entry.etag === undefined ? {} : { etag: entry.etag }),
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
async list(prefix, options): Promise<HostFileEntry[]> {
|
|
181
|
+
const scopePrefix = mintPrefix(state, options?.scope);
|
|
182
|
+
const rel = prefix === undefined ? "" : normalizeRelPath(prefix, true);
|
|
183
|
+
const entries = await state.sink.list(`${scopePrefix}${rel}`);
|
|
184
|
+
const out: HostFileEntry[] = [];
|
|
185
|
+
for (const entry of entries) {
|
|
186
|
+
if (!entry.key.startsWith(scopePrefix)) {
|
|
187
|
+
// A sink that widens the prefix must not leak keys from another
|
|
188
|
+
// scope through a listing.
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
out.push({
|
|
192
|
+
path: entry.key.slice(scopePrefix.length),
|
|
193
|
+
size: entry.size,
|
|
194
|
+
...(entry.mtimeMs === undefined ? {} : { mtimeMs: entry.mtimeMs }),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return out.sort((a, b) =>
|
|
198
|
+
a.path < b.path ? -1 : a.path > b.path ? 1 : 0
|
|
199
|
+
);
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
materializedPath(path, options): string | undefined {
|
|
203
|
+
if (!capabilities.materialized) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
return state.sink.materializedPath?.(keyFor(path, options?.scope));
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
return api;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function statKey(
|
|
213
|
+
sink: FileSink,
|
|
214
|
+
key: string
|
|
215
|
+
): Promise<FileSinkEntry | undefined> {
|
|
216
|
+
if (typeof sink.stat === "function") {
|
|
217
|
+
return await sink.stat(key);
|
|
218
|
+
}
|
|
219
|
+
const entries = await sink.list(key);
|
|
220
|
+
return entries.find((entry) => entry.key === key);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ============================================================================
|
|
224
|
+
// Key minting
|
|
225
|
+
// ============================================================================
|
|
226
|
+
|
|
227
|
+
function mintKey(
|
|
228
|
+
state: BoundState,
|
|
229
|
+
path: string,
|
|
230
|
+
scope: HostFilesScope | undefined
|
|
231
|
+
): string {
|
|
232
|
+
const rel = normalizeRelPath(path, false);
|
|
233
|
+
const resolved = resolveScope(state, scope);
|
|
234
|
+
if (resolved.kind === "session") {
|
|
235
|
+
return fileKeys.session(state.agentName, resolved.sessionId, rel);
|
|
236
|
+
}
|
|
237
|
+
return resolved.partition === undefined
|
|
238
|
+
? fileKeys.deployment(state.agentName, rel)
|
|
239
|
+
: fileKeys.deploymentPartition(state.agentName, resolved.partition, rel);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function mintPrefix(
|
|
243
|
+
state: BoundState,
|
|
244
|
+
scope: HostFilesScope | undefined
|
|
245
|
+
): string {
|
|
246
|
+
const resolved = resolveScope(state, scope);
|
|
247
|
+
if (resolved.kind === "session") {
|
|
248
|
+
return fileKeys.sessionPrefix(state.agentName, resolved.sessionId);
|
|
249
|
+
}
|
|
250
|
+
const base = fileKeys.deploymentPrefix(state.agentName);
|
|
251
|
+
return resolved.partition === undefined
|
|
252
|
+
? base
|
|
253
|
+
: `${base}${resolved.partition}/`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
type ResolvedScope =
|
|
257
|
+
| { kind: "session"; sessionId: string }
|
|
258
|
+
| { kind: "deployment"; partition?: string };
|
|
259
|
+
|
|
260
|
+
function resolveScope(
|
|
261
|
+
state: BoundState,
|
|
262
|
+
scope: HostFilesScope | undefined
|
|
263
|
+
): ResolvedScope {
|
|
264
|
+
if (scope === "deployment") {
|
|
265
|
+
return { kind: "deployment" };
|
|
266
|
+
}
|
|
267
|
+
if (scope !== undefined && typeof scope === "object") {
|
|
268
|
+
if (scope.kind === "deployment") {
|
|
269
|
+
return scope.partition === undefined
|
|
270
|
+
? { kind: "deployment" }
|
|
271
|
+
: { kind: "deployment", partition: segment(scope.partition) };
|
|
272
|
+
}
|
|
273
|
+
const explicit = scope.sessionId ?? state.sessionId;
|
|
274
|
+
return { kind: "session", sessionId: requireSession(explicit) };
|
|
275
|
+
}
|
|
276
|
+
// Default and explicit `"session"` both bind to the caller's own session, so
|
|
277
|
+
// a relative path can never be re-read as another session's.
|
|
278
|
+
return { kind: "session", sessionId: requireSession(state.sessionId) };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function requireSession(sessionId: string | undefined): string {
|
|
282
|
+
if (sessionId === undefined || sessionId.trim() === "") {
|
|
283
|
+
throw new FileSessionRequiredError(
|
|
284
|
+
"host.files needs a session in scope: call forSession(sessionId), pass { scope: { kind: 'session', sessionId } }, or use { scope: 'deployment' }"
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
return segment(sessionId);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Normalize an author path into key-relative form. Rejects traversal, NUL,
|
|
292
|
+
* backslashes, trailing slashes, and the `.cursor*` prefix the Agent Store
|
|
293
|
+
* reserves for Cursor-managed content — refusing here turns an opaque failure
|
|
294
|
+
* deep in a sink (or a 400 from the hosted API, which accepts each path in
|
|
295
|
+
* exactly one spelling) into one the author can act on, and keeps the rule
|
|
296
|
+
* identical across sinks.
|
|
297
|
+
*/
|
|
298
|
+
function normalizeRelPath(path: string, allowEmpty: boolean): string {
|
|
299
|
+
if (typeof path !== "string") {
|
|
300
|
+
throw new FilePathRejectedError("host.files path must be a string");
|
|
301
|
+
}
|
|
302
|
+
const trimmed = path.trim().replace(/^\/+/, "");
|
|
303
|
+
if (trimmed === "") {
|
|
304
|
+
if (allowEmpty) {
|
|
305
|
+
return "";
|
|
306
|
+
}
|
|
307
|
+
throw new FilePathRejectedError("host.files path must be non-empty");
|
|
308
|
+
}
|
|
309
|
+
if (trimmed.includes("\0")) {
|
|
310
|
+
throw new FilePathRejectedError(`host.files path is not allowed: ${path}`);
|
|
311
|
+
}
|
|
312
|
+
// A backslash is a separator on Windows and a literal on POSIX, so a key
|
|
313
|
+
// minted from one would name different objects on different hosts — and the
|
|
314
|
+
// hosted API refuses it. Same rule as `segment()` below.
|
|
315
|
+
if (trimmed.includes("\\")) {
|
|
316
|
+
throw new FilePathRejectedError(`host.files path is not allowed: ${path}`);
|
|
317
|
+
}
|
|
318
|
+
// On an object path, a trailing slash would mint a key ending in "/" — an
|
|
319
|
+
// empty "directory marker" object, never what an author writing a file
|
|
320
|
+
// meant, and refused by the hosted API. A listing prefix (`allowEmpty`) is
|
|
321
|
+
// a different thing: there a trailing slash legitimately scopes to a
|
|
322
|
+
// directory's contents.
|
|
323
|
+
if (!allowEmpty && trimmed.endsWith("/")) {
|
|
324
|
+
throw new FilePathRejectedError(`host.files path is not allowed: ${path}`);
|
|
325
|
+
}
|
|
326
|
+
const normalized = normalize(trimmed).split(sep).join("/");
|
|
327
|
+
if (
|
|
328
|
+
normalized === ".." ||
|
|
329
|
+
normalized === "." ||
|
|
330
|
+
normalized.startsWith("../") ||
|
|
331
|
+
normalized.includes("/../") ||
|
|
332
|
+
normalized.endsWith("/..")
|
|
333
|
+
) {
|
|
334
|
+
throw new FilePathRejectedError(`host.files path is not allowed: ${path}`);
|
|
335
|
+
}
|
|
336
|
+
for (const part of normalized.split("/")) {
|
|
337
|
+
if (isReservedSegment(part)) {
|
|
338
|
+
throw new FilePathRejectedError(
|
|
339
|
+
`host.files path segment "${part}" is reserved for Cursor-managed content: ${path}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return normalized;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** One key segment (session id, partition): no separators, no traversal. */
|
|
347
|
+
function segment(value: string): string {
|
|
348
|
+
const trimmed = value.trim();
|
|
349
|
+
if (
|
|
350
|
+
trimmed === "" ||
|
|
351
|
+
trimmed === "." ||
|
|
352
|
+
trimmed === ".." ||
|
|
353
|
+
trimmed.includes("/") ||
|
|
354
|
+
trimmed.includes("\\") ||
|
|
355
|
+
trimmed.includes("\0")
|
|
356
|
+
) {
|
|
357
|
+
throw new FilePathRejectedError(
|
|
358
|
+
`host.files key segment is not allowed: ${value}`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
if (isReservedSegment(trimmed)) {
|
|
362
|
+
throw new FilePathRejectedError(
|
|
363
|
+
`host.files key segment "${trimmed}" is reserved for Cursor-managed content`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
return trimmed;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Mirrors the server's reserved-prefix rule (`AGENT_STORE_RESERVED_CURSOR_PATH_PREFIX`). */
|
|
370
|
+
function isReservedSegment(value: string): boolean {
|
|
371
|
+
return value.toLowerCase().startsWith(".cursor");
|
|
372
|
+
}
|
|
@@ -136,7 +136,7 @@ export async function warmupHostGitHubAuth(options: {
|
|
|
136
136
|
const source = options.authSource ?? (await resolveHostGitHubAuthSource());
|
|
137
137
|
if (source === "unavailable") {
|
|
138
138
|
options.logger(
|
|
139
|
-
"[
|
|
139
|
+
"[agent-sdk] GitHub auth: unavailable (set GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY + GITHUB_APP_INSTALLATION_ID, or GITHUB_TOKEN / GH_TOKEN, or run `gh auth login`)"
|
|
140
140
|
);
|
|
141
141
|
return source;
|
|
142
142
|
}
|
|
@@ -147,7 +147,7 @@ export async function warmupHostGitHubAuth(options: {
|
|
|
147
147
|
exportedGhToken = await ensureGhCliTokenEnv();
|
|
148
148
|
} catch (error) {
|
|
149
149
|
options.logger(
|
|
150
|
-
`[
|
|
150
|
+
`[agent-sdk] GitHub auth: failed to export GH_TOKEN for gh CLI: ${
|
|
151
151
|
error instanceof Error ? error.message : String(error)
|
|
152
152
|
}`
|
|
153
153
|
);
|
|
@@ -165,16 +165,16 @@ export async function warmupHostGitHubAuth(options: {
|
|
|
165
165
|
? "GITHUB_TOKEN/GH_TOKEN"
|
|
166
166
|
: "gh auth token";
|
|
167
167
|
if (options.github === undefined) {
|
|
168
|
-
options.logger(`[
|
|
168
|
+
options.logger(`[agent-sdk] GitHub auth: ${label}`);
|
|
169
169
|
return source;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
try {
|
|
173
173
|
await options.github.getOctokit();
|
|
174
|
-
options.logger(`[
|
|
174
|
+
options.logger(`[agent-sdk] GitHub auth: ${label}`);
|
|
175
175
|
} catch (error) {
|
|
176
176
|
options.logger(
|
|
177
|
-
`[
|
|
177
|
+
`[agent-sdk] GitHub auth: ${label} resolved but Octokit warmup failed: ${
|
|
178
178
|
error instanceof Error ? error.message : String(error)
|
|
179
179
|
}`
|
|
180
180
|
);
|
package/src/internal/hosting.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client-side mirrors of the Agent Serve hosting validation rules
|
|
3
3
|
* (backend/server/src/agentServe/agentServeShared.ts). Shared by discovery
|
|
4
|
-
* (`hosting` block diagnostics on `
|
|
4
|
+
* (`hosting` block diagnostics on `agent-sdk validate`) and the deploy /
|
|
5
5
|
* secrets CLI verbs (actionable errors before any network call). The
|
|
6
6
|
* backend stays authoritative — these exist so mistakes fail fast and
|
|
7
7
|
* locally with the same grammar the server enforces.
|
|
@@ -326,6 +326,35 @@ export function buildHttpChannelRoutes(args: {
|
|
|
326
326
|
},
|
|
327
327
|
};
|
|
328
328
|
|
|
329
|
+
const cost: ServerRoute = {
|
|
330
|
+
method: "GET",
|
|
331
|
+
pattern: `${base}/v1/session/:sessionId/cost`,
|
|
332
|
+
auth,
|
|
333
|
+
handler: async (_request, ctx) => {
|
|
334
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
335
|
+
const record = await engine.getOrRestoreSession(sessionId);
|
|
336
|
+
if (record === undefined) {
|
|
337
|
+
return errorResponse(
|
|
338
|
+
404,
|
|
339
|
+
"session_not_found",
|
|
340
|
+
`Unknown session ${sessionId}.`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
344
|
+
relax: relaxSessionReadAuth,
|
|
345
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
346
|
+
requestIp: ctx.requestIp,
|
|
347
|
+
});
|
|
348
|
+
if (ownership !== undefined) {
|
|
349
|
+
return ownership;
|
|
350
|
+
}
|
|
351
|
+
const payload = await engine.sessionCost(sessionId);
|
|
352
|
+
return jsonResponse(payload, {
|
|
353
|
+
headers: { [SESSION_ID_HEADER]: sessionId },
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
|
|
329
358
|
const listApprovals: ServerRoute = {
|
|
330
359
|
method: "GET",
|
|
331
360
|
pattern: `${base}/v1/session/:sessionId/approvals`,
|
|
@@ -459,6 +488,7 @@ export function buildHttpChannelRoutes(args: {
|
|
|
459
488
|
stop,
|
|
460
489
|
stream,
|
|
461
490
|
events,
|
|
491
|
+
cost,
|
|
462
492
|
listApprovals,
|
|
463
493
|
resolveApproval,
|
|
464
494
|
];
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
access,
|
|
12
|
+
chmod,
|
|
12
13
|
cp,
|
|
13
14
|
mkdir,
|
|
14
15
|
readdir,
|
|
15
16
|
readFile,
|
|
16
17
|
rm,
|
|
18
|
+
stat,
|
|
17
19
|
writeFile,
|
|
18
20
|
} from "node:fs/promises";
|
|
19
21
|
import { homedir } from "node:os";
|
|
@@ -146,6 +148,11 @@ export async function installCursorSkills(
|
|
|
146
148
|
for (const skill of skills) {
|
|
147
149
|
const target = skillInstallPath(skill, skillsHome);
|
|
148
150
|
await cp(skill.sourceDir, target, { recursive: true, force: true });
|
|
151
|
+
// cp() preserves source modes, and installs can come from read-only
|
|
152
|
+
// stores (Bazel runfiles, pnpm's content-addressed store, nix). Make the
|
|
153
|
+
// copies writable so the SKILL.md rewrite below and the overwrite on the
|
|
154
|
+
// next upgrade both work.
|
|
155
|
+
await makeTreeWritable(target);
|
|
149
156
|
const skillMdPath = join(target, "SKILL.md");
|
|
150
157
|
const raw = await readFile(skillMdPath, "utf8");
|
|
151
158
|
const adjusted = prepareSkillMarkdownForCursorInstall(raw);
|
|
@@ -157,6 +164,27 @@ export async function installCursorSkills(
|
|
|
157
164
|
return { installed, removed };
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
async function makeTreeWritable(root: string): Promise<void> {
|
|
168
|
+
await addOwnerWrite(root);
|
|
169
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
const child = join(root, entry.name);
|
|
172
|
+
if (entry.isDirectory()) {
|
|
173
|
+
await makeTreeWritable(child);
|
|
174
|
+
} else {
|
|
175
|
+
await addOwnerWrite(child);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Add owner-write, preserving every other mode bit (e.g. exec on scripts). */
|
|
181
|
+
async function addOwnerWrite(path: string): Promise<void> {
|
|
182
|
+
const mode = (await stat(path)).mode & 0o7777;
|
|
183
|
+
if ((mode & 0o200) === 0) {
|
|
184
|
+
await chmod(path, mode | 0o200);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
160
188
|
/** Installed leaf dirs the package no longer ships. Installing deletes these. */
|
|
161
189
|
async function orphanLeaves(
|
|
162
190
|
namespaceDir: string,
|
|
@@ -243,14 +271,14 @@ export async function planSkillInstall(options?: {
|
|
|
243
271
|
};
|
|
244
272
|
}
|
|
245
273
|
|
|
246
|
-
/** `Installed 9
|
|
274
|
+
/** `Installed 9 Agent SDK skills`, what it dropped, and where it went. */
|
|
247
275
|
export function formatSkillInstall(
|
|
248
276
|
plan: SkillInstallPlan,
|
|
249
277
|
result: SkillInstallResult
|
|
250
278
|
): string {
|
|
251
279
|
const noun = result.installed.length === 1 ? "skill" : "skills";
|
|
252
280
|
const verb = plan.firstInstall ? "Installed" : "Updated";
|
|
253
|
-
const lines = [`${verb} ${result.installed.length}
|
|
281
|
+
const lines = [`${verb} ${result.installed.length} Agent SDK ${noun}`];
|
|
254
282
|
if (result.removed.length > 0) {
|
|
255
283
|
lines.push(` removed: ${result.removed.join(", ")}`);
|
|
256
284
|
}
|
|
@@ -297,7 +325,7 @@ export async function offerInstallCursorSkills(
|
|
|
297
325
|
const verb = plan.firstInstall ? "Install" : "Update";
|
|
298
326
|
const c = stdoutPalette();
|
|
299
327
|
out(
|
|
300
|
-
`${verb} ${plan.shipped.length}
|
|
328
|
+
`${verb} ${plan.shipped.length} Agent SDK ${noun} in ${plan.directory}?\n`
|
|
301
329
|
);
|
|
302
330
|
out(c.dim(` ${plan.leaves.join(", ")}\n`));
|
|
303
331
|
if (!plan.firstInstall) {
|
|
@@ -91,7 +91,7 @@ export async function createLocalControlPlane(opts: {
|
|
|
91
91
|
}
|
|
92
92
|
void opts.fireSchedule(name).catch((error) => {
|
|
93
93
|
logger(
|
|
94
|
-
`[
|
|
94
|
+
`[agent-sdk] schedule "${name}" dispatch failed: ${
|
|
95
95
|
error instanceof Error ? error.message : String(error)
|
|
96
96
|
}`
|
|
97
97
|
);
|
|
@@ -127,7 +127,7 @@ export async function createLocalControlPlane(opts: {
|
|
|
127
127
|
}
|
|
128
128
|
void opts.fireReminder(current.id, current.fireCount).catch((error) => {
|
|
129
129
|
logger(
|
|
130
|
-
`[
|
|
130
|
+
`[agent-sdk] reminder "${current.id}" dispatch failed: ${
|
|
131
131
|
error instanceof Error ? error.message : String(error)
|
|
132
132
|
}`
|
|
133
133
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
2
|
+
* `agent-sdk logs` — follow deploy progress (hosted) then runtime `/v1/logs`.
|
|
3
3
|
*
|
|
4
4
|
* Customer-facing output never includes hosting URLs, tokens, or infra jargon.
|
|
5
5
|
*/
|
|
@@ -110,7 +110,7 @@ export function sanitizeCustomerError(message: string): string {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
* One-line label for `
|
|
113
|
+
* One-line label for `agent-sdk deploy` polling (TTY spinner / non-TTY
|
|
114
114
|
* transitions). Uses statusMessage → progress → raw status.
|
|
115
115
|
*/
|
|
116
116
|
export function deployProgressLabel(detail: {
|
|
@@ -106,7 +106,7 @@ export async function handleStatelessMcpRequest(args: {
|
|
|
106
106
|
// so closing in `finally` never truncates a streamed response.
|
|
107
107
|
return await transport.handleRequest(args.request);
|
|
108
108
|
} catch (error) {
|
|
109
|
-
logger(`[
|
|
109
|
+
logger(`[agent-sdk] ${args.label} request failed: ${describeError(error)}`);
|
|
110
110
|
return new Response(
|
|
111
111
|
JSON.stringify({
|
|
112
112
|
jsonrpc: "2.0",
|
|
@@ -278,7 +278,7 @@ export class HostMcpOAuthProvider implements OAuthClientProvider {
|
|
|
278
278
|
token_endpoint_auth_method: "none",
|
|
279
279
|
grant_types: ["authorization_code", "refresh_token"],
|
|
280
280
|
response_types: ["code"],
|
|
281
|
-
client_name: "
|
|
281
|
+
client_name: "Agent SDK",
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -432,7 +432,7 @@ export async function waitForMcpOAuthCallback(args?: {
|
|
|
432
432
|
res
|
|
433
433
|
.writeHead(200, { "content-type": "text/html; charset=utf-8" })
|
|
434
434
|
.end(
|
|
435
|
-
"<!doctype html><html><body><h1>Authorized</h1><p>Return to
|
|
435
|
+
"<!doctype html><html><body><h1>Authorized</h1><p>Return to Agent SDK.</p></body></html>"
|
|
436
436
|
);
|
|
437
437
|
finish({ code, state });
|
|
438
438
|
return;
|
|
@@ -32,7 +32,7 @@ export async function syncHostedPlatformSchedules(args: {
|
|
|
32
32
|
} catch (error) {
|
|
33
33
|
failedDeletes.push(name);
|
|
34
34
|
args.logger(
|
|
35
|
-
`[
|
|
35
|
+
`[agent-sdk] platform timer delete failed for schedule "${name}": ${
|
|
36
36
|
error instanceof Error ? error.message : String(error)
|
|
37
37
|
}`
|
|
38
38
|
);
|
|
@@ -47,7 +47,7 @@ export async function syncHostedPlatformSchedules(args: {
|
|
|
47
47
|
});
|
|
48
48
|
} catch (error) {
|
|
49
49
|
args.logger(
|
|
50
|
-
`[
|
|
50
|
+
`[agent-sdk] platform timer upsert failed for schedule "${schedule.name}": ${
|
|
51
51
|
error instanceof Error ? error.message : String(error)
|
|
52
52
|
}`
|
|
53
53
|
);
|
|
@@ -121,7 +121,7 @@ export async function runPlaygroundBuild(
|
|
|
121
121
|
"playground vite toolchain unavailable (need playground/ sources and the vite package)"
|
|
122
122
|
);
|
|
123
123
|
}
|
|
124
|
-
logger("[
|
|
124
|
+
logger("[agent-sdk] building playground (vite)...");
|
|
125
125
|
const code = await spawnVite(toolchain, ["build", "--config", VITE_CONFIG], {
|
|
126
126
|
env: process.env,
|
|
127
127
|
});
|
|
@@ -133,7 +133,7 @@ export async function runPlaygroundBuild(
|
|
|
133
133
|
"playground vite build finished but dist/playground/index.html is missing"
|
|
134
134
|
);
|
|
135
135
|
}
|
|
136
|
-
logger("[
|
|
136
|
+
logger("[agent-sdk] playground build complete");
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
@@ -149,7 +149,7 @@ export async function ensurePlaygroundBundle(
|
|
|
149
149
|
}
|
|
150
150
|
if (resolvePlaygroundToolchain() === undefined) {
|
|
151
151
|
logger(
|
|
152
|
-
"[
|
|
152
|
+
"[agent-sdk] playground bundle missing and vite toolchain unavailable; /playground will show a build hint"
|
|
153
153
|
);
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
@@ -215,7 +215,7 @@ export function startPlaygroundDevServer(options: {
|
|
|
215
215
|
child.stderr?.on("data", (chunk: Buffer) => {
|
|
216
216
|
const text = chunk.toString().trimEnd();
|
|
217
217
|
if (text !== "") {
|
|
218
|
-
logger(`[
|
|
218
|
+
logger(`[agent-sdk] playground: ${text}`);
|
|
219
219
|
}
|
|
220
220
|
});
|
|
221
221
|
|
|
@@ -225,7 +225,7 @@ export function startPlaygroundDevServer(options: {
|
|
|
225
225
|
return;
|
|
226
226
|
}
|
|
227
227
|
logger(
|
|
228
|
-
`[
|
|
228
|
+
`[agent-sdk] playground spawn failed: ${err.message} — static /playground still served when built`
|
|
229
229
|
);
|
|
230
230
|
});
|
|
231
231
|
child.on("exit", (code, signal) => {
|
|
@@ -234,7 +234,7 @@ export function startPlaygroundDevServer(options: {
|
|
|
234
234
|
}
|
|
235
235
|
if (code !== 0 && code !== null) {
|
|
236
236
|
logger(
|
|
237
|
-
`[
|
|
237
|
+
`[agent-sdk] playground exited (code ${code}${
|
|
238
238
|
signal ? `, signal ${signal}` : ""
|
|
239
239
|
}) — static /playground still served when built`
|
|
240
240
|
);
|