@skaile/workspaces 3.8.1 → 3.9.1

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/app-sdk/index.js +1 -1
  3. package/dist/{asset-feeds-6A2KVBQZ.js → asset-feeds-TFQDBOYM.js} +4 -4
  4. package/dist/{asset-feeds-6A2KVBQZ.js.map → asset-feeds-TFQDBOYM.js.map} +1 -1
  5. package/dist/asset-manager/index.js +1 -1
  6. package/dist/bridge/drivers/claude-sdk.js +12 -4
  7. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  8. package/dist/bridge/drivers/codex.js +1 -1
  9. package/dist/bridge/drivers/continue.js +2 -2
  10. package/dist/bridge/drivers/echo.js +1 -1
  11. package/dist/bridge/drivers/gemini.js +3 -3
  12. package/dist/bridge/drivers/goose.js +2 -2
  13. package/dist/bridge/drivers/omp.js +1 -1
  14. package/dist/bridge/drivers/opencode.js +2 -2
  15. package/dist/bridge/drivers/qwen.js +3 -3
  16. package/dist/bridge/index.js +2 -2
  17. package/dist/bridge/src/drivers/claude-sdk.d.ts +6 -0
  18. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  19. package/dist/{chunk-7SOLXVES.js → chunk-2KANBOIO.js} +29 -17
  20. package/dist/chunk-2KANBOIO.js.map +1 -0
  21. package/dist/{chunk-O3LEV6KB.js → chunk-2KBA5OO2.js} +4 -4
  22. package/dist/{chunk-O3LEV6KB.js.map → chunk-2KBA5OO2.js.map} +1 -1
  23. package/dist/{chunk-KLATRNFG.js → chunk-32MHUAED.js} +3 -3
  24. package/dist/{chunk-KLATRNFG.js.map → chunk-32MHUAED.js.map} +1 -1
  25. package/dist/{chunk-NVYEK4FI.js → chunk-4W2OOVN5.js} +3 -3
  26. package/dist/{chunk-NVYEK4FI.js.map → chunk-4W2OOVN5.js.map} +1 -1
  27. package/dist/{chunk-HCGVNO7F.js → chunk-6OVS6IAK.js} +2 -2
  28. package/dist/{chunk-HCGVNO7F.js.map → chunk-6OVS6IAK.js.map} +1 -1
  29. package/dist/{chunk-5YIGODSZ.js → chunk-BIA7TJWH.js} +2 -2
  30. package/dist/{chunk-5YIGODSZ.js.map → chunk-BIA7TJWH.js.map} +1 -1
  31. package/dist/{chunk-Q57ZGD4V.js → chunk-BO4NC4G7.js} +112 -83
  32. package/dist/chunk-BO4NC4G7.js.map +1 -0
  33. package/dist/{chunk-XNAY6FBK.js → chunk-DPIOHTDD.js} +3 -3
  34. package/dist/{chunk-XNAY6FBK.js.map → chunk-DPIOHTDD.js.map} +1 -1
  35. package/dist/{chunk-D5X2IXY7.js → chunk-HASPIEOD.js} +6 -6
  36. package/dist/{chunk-D5X2IXY7.js.map → chunk-HASPIEOD.js.map} +1 -1
  37. package/dist/{chunk-5MIXT2MV.js → chunk-HNKVHE4B.js} +4 -4
  38. package/dist/{chunk-5MIXT2MV.js.map → chunk-HNKVHE4B.js.map} +1 -1
  39. package/dist/{chunk-OI5VPP4P.js → chunk-K7W7HC3C.js} +3 -3
  40. package/dist/{chunk-OI5VPP4P.js.map → chunk-K7W7HC3C.js.map} +1 -1
  41. package/dist/{chunk-4P2P5KA5.js → chunk-NXUUNPIB.js} +3 -3
  42. package/dist/{chunk-4P2P5KA5.js.map → chunk-NXUUNPIB.js.map} +1 -1
  43. package/dist/{chunk-SO3BKY2Y.js → chunk-R2IQAJSU.js} +6 -6
  44. package/dist/{chunk-SO3BKY2Y.js.map → chunk-R2IQAJSU.js.map} +1 -1
  45. package/dist/{chunk-OIOJMSW2.js → chunk-RPZAX3II.js} +3 -3
  46. package/dist/{chunk-OIOJMSW2.js.map → chunk-RPZAX3II.js.map} +1 -1
  47. package/dist/{chunk-3ZL3GHON.js → chunk-WUOHDYDH.js} +2 -2
  48. package/dist/{chunk-3ZL3GHON.js.map → chunk-WUOHDYDH.js.map} +1 -1
  49. package/dist/{chunk-IWHPJFQ2.js → chunk-ZIC7S44L.js} +3 -3
  50. package/dist/{chunk-IWHPJFQ2.js.map → chunk-ZIC7S44L.js.map} +1 -1
  51. package/dist/cli/index.js +30 -30
  52. package/dist/connectors/index.js +3 -3
  53. package/dist/connectors/src/managed-gitconfig.d.ts +12 -21
  54. package/dist/connectors/src/managed-gitconfig.d.ts.map +1 -1
  55. package/dist/{ensure-sources-7DUTA24P.js → ensure-sources-PDAH5SAV.js} +4 -4
  56. package/dist/{ensure-sources-7DUTA24P.js.map → ensure-sources-PDAH5SAV.js.map} +1 -1
  57. package/dist/factory-assets/connectors/box.js +3 -3
  58. package/dist/factory-assets/connectors/deploy.js +3 -3
  59. package/dist/factory-assets/connectors/devserver.js +3 -3
  60. package/dist/factory-assets/connectors/flow/adapter.js +3 -3
  61. package/dist/factory-assets/connectors/flow/run-flow.js +4 -4
  62. package/dist/factory-assets/connectors/flow.js +3 -3
  63. package/dist/factory-assets/connectors/git/driver.d.ts +10 -15
  64. package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
  65. package/dist/factory-assets/connectors/git.js +3 -3
  66. package/dist/factory-assets/connectors/gmail.js +3 -3
  67. package/dist/factory-assets/connectors/googledrive.js +3 -3
  68. package/dist/factory-assets/connectors/local.js +3 -3
  69. package/dist/factory-assets/connectors/mattermost.js +3 -3
  70. package/dist/factory-assets/connectors/memory.js +3 -3
  71. package/dist/factory-assets/connectors/minio.js +3 -3
  72. package/dist/factory-assets/connectors/postgres.js +3 -3
  73. package/dist/factory-assets/connectors/s3.js +3 -3
  74. package/dist/factory-assets/connectors/sharepoint.js +3 -3
  75. package/dist/factory-assets/connectors/sqlite.js +3 -3
  76. package/dist/factory-assets/connectors/static-server.js +3 -3
  77. package/dist/factory-assets/connectors/tunnel.js +3 -3
  78. package/dist/factory-assets/connectors/webdav.js +3 -3
  79. package/dist/factory-assets/connectors/xstate-store.js +3 -3
  80. package/dist/factory-assets/connectors/xstate.js +3 -3
  81. package/dist/{helpers-IA562IEW.js → helpers-5OP6O3WS.js} +4 -4
  82. package/dist/{helpers-IA562IEW.js.map → helpers-5OP6O3WS.js.map} +1 -1
  83. package/dist/{library-publish-RQUQXZW6.js → library-publish-NNGVXORH.js} +6 -6
  84. package/dist/{library-publish-RQUQXZW6.js.map → library-publish-NNGVXORH.js.map} +1 -1
  85. package/dist/{open-library-74EQADJ4.js → open-library-5CEK2TSH.js} +5 -5
  86. package/dist/{open-library-74EQADJ4.js.map → open-library-5CEK2TSH.js.map} +1 -1
  87. package/dist/{project-OKXPPH2C.js → project-QOVJ7I6I.js} +5 -5
  88. package/dist/{project-OKXPPH2C.js.map → project-QOVJ7I6I.js.map} +1 -1
  89. package/dist/runner/index.js +7 -7
  90. package/dist/runner/src/ai-credential-retry.d.ts +21 -7
  91. package/dist/runner/src/ai-credential-retry.d.ts.map +1 -1
  92. package/dist/runner/src/ai-provider-switch.d.ts +8 -1
  93. package/dist/runner/src/ai-provider-switch.d.ts.map +1 -1
  94. package/dist/runner/src/serve.d.ts.map +1 -1
  95. package/dist/sdk/asset-manager.js +1 -1
  96. package/dist/sdk/bridge.js +2 -2
  97. package/dist/sdk/index.js +7 -7
  98. package/dist/sdk/runner.js +7 -7
  99. package/dist/sdk/session.js +2 -2
  100. package/dist/sdk/types.js +1 -1
  101. package/dist/session/index.js +2 -2
  102. package/dist/{setup-Q6ANIFZE.js → setup-ZB6U5MSS.js} +4 -4
  103. package/dist/{setup-Q6ANIFZE.js.map → setup-ZB6U5MSS.js.map} +1 -1
  104. package/dist/{source-P27ND6I4.js → source-O34YYH3U.js} +6 -6
  105. package/dist/{source-P27ND6I4.js.map → source-O34YYH3U.js.map} +1 -1
  106. package/dist/{source-manifest-publish-PKYHNVGG.js → source-manifest-publish-5TRCSBK7.js} +7 -7
  107. package/dist/{source-manifest-publish-PKYHNVGG.js.map → source-manifest-publish-5TRCSBK7.js.map} +1 -1
  108. package/dist/tui/index.js +7 -7
  109. package/dist/types/index.js +1 -1
  110. package/dist/types/src/index.d.ts +1 -1
  111. package/dist/types/src/index.d.ts.map +1 -1
  112. package/dist/types/src/lifecycle.d.ts +29 -0
  113. package/dist/types/src/lifecycle.d.ts.map +1 -1
  114. package/dist/types/src/version.d.ts +23 -1
  115. package/dist/types/src/version.d.ts.map +1 -1
  116. package/dist/workspace-plugin/index.js +1 -1
  117. package/package.json +1 -1
  118. package/dist/chunk-7SOLXVES.js.map +0 -1
  119. package/dist/chunk-Q57ZGD4V.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { resolveAuthRef } from './chunk-3UU3D2Q3.js';
