@cursor/july 0.1.108 → 0.1.109
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 +2 -6
- package/README.md +3 -6
- package/dist/channels/bitbucket/api.d.ts +41 -0
- package/dist/channels/bitbucket/api.d.ts.map +1 -1
- package/dist/channels/bitbucket/api.js +260 -0
- package/dist/channels/bitbucket/binding.d.ts +4 -0
- package/dist/channels/bitbucket/binding.d.ts.map +1 -1
- package/dist/channels/bitbucket/binding.js +16 -0
- package/dist/channels/bitbucket/index.d.ts +1 -1
- package/dist/channels/bitbucket/index.d.ts.map +1 -1
- package/dist/channels/bitbucket/index.js +1 -1
- package/dist/channels/gitlab/api.d.ts +27 -0
- package/dist/channels/gitlab/api.d.ts.map +1 -1
- package/dist/channels/gitlab/api.js +88 -0
- package/dist/channels/gitlab/binding.d.ts +5 -0
- package/dist/channels/gitlab/binding.d.ts.map +1 -1
- package/dist/channels/gitlab/binding.js +10 -0
- package/dist/channels/gitlab/index.d.ts +1 -1
- package/dist/channels/gitlab/index.d.ts.map +1 -1
- package/dist/channels/gitlab/index.js +1 -1
- package/dist/channels/slack/dispatch.d.ts +10 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +20 -3
- package/dist/channels/slack/slack-channel.d.ts +12 -5
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +59 -8
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BASKM3M4.js → app.Cr-wVbnB.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.js → building-with-agents.md.D0KbSkJn.js} +2 -2
- package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.lean.js → building-with-agents.md.D0KbSkJn.lean.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.CFVQ4S17.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BOKxlYGP.js → VPLocalSearchBox.CVQERt56.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DbDZW-zb.js → theme.Dnsd3XOn.js} +2 -2
- package/dist/docs/assets/concepts.md.B4o63Gul.js +1 -0
- package/dist/docs/assets/evals.md.C7JLjoEP.js +211 -0
- package/dist/docs/assets/evals.md.C7JLjoEP.lean.js +1 -0
- package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.js +10 -0
- package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.lean.js +1 -0
- package/dist/docs/assets/{guides_github.md.BH33UEBJ.js → guides_github.md.TZaTZlfz.js} +13 -3
- package/dist/docs/assets/{guides_github.md.BH33UEBJ.lean.js → guides_github.md.TZaTZlfz.lean.js} +1 -1
- package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.js +14 -0
- package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.lean.js +1 -0
- package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.js → guides_webhooks.md.CJK484ex.js} +2 -2
- package/dist/docs/assets/{hillclimbing.md.CpTGTCle.js → hillclimbing.md.BOiVo1tf.js} +1 -1
- package/dist/docs/assets/index.md.DD9Q2XuJ.js +5 -0
- package/dist/docs/assets/{index.md.BjH1w2ZW.lean.js → index.md.DD9Q2XuJ.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.D-qTqwcq.js → reference_channels.md.CAo-iK4j.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.D-qTqwcq.lean.js → reference_channels.md.CAo-iK4j.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.Ca26u0Es.js → reference_cli.md.Deg7849l.js} +1 -1
- package/dist/docs/assets/{reference_extensions.md.CPWt00ds.js → reference_extensions.md.ZAVUyuEX.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.js → reference_hooks.md.BlM_bOg6.js} +3 -3
- package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.lean.js → reference_hooks.md.BlM_bOg6.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.oySXBO8o.js → reference_http-api.md.BwaCo-VO.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.4myJPxrf.js → reference_playground.md.DLnoaczX.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.4myJPxrf.lean.js → reference_playground.md.DLnoaczX.lean.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.js → reference_project-layout.md.BEU8MtQV.js} +3 -3
- package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.lean.js → reference_project-layout.md.BEU8MtQV.lean.js} +1 -1
- package/dist/docs/assets/reference_sessions.md.CyXV1MUw.js +1 -0
- package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.js +35 -0
- package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.lean.js +1 -0
- package/dist/docs/assets/{skills_evals.md.BhovOvrl.js → skills_evals.md.DFxYPErF.js} +3 -3
- package/dist/docs/assets/skills_evals.md.DFxYPErF.lean.js +1 -0
- package/dist/docs/assets/{skills_framework-map.md.D-tFZhFS.js → skills_framework-map.md.BxLSOhSY.js} +1 -1
- package/dist/docs/assets/skills_index.md.DL7EHaQ-.js +1 -0
- package/dist/docs/assets/skills_index.md.DL7EHaQ-.lean.js +1 -0
- package/dist/docs/assets/{storage.md.BOHeqk2M.js → storage.md.BUrhJ-Zz.js} +4 -4
- package/dist/docs/assets/{storage.md.BOHeqk2M.lean.js → storage.md.BUrhJ-Zz.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/building-with-agents.md +3 -2
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/concepts.md +2 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +161 -35
- package/dist/docs/evals.md +612 -297
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/bitbucket.html +36 -0
- package/dist/docs/guides/bitbucket.md +84 -0
- package/dist/docs/guides/cloud-agents.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +17 -7
- package/dist/docs/guides/github.md +31 -0
- package/dist/docs/guides/gitlab.html +40 -0
- package/dist/docs/guides/gitlab.md +92 -0
- package/dist/docs/guides/grokbot-agents.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/improve.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +5 -5
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/guides/webhooks.md +4 -2
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/hillclimbing.md +2 -2
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +10 -6
- package/dist/docs/llms-full.txt +1113 -778
- package/dist/docs/llms.txt +6 -5
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +6 -6
- package/dist/docs/reference/channels.md +16 -3
- package/dist/docs/reference/cli.html +6 -6
- package/dist/docs/reference/cli.md +6 -4
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/extensions.html +7 -7
- package/dist/docs/reference/extensions.md +0 -3
- package/dist/docs/reference/hooks.html +7 -7
- package/dist/docs/reference/hooks.md +9 -12
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +2 -3
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/playground.md +0 -4
- package/dist/docs/reference/project-layout.html +7 -7
- package/dist/docs/reference/project-layout.md +1 -8
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/result.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/sessions.md +1 -2
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/skills/create-agent.html +4 -4
- package/dist/docs/skills/debug.html +4 -4
- package/dist/docs/skills/deploy.html +61 -0
- package/dist/docs/skills/deploy.md +161 -0
- package/dist/docs/skills/evals.html +8 -8
- package/dist/docs/skills/evals.md +44 -6
- package/dist/docs/skills/framework-map.html +5 -5
- package/dist/docs/skills/framework-map.md +1 -2
- package/dist/docs/skills/github.html +4 -4
- package/dist/docs/skills/hillclimb.html +4 -4
- package/dist/docs/skills/index.html +6 -6
- package/dist/docs/skills/index.md +1 -1
- package/dist/docs/skills/mcp-auth.html +4 -4
- package/dist/docs/skills/otel.html +4 -4
- package/dist/docs/skills/setup-slack.html +4 -4
- package/dist/docs/storage.html +8 -8
- package/dist/docs/storage.md +15 -24
- 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/grokbot-agents.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +4 -4
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/extensions.d.ts +2 -3
- package/dist/extensions.d.ts.map +1 -1
- package/dist/extensions.js +2 -5
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/internal/authored-alias-hooks.d.ts +5 -0
- package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
- package/dist/internal/authored-alias-hooks.js +17 -0
- package/dist/internal/authored-loaders.d.ts +4 -0
- package/dist/internal/authored-loaders.d.ts.map +1 -1
- package/dist/internal/authored-loaders.js +21 -2
- package/dist/internal/cli-ax.d.ts +1 -2
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +1 -2
- package/dist/internal/continuation-channel.d.ts.map +1 -1
- package/dist/internal/continuation-channel.js +2 -2
- package/dist/internal/continuation-identity.js +8 -3
- package/dist/internal/discovery/agent.d.ts +1 -1
- package/dist/internal/discovery/agent.d.ts.map +1 -1
- package/dist/internal/discovery/agent.js +0 -5
- package/dist/internal/discovery/extension-overlay.d.ts +1 -2
- package/dist/internal/discovery/extension-overlay.d.ts.map +1 -1
- package/dist/internal/discovery/extension-overlay.js +0 -14
- package/dist/internal/discovery/extensions.d.ts +1 -2
- package/dist/internal/discovery/extensions.d.ts.map +1 -1
- package/dist/internal/discovery/extensions.js +4 -22
- package/dist/internal/discovery/info.d.ts.map +1 -1
- package/dist/internal/discovery/info.js +42 -24
- package/dist/internal/discovery/modules.js +0 -1
- package/dist/internal/discovery/project.d.ts.map +1 -1
- package/dist/internal/discovery/project.js +0 -16
- package/dist/internal/eval-runner.js +0 -1
- package/dist/internal/framework-file-storage.d.ts +4 -5
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +4 -5
- package/dist/internal/framework-storage-selection.d.ts +2 -2
- package/dist/internal/framework-storage-selection.js +2 -2
- package/dist/internal/init-scaffold.d.ts.map +1 -1
- package/dist/internal/init-scaffold.js +1 -2
- package/dist/internal/install-cursor-skills.d.ts +5 -2
- package/dist/internal/install-cursor-skills.d.ts.map +1 -1
- package/dist/internal/install-cursor-skills.js +25 -5
- package/dist/internal/run-client.d.ts +1 -1
- package/dist/internal/sdk-runner.js +1 -1
- package/dist/internal/server.js +0 -14
- package/dist/internal/session-engine.d.ts +5 -35
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +17 -162
- package/dist/internal/storage-coordinator.d.ts +5 -19
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +3 -62
- package/dist/internal/storage-roles.d.ts +4 -9
- package/dist/internal/storage-roles.d.ts.map +1 -1
- package/dist/internal/storage-roles.js +2 -2
- package/dist/playground/assets/index-Bhxzrcf6.css +1 -0
- package/dist/playground/assets/index-CqLX5uF3.js +67 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted-v2.d.ts +4 -5
- package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted-v2.js +4 -5
- package/dist/storage-backends/cursor-hosted.d.ts +1 -2
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +0 -30
- package/dist/storage-backends/file-kv.d.ts +9 -12
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +11 -47
- package/dist/storage-protocol.d.ts +3 -11
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +3 -11
- package/dist/storage.d.ts +8 -36
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +8 -44
- package/dist/types.d.ts +20 -57
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +10 -6
- package/docs/building-with-agents.md +3 -2
- package/docs/concepts.md +2 -4
- package/docs/evals.md +613 -298
- package/docs/guides/bitbucket.md +89 -0
- package/docs/guides/github.md +31 -0
- package/docs/guides/gitlab.md +97 -0
- package/docs/guides/webhooks.md +4 -2
- package/docs/hillclimbing.md +2 -2
- package/docs/reference/channels.md +16 -3
- package/docs/reference/cli.md +6 -4
- package/docs/reference/extensions.md +0 -3
- package/docs/reference/hooks.md +9 -12
- package/docs/reference/http-api.md +2 -3
- package/docs/reference/playground.md +0 -4
- package/docs/reference/project-layout.md +1 -8
- package/docs/reference/sessions.md +1 -2
- package/docs/skills/index.md +2 -2
- package/docs/storage.md +15 -24
- package/package.json +1 -7
- package/skills/deploy/SKILL.md +169 -0
- package/skills/evals/SKILL.md +45 -8
- package/skills/framework-map/SKILL.md +1 -2
- package/src/channels/bitbucket/api.ts +341 -0
- package/src/channels/bitbucket/binding.ts +25 -0
- package/src/channels/bitbucket/index.ts +2 -0
- package/src/channels/gitlab/api.ts +123 -0
- package/src/channels/gitlab/binding.ts +12 -0
- package/src/channels/gitlab/index.ts +1 -0
- package/src/channels/slack/dispatch.ts +30 -0
- package/src/channels/slack/slack-channel.ts +69 -7
- package/src/extensions.ts +2 -6
- package/src/index.ts +0 -3
- package/src/internal/authored-alias-hooks.ts +32 -0
- package/src/internal/authored-loaders.ts +26 -2
- package/src/internal/cli-ax.ts +1 -2
- package/src/internal/continuation-channel.ts +2 -1
- package/src/internal/continuation-identity.ts +10 -2
- package/src/internal/discovery/agent.ts +1 -7
- package/src/internal/discovery/extension-overlay.ts +0 -18
- package/src/internal/discovery/extensions.ts +2 -26
- package/src/internal/discovery/info.ts +3 -13
- package/src/internal/discovery/modules.ts +0 -1
- package/src/internal/discovery/project.ts +0 -16
- package/src/internal/eval-runner.ts +0 -1
- package/src/internal/framework-file-storage.ts +4 -5
- package/src/internal/framework-storage-selection.ts +2 -2
- package/src/internal/init-scaffold.ts +1 -2
- package/src/internal/install-cursor-skills.ts +38 -5
- package/src/internal/run-client.ts +1 -1
- package/src/internal/sdk-runner.ts +1 -1
- package/src/internal/server.ts +0 -16
- package/src/internal/session-engine.ts +14 -202
- package/src/internal/storage-coordinator.ts +5 -76
- package/src/internal/storage-roles.ts +4 -9
- package/src/storage-backends/cursor-hosted-v2.ts +4 -7
- package/src/storage-backends/cursor-hosted.ts +0 -37
- package/src/storage-backends/file-kv.ts +10 -51
- package/src/storage-protocol.ts +3 -17
- package/src/storage.ts +10 -101
- package/src/types.ts +19 -56
- package/templates/demo/README.md +10 -6
- package/templates/demo/agent/channels/github.ts +2 -0
- package/templates/demo/agent/channels/queue.ts +6 -2
- package/templates/demo/agent/lib/repos.ts +5 -0
- package/templates/demo/init.json +25 -0
- package/dist/ab.d.ts +0 -209
- package/dist/ab.d.ts.map +0 -1
- package/dist/ab.js +0 -246
- package/dist/docs/ab.html +0 -80
- package/dist/docs/ab.md +0 -332
- package/dist/docs/assets/ab.md.mlVgqvSk.js +0 -54
- package/dist/docs/assets/ab.md.mlVgqvSk.lean.js +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BHZYsNVi.js +0 -1
- package/dist/docs/assets/concepts.md.DgEcZOfT.js +0 -1
- package/dist/docs/assets/evals.md.C1ekS3k2.js +0 -85
- package/dist/docs/assets/evals.md.C1ekS3k2.lean.js +0 -1
- package/dist/docs/assets/index.md.BjH1w2ZW.js +0 -5
- package/dist/docs/assets/reference_sessions.md.CueyOHSL.js +0 -1
- package/dist/docs/assets/skills_ab.md.CsFNatVx.js +0 -26
- package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +0 -1
- package/dist/docs/assets/skills_evals.md.BhovOvrl.lean.js +0 -1
- package/dist/docs/assets/skills_index.md.DKwIxzGg.js +0 -1
- package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +0 -1
- package/dist/docs/skills/ab.html +0 -52
- package/dist/docs/skills/ab.md +0 -50
- package/dist/internal/ab-collector.d.ts +0 -44
- package/dist/internal/ab-collector.d.ts.map +0 -1
- package/dist/internal/ab-collector.js +0 -142
- package/dist/internal/ab-fold.d.ts +0 -36
- package/dist/internal/ab-fold.d.ts.map +0 -1
- package/dist/internal/ab-fold.js +0 -175
- package/dist/internal/ab-snapshot.d.ts +0 -68
- package/dist/internal/ab-snapshot.d.ts.map +0 -1
- package/dist/internal/ab-snapshot.js +0 -208
- package/dist/internal/discovery/ab.d.ts +0 -9
- package/dist/internal/discovery/ab.d.ts.map +0 -1
- package/dist/internal/discovery/ab.js +0 -113
- package/dist/playground/assets/index-BMDqAeXu.js +0 -67
- package/dist/playground/assets/index-LUgJoWdL.css +0 -1
- package/docs/ab.md +0 -337
- package/skills/ab/SKILL.md +0 -58
- package/src/ab.ts +0 -430
- package/src/internal/ab-collector.ts +0 -200
- package/src/internal/ab-fold.ts +0 -232
- package/src/internal/ab-snapshot.ts +0 -331
- package/src/internal/discovery/ab.ts +0 -131
- /package/dist/docs/assets/{concepts.md.DgEcZOfT.lean.js → concepts.md.B4o63Gul.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.lean.js → guides_webhooks.md.CJK484ex.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.CpTGTCle.lean.js → hillclimbing.md.BOiVo1tf.lean.js} +0 -0
- /package/dist/docs/assets/{reference_cli.md.Ca26u0Es.lean.js → reference_cli.md.Deg7849l.lean.js} +0 -0
- /package/dist/docs/assets/{reference_extensions.md.CPWt00ds.lean.js → reference_extensions.md.ZAVUyuEX.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.oySXBO8o.lean.js → reference_http-api.md.BwaCo-VO.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.CueyOHSL.lean.js → reference_sessions.md.CyXV1MUw.lean.js} +0 -0
- /package/dist/docs/assets/{skills_framework-map.md.D-tFZhFS.lean.js → skills_framework-map.md.BxLSOhSY.lean.js} +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentsdk-deploy
|
|
3
|
+
description: >-
|
|
4
|
+
Deploy or redeploy an Agent SDK project to Cursor-managed hosting
|
|
5
|
+
with an attached service account. Use when asked to deploy,
|
|
6
|
+
redeploy, publish, or update a hosted Agent SDK agent.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Deploy an Agent SDK agent
|
|
10
|
+
|
|
11
|
+
Use this skill only after a person asks for a deployment. It deploys a
|
|
12
|
+
pushed Git ref to Cursor-managed hosting. Local files never upload.
|
|
13
|
+
|
|
14
|
+
Use the exact published `@cursor/july` release embedded in the installed
|
|
15
|
+
skill. Do not use a floating npm tag or a workspace build of the CLI.
|
|
16
|
+
|
|
17
|
+
## Gather the target
|
|
18
|
+
|
|
19
|
+
Resolve these values from the request and checkout:
|
|
20
|
+
|
|
21
|
+
- Agent directory. Default to the current directory only when it contains
|
|
22
|
+
one Agent SDK project.
|
|
23
|
+
- Deployment slug. Default to the normalized directory name.
|
|
24
|
+
- Git ref. Default to the exact pushed `HEAD` commit.
|
|
25
|
+
- Team. Use the service account's team unless the request names another.
|
|
26
|
+
- Cursor-event repositories and CLI-only egress domains.
|
|
27
|
+
|
|
28
|
+
Ask one focused question when the target or requested ref is ambiguous.
|
|
29
|
+
Do not ask for values the checkout or existing deployment supplies.
|
|
30
|
+
|
|
31
|
+
## Use the attached service account
|
|
32
|
+
|
|
33
|
+
Continue only when `CURSOR_SERVICE_ACCOUNT_KEY` is present. Never print
|
|
34
|
+
the value. Do not run `agent-sdk login`.
|
|
35
|
+
|
|
36
|
+
On Linux and macOS, run every Agent SDK command through this wrapper:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
CURSOR_JULY_VERSION="__CURSOR_JULY_VERSION__"
|
|
40
|
+
case "$CURSOR_JULY_VERSION" in
|
|
41
|
+
__CURSOR_JULY_*__)
|
|
42
|
+
echo "The Agent SDK deploy skill is not bound to a package version." >&2
|
|
43
|
+
exit 1
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
run_agent_sdk() {
|
|
48
|
+
env -u NODE_OPTIONS -u CURSOR_API_KEY \
|
|
49
|
+
CURSOR_API_KEY_FILE=/dev/null \
|
|
50
|
+
npx --yes "@cursor/july@$CURSOR_JULY_VERSION" "$@"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The installed copy pins the release it came from. The wrapper isolates that
|
|
55
|
+
published CLI and the attached service account. The presence check prevents a
|
|
56
|
+
stored personal login from being used when the attachment is missing.
|
|
57
|
+
|
|
58
|
+
Verify the principal before any write:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
test -n "${CURSOR_SERVICE_ACCOUNT_KEY:-}" || {
|
|
62
|
+
echo "No attached Cursor service account." >&2
|
|
63
|
+
exit 1
|
|
64
|
+
}
|
|
65
|
+
run_agent_sdk whoami --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Continue only when `credentialSource` is `service-account`. Record the
|
|
69
|
+
team and complete service-account ID for the final report. Stop on an
|
|
70
|
+
authentication, team-access, repository-scope, or hosting-entitlement
|
|
71
|
+
error.
|
|
72
|
+
|
|
73
|
+
## Pin pushed source
|
|
74
|
+
|
|
75
|
+
Find the Git root and commit:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
GIT_ROOT="$(git -C "$AGENT_DIR" rev-parse --show-toplevel)"
|
|
79
|
+
SOURCE_REF="$(git -C "$GIT_ROOT" rev-parse HEAD)"
|
|
80
|
+
git -C "$GIT_ROOT" status --short
|
|
81
|
+
git -C "$GIT_ROOT" branch -r --contains "$SOURCE_REF"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use a ref from the request instead of `SOURCE_REF` when the person names
|
|
85
|
+
one. Confirm the selected commit exists on the remote. If intended
|
|
86
|
+
changes are uncommitted or unpushed, stop and explain they will not ship.
|
|
87
|
+
Do not commit or push unless the request includes that work.
|
|
88
|
+
|
|
89
|
+
The CLI infers the normalized HTTPS `origin`, agent path, and slug from
|
|
90
|
+
`--dir`. Pass `--repo`, `--path`, or `--slug` when the request overrides
|
|
91
|
+
the inferred value. Never print a remote URL that contains credentials.
|
|
92
|
+
|
|
93
|
+
## Preserve deployment inputs
|
|
94
|
+
|
|
95
|
+
A redeploy replaces its source, Cursor-event repositories, and
|
|
96
|
+
CLI-supplied egress domains. Preserve the existing
|
|
97
|
+
`cursorEventRepos` and `egressAllowedDomains` unless the request or
|
|
98
|
+
project changes them. Reapply each value with:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
--cursor-events-repo <owner/repo>
|
|
102
|
+
--allow-domain <hostname>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Read existing settings through a filter that selects only those two
|
|
106
|
+
fields:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
run_agent_sdk deployment "$SLUG" --json |
|
|
110
|
+
node -e '
|
|
111
|
+
let raw = "";
|
|
112
|
+
process.stdin.setEncoding("utf8");
|
|
113
|
+
process.stdin.on("data", (chunk) => { raw += chunk; });
|
|
114
|
+
process.stdin.on("end", () => {
|
|
115
|
+
const value = JSON.parse(raw);
|
|
116
|
+
console.log(JSON.stringify({
|
|
117
|
+
cursorEventRepos: value.cursorEventRepos ?? [],
|
|
118
|
+
egressAllowedDomains: value.egressAllowedDomains ?? [],
|
|
119
|
+
}, null, 2));
|
|
120
|
+
});
|
|
121
|
+
'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Never print or save the full response because it can contain short-lived
|
|
125
|
+
engine-access headers.
|
|
126
|
+
|
|
127
|
+
For a new SCM-channel deployment, ask which repositories should wake the
|
|
128
|
+
agent when the project does not declare the answer. The source repository
|
|
129
|
+
is not always the event repository.
|
|
130
|
+
|
|
131
|
+
## Validate, deploy, and verify
|
|
132
|
+
|
|
133
|
+
Validate with the same published package and principal:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
run_agent_sdk validate --dir "$AGENT_DIR"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Stop on validation errors. Review hosting warnings about secret names,
|
|
140
|
+
egress domains, and channel configuration before continuing.
|
|
141
|
+
|
|
142
|
+
Deploy the pinned source. Add the preserved or requested repeatable
|
|
143
|
+
flags:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
run_agent_sdk deploy \
|
|
147
|
+
--dir "$AGENT_DIR" \
|
|
148
|
+
--ref "$SOURCE_REF"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The command waits for a terminal deployment state. Do not treat
|
|
152
|
+
`pending`, `accepted`, or `deploying` as success. If the command is
|
|
153
|
+
interrupted, resume inspection with:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
run_agent_sdk deployment "$SLUG"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
A first deployment prints a one-time alias token. Never paste it into
|
|
160
|
+
chat or expose it in an agent-captured terminal. Before a first deploy,
|
|
161
|
+
ask for a secure destination or ask the person to run the final command
|
|
162
|
+
in a private terminal. When writing the token, use mode `0600` and print
|
|
163
|
+
only the path. Redeploys do not print the token. JSON deployment output
|
|
164
|
+
can also contain credentials, so filter it before display.
|
|
165
|
+
|
|
166
|
+
Finish only when the deployment reports `running`. Report the slug,
|
|
167
|
+
team, generation, pinned ref, and complete service-account ID. On
|
|
168
|
+
failure, report the deployment status and sanitized error without
|
|
169
|
+
retrying a different ref or principal.
|
package/skills/evals/SKILL.md
CHANGED
|
@@ -3,17 +3,17 @@ name: agentsdk-evals
|
|
|
3
3
|
description: >-
|
|
4
4
|
Author and run defineEval cases. Use when writing, fixing, seeding,
|
|
5
5
|
or hillclimbing evals. Ask whether to generate samples or take
|
|
6
|
-
uploaded data. Materialize API-backed fixtures first.
|
|
7
|
-
defineAB (skills/ab), not defineEval.
|
|
6
|
+
uploaded data. Materialize API-backed fixtures first.
|
|
8
7
|
---
|
|
9
8
|
|
|
10
9
|
# Agent SDK evals
|
|
11
10
|
|
|
12
11
|
Fixed input, model turn, gates on the trajectory. Files live at
|
|
13
12
|
project-root `evals/**/*.eval.ts`. `agent/evals/` is ignored.
|
|
13
|
+
Guide: `docs/evals.md`.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
Observing production: hooks. Tool logic without a model:
|
|
16
|
+
`agent-sdk call <tool> --input '{...}'`.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
agent-sdk eval --dir . --list
|
|
@@ -27,9 +27,13 @@ agent-sdk eval --dir . --tag smoke
|
|
|
27
27
|
| `evals/weather.eval.ts` + `test` | `weather` |
|
|
28
28
|
| `evals/weather/nyc.eval.ts` + `test` | `weather/nyc` |
|
|
29
29
|
| `evals/weather.eval.ts` + `{ id: "nyc" }` | `weather/nyc` |
|
|
30
|
+
| `evals/sql.eval.ts` exporting an array of `defineEval` calls | `sql/0000`, `sql/0001`, ... |
|
|
30
31
|
|
|
31
32
|
`eval` boots an ephemeral server and a temp state root. `--url`
|
|
32
|
-
points at a running agent. Model turns need a Cursor credential
|
|
33
|
+
points at a running agent. Model turns need a Cursor credential
|
|
34
|
+
(`CURSOR_API_KEY`, then `CURSOR_API_KEY_FILE`, then
|
|
35
|
+
`CURSOR_SERVICE_ACCOUNT_KEY`, then `agent-sdk login`); `--list` does
|
|
36
|
+
not. Node 22.13+, never Bun.
|
|
33
37
|
|
|
34
38
|
## Seeding
|
|
35
39
|
|
|
@@ -79,9 +83,30 @@ export default defineEvalConfig({
|
|
|
79
83
|
});
|
|
80
84
|
```
|
|
81
85
|
|
|
82
|
-
Either `test(t)` or `cases`, not both. `t.send` waits for
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
Either `test(t)` or `cases`, not both. `t.send` waits for the turn to
|
|
87
|
+
settle (complete, park, or fail) and returns it; `turn.calledTool(...)`
|
|
88
|
+
reads only that turn, `t.*` reads the whole run. First-send options:
|
|
89
|
+
`workspaceFiles`, `workspaceDir`, `cloud`.
|
|
90
|
+
|
|
91
|
+
Gates: `t.succeeded()` / `t.parked()`,
|
|
92
|
+
`calledTool(name, { input, output, status, count })` / `notCalledTool`,
|
|
93
|
+
`toolOrder`, `maxToolCalls`, `taggedArtifact`, `event` / `notEvent`,
|
|
94
|
+
`t.check(value, includes | equals | matches | similarity | satisfies)`.
|
|
95
|
+
Records: `t.metric`, `t.log`, `t.score` (soft 0-1).
|
|
96
|
+
|
|
97
|
+
Severity is on the handle: default gate; `.soft()` tracked;
|
|
98
|
+
`.atLeast(0.8)` soft with a bar (verdict `scored`, exit 1 only under
|
|
99
|
+
`--strict`); `.gate(0.8)` hard. `t.judge.factuality`, `summarizes`,
|
|
100
|
+
`closedQA`, and `sql` are soft by default and need a judge model
|
|
101
|
+
(`judge` in `evals.config.ts`, on the eval or case, or per-call
|
|
102
|
+
`{ model }`).
|
|
103
|
+
|
|
104
|
+
## Side effects
|
|
105
|
+
|
|
106
|
+
Eval sessions run real tools. Guard actuation with
|
|
107
|
+
`ctx.session.purpose === "eval"` in the tool, hook, or `defineResult`
|
|
108
|
+
and return a shaped result so `calledTool` can still assert the
|
|
109
|
+
decision.
|
|
85
110
|
|
|
86
111
|
## What to gate
|
|
87
112
|
|
|
@@ -103,6 +128,18 @@ drifting inputs (pin them).
|
|
|
103
128
|
| GitHub | `github replay … --dry-run --out fixtures/github` |
|
|
104
129
|
| Host-prep PR review | A team-owned PR; gate findings shape, not counts |
|
|
105
130
|
| Workspace | `workspaceFiles` in `t.send` |
|
|
131
|
+
| Dataset | `loadJson` / `loadJsonl` / `loadYaml` from `@cursor/july/evals/loaders`, paths from the project root |
|
|
132
|
+
|
|
133
|
+
## Debug and CI
|
|
134
|
+
|
|
135
|
+
A failed local run leaves `evals/<case-id>.json` (assertions, inputs,
|
|
136
|
+
tool I/O, final text, logs) under `evals/<stamp>/` in the project state
|
|
137
|
+
directory (the CLI prints the path); read it before editing the eval.
|
|
138
|
+
`--state-root <path>` keeps the raw session events too.
|
|
139
|
+
|
|
140
|
+
CI: `agent-sdk eval --dir . --json --no-stream --junit reports/evals.xml`.
|
|
141
|
+
Exit `1` on a failed gate, `2` when nothing matched, `--strict` to fail
|
|
142
|
+
on `scored`.
|
|
106
143
|
|
|
107
144
|
Every kept hillclimb change lands an eval that would have failed
|
|
108
145
|
before it. Never weaken a gate to pass a round.
|
|
@@ -51,7 +51,6 @@ Path is identity. Full list: README "Folder structure".
|
|
|
51
51
|
| `agent/hooks/*.ts` | Observe-only |
|
|
52
52
|
| `agent/artifacts.ts` | Durable tagged outputs (`defineArtifacts`) |
|
|
53
53
|
| `agent/result.ts` | Host `commit` on the final assistant text (`defineResult`) |
|
|
54
|
-
| `agent/ab.ts` or `agent/ab/*.ts` | Live A/B (`defineAB`) |
|
|
55
54
|
| `agent/otel.ts` | OpenTelemetry (`defineOtel`) |
|
|
56
55
|
| `agent/schedules/*` | Cron. Never auto-fire under `--dev` |
|
|
57
56
|
| `agent/sandbox/workspace/` | Session seed files (local only) |
|
|
@@ -99,10 +98,10 @@ only this agent's directory.
|
|
|
99
98
|
| --- | --- |
|
|
100
99
|
| Scaffold | `skills/create-agent/SKILL.md` |
|
|
101
100
|
| Evals | `skills/evals/SKILL.md` |
|
|
102
|
-
| Live A/B | `skills/ab/SKILL.md` |
|
|
103
101
|
| OpenTelemetry | `skills/otel/SKILL.md` |
|
|
104
102
|
| GitHub | `skills/github/SKILL.md` |
|
|
105
103
|
| Slack | `skills/setup-slack/SKILL.md` |
|
|
106
104
|
| Host MCP OAuth | `skills/mcp-auth/SKILL.md` |
|
|
105
|
+
| Managed deployment | `skills/deploy/SKILL.md` |
|
|
107
106
|
| Local triage | `skills/debug/SKILL.md` |
|
|
108
107
|
| Measured improvement | `skills/hillclimb/SKILL.md` |
|
|
@@ -290,6 +290,8 @@ export interface BitbucketApiPullRequest {
|
|
|
290
290
|
title?: string;
|
|
291
291
|
description?: string;
|
|
292
292
|
state?: string;
|
|
293
|
+
draft?: boolean;
|
|
294
|
+
authorUsername?: string;
|
|
293
295
|
sourceBranch?: string;
|
|
294
296
|
targetBranch?: string;
|
|
295
297
|
headSha?: string;
|
|
@@ -298,6 +300,20 @@ export interface BitbucketApiPullRequest {
|
|
|
298
300
|
raw: unknown;
|
|
299
301
|
}
|
|
300
302
|
|
|
303
|
+
export interface BitbucketApiChangedFile {
|
|
304
|
+
path: string;
|
|
305
|
+
previousPath?: string;
|
|
306
|
+
status: "added" | "modified" | "removed" | "renamed";
|
|
307
|
+
patch?: string;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface BitbucketPullRequestDiffInput {
|
|
311
|
+
headSha?: string;
|
|
312
|
+
baseSha?: string;
|
|
313
|
+
mergeBaseSha?: string;
|
|
314
|
+
mergeBaseResolved?: boolean;
|
|
315
|
+
}
|
|
316
|
+
|
|
301
317
|
/**
|
|
302
318
|
* The handful of operations review products need, implemented once per
|
|
303
319
|
* dialect. `ctx.bitbucket.api` is the repo-bound instance.
|
|
@@ -318,6 +334,30 @@ export interface BitbucketApi {
|
|
|
318
334
|
getFileAtRef(path: string, ref: string): Promise<string>;
|
|
319
335
|
}
|
|
320
336
|
|
|
337
|
+
export interface BitbucketPullRequestReadApi {
|
|
338
|
+
getPullRequest(id: number): Promise<BitbucketApiPullRequest>;
|
|
339
|
+
getMergeBaseSha(
|
|
340
|
+
id: number,
|
|
341
|
+
base: string,
|
|
342
|
+
headSha: string
|
|
343
|
+
): Promise<string | undefined>;
|
|
344
|
+
listChangedFiles(
|
|
345
|
+
id: number,
|
|
346
|
+
input?: BitbucketPullRequestDiffInput
|
|
347
|
+
): Promise<BitbucketApiChangedFile[]>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export interface BitbucketPullRequestReadClient {
|
|
351
|
+
readonly repository: BitbucketRepositoryRef;
|
|
352
|
+
readonly api: Pick<BitbucketApi, "getPullRequest" | "getPullRequestDiff">;
|
|
353
|
+
request<T = unknown>(input: BitbucketRequestInput): Promise<T>;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export type BitbucketPullRequestReadDiagnostic =
|
|
357
|
+
| { kind: "commit-expansion-failed"; sha: string; error: unknown }
|
|
358
|
+
| { kind: "diff-fallback"; status: number }
|
|
359
|
+
| { kind: "metadata-fallback"; status: number };
|
|
360
|
+
|
|
321
361
|
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
322
362
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
323
363
|
? (value as Record<string, unknown>)
|
|
@@ -334,6 +374,111 @@ function num(value: unknown): number | undefined {
|
|
|
334
374
|
: undefined;
|
|
335
375
|
}
|
|
336
376
|
|
|
377
|
+
function errorStatus(error: unknown): number | undefined {
|
|
378
|
+
return num(asRecord(error)?.status);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function bitbucketAuthorUsername(raw: unknown): string | undefined {
|
|
382
|
+
const author = asRecord(asRecord(raw)?.author);
|
|
383
|
+
const user = asRecord(author?.user);
|
|
384
|
+
return (
|
|
385
|
+
str(author?.nickname) ??
|
|
386
|
+
str(user?.name) ??
|
|
387
|
+
str(user?.slug) ??
|
|
388
|
+
str(author?.display_name) ??
|
|
389
|
+
str(user?.displayName)
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const GIT_PATH_ESCAPES: Readonly<Record<string, string>> = {
|
|
394
|
+
a: "\u0007",
|
|
395
|
+
b: "\b",
|
|
396
|
+
f: "\f",
|
|
397
|
+
n: "\n",
|
|
398
|
+
r: "\r",
|
|
399
|
+
t: "\t",
|
|
400
|
+
v: "\v",
|
|
401
|
+
"\\": "\\",
|
|
402
|
+
'"': '"',
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
function unescapeGitPath(path: string, quoted: boolean): string {
|
|
406
|
+
if (!quoted) {
|
|
407
|
+
return path;
|
|
408
|
+
}
|
|
409
|
+
const bytes: number[] = [];
|
|
410
|
+
let output = "";
|
|
411
|
+
const flush = () => {
|
|
412
|
+
if (bytes.length > 0) {
|
|
413
|
+
output += Buffer.from(bytes).toString("utf8");
|
|
414
|
+
bytes.length = 0;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
for (let index = 0; index < path.length; index += 1) {
|
|
418
|
+
const character = path[index] as string;
|
|
419
|
+
if (character !== "\\") {
|
|
420
|
+
flush();
|
|
421
|
+
output += character;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const octal = /^[0-7]{1,3}/.exec(path.slice(index + 1));
|
|
425
|
+
if (octal !== null) {
|
|
426
|
+
bytes.push(Number.parseInt(octal[0], 8));
|
|
427
|
+
index += octal[0].length;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
flush();
|
|
431
|
+
const next = path[index + 1] ?? "";
|
|
432
|
+
output += GIT_PATH_ESCAPES[next] ?? next;
|
|
433
|
+
index += 1;
|
|
434
|
+
}
|
|
435
|
+
flush();
|
|
436
|
+
return output;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Split a Git-style unified diff into normalized changed files. */
|
|
440
|
+
export function splitBitbucketUnifiedDiff(
|
|
441
|
+
diff: string
|
|
442
|
+
): BitbucketApiChangedFile[] {
|
|
443
|
+
const files: BitbucketApiChangedFile[] = [];
|
|
444
|
+
const sections = diff.split(/^(?=diff --git )/m).filter(Boolean);
|
|
445
|
+
for (const section of sections) {
|
|
446
|
+
const lines = section.replace(/\n$/, "").split("\n");
|
|
447
|
+
const header = /^diff --git ("?)a\/(.+?)\1 ("?)b\/(.+?)\3$/.exec(
|
|
448
|
+
lines[0] ?? ""
|
|
449
|
+
);
|
|
450
|
+
if (header === null) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
const oldPath = unescapeGitPath(header[2] ?? "", header[1] !== "");
|
|
454
|
+
const newPath = unescapeGitPath(header[4] ?? "", header[3] !== "");
|
|
455
|
+
let status: BitbucketApiChangedFile["status"] = "modified";
|
|
456
|
+
let bodyStart = 1;
|
|
457
|
+
for (; bodyStart < lines.length; bodyStart += 1) {
|
|
458
|
+
const line = lines[bodyStart] ?? "";
|
|
459
|
+
if (line.startsWith("@@")) {
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
if (line === "--- /dev/null") {
|
|
463
|
+
status = "added";
|
|
464
|
+
} else if (line === "+++ /dev/null") {
|
|
465
|
+
status = "removed";
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (status === "modified" && oldPath !== newPath) {
|
|
469
|
+
status = "renamed";
|
|
470
|
+
}
|
|
471
|
+
const patch = lines.slice(bodyStart).join("\n");
|
|
472
|
+
files.push({
|
|
473
|
+
path: newPath,
|
|
474
|
+
previousPath: status === "renamed" ? oldPath : undefined,
|
|
475
|
+
status,
|
|
476
|
+
patch: patch === "" ? undefined : patch,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
return files;
|
|
480
|
+
}
|
|
481
|
+
|
|
337
482
|
function encodePath(path: string): string {
|
|
338
483
|
return path
|
|
339
484
|
.split("/")
|
|
@@ -367,6 +512,202 @@ export function bitbucketDataCenterRepoPath(repository: {
|
|
|
367
512
|
return `/projects/${encodeURIComponent(repository.owner)}/repos/${encodeURIComponent(repository.slug)}`;
|
|
368
513
|
}
|
|
369
514
|
|
|
515
|
+
export async function expandBitbucketCloudCommitSha(
|
|
516
|
+
bitbucket: Pick<BitbucketClient, "request">,
|
|
517
|
+
repository: Pick<BitbucketRepositoryRef, "owner" | "slug">,
|
|
518
|
+
sha: string | undefined,
|
|
519
|
+
onError?: (error: unknown) => void
|
|
520
|
+
): Promise<string | undefined> {
|
|
521
|
+
if (sha === undefined || !/^[0-9a-f]{7,39}$/i.test(sha)) {
|
|
522
|
+
return sha;
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
const commit = await bitbucket.request<{ hash?: string }>({
|
|
526
|
+
method: "GET",
|
|
527
|
+
path: `${bitbucketCloudRepoPath(repository)}/commit/${encodeURIComponent(sha)}`,
|
|
528
|
+
});
|
|
529
|
+
return /^[0-9a-f]{40}$/i.test(commit.hash ?? "") ? commit.hash : sha;
|
|
530
|
+
} catch (error) {
|
|
531
|
+
onError?.(error);
|
|
532
|
+
return sha;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function bitbucketPullRequestFromRaw(
|
|
537
|
+
raw: Record<string, unknown>,
|
|
538
|
+
id: number,
|
|
539
|
+
htmlUrl?: string
|
|
540
|
+
): BitbucketApiPullRequest {
|
|
541
|
+
const source = asRecord(raw.source);
|
|
542
|
+
const destination = asRecord(raw.destination);
|
|
543
|
+
return {
|
|
544
|
+
id,
|
|
545
|
+
title: str(raw.title),
|
|
546
|
+
description: str(raw.description),
|
|
547
|
+
state: str(raw.state),
|
|
548
|
+
draft: typeof raw.draft === "boolean" ? raw.draft : undefined,
|
|
549
|
+
authorUsername: bitbucketAuthorUsername(raw),
|
|
550
|
+
sourceBranch:
|
|
551
|
+
str(asRecord(source?.branch)?.name) ??
|
|
552
|
+
str(asRecord(raw.fromRef)?.displayId),
|
|
553
|
+
targetBranch:
|
|
554
|
+
str(asRecord(destination?.branch)?.name) ??
|
|
555
|
+
str(asRecord(raw.toRef)?.displayId),
|
|
556
|
+
headSha:
|
|
557
|
+
str(asRecord(source?.commit)?.hash) ??
|
|
558
|
+
str(asRecord(raw.fromRef)?.latestCommit),
|
|
559
|
+
baseSha:
|
|
560
|
+
str(asRecord(destination?.commit)?.hash) ??
|
|
561
|
+
str(asRecord(raw.toRef)?.latestCommit),
|
|
562
|
+
htmlUrl,
|
|
563
|
+
raw,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export function createBitbucketPullRequestReadApi(
|
|
568
|
+
bitbucket: BitbucketPullRequestReadClient,
|
|
569
|
+
options: {
|
|
570
|
+
onDiagnostic?: (diagnostic: BitbucketPullRequestReadDiagnostic) => void;
|
|
571
|
+
} = {}
|
|
572
|
+
): BitbucketPullRequestReadApi {
|
|
573
|
+
const { repository } = bitbucket;
|
|
574
|
+
const repo =
|
|
575
|
+
repository.dialect === "cloud"
|
|
576
|
+
? bitbucketCloudRepoPath(repository)
|
|
577
|
+
: bitbucketDataCenterRepoPath(repository);
|
|
578
|
+
const cloudPullRequestFromActivity = async (
|
|
579
|
+
id: number
|
|
580
|
+
): Promise<BitbucketApiPullRequest | undefined> => {
|
|
581
|
+
let path = `${repo}/pullrequests/${id}/activity`;
|
|
582
|
+
let query: Record<string, string | number> | undefined = { pagelen: 50 };
|
|
583
|
+
for (let page = 0; page < 20; page += 1) {
|
|
584
|
+
const response = await bitbucket.request<Record<string, unknown>>({
|
|
585
|
+
method: "GET",
|
|
586
|
+
path,
|
|
587
|
+
query,
|
|
588
|
+
});
|
|
589
|
+
for (const value of Array.isArray(response.values)
|
|
590
|
+
? response.values
|
|
591
|
+
: []) {
|
|
592
|
+
const update = asRecord(asRecord(value)?.update);
|
|
593
|
+
if (update !== undefined) {
|
|
594
|
+
return bitbucketPullRequestFromRaw(update, id);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const next = str(response.next);
|
|
598
|
+
if (next === undefined) {
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
const nextUrl = new URL(next);
|
|
602
|
+
const marker = nextUrl.pathname.indexOf("/repositories/");
|
|
603
|
+
path = marker === -1 ? nextUrl.pathname : nextUrl.pathname.slice(marker);
|
|
604
|
+
query = Object.fromEntries(nextUrl.searchParams.entries());
|
|
605
|
+
}
|
|
606
|
+
return undefined;
|
|
607
|
+
};
|
|
608
|
+
return {
|
|
609
|
+
async getPullRequest(id) {
|
|
610
|
+
let pullRequest: BitbucketApiPullRequest;
|
|
611
|
+
try {
|
|
612
|
+
pullRequest = await bitbucket.api.getPullRequest(id);
|
|
613
|
+
} catch (error) {
|
|
614
|
+
const status = errorStatus(error);
|
|
615
|
+
if (
|
|
616
|
+
repository.dialect !== "cloud" ||
|
|
617
|
+
status === undefined ||
|
|
618
|
+
status < 500
|
|
619
|
+
) {
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
options.onDiagnostic?.({ kind: "metadata-fallback", status });
|
|
623
|
+
const fallback = await cloudPullRequestFromActivity(id);
|
|
624
|
+
if (fallback === undefined) {
|
|
625
|
+
throw error;
|
|
626
|
+
}
|
|
627
|
+
pullRequest = fallback;
|
|
628
|
+
}
|
|
629
|
+
const normalized = {
|
|
630
|
+
...pullRequest,
|
|
631
|
+
draft: asRecord(pullRequest.raw)?.draft === true,
|
|
632
|
+
authorUsername: bitbucketAuthorUsername(pullRequest.raw),
|
|
633
|
+
};
|
|
634
|
+
if (repository.dialect !== "cloud") {
|
|
635
|
+
return normalized;
|
|
636
|
+
}
|
|
637
|
+
const [headSha, baseSha] = await Promise.all([
|
|
638
|
+
expandBitbucketCloudCommitSha(
|
|
639
|
+
bitbucket,
|
|
640
|
+
repository,
|
|
641
|
+
pullRequest.headSha,
|
|
642
|
+
(error) =>
|
|
643
|
+
pullRequest.headSha === undefined
|
|
644
|
+
? undefined
|
|
645
|
+
: options.onDiagnostic?.({
|
|
646
|
+
kind: "commit-expansion-failed",
|
|
647
|
+
sha: pullRequest.headSha,
|
|
648
|
+
error,
|
|
649
|
+
})
|
|
650
|
+
),
|
|
651
|
+
expandBitbucketCloudCommitSha(
|
|
652
|
+
bitbucket,
|
|
653
|
+
repository,
|
|
654
|
+
pullRequest.baseSha,
|
|
655
|
+
(error) =>
|
|
656
|
+
pullRequest.baseSha === undefined
|
|
657
|
+
? undefined
|
|
658
|
+
: options.onDiagnostic?.({
|
|
659
|
+
kind: "commit-expansion-failed",
|
|
660
|
+
sha: pullRequest.baseSha,
|
|
661
|
+
error,
|
|
662
|
+
})
|
|
663
|
+
),
|
|
664
|
+
]);
|
|
665
|
+
return { ...normalized, headSha, baseSha };
|
|
666
|
+
},
|
|
667
|
+
async getMergeBaseSha(id, base, headSha) {
|
|
668
|
+
if (repository.dialect === "cloud") {
|
|
669
|
+
const commit = await bitbucket.request<{ hash?: string }>({
|
|
670
|
+
method: "GET",
|
|
671
|
+
path: `${repo}/merge-base/${encodeURIComponent(headSha)}..${encodeURIComponent(base)}`,
|
|
672
|
+
});
|
|
673
|
+
return str(commit.hash);
|
|
674
|
+
}
|
|
675
|
+
const commit = await bitbucket.request<{ id?: string }>({
|
|
676
|
+
method: "GET",
|
|
677
|
+
path: `${repo}/pull-requests/${id}/merge-base`,
|
|
678
|
+
});
|
|
679
|
+
return str(commit.id);
|
|
680
|
+
},
|
|
681
|
+
async listChangedFiles(id, input) {
|
|
682
|
+
try {
|
|
683
|
+
return splitBitbucketUnifiedDiff(
|
|
684
|
+
await bitbucket.api.getPullRequestDiff(id)
|
|
685
|
+
);
|
|
686
|
+
} catch (error) {
|
|
687
|
+
const status = errorStatus(error);
|
|
688
|
+
const comparisonBase = input?.mergeBaseSha ?? input?.baseSha;
|
|
689
|
+
if (
|
|
690
|
+
repository.dialect !== "cloud" ||
|
|
691
|
+
status === undefined ||
|
|
692
|
+
status < 500 ||
|
|
693
|
+
input?.headSha === undefined ||
|
|
694
|
+
comparisonBase === undefined
|
|
695
|
+
) {
|
|
696
|
+
throw error;
|
|
697
|
+
}
|
|
698
|
+
options.onDiagnostic?.({ kind: "diff-fallback", status });
|
|
699
|
+
const diff = await bitbucket.request<string>({
|
|
700
|
+
method: "GET",
|
|
701
|
+
path: `${repo}/diff/${encodeURIComponent(input.headSha)}..${encodeURIComponent(comparisonBase)}`,
|
|
702
|
+
query: { topic: input.mergeBaseResolved === true ? "false" : "true" },
|
|
703
|
+
accept: "text/plain",
|
|
704
|
+
});
|
|
705
|
+
return splitBitbucketUnifiedDiff(diff);
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
370
711
|
export function cloudBitbucketApi(
|
|
371
712
|
client: BitbucketClient,
|
|
372
713
|
repository: BitbucketRepositoryRef
|
|
@@ -265,6 +265,31 @@ export function bitbucketPullRequestUrl(
|
|
|
265
265
|
: `${repository.htmlUrl.replace(/\/browse\/?$/, "")}/pull-requests/${id}`;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
/** Absolute PR URL, or undefined when a Data Center payload has no repo URL. */
|
|
269
|
+
export function bitbucketAbsolutePullRequestUrl(
|
|
270
|
+
repository: BitbucketRepositoryRef,
|
|
271
|
+
id: number,
|
|
272
|
+
explicit?: string
|
|
273
|
+
): string | undefined {
|
|
274
|
+
if (explicit !== undefined) {
|
|
275
|
+
return explicit;
|
|
276
|
+
}
|
|
277
|
+
if (repository.dialect === "cloud") {
|
|
278
|
+
return `https://bitbucket.org/${repository.fullName}/pull-requests/${id}`;
|
|
279
|
+
}
|
|
280
|
+
return repository.htmlUrl === undefined
|
|
281
|
+
? undefined
|
|
282
|
+
: `${repository.htmlUrl.replace(/\/+$/, "").replace(/\/browse$/, "")}/pull-requests/${id}`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Whether a Data Center `updated` payload publishes a draft pull request. */
|
|
286
|
+
export function bitbucketDraftMarkedReady(
|
|
287
|
+
payload: Record<string, unknown>,
|
|
288
|
+
draft: boolean | undefined
|
|
289
|
+
): boolean {
|
|
290
|
+
return payload.previousDraft === true && draft === false;
|
|
291
|
+
}
|
|
292
|
+
|
|
268
293
|
/**
|
|
269
294
|
* Normalize the pull request from either dialect. `action` is the suffix of
|
|
270
295
|
* the Cloud-normalized event key (`pullrequest:created` → `created`).
|
|
@@ -24,8 +24,10 @@
|
|
|
24
24
|
export * from "./api.js";
|
|
25
25
|
export {
|
|
26
26
|
type BitbucketHandle,
|
|
27
|
+
bitbucketAbsolutePullRequestUrl,
|
|
27
28
|
bitbucketCommentFromPayload,
|
|
28
29
|
bitbucketDialectOf,
|
|
30
|
+
bitbucketDraftMarkedReady,
|
|
29
31
|
bitbucketPullRequestFromPayload,
|
|
30
32
|
bitbucketPullRequestUrl,
|
|
31
33
|
bitbucketPushFromPayload,
|