@proagentstore/cli 0.4.38 → 0.4.39

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.
@@ -19,11 +19,35 @@ import { join } from "node:path";
19
19
  export function sanitizeSessionName(label) {
20
20
  return label.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60) || "session";
21
21
  }
22
+ /**
23
+ * The clone URL with the credential embedded, or the URL untouched.
24
+ *
25
+ * PURE and exported so the one line that decides where a credential goes is unit-testable
26
+ * without a network or a git binary. `username` is provider-specific — GitHub wants
27
+ * `x-access-token`, GitLab `oauth2`, Bitbucket `x-token-auth` (#221) — and it defaults to the
28
+ * value this function used to hardcode, so a cloud that sends only `token` behaves as before.
29
+ *
30
+ * Only https carries a credential: git ignores userinfo on an ssh URL, so injecting there would
31
+ * be pure exposure for no effect. Both halves are percent-encoded — a secret containing `@`,
32
+ * `/` or `:` would otherwise re-parse the URL into a DIFFERENT host and send the credential
33
+ * there. GitHub's tokens contain none of those, so nothing changes for the existing provider.
34
+ */
35
+ export function authenticatedCloneUrl(cloneUrl, token, username) {
36
+ if (!token || !/^https:\/\//i.test(cloneUrl))
37
+ return cloneUrl;
38
+ const user = encodeURIComponent(username || "x-access-token");
39
+ return cloneUrl.replace(/^https:\/\//i, `https://${user}:${encodeURIComponent(token)}@`);
40
+ }
22
41
  /**
23
42
  * Ensure a repo is present at `dir`, cloning it from `cloneUrl` if not. Idempotent
24
- * — an existing checkout is left alone (no clobber). For private repos a GitHub
25
- * App installation token is injected as `x-access-token` into an https URL. The
26
- * coding CLI then runs in this directory.
43
+ * — an existing checkout is left alone (no clobber). For private repos the cloud
44
+ * sends a token, injected as the password half of an https URL. The coding CLI then
45
+ * runs in this directory.
46
+ *
47
+ * `tokenUsername` is the USERNAME half, and it is provider-specific: GitHub wants
48
+ * `x-access-token`, GitLab `oauth2`, Bitbucket `x-token-auth` (#221). It defaults to
49
+ * `x-access-token` — the value this function used to hardcode — so an older cloud that
50
+ * sends only `token` behaves exactly as before.
27
51
  *
28
52
  * Returns the absolute working directory. Throws on clone failure so the caller
29
53
  * can surface it (a session can't start without its repo).
@@ -50,10 +74,7 @@ export function ensureRepo(dir, opts = {}) {
50
74
  }
51
75
  rmSync(dir, { recursive: true, force: true });
52
76
  }
53
- let url = opts.cloneUrl;
54
- if (opts.token && /^https:\/\//.test(url)) {
55
- url = url.replace(/^https:\/\//, `https://x-access-token:${opts.token}@`);
56
- }
77
+ const url = authenticatedCloneUrl(opts.cloneUrl, opts.token, opts.tokenUsername);
57
78
  const args = ["clone", "--depth", "1"];
58
79
  if (opts.branch)
59
80
  args.push("--branch", opts.branch);
@@ -71,7 +71,7 @@ export class CodingRuntime {
71
71
  const workDir = input.workDir
72
72
  ? resolve(input.workDir.replace(/^~(?=$|\/)/, homedir()))
73
73
  : join(this.reposBaseDir, sanitizeSessionName(input.repoId));
74
- ensureRepo(workDir, { cloneUrl: input.cloneUrl, branch: input.branch, token: input.token });
74
+ ensureRepo(workDir, { cloneUrl: input.cloneUrl, branch: input.branch, token: input.token, tokenUsername: input.tokenUsername });
75
75
  session = new HeadlessSession({
76
76
  id: input.sessionId,
77
77
  workDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.38",
3
+ "version": "0.4.39",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",