@cursor/july 0.1.68 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -5
- package/README.md +23 -11
- package/dist/bin/agent-serve.js +3 -2
- package/dist/channels/github/api.d.ts +2 -0
- package/dist/channels/github/api.d.ts.map +1 -1
- package/dist/channels/github/api.js +2 -1
- package/dist/channels/github/binding.d.ts +7 -0
- package/dist/channels/github/binding.d.ts.map +1 -1
- package/dist/channels/github/binding.js +4 -0
- package/dist/channels/github/checks.d.ts +99 -0
- package/dist/channels/github/checks.d.ts.map +1 -0
- package/dist/channels/github/checks.js +108 -0
- package/dist/channels/github/cursor-account.d.ts +4 -4
- package/dist/channels/github/cursor-account.d.ts.map +1 -1
- package/dist/channels/github/cursor-account.js +7 -5
- package/dist/channels/github/index.d.ts +1 -0
- package/dist/channels/github/index.d.ts.map +1 -1
- package/dist/channels/github/index.js +1 -0
- package/dist/channels/github/types.d.ts +8 -0
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/manifest.d.ts +2 -2
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +13 -11
- package/dist/channels/slack/types.d.ts +2 -2
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +17 -5
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +17 -5
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.C5XUTCw9.js → app.CdbcFD8T.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DQad--_z.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CGDTAYHY.js → VPLocalSearchBox.D_NKImM7.js} +1 -1
- package/dist/docs/assets/chunks/{theme.lPixh250.js → theme.CMvz7cu9.js} +2 -2
- package/dist/docs/assets/{concepts.md.CqOsxbMU.js → concepts.md.BXAm6G-C.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.js → guides_mcp-oauth.md.CzEB6RaG.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.js → reference_agent-config.md.BZnEKfEc.js} +3 -4
- package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.lean.js → reference_agent-config.md.BZnEKfEc.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Bwswbm6H.js → reference_connections.md.Cu3N-S3Q.js} +18 -11
- package/dist/docs/assets/{reference_connections.md.Bwswbm6H.lean.js → reference_connections.md.Cu3N-S3Q.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.js → reference_sessions.md.B0DdlM-K.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.Wmvb7Lob.js → reference_tools.md.DTg_kEsx.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.DQ-hYuZT.js +1 -0
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +3 -3
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/convert-automation.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +5 -5
- package/dist/docs/guides/opentelemetry.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +5 -6
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +20 -13
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +5 -5
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/templates/agentic-owners.html +3 -3
- package/dist/docs/templates/demo.html +3 -3
- package/dist/docs/templates/pr-autofixer.html +3 -3
- package/dist/docs/templates/security-reviewer.html +3 -3
- package/dist/docs/templates/triage.html +3 -3
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/internal/advertise-tools.d.ts +11 -6
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +63 -30
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +2 -4
- package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
- package/dist/internal/convert-automation/convert-workflow.js +2 -10
- package/dist/internal/cursor/account-mcp.d.ts +29 -3
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +147 -67
- package/dist/internal/cursor/backend-client.d.ts +11 -6
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +32 -10
- package/dist/internal/cursor-account-mcp-auth.d.ts +11 -0
- package/dist/internal/cursor-account-mcp-auth.d.ts.map +1 -1
- package/dist/internal/cursor-account-mcp-auth.js +69 -0
- package/dist/internal/deploy-client.d.ts +0 -7
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +2 -4
- package/dist/internal/deploy-manifest.d.ts +15 -24
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +38 -27
- package/dist/internal/deployment-scm-event-stream.d.ts +4 -1
- package/dist/internal/deployment-scm-event-stream.d.ts.map +1 -1
- package/dist/internal/deployment-scm-event-stream.js +15 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +42 -10
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +7 -106
- package/dist/internal/init-scaffold.d.ts +8 -0
- package/dist/internal/init-scaffold.d.ts.map +1 -0
- package/dist/internal/init-scaffold.js +168 -0
- package/dist/internal/inline-stdio-mcp.d.ts +2 -0
- package/dist/internal/inline-stdio-mcp.d.ts.map +1 -1
- package/dist/internal/inline-stdio-mcp.js +10 -8
- package/dist/internal/json-schema.d.ts +7 -0
- package/dist/internal/json-schema.d.ts.map +1 -1
- package/dist/internal/json-schema.js +18 -3
- package/dist/internal/mcp-endpoint.js +7 -7
- package/dist/internal/mcp-host.js +4 -2
- package/dist/internal/mcp-oauth.d.ts +22 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +40 -1
- package/dist/internal/package-inline-stdio.d.ts.map +1 -1
- package/dist/internal/package-inline-stdio.js +5 -5
- package/dist/internal/review-comments.d.ts +97 -0
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +151 -0
- package/dist/internal/sanitize-mcp-tool-name.d.ts +20 -0
- package/dist/internal/sanitize-mcp-tool-name.d.ts.map +1 -0
- package/dist/internal/sanitize-mcp-tool-name.js +30 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +4 -6
- package/dist/internal/shallow-clone.d.ts +94 -39
- package/dist/internal/shallow-clone.d.ts.map +1 -1
- package/dist/internal/shallow-clone.js +188 -68
- package/dist/internal/terminal-style.d.ts +18 -0
- package/dist/internal/terminal-style.d.ts.map +1 -1
- package/dist/internal/terminal-style.js +46 -1
- package/dist/internal/workspace.d.ts +2 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +5 -0
- package/dist/playground/assets/index-77uhu5Kr.css +1 -0
- package/dist/playground/assets/{index-yxs1heea.js → index-D4buox4m.js} +42 -42
- package/dist/playground/index.html +2 -2
- package/dist/tools.d.ts +7 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +28 -3
- package/dist/types.d.ts.map +1 -1
- package/docs/concepts.md +4 -4
- package/docs/guides/mcp-oauth.md +3 -1
- package/docs/reference/agent-config.md +11 -12
- package/docs/reference/connections.md +44 -26
- package/docs/reference/sessions.md +2 -2
- package/docs/reference/tools.md +1 -1
- package/docs/troubleshooting.md +3 -2
- package/package.json +4 -1
- package/skills/create-agent/SKILL.md +12 -9
- package/skills/debug/SKILL.md +2 -1
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/mcp-auth/SKILL.md +8 -6
- package/src/bin/agent-serve.ts +3 -2
- package/src/channels/github/api.ts +6 -1
- package/src/channels/github/binding.ts +21 -0
- package/src/channels/github/checks.ts +179 -0
- package/src/channels/github/cursor-account.ts +9 -6
- package/src/channels/github/index.ts +1 -0
- package/src/channels/github/types.ts +8 -0
- package/src/channels/slack/manifest.ts +8 -10
- package/src/channels/slack/types.ts +2 -2
- package/src/connections.ts +17 -5
- package/src/internal/advertise-tools.ts +72 -23
- package/src/internal/cli-deploy.ts +4 -15
- package/src/internal/convert-automation/convert-workflow.ts +2 -11
- package/src/internal/cursor/account-mcp.ts +208 -73
- package/src/internal/cursor/backend-client.ts +45 -11
- package/src/internal/cursor-account-mcp-auth.ts +83 -0
- package/src/internal/deploy-client.ts +0 -10
- package/src/internal/deploy-manifest.ts +33 -39
- package/src/internal/deployment-scm-event-stream.ts +17 -1
- package/src/internal/discovery.ts +47 -3
- package/src/internal/init-project.ts +7 -133
- package/src/internal/init-scaffold.ts +176 -0
- package/src/internal/inline-stdio-mcp.ts +13 -0
- package/src/internal/json-schema.ts +24 -3
- package/src/internal/mcp-endpoint.ts +6 -0
- package/src/internal/mcp-host.ts +4 -0
- package/src/internal/mcp-oauth.ts +55 -1
- package/src/internal/package-inline-stdio.ts +5 -1
- package/src/internal/review-comments.ts +245 -0
- package/src/internal/sanitize-mcp-tool-name.ts +33 -0
- package/src/internal/session-engine.ts +7 -0
- package/src/internal/shallow-clone.ts +293 -105
- package/src/internal/terminal-style.ts +67 -1
- package/src/internal/workspace.ts +6 -0
- package/src/tools.ts +7 -0
- package/src/types.ts +32 -4
- package/templates/agentic-owners/agent/agent.ts +3 -0
- package/templates/demo/agent/agent.ts +3 -0
- package/templates/security-reviewer/agent/agent.ts +3 -0
- package/templates/triage/agent/agent.ts +3 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DvUR3lv9.js +0 -1
- package/dist/docs/assets/troubleshooting.md.CuVztCKs.js +0 -1
- package/dist/playground/assets/index-CoL7xCJl.css +0 -1
- /package/dist/docs/assets/{concepts.md.CqOsxbMU.lean.js → concepts.md.BXAm6G-C.lean.js} +0 -0
- /package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.lean.js → guides_mcp-oauth.md.CzEB6RaG.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.lean.js → reference_sessions.md.B0DdlM-K.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.Wmvb7Lob.lean.js → reference_tools.md.DTg_kEsx.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.CuVztCKs.lean.js → troubleshooting.md.DQ-hYuZT.lean.js} +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool-name sanitization shared by the Cursor-account bridge
|
|
3
|
+
* (`account-mcp.ts`) and advertised connections (`advertise-tools.ts`).
|
|
4
|
+
*
|
|
5
|
+
* Connector display names — and the aggregate `/v1/agent/mcp` names minted
|
|
6
|
+
* from them (`<serverIdentifier>-<tool>`) — can contain spaces, dots, and
|
|
7
|
+
* other characters that are illegal as the tool name a model sees.
|
|
8
|
+
*
|
|
9
|
+
* Character class matches `packages/agent` `normalizeMcpToolName`
|
|
10
|
+
* (`[^a-zA-Z0-9_-]` → `_`). Length cap and the empty fallback match the
|
|
11
|
+
* account bridge (MCP clients commonly enforce `^[a-zA-Z0-9_-]{1,128}$`).
|
|
12
|
+
* Callers that talk to the backend keep the original advertised name.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** MCP clients commonly enforce `^[a-zA-Z0-9_-]{1,128}$` for tool names. */
|
|
16
|
+
export const MAX_MCP_TOOL_NAME_LENGTH = 128;
|
|
17
|
+
|
|
18
|
+
/** Connector display names can contain anything (spaces, dots, emoji). */
|
|
19
|
+
export function sanitizeMcpToolName(name: string): string {
|
|
20
|
+
const cleaned = name
|
|
21
|
+
.replace(/[^a-zA-Z0-9_-]/g, "_")
|
|
22
|
+
.slice(0, MAX_MCP_TOOL_NAME_LENGTH);
|
|
23
|
+
return cleaned === "" ? "tool" : cleaned;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** `base` for the first claimant, `base_2` / `base_3` … for colliders. */
|
|
27
|
+
export function suffixMcpToolName(base: string, index: number): string {
|
|
28
|
+
if (index === 0) {
|
|
29
|
+
return base;
|
|
30
|
+
}
|
|
31
|
+
const suffix = `_${index + 1}`;
|
|
32
|
+
return `${base.slice(0, MAX_MCP_TOOL_NAME_LENGTH - suffix.length)}${suffix}`;
|
|
33
|
+
}
|
|
@@ -2327,6 +2327,13 @@ export class SessionEngine {
|
|
|
2327
2327
|
tools[tool.name] = {
|
|
2328
2328
|
description: tool.description,
|
|
2329
2329
|
inputSchema: tool.inputSchema as SDKCustomTool["inputSchema"],
|
|
2330
|
+
// `SDKCustomTool.outputSchema` ships in the next published
|
|
2331
|
+
// @cursor/sdk; the conditional spread carries the field through the
|
|
2332
|
+
// pinned SDK's type until the dependency bumps, at which point local
|
|
2333
|
+
// runs start advertising it.
|
|
2334
|
+
...(tool.outputSchema === undefined
|
|
2335
|
+
? {}
|
|
2336
|
+
: { outputSchema: tool.outputSchema }),
|
|
2330
2337
|
execute: async (args, context) => {
|
|
2331
2338
|
return this.executeServerTool({
|
|
2332
2339
|
tool,
|
|
@@ -5,7 +5,7 @@ import { promisify } from "node:util";
|
|
|
5
5
|
const execFileAsync = promisify(execFile);
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Shallow
|
|
8
|
+
* Shallow SCM PR checkout for SDK agents that review a PR's code.
|
|
9
9
|
*
|
|
10
10
|
* Mirrors Bugbot's `shallow_fetch` prefetch strategy
|
|
11
11
|
* (`backend/crates/napi_bugbot/src/temp_clone.rs`): instead of cloning the
|
|
@@ -16,11 +16,19 @@ const execFileAsync = promisify(execFile);
|
|
|
16
16
|
* clone because its tools stream objects on demand; SDK agents read a real
|
|
17
17
|
* working tree, so we materialize the head checkout instead.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* SCM support follows Bugbot's provider seam (`IGitProvider.getCloneTarget`
|
|
20
|
+
* / the Rust `clone_url` dispatch): everything provider-specific — remote
|
|
21
|
+
* URL shape, git credential username convention, PR head ref layout — lives
|
|
22
|
+
* in one {@link ScmCloneTarget} produced by {@link resolveScmCloneTarget}.
|
|
23
|
+
* Supporting another SCM (GitLab, Bitbucket, …) means adding a resolver
|
|
24
|
+
* case and a default credential source; the fetch/verify/checkout machinery
|
|
25
|
+
* is provider-agnostic.
|
|
26
|
+
*
|
|
27
|
+
* Auth also mirrors Bugbot (`IGitProvider.getAccessToken` → token handed
|
|
28
|
+
* straight to git): the clone takes one explicit repo-scoped bearer token.
|
|
29
|
+
* For GitHub the default source is the serve host's Cursor-account lease —
|
|
30
|
+
* the same backend `GithubAccessService` mint Bugbot uses — which
|
|
31
|
+
* `CursorGithubCredentialProvider` installs as `GH_TOKEN` for child
|
|
24
32
|
* processes. Where Bugbot embeds the token in the clone URL, this module
|
|
25
33
|
* serves it through an inline credential helper that reads a child-process
|
|
26
34
|
* env var, so the token never lands in argv or in `.git/config` inside a
|
|
@@ -31,23 +39,72 @@ const execFileAsync = promisify(execFile);
|
|
|
31
39
|
* source imports, following `tenant-mcp/run-mcp-registry.ts`.
|
|
32
40
|
*/
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
/** SCMs with shallow-clone support. */
|
|
43
|
+
export type ScmProvider = "github";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Everything git needs to clone one SCM's PR head. Provider-specific
|
|
47
|
+
* conventions live here and nowhere else.
|
|
48
|
+
*/
|
|
49
|
+
export type ScmCloneTarget = {
|
|
50
|
+
provider: ScmProvider;
|
|
51
|
+
/** `owner/name` — used for logs and error messages. */
|
|
52
|
+
repo: string;
|
|
53
|
+
prNumber: number;
|
|
54
|
+
/** HTTPS remote to fetch from. */
|
|
55
|
+
remoteUrl: string;
|
|
56
|
+
/** Username paired with the bearer token for git-over-HTTPS basic auth. */
|
|
57
|
+
credentialUsername: string;
|
|
58
|
+
/**
|
|
59
|
+
* Server-advertised PR head ref (e.g. GitHub `refs/pull/<n>/head`,
|
|
60
|
+
* GitLab `refs/merge-requests/<n>/head`) — the fallback when the pinned
|
|
61
|
+
* SHA cannot be fetched directly.
|
|
62
|
+
*/
|
|
63
|
+
prHeadRef: string;
|
|
42
64
|
};
|
|
43
65
|
|
|
44
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Resolve a PR URL to its clone target, or `undefined` when the SCM has no
|
|
68
|
+
* shallow-clone support (callers then review on their fallback checkout —
|
|
69
|
+
* e.g. Origin PRs, where the host checkout already is the reviewed repo).
|
|
70
|
+
*/
|
|
71
|
+
export function resolveScmCloneTarget(
|
|
72
|
+
prUrl: string
|
|
73
|
+
): ScmCloneTarget | undefined {
|
|
74
|
+
let url: URL;
|
|
75
|
+
try {
|
|
76
|
+
url = new URL(prUrl);
|
|
77
|
+
} catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
81
|
+
if (
|
|
82
|
+
url.hostname === "github.com" &&
|
|
83
|
+
parts.length >= 4 &&
|
|
84
|
+
parts[2] === "pull" &&
|
|
85
|
+
Number.isInteger(Number(parts[3]))
|
|
86
|
+
) {
|
|
87
|
+
const repo = `${parts[0]}/${parts[1]}`;
|
|
88
|
+
const prNumber = Number(parts[3]);
|
|
89
|
+
return {
|
|
90
|
+
provider: "github",
|
|
91
|
+
repo,
|
|
92
|
+
prNumber,
|
|
93
|
+
remoteUrl: `https://github.com/${repo}.git`,
|
|
94
|
+
credentialUsername: "x-access-token",
|
|
95
|
+
prHeadRef: `refs/pull/${prNumber}/head`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Repo-scoped bearer for git-over-HTTPS. */
|
|
45
102
|
export type ShallowCloneAuth = {
|
|
46
103
|
token: string;
|
|
47
104
|
};
|
|
48
105
|
|
|
49
106
|
/**
|
|
50
|
-
* Default clone credential: the serve host's Cursor-account
|
|
107
|
+
* Default GitHub clone credential: the serve host's Cursor-account lease.
|
|
51
108
|
* `CursorGithubCredentialProvider` mints it repo-scoped from the backend and
|
|
52
109
|
* keeps `GH_TOKEN` refreshed for child processes; `GITHUB_TOKEN` covers
|
|
53
110
|
* local/CI runs that export the conventional variable instead.
|
|
@@ -59,6 +116,154 @@ export function serveHostGithubAuth(
|
|
|
59
116
|
return token === "" ? undefined : { token };
|
|
60
117
|
}
|
|
61
118
|
|
|
119
|
+
/** Pair the provider's git-over-HTTPS username with the bearer token. */
|
|
120
|
+
function cloneCredential(
|
|
121
|
+
target: ScmCloneTarget,
|
|
122
|
+
auth: ShallowCloneAuth | undefined
|
|
123
|
+
): GitCredential | undefined {
|
|
124
|
+
return auth === undefined
|
|
125
|
+
? undefined
|
|
126
|
+
: { username: target.credentialUsername, token: auth.token };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Default clone credential source per provider. */
|
|
130
|
+
function defaultCloneAuth(
|
|
131
|
+
target: ScmCloneTarget
|
|
132
|
+
): ShallowCloneAuth | undefined {
|
|
133
|
+
switch (target.provider) {
|
|
134
|
+
case "github":
|
|
135
|
+
return serveHostGithubAuth();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Cap on diff text handed to a model; beyond this it is truncated. */
|
|
140
|
+
const DIFF_MAX_CHARS = 80_000;
|
|
141
|
+
|
|
142
|
+
export type CommitRangeDiff =
|
|
143
|
+
| { status: "ok"; diff: string }
|
|
144
|
+
| { status: "unavailable"; reason: string };
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Diff two commits inside an existing shallow PR checkout, fetching either
|
|
148
|
+
* end on demand when the shallow history does not already contain it.
|
|
149
|
+
*
|
|
150
|
+
* Lives here because it needs the same authenticated git the clone uses —
|
|
151
|
+
* a `--depth=1` checkout usually lacks the older commit, so reading a range
|
|
152
|
+
* means another credentialed fetch. Never throws: every failure becomes an
|
|
153
|
+
* `unavailable` reason the caller can act on or surface.
|
|
154
|
+
*/
|
|
155
|
+
export async function tryDiffCommitRange(args: {
|
|
156
|
+
/** Existing checkout to run git in (see {@link createShallowPrCheckout}). */
|
|
157
|
+
checkoutDir: string;
|
|
158
|
+
/** The checkout's clone target; supplies the remote's ref + auth conventions. */
|
|
159
|
+
target: ScmCloneTarget;
|
|
160
|
+
from: string;
|
|
161
|
+
to: string;
|
|
162
|
+
/** Restrict the diff to one path when set. */
|
|
163
|
+
file?: string | undefined;
|
|
164
|
+
/** Fetch credential; defaults to the target provider's credential source. */
|
|
165
|
+
auth?: ShallowCloneAuth | undefined;
|
|
166
|
+
}): Promise<CommitRangeDiff> {
|
|
167
|
+
if (!isFullCommitSha(args.from) || !isFullCommitSha(args.to)) {
|
|
168
|
+
return {
|
|
169
|
+
status: "unavailable",
|
|
170
|
+
reason:
|
|
171
|
+
"Could not compute a reliable diff because a commit SHA was not a full 40-character SHA.",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const credential = cloneCredential(
|
|
175
|
+
args.target,
|
|
176
|
+
args.auth ?? defaultCloneAuth(args.target)
|
|
177
|
+
);
|
|
178
|
+
for (const sha of [args.from, args.to]) {
|
|
179
|
+
if (
|
|
180
|
+
!(await ensureCommitFetched(
|
|
181
|
+
args.checkoutDir,
|
|
182
|
+
sha,
|
|
183
|
+
args.target,
|
|
184
|
+
credential
|
|
185
|
+
))
|
|
186
|
+
) {
|
|
187
|
+
return {
|
|
188
|
+
status: "unavailable",
|
|
189
|
+
reason:
|
|
190
|
+
"Could not compute a reliable diff because a commit was unavailable in the checkout.",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const diff = await git(args.checkoutDir, [
|
|
196
|
+
"diff",
|
|
197
|
+
"--no-ext-diff",
|
|
198
|
+
"--unified=80",
|
|
199
|
+
`${args.from}..${args.to}`,
|
|
200
|
+
...(args.file === undefined ? [] : ["--", args.file]),
|
|
201
|
+
]);
|
|
202
|
+
return {
|
|
203
|
+
status: "ok",
|
|
204
|
+
diff:
|
|
205
|
+
diff.length <= DIFF_MAX_CHARS
|
|
206
|
+
? diff
|
|
207
|
+
: `${diff.slice(0, DIFF_MAX_CHARS)}\n\n[diff truncated at ${DIFF_MAX_CHARS} characters]`,
|
|
208
|
+
};
|
|
209
|
+
} catch {
|
|
210
|
+
return {
|
|
211
|
+
status: "unavailable",
|
|
212
|
+
reason: "Could not compute a reliable diff because git diff failed.",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isFullCommitSha(value: string): boolean {
|
|
218
|
+
return /^[0-9a-f]{40}$/i.test(value);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Present already, or fetchable by SHA, or reachable from the PR head ref. */
|
|
222
|
+
async function ensureCommitFetched(
|
|
223
|
+
checkoutDir: string,
|
|
224
|
+
sha: string,
|
|
225
|
+
target: ScmCloneTarget,
|
|
226
|
+
credential: GitCredential | undefined
|
|
227
|
+
): Promise<boolean> {
|
|
228
|
+
if ((await revParse(checkoutDir, sha)) !== undefined) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const attempts = [
|
|
232
|
+
[...FETCH_ARGS, sha],
|
|
233
|
+
// Deeper history on the PR head ref: the older end of an inter-run range
|
|
234
|
+
// is usually an ancestor of the tip rather than the tip itself.
|
|
235
|
+
[
|
|
236
|
+
"fetch",
|
|
237
|
+
"--depth=200",
|
|
238
|
+
"--no-tags",
|
|
239
|
+
"--quiet",
|
|
240
|
+
"origin",
|
|
241
|
+
target.prHeadRef,
|
|
242
|
+
],
|
|
243
|
+
];
|
|
244
|
+
for (const attempt of attempts) {
|
|
245
|
+
try {
|
|
246
|
+
await git(checkoutDir, attempt, credential);
|
|
247
|
+
if ((await revParse(checkoutDir, sha)) !== undefined) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
// Try the next strategy; the caller fails closed if none work.
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export type ShallowPrCheckout = {
|
|
258
|
+
/** Directory containing the PR head working tree (detached at headSha). */
|
|
259
|
+
checkoutDir: string;
|
|
260
|
+
headSha: string;
|
|
261
|
+
/** True when the merge-base commit was also fetched (enables local diffs). */
|
|
262
|
+
baseFetched: boolean;
|
|
263
|
+
/** How the head commit was obtained. */
|
|
264
|
+
headSource: "sha_fetch" | "pr_ref_fetch";
|
|
265
|
+
};
|
|
266
|
+
|
|
62
267
|
function logShallowClone(
|
|
63
268
|
message: string,
|
|
64
269
|
fields: Record<string, string | number | boolean | undefined> = {}
|
|
@@ -99,17 +304,22 @@ function gitError(args: string[], error: unknown): Error {
|
|
|
99
304
|
}
|
|
100
305
|
|
|
101
306
|
/**
|
|
102
|
-
* The one credential helper git may use: serve the caller-provided
|
|
103
|
-
* from the child process env at request time. The shell reads
|
|
104
|
-
*
|
|
307
|
+
* The one credential helper git may use: serve the caller-provided
|
|
308
|
+
* credential from the child process env at request time. The shell reads
|
|
309
|
+
* the values when git asks, keeping the token out of argv.
|
|
105
310
|
*/
|
|
106
|
-
const
|
|
107
|
-
'!f() { test "$1" = get && printf "username
|
|
311
|
+
const CREDENTIAL_HELPER =
|
|
312
|
+
'!f() { test "$1" = get && printf "username=$SHALLOW_CLONE_GIT_USERNAME\\npassword=$SHALLOW_CLONE_GIT_TOKEN\\n"; }; f';
|
|
313
|
+
|
|
314
|
+
type GitCredential = {
|
|
315
|
+
username: string;
|
|
316
|
+
token: string;
|
|
317
|
+
};
|
|
108
318
|
|
|
109
319
|
async function git(
|
|
110
320
|
cwd: string,
|
|
111
321
|
args: string[],
|
|
112
|
-
|
|
322
|
+
credential?: GitCredential
|
|
113
323
|
): Promise<string> {
|
|
114
324
|
// Async on purpose: fetches/checkouts of large repos take minutes, and the
|
|
115
325
|
// serve host runs the clone in-process. A synchronous git call blocks the
|
|
@@ -119,9 +329,9 @@ async function git(
|
|
|
119
329
|
const { stdout } = await execFileAsync(
|
|
120
330
|
"git",
|
|
121
331
|
[
|
|
122
|
-
...(
|
|
332
|
+
...(credential === undefined
|
|
123
333
|
? []
|
|
124
|
-
: ["-c", `credential.helper=${
|
|
334
|
+
: ["-c", `credential.helper=${CREDENTIAL_HELPER}`]),
|
|
125
335
|
...args,
|
|
126
336
|
],
|
|
127
337
|
{
|
|
@@ -138,9 +348,12 @@ async function git(
|
|
|
138
348
|
GIT_CONFIG_GLOBAL: "/dev/null",
|
|
139
349
|
GIT_CONFIG_SYSTEM: "/dev/null",
|
|
140
350
|
GIT_TERMINAL_PROMPT: "0",
|
|
141
|
-
...(
|
|
351
|
+
...(credential === undefined
|
|
142
352
|
? {}
|
|
143
|
-
: {
|
|
353
|
+
: {
|
|
354
|
+
SHALLOW_CLONE_GIT_USERNAME: credential.username,
|
|
355
|
+
SHALLOW_CLONE_GIT_TOKEN: credential.token,
|
|
356
|
+
}),
|
|
144
357
|
},
|
|
145
358
|
}
|
|
146
359
|
);
|
|
@@ -163,14 +376,17 @@ async function revParse(cwd: string, rev: string): Promise<string | undefined> {
|
|
|
163
376
|
|
|
164
377
|
const FETCH_ARGS = ["fetch", "--depth=1", "--no-tags", "--quiet", "origin"];
|
|
165
378
|
|
|
379
|
+
/** Local tracking ref the PR head ref is fetched into. */
|
|
380
|
+
const LOCAL_PR_HEAD_REF = "refs/remotes/origin/shallow-clone-pr-head";
|
|
381
|
+
|
|
166
382
|
/**
|
|
167
|
-
* Create a fresh shallow checkout of a
|
|
383
|
+
* Create a fresh shallow checkout of a PR head at `checkoutDir`.
|
|
168
384
|
*
|
|
169
385
|
* Fetch order (both single depth-1 round-trips):
|
|
170
386
|
* 1. Fetch `headSha` (and `baseSha` when known) directly — GitHub advertises
|
|
171
387
|
* `allow-reachable-sha1-in-want`, and this pins the exact reviewed commit
|
|
172
388
|
* the way Bugbot's `shallow_fetch` does.
|
|
173
|
-
* 2. Fall back to
|
|
389
|
+
* 2. Fall back to the target's PR head ref, verifying it still resolves to
|
|
174
390
|
* `headSha` so the working tree cannot silently drift from the pinned
|
|
175
391
|
* patch in the review bundle.
|
|
176
392
|
*
|
|
@@ -178,36 +394,33 @@ const FETCH_ARGS = ["fetch", "--depth=1", "--no-tags", "--quiet", "origin"];
|
|
|
178
394
|
* patch text in their prompt); a missing head checkout throws.
|
|
179
395
|
*/
|
|
180
396
|
export async function createShallowPrCheckout(args: {
|
|
181
|
-
|
|
182
|
-
repo: string;
|
|
183
|
-
prNumber?: number | undefined;
|
|
397
|
+
target: ScmCloneTarget;
|
|
184
398
|
headSha: string;
|
|
185
399
|
/** Merge-base SHA; fetched too so `git diff baseSha headSha` works locally. */
|
|
186
400
|
baseSha?: string | undefined;
|
|
187
401
|
checkoutDir: string;
|
|
188
|
-
/** Clone credential; required for
|
|
402
|
+
/** Clone credential; required for HTTPS remotes, unused for file fixtures. */
|
|
189
403
|
auth?: ShallowCloneAuth | undefined;
|
|
190
|
-
/** Test seam: clone from this URL instead of `https://github.com/<repo>.git`. */
|
|
191
|
-
remoteUrl?: string | undefined;
|
|
192
404
|
}): Promise<ShallowPrCheckout> {
|
|
193
|
-
const {
|
|
405
|
+
const { target, headSha, baseSha, checkoutDir, auth } = args;
|
|
406
|
+
const { repo, prNumber } = target;
|
|
407
|
+
const credential = cloneCredential(target, auth);
|
|
194
408
|
const startedAt = Date.now();
|
|
195
409
|
logShallowClone("cloning PR head", { repo, prNumber, headSha, baseSha });
|
|
196
410
|
rmSync(checkoutDir, { recursive: true, force: true });
|
|
197
411
|
mkdirSync(checkoutDir, { recursive: true });
|
|
198
412
|
await git(checkoutDir, ["init", "--quiet"]);
|
|
199
|
-
await git(checkoutDir, [
|
|
200
|
-
"remote",
|
|
201
|
-
"add",
|
|
202
|
-
"origin",
|
|
203
|
-
args.remoteUrl ?? `https://github.com/${repo}.git`,
|
|
204
|
-
]);
|
|
413
|
+
await git(checkoutDir, ["remote", "add", "origin", target.remoteUrl]);
|
|
205
414
|
|
|
206
415
|
const shaFetch = async (): Promise<void> => {
|
|
207
416
|
const extraBase =
|
|
208
417
|
baseSha === undefined || baseSha === headSha ? [] : [baseSha];
|
|
209
418
|
try {
|
|
210
|
-
await git(
|
|
419
|
+
await git(
|
|
420
|
+
checkoutDir,
|
|
421
|
+
[...FETCH_ARGS, headSha, ...extraBase],
|
|
422
|
+
credential
|
|
423
|
+
);
|
|
211
424
|
} catch (error) {
|
|
212
425
|
if (extraBase.length === 0) {
|
|
213
426
|
throw error;
|
|
@@ -220,38 +433,28 @@ export async function createShallowPrCheckout(args: {
|
|
|
220
433
|
baseSha,
|
|
221
434
|
error: errorSummary(error),
|
|
222
435
|
});
|
|
223
|
-
await git(checkoutDir, [...FETCH_ARGS, headSha],
|
|
436
|
+
await git(checkoutDir, [...FETCH_ARGS, headSha], credential);
|
|
224
437
|
}
|
|
225
438
|
};
|
|
226
439
|
|
|
227
440
|
let headSource: ShallowPrCheckout["headSource"];
|
|
228
|
-
let shaFetchError: string | undefined;
|
|
229
441
|
try {
|
|
230
442
|
await shaFetch();
|
|
231
443
|
headSource = "sha_fetch";
|
|
232
444
|
} catch (error) {
|
|
233
|
-
shaFetchError = errorSummary(error);
|
|
234
|
-
if (prNumber === undefined) {
|
|
235
|
-
throw new Error(
|
|
236
|
-
`Shallow SHA fetch failed for ${repo}@${headSha} and no PR number is available for a ref fallback: ${shaFetchError}`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
445
|
+
const shaFetchError = errorSummary(error);
|
|
239
446
|
logShallowClone("sha fetch failed; falling back to PR head ref", {
|
|
240
447
|
repo,
|
|
241
448
|
prNumber,
|
|
242
449
|
headSha,
|
|
243
450
|
error: shaFetchError,
|
|
244
451
|
});
|
|
245
|
-
const prRef = `refs/pull/${prNumber}/head`;
|
|
246
452
|
await git(
|
|
247
453
|
checkoutDir,
|
|
248
|
-
[...FETCH_ARGS, `+${
|
|
249
|
-
|
|
250
|
-
);
|
|
251
|
-
const fetchedSha = await revParse(
|
|
252
|
-
checkoutDir,
|
|
253
|
-
`refs/remotes/origin/pr/${prNumber}/head`
|
|
454
|
+
[...FETCH_ARGS, `+${target.prHeadRef}:${LOCAL_PR_HEAD_REF}`],
|
|
455
|
+
credential
|
|
254
456
|
);
|
|
457
|
+
const fetchedSha = await revParse(checkoutDir, LOCAL_PR_HEAD_REF);
|
|
255
458
|
if (fetchedSha !== headSha) {
|
|
256
459
|
throw new Error(
|
|
257
460
|
`Shallow PR ref fetch for ${repo}#${prNumber} resolved to ${fetchedSha ?? "nothing"}, expected pinned head ${headSha} (sha fetch error: ${shaFetchError})`
|
|
@@ -279,7 +482,7 @@ export async function createShallowPrCheckout(args: {
|
|
|
279
482
|
// Best-effort: local diffs are nice-to-have, the pinned patch in the
|
|
280
483
|
// prompt is the authoritative delta either way.
|
|
281
484
|
try {
|
|
282
|
-
await git(checkoutDir, [...FETCH_ARGS, baseSha],
|
|
485
|
+
await git(checkoutDir, [...FETCH_ARGS, baseSha], credential);
|
|
283
486
|
baseFetched = (await revParse(checkoutDir, baseSha)) !== undefined;
|
|
284
487
|
} catch (error) {
|
|
285
488
|
logShallowClone("merge-base fetch failed; continuing without it", {
|
|
@@ -303,37 +506,18 @@ export async function createShallowPrCheckout(args: {
|
|
|
303
506
|
return { checkoutDir, headSha, baseFetched, headSource };
|
|
304
507
|
}
|
|
305
508
|
|
|
306
|
-
/** True for `https://github.com/<owner>/<repo>/pull/<n>` URLs. */
|
|
307
|
-
export function isGithubPrUrl(prUrl: string): boolean {
|
|
308
|
-
try {
|
|
309
|
-
const url = new URL(prUrl);
|
|
310
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
311
|
-
return (
|
|
312
|
-
url.hostname === "github.com" &&
|
|
313
|
-
parts.length >= 4 &&
|
|
314
|
-
parts[2] === "pull" &&
|
|
315
|
-
Number.isInteger(Number(parts[3]))
|
|
316
|
-
);
|
|
317
|
-
} catch {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
509
|
export type TryShallowPrCheckoutOptions = {
|
|
323
|
-
/** PR URL;
|
|
510
|
+
/** PR URL; resolved to a clone target (unsupported SCMs skip). */
|
|
324
511
|
prUrl: string;
|
|
325
|
-
/** `owner/name`. */
|
|
326
|
-
repo: string;
|
|
327
|
-
prNumber?: number | undefined;
|
|
328
512
|
/** Pinned head SHA; skipped (undefined result) when unknown. */
|
|
329
513
|
headSha?: string | undefined;
|
|
330
514
|
/** Merge-base SHA; fetched too so `git diff baseSha headSha` works locally. */
|
|
331
515
|
baseSha?: string | undefined;
|
|
332
516
|
checkoutDir: string;
|
|
333
|
-
/** Clone credential; defaults to
|
|
517
|
+
/** Clone credential; defaults to the target provider's credential source. */
|
|
334
518
|
auth?: ShallowCloneAuth | undefined;
|
|
335
|
-
/** Test seam: clone
|
|
336
|
-
|
|
519
|
+
/** Test seam: clone this target instead of resolving `prUrl`. */
|
|
520
|
+
target?: ScmCloneTarget | undefined;
|
|
337
521
|
};
|
|
338
522
|
|
|
339
523
|
export type TryShallowPrCheckoutResult = {
|
|
@@ -352,53 +536,57 @@ export type TryShallowPrCheckoutResult = {
|
|
|
352
536
|
* reviewed repo instead of the host's own checkout.
|
|
353
537
|
*
|
|
354
538
|
* Returns no checkout — leaving the caller on its fallback working
|
|
355
|
-
* directory — when the PR
|
|
356
|
-
* checkout is the reviewed repo), when no head SHA is
|
|
357
|
-
* credential is available, or when the clone fails;
|
|
358
|
-
* which. Failures are logged, never thrown: agents
|
|
359
|
-
* patch in their prompts, so a missing checkout
|
|
360
|
-
* than the run.
|
|
539
|
+
* directory — when the PR's SCM has no clone support (e.g. Origin PRs,
|
|
540
|
+
* where the host checkout is the reviewed repo), when no head SHA is
|
|
541
|
+
* pinned, when no clone credential is available, or when the clone fails;
|
|
542
|
+
* `fallbackReason` says which. Failures are logged, never thrown: agents
|
|
543
|
+
* still have the pinned patch in their prompts, so a missing checkout
|
|
544
|
+
* degrades quality rather than the run.
|
|
361
545
|
*/
|
|
362
546
|
export async function tryCreateShallowPrCheckout(
|
|
363
547
|
options: TryShallowPrCheckoutOptions
|
|
364
548
|
): Promise<TryShallowPrCheckoutResult> {
|
|
365
|
-
const { prUrl,
|
|
366
|
-
|
|
367
|
-
if (
|
|
368
|
-
logShallowClone("skipped:
|
|
369
|
-
return { fallbackReason: "skipped:
|
|
549
|
+
const { prUrl, headSha, baseSha, checkoutDir } = options;
|
|
550
|
+
const target = options.target ?? resolveScmCloneTarget(prUrl);
|
|
551
|
+
if (target === undefined) {
|
|
552
|
+
logShallowClone("skipped: unsupported SCM for shallow clone", { prUrl });
|
|
553
|
+
return { fallbackReason: "skipped: unsupported SCM for shallow clone" };
|
|
370
554
|
}
|
|
371
555
|
if (headSha === undefined) {
|
|
372
|
-
logShallowClone("skipped: no pinned head SHA", {
|
|
556
|
+
logShallowClone("skipped: no pinned head SHA", {
|
|
557
|
+
repo: target.repo,
|
|
558
|
+
prUrl,
|
|
559
|
+
});
|
|
373
560
|
return { fallbackReason: "skipped: no pinned head SHA" };
|
|
374
561
|
}
|
|
375
|
-
const auth = options.auth ??
|
|
376
|
-
if (
|
|
377
|
-
// Fail fast instead of letting an unauthenticated fetch 404/hang:
|
|
378
|
-
//
|
|
379
|
-
logShallowClone("skipped: no
|
|
562
|
+
const auth = options.auth ?? defaultCloneAuth(target);
|
|
563
|
+
if (auth === undefined && target.remoteUrl.startsWith("https://")) {
|
|
564
|
+
// Fail fast instead of letting an unauthenticated fetch 404/hang: HTTPS
|
|
565
|
+
// clones need the provider's credential (or an explicit token).
|
|
566
|
+
logShallowClone("skipped: no clone credential", {
|
|
567
|
+
repo: target.repo,
|
|
568
|
+
provider: target.provider,
|
|
569
|
+
prUrl,
|
|
570
|
+
});
|
|
380
571
|
return {
|
|
381
|
-
fallbackReason:
|
|
382
|
-
"skipped: no GitHub clone credential (serve host GH_TOKEN lease not installed)",
|
|
572
|
+
fallbackReason: `skipped: no ${target.provider} clone credential (serve host token lease not installed)`,
|
|
383
573
|
};
|
|
384
574
|
}
|
|
385
575
|
try {
|
|
386
576
|
return {
|
|
387
577
|
checkout: await createShallowPrCheckout({
|
|
388
|
-
|
|
389
|
-
prNumber,
|
|
578
|
+
target,
|
|
390
579
|
headSha,
|
|
391
580
|
baseSha,
|
|
392
581
|
checkoutDir,
|
|
393
582
|
auth,
|
|
394
|
-
remoteUrl,
|
|
395
583
|
}),
|
|
396
584
|
};
|
|
397
585
|
} catch (error) {
|
|
398
586
|
const reason = errorSummary(error);
|
|
399
587
|
logShallowClone("failed; caller falls back to host checkout", {
|
|
400
|
-
repo,
|
|
401
|
-
prNumber,
|
|
588
|
+
repo: target.repo,
|
|
589
|
+
prNumber: target.prNumber,
|
|
402
590
|
headSha,
|
|
403
591
|
error: reason,
|
|
404
592
|
});
|