2
- import { EventNormalizer } from './chunk-KLATRNFG.js';
2
+ import { EventNormalizer } from './chunk-32MHUAED.js';
3
3
  import { resolveModelTier } from './chunk-V34ZEXSE.js';
4
- import { createDriver } from './chunk-5YIGODSZ.js';
4
+ import { createDriver } from './chunk-BIA7TJWH.js';
5
5
  import { pluginRegistry } from './chunk-6E6PKKAD.js';
6
6
  import { computeStimulus } from './chunk-IFGTRL2I.js';
7
7
  import { resolveNodeBindings, getConsumedOutputSchema, validateConsumedNodeOutput, appendAttempt, resolveTerminalFailureStatus, remainingActiveExecutionMs, interpolateNodeInstruction, deriveCheckEvidence, computeFlowStateFromSnapshots, availableRouterFrontier, evaluateRouterSelection, routerSelectionOutput, planRouterSkips, unsettledRouterBranchIds, countFailedAttempts, hasAutomaticRetryBudget, persistedRouterSelection } from './chunk-OYZIURPH.js';
@@ -1353,11 +1353,14 @@ function git(args, cwd, timeout = 3e4) {
1353
1353
  function pathExists(path) {
1354
1354
  return tryWithFsDeadline(`stat ${path}`, () => stat(path).then(() => true), false);
1355
1355
  }
1356
- async function syncSubmodules(cwd) {
1356
+ async function syncSubmodules(cwd, log) {
1357
1357
  if (!await pathExists(join(cwd, ".gitmodules"))) return;
1358
1358
  try {
1359
1359
  await git(["submodule", "update", "--init", "--recursive"], cwd, 12e4);
1360
- } catch {
1360
+ } catch (err) {
1361
+ log.warn("git submodule update failed \u2014 checkout may be incomplete", {
1362
+ error: redactUrlAuth(err instanceof Error ? err.message : String(err))
1363
+ });
1361
1364
  }
1362
1365
  }
1363
1366
  function isValidGitRefOrSha(ref) {
@@ -1487,6 +1490,8 @@ var GitConnector = class extends AbstractConnector {
1487
1490
  const opts = declaration.options;
1488
1491
  const url = String(declaration.mount?.source ?? "");
1489
1492
  const branch = String(opts?.branch ?? "main");
1493
+ let credentialScopeUrl = url;
1494
+ let credentialAlignmentAttempted = false;
1490
1495
  if (!url) {
1491
1496
  this.log.error("connect failed: missing mount.source URL", void 0);
1492
1497
  throw new Error("Git connector requires a mount.source URL");
@@ -1523,15 +1528,17 @@ var GitConnector = class extends AbstractConnector {
1523
1528
  }
1524
1529
  if (declaration.mount?.exposeAccessToken === true) {
1525
1530
  try {
1526
- this.exposeManagedCredential(declaration, state, url, initial);
1531
+ if (initial.token && (url.startsWith("https://") || url.startsWith("http://")) && process.env.GIT_CONFIG_GLOBAL) {
1532
+ credentialAlignmentAttempted = true;
1533
+ credentialScopeUrl = await this.alignRemoteWithCredentialScope(targetDir, url);
1534
+ }
1535
+ this.exposeManagedCredential(declaration, state, credentialScopeUrl, initial);
1527
1536
  } catch (err) {
1528
1537
  this.log.error("managed-gitconfig write failed", err, { connectorId: declaration.id });
1529
1538
  throw err;
1530
1539
  }
1531
1540
  }
1532
- if (state.managedGitconfig) {
1533
- await this.stripRemoteInlineToken(targetDir);
1534
- } else {
1541
+ if (!state.managedGitconfig) {
1535
1542
  await this.rebakeRemoteAuth(targetDir, state);
1536
1543
  if (initial.authRef?.kind === "backend" && initial.expiresAt && state.tokenMediator) {
1537
1544
  this.scheduleRefresh(declaration.id, state, initial.expiresAt);
@@ -1544,7 +1551,18 @@ var GitConnector = class extends AbstractConnector {
1544
1551
  });
1545
1552
  return this.makeHandle(declaration, state, targetDir);
1546
1553
  } catch (err) {
1547
- this.registerUnavailableCredentialHelper(declaration, url, err);
1554
+ if (declaration.mount?.exposeAccessToken === true && (url.startsWith("https://") || url.startsWith("http://")) && process.env.GIT_CONFIG_GLOBAL && !credentialAlignmentAttempted && await pathExists(join(targetDir, ".git"))) {
1555
+ try {
1556
+ credentialAlignmentAttempted = true;
1557
+ credentialScopeUrl = await this.alignRemoteWithCredentialScope(targetDir, url);
1558
+ } catch (alignErr) {
1559
+ this.log.warn("failed to align origin for unavailable credential helper", {
1560
+ connectorId: declaration.id,
1561
+ error: alignErr instanceof Error ? alignErr.message : String(alignErr)
1562
+ });
1563
+ }
1564
+ }
1565
+ this.registerUnavailableCredentialHelper(declaration, credentialScopeUrl, err);
1548
1566
  throw err;
1549
1567
  }
1550
1568
  }
@@ -1654,7 +1672,7 @@ var GitConnector = class extends AbstractConnector {
1654
1672
  created = true;
1655
1673
  }
1656
1674
  }
1657
- await syncSubmodules(targetDir);
1675
+ await syncSubmodules(targetDir, this.log);
1658
1676
  state.activeBranch = sessionBranch;
1659
1677
  this.log.info("session branch checked out", { sessionBranch });
1660
1678
  if (created && state.lifecycle.publishOnCreate) {
@@ -1819,7 +1837,7 @@ var GitConnector = class extends AbstractConnector {
1819
1837
  this.log.debug("sync (pull) start", { branch: s.activeBranch });
1820
1838
  try {
1821
1839
  await git(["pull", "origin", s.activeBranch], handle.mountPath, 6e4);
1822
- await syncSubmodules(handle.mountPath);
1840
+ await syncSubmodules(handle.mountPath, this.log);
1823
1841
  this.log.debug("sync ok");
1824
1842
  } catch (err) {
1825
1843
  this.log.error("sync failed", err, { branch: s.activeBranch });
@@ -1892,51 +1910,46 @@ var GitConnector = class extends AbstractConnector {
1892
1910
  }
1893
1911
  const lc = s.lifecycle;
1894
1912
  const details = [];
1895
- const commitResult = await commitAll(handle.mountPath, `skaile: session close`);
1896
- if (commitResult) {
1897
- const sha = await git(["rev-parse", "--short", "HEAD"], handle.mountPath);
1898
- details.push(`Committed ${sha}`);
1899
- }
1900
- if (lc.pushOnClose || lc.mergeOnClose) {
1901
- await git(["push", "origin", s.activeBranch], handle.mountPath, 6e4);
1902
- details.push(`Pushed ${s.activeBranch}`);
1903
- }
1904
- if (lc.mergeOnClose && s.activeBranch !== s.branch) {
1905
- await git(["checkout", s.branch], handle.mountPath);
1906
- await git(["pull", "origin", s.branch], handle.mountPath, 6e4);
1907
- await syncSubmodules(handle.mountPath);
1908
- try {
1909
- await git(["merge", s.activeBranch], handle.mountPath);
1910
- } catch {
1911
- const resolved = await this.resolveConflictsOrAbort(s, handle.mountPath, "merge");
1912
- if (resolved) {
1913
- details.push("Resolved merge conflicts (created .conflict files)");
1914
- }
1913
+ try {
1914
+ const commitResult = await commitAll(handle.mountPath, `skaile: session close`);
1915
+ if (commitResult) {
1916
+ const sha = await git(["rev-parse", "--short", "HEAD"], handle.mountPath);
1917
+ details.push(`Committed ${sha}`);
1915
1918
  }
1916
- if (lc.pushOnClose) {
1917
- await git(["push", "origin", s.branch], handle.mountPath, 6e4);
1919
+ if (lc.pushOnClose || lc.mergeOnClose) {
1920
+ await git(["push", "origin", s.activeBranch], handle.mountPath, 6e4);
1921
+ details.push(`Pushed ${s.activeBranch}`);
1918
1922
  }
1919
- details.push(`Merged ${s.activeBranch} into ${s.branch}`);
1923
+ if (lc.mergeOnClose && s.activeBranch !== s.branch) {
1924
+ await git(["checkout", s.branch], handle.mountPath);
1925
+ await git(["pull", "origin", s.branch], handle.mountPath, 6e4);
1926
+ await syncSubmodules(handle.mountPath, this.log);
1927
+ try {
1928
+ await git(["merge", s.activeBranch], handle.mountPath);
1929
+ } catch {
1930
+ const resolved = await this.resolveConflictsOrAbort(s, handle.mountPath, "merge");
1931
+ if (resolved) {
1932
+ details.push("Resolved merge conflicts (created .conflict files)");
1933
+ }
1934
+ }
1935
+ if (lc.pushOnClose) {
1936
+ await git(["push", "origin", s.branch], handle.mountPath, 6e4);
1937
+ }
1938
+ details.push(`Merged ${s.activeBranch} into ${s.branch}`);
1939
+ }
1940
+ return details.join("; ") || void 0;
1941
+ } finally {
1942
+ this.teardownManagedCredential(handle.id, s);
1920
1943
  }
1921
- this.teardownManagedCredential(handle.id, s);
1922
- return details.join("; ") || void 0;
1923
1944
  }
1924
1945
  // ── Private: managed gitconfig (Tier-2 credential exposure) ──────────────
1925
1946
  /**
1926
- * Compute the URL prefix used to scope the credential helper. We key on
1927
- * host plus the first path segment when one is present (e.g. for
1928
- * `https://github.com/orgA/repo.git` we register
1929
- * `https://github.com/orgA/`). This lets two connectors on the same host
1930
- * with disjoint org prefixes coexist; same-host repos under one org just
1931
- * share the same scope.
1947
+ * Scope the credential helper to the sanitized full repository URL.
1948
+ * Userinfo, query, and fragment data must never enter managed gitconfig.
1932
1949
  */
1933
- deriveUrlPrefix(url) {
1950
+ deriveCredentialScope(url) {
1934
1951
  const u = new URL(url);
1935
- const segments = u.pathname.split("/").filter(Boolean);
1936
- if (segments.length > 0) {
1937
- return `${u.protocol}//${u.host}/${segments[0]}/`;
1938
- }
1939
- return `${u.protocol}//${u.host}`;
1952
+ return `${u.protocol}//${u.host}${u.pathname}`;
1940
1953
  }
1941
1954
  /**
1942
1955
  * Acquire the initial credential for a connector.
@@ -2021,7 +2034,7 @@ var GitConnector = class extends AbstractConnector {
2021
2034
  if (!gitconfigPath) return;
2022
2035
  const skaileDir = dirname(gitconfigPath);
2023
2036
  const credentialsPath = join(skaileDir, "git-credentials");
2024
- const urlPrefix = this.deriveUrlPrefix(url);
2037
+ const urlPrefix = this.deriveCredentialScope(url);
2025
2038
  const helperScriptPath = join(skaileDir, `credential-helper-${declaration.id}.sh`);
2026
2039
  const refreshAttemptPath = join(skaileDir, `refresh-attempt-${declaration.id}`);
2027
2040
  const reason = redactUrlAuth(err instanceof Error ? err.message : String(err));
@@ -2072,8 +2085,8 @@ var GitConnector = class extends AbstractConnector {
2072
2085
  /**
2073
2086
  * Best-effort removal of the unavailable-mount blocks that would answer this
2074
2087
  * connector's git operations: its own from a previous failed session, and any
2075
- * left under the same URL prefix by a sibling mount that failed earlier in
2076
- * this `connectAll` (git matches helpers by URL, not by mount id).
2088
+ * left under the same repository scope by a sibling mount that failed earlier
2089
+ * in this `connectAll` (git matches helpers by URL, not by mount id).
2077
2090
  */
2078
2091
  clearUnavailableCredentialHelper(connectorId, url) {
2079
2092
  const gitconfigPath = process.env.GIT_CONFIG_GLOBAL;
@@ -2081,7 +2094,7 @@ var GitConnector = class extends AbstractConnector {
2081
2094
  let urlPrefix;
2082
2095
  if (url.startsWith("https://") || url.startsWith("http://")) {
2083
2096
  try {
2084
- urlPrefix = this.deriveUrlPrefix(url);
2097
+ urlPrefix = this.deriveCredentialScope(url);
2085
2098
  } catch {
2086
2099
  }
2087
2100
  }
@@ -2122,7 +2135,7 @@ var GitConnector = class extends AbstractConnector {
2122
2135
  }
2123
2136
  const skaileDir = dirname(gitconfigPath);
2124
2137
  const credentialsPath = join(skaileDir, "git-credentials");
2125
- const urlPrefix = this.deriveUrlPrefix(url);
2138
+ const urlPrefix = this.deriveCredentialScope(url);
2126
2139
  const refreshFlagPath = join(skaileDir, "refresh-request");
2127
2140
  const helperScriptPath = join(skaileDir, `credential-helper-${declaration.id}.sh`);
2128
2141
  const refreshAttemptPath = join(skaileDir, `refresh-attempt-${declaration.id}`);
@@ -2446,7 +2459,7 @@ var GitConnector = class extends AbstractConnector {
2446
2459
  await git(["fetch", "--depth=1", "origin", branch], targetDir, 12e4);
2447
2460
  await this.preserveConflictingUntracked(targetDir, branch);
2448
2461
  await git(["checkout", "-B", branch, `origin/${branch}`], targetDir, 3e4);
2449
- await syncSubmodules(targetDir);
2462
+ await syncSubmodules(targetDir, this.log);
2450
2463
  try {
2451
2464
  await git(["branch", `--set-upstream-to=origin/${branch}`, branch], targetDir, 5e3);
2452
2465
  } catch {
@@ -2507,26 +2520,20 @@ var GitConnector = class extends AbstractConnector {
2507
2520
  return s.url;
2508
2521
  }
2509
2522
  /**
2510
- * Rewrite `origin` to drop any inline `user:password@` credentials, leaving
2511
- * a bare https(s) URL. Tier-2 only: the managed credential helper supplies
2512
- * (and refreshes) the token, but git ignores helpers when the URL already
2513
- * carries creds — so the baked-in token must go. Best-effort: a missing
2514
- * origin or a non-http(s) remote (e.g. file:// in tests) is left untouched.
2523
+ * Align `origin` with the exact sanitized URL used by the Tier-2 helper.
2524
+ * Git does not normalize query/fragment data, path case, or `.git` aliases
2525
+ * when matching `credential.<url>` sections, so the two strings must agree.
2526
+ * The declared mount source remains authoritative over an existing remote.
2515
2527
  */
2516
- async stripRemoteInlineToken(targetDir) {
2517
- try {
2518
- const current = await git(["remote", "get-url", "origin"], targetDir, 5e3);
2519
- if (!current.startsWith("https://") && !current.startsWith("http://")) return;
2520
- const u = new URL(current);
2521
- if (!u.username && !u.password) return;
2522
- u.username = "";
2523
- u.password = "";
2524
- await git(["remote", "set-url", "origin", u.toString()], targetDir, 5e3);
2525
- } catch (err) {
2526
- this.log.warn("managed-gitconfig: failed to strip inline token from origin", {
2527
- error: err instanceof Error ? err.message : String(err)
2528
- });
2528
+ async alignRemoteWithCredentialScope(targetDir, declaredUrl) {
2529
+ const credentialScopeUrl = this.deriveCredentialScope(declaredUrl);
2530
+ const remotes = (await git(["remote"], targetDir, 5e3)).split(/\r?\n/);
2531
+ if (!remotes.includes("origin")) {
2532
+ await git(["remote", "add", "origin", credentialScopeUrl], targetDir, 5e3);
2533
+ } else if (await git(["remote", "get-url", "origin"], targetDir, 5e3) !== credentialScopeUrl) {
2534
+ await git(["remote", "set-url", "origin", credentialScopeUrl], targetDir, 5e3);
2529
2535
  }
2536
+ return credentialScopeUrl;
2530
2537
  }
2531
2538
  /**
2532
2539
  * Tier-1 only: rewrite `origin` so it carries the token freshly minted on
@@ -2579,11 +2586,11 @@ var GitConnector = class extends AbstractConnector {
2579
2586
  await this.resolveConflictsOrAbort(s, mountPath, "rebase");
2580
2587
  }
2581
2588
  if (s.disposed) return;
2582
- await syncSubmodules(mountPath);
2589
+ await syncSubmodules(mountPath, this.log);
2583
2590
  } else if (s.sync.autoPull) {
2584
2591
  await git(["pull", "origin", s.activeBranch], mountPath, 6e4);
2585
2592
  if (s.disposed) return;
2586
- await syncSubmodules(mountPath);
2593
+ await syncSubmodules(mountPath, this.log);
2587
2594
  }
2588
2595
  }
2589
2596
  // ── Conflict resolution ──────────────────────────────────────────────────
@@ -7573,7 +7580,7 @@ var ManagedGitconfigCollisionError = class extends Error {
7573
7580
  newMountId;
7574
7581
  constructor(urlPrefix, existingMountId, newMountId) {
7575
7582
  super(
7576
- `Mount '${newMountId}' tried to register URL prefix '${urlPrefix}' but mount '${existingMountId}' already owns it with a different credential. Narrow the prefixes (e.g. include the org segment) or consolidate the mounts.`
7583
+ `Mount '${newMountId}' tried to register repository credential scope '${urlPrefix}' but mount '${existingMountId}' already owns the same repository identity. Use one credential-exposing mount per repository or disable exposeAccessToken on one mount.`
7577
7584
  );
7578
7585
  this.name = "ManagedGitconfigCollisionError";
7579
7586
  this.urlPrefix = urlPrefix;
@@ -7689,6 +7696,21 @@ function blockUrlPrefix(block) {
7689
7696
  }
7690
7697
  return void 0;
7691
7698
  }
7699
+ function repositoryScopeIdentity(scope) {
7700
+ try {
7701
+ const url = new URL(scope);
7702
+ let pathname = url.pathname.replace(/\/+$/, "").replace(/\.git$/i, "");
7703
+ if (url.hostname === "github.com") {
7704
+ pathname = pathname.toLowerCase();
7705
+ }
7706
+ return `${url.protocol}//${url.host}${pathname}`;
7707
+ } catch {
7708
+ return scope;
7709
+ }
7710
+ }
7711
+ function scopesTargetSameRepository(left, right) {
7712
+ return repositoryScopeIdentity(left) === repositoryScopeIdentity(right);
7713
+ }
7692
7714
  function isUnavailableBlock(block) {
7693
7715
  return block.lines.some((l) => l.trim() === UNAVAILABLE_MARKER);
7694
7716
  }
@@ -7700,11 +7722,14 @@ function writeMountBlock(opts) {
7700
7722
  if (b.mountId === "" || b.mountId === mountId) continue;
7701
7723
  if (isUnavailableBlock(b)) continue;
7702
7724
  const otherPrefix = blockUrlPrefix(b);
7703
- if (otherPrefix === urlPrefix) {
7725
+ if (otherPrefix !== void 0 && scopesTargetSameRepository(otherPrefix, urlPrefix)) {
7704
7726
  throw new ManagedGitconfigCollisionError(urlPrefix, b.mountId, mountId);
7705
7727
  }
7706
7728
  }
7707
- const blocks = parsed.filter((b) => !(isUnavailableBlock(b) && blockUrlPrefix(b) === urlPrefix));
7729
+ const blocks = parsed.filter((b) => {
7730
+ const otherPrefix = blockUrlPrefix(b);
7731
+ return !(isUnavailableBlock(b) && otherPrefix !== void 0 && scopesTargetSameRepository(otherPrefix, urlPrefix));
7732
+ });
7708
7733
  const newBlock = {
7709
7734
  mountId,
7710
7735
  lines: buildBlock(mountId, urlPrefix, credentialsPath, helperScriptPath)
@@ -7734,7 +7759,8 @@ function writeUnavailableMountBlock(opts) {
7734
7759
  for (const b of blocks) {
7735
7760
  if (b.mountId === "" || b.mountId === mountId) continue;
7736
7761
  if (isUnavailableBlock(b)) continue;
7737
- if (blockUrlPrefix(b) === urlPrefix) return;
7762
+ const otherPrefix = blockUrlPrefix(b);
7763
+ if (otherPrefix !== void 0 && scopesTargetSameRepository(otherPrefix, urlPrefix)) return;
7738
7764
  }
7739
7765
  const newLines = [
7740
7766
  blockStart(mountId),
@@ -7757,9 +7783,12 @@ function removeUnavailableMountBlock(opts) {
7757
7783
  if (text.length === 0) return;
7758
7784
  const blocks = parseBlocks(text);
7759
7785
  const doomed = new Set(
7760
- blocks.filter(
7761
- (b) => isUnavailableBlock(b) && (b.mountId === mountId || urlPrefix !== void 0 && blockUrlPrefix(b) === urlPrefix)
7762
- )
7786
+ blocks.filter((b) => {
7787
+ if (!isUnavailableBlock(b)) return false;
7788
+ if (b.mountId === mountId) return true;
7789
+ const otherPrefix = blockUrlPrefix(b);
7790
+ return urlPrefix !== void 0 && otherPrefix !== void 0 && scopesTargetSameRepository(otherPrefix, urlPrefix);
7791
+ })
7763
7792
  );
7764
7793
  if (doomed.size === 0) return;
7765
7794
  atomicWrite(gitconfigPath, renderBlocks(blocks.filter((b) => !doomed.has(b))), 416);
@@ -10553,5 +10582,5 @@ function createConnector() {
10553
10582
  }
10554
10583
 
10555
10584
  export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, BoxConnector, ConnectorFieldMissingError, ConnectorManager, ConnectorStartupError, DeployConnector, DevServerConnector, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, PortPool, PostgresConnector, S3Connector, SQLiteConnector, SessionInlineSubFlowRunner, SessionNodeExecutor, SessionSubpromptRunner, SharePointConnector, StaticServerConnector, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, __test, atomicReplaceCredential, buildConnectorPromptSection, buildFlowPromptEvent, buildSdkConnectorTools, buildSdkFlowTools, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector20, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createFsWatcher, createWorktree, defaultSpawn, driveOrchestratorTurn, ensureDirMode, ensureFleetMounted, ensureRefreshAttemptStamp, findGitRoot, findMissingPackages, getConnector, installNpmPackages, isFleetManaged, isPackageResolvable, listConnectors, listWorktrees, readGitSyncStatus, registerBuiltinConnectors, removeMountBlock, removeUnavailableMountBlock, renderCredentialHelperScript, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock, writeUnavailableMountBlock };
10556
- //# sourceMappingURL=chunk-Q57ZGD4V.js.map
10557
- //# sourceMappingURL=chunk-Q57ZGD4V.js.map
10585
+ //# sourceMappingURL=chunk-BO4NC4G7.js.map
10586
+ //# sourceMappingURL=chunk-BO4NC4G7.js.map