@databricks-solutions/lakebase-scm-utils 0.2.47 → 0.2.49

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 (52) hide show
  1. package/dist/ci-secrets-CnGrdQV-.d.cts +84 -0
  2. package/dist/ci-secrets-CnGrdQV-.d.ts +84 -0
  3. package/dist/scripts/index.cjs +2230 -2052
  4. package/dist/scripts/index.d.cts +3 -2
  5. package/dist/scripts/index.d.ts +3 -2
  6. package/dist/scripts/index.js +305 -134
  7. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
  8. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
  9. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
  10. package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
  11. package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
  12. package/dist/scripts/lakebase/detect-language.cli.js +2 -2
  13. package/dist/scripts/lakebase/doctor.cli.cjs +2 -2
  14. package/dist/scripts/lakebase/doctor.cli.js +2 -2
  15. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  16. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  17. package/dist/scripts/lakebase/index.cjs +2216 -2050
  18. package/dist/scripts/lakebase/index.d.cts +37 -11
  19. package/dist/scripts/lakebase/index.d.ts +37 -11
  20. package/dist/scripts/lakebase/index.js +295 -130
  21. package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
  22. package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
  23. package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
  24. package/dist/scripts/lakebase/new-migration.cli.js +2 -2
  25. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  26. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  27. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
  28. package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
  29. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
  30. package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
  31. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  32. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  33. package/dist/scripts/lakebase/scm-merge.cli.cjs +2345 -1994
  34. package/dist/scripts/lakebase/scm-merge.cli.js +425 -74
  35. package/dist/scripts/lakebase/scm-prepare-pr.cli.cjs +479 -86
  36. package/dist/scripts/lakebase/scm-prepare-pr.cli.js +479 -86
  37. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  38. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  39. package/dist/scripts/lakebase/sync-ci-secrets.cli.cjs +56 -30
  40. package/dist/scripts/lakebase/sync-ci-secrets.cli.js +56 -30
  41. package/dist/scripts/util/index.cjs +142 -25
  42. package/dist/scripts/util/index.d.cts +2 -27
  43. package/dist/scripts/util/index.d.ts +2 -27
  44. package/dist/scripts/util/index.js +136 -25
  45. package/package.json +1 -1
  46. package/scripts/lakebase/create-project.ts +2 -2
  47. package/scripts/lakebase/scm-merge.ts +112 -0
  48. package/scripts/lakebase/scm-prepare-pr.ts +10 -1
  49. package/scripts/lakebase/sync-ci-secrets.cli.ts +2 -2
  50. package/scripts/util/ci-secrets.ts +212 -26
  51. package/templates/project/common/.gitignore.base +4 -6
  52. package/templates/project/common/scripts/create-token-and-sync-secrets.sh +9 -86
@@ -1457,7 +1457,7 @@ var require_light = __commonJS({
1457
1457
 
1458
1458
  // scripts/lakebase/scm-merge.cli.ts
1459
1459
  init_esm_shims();
1460
- import * as path13 from "path";
1460
+ import * as path14 from "path";
1461
1461
 
1462
1462
  // scripts/util/cli-entry.ts
1463
1463
  init_esm_shims();
@@ -2549,7 +2549,7 @@ paginateRest.VERSION = VERSION5;
2549
2549
 
2550
2550
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
2551
2551
  init_esm_shims();
2552
- var generateMessage = (path14, cursorValue) => `The cursor at "${path14.join(
2552
+ var generateMessage = (path15, cursorValue) => `The cursor at "${path15.join(
2553
2553
  ","
2554
2554
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
2555
2555
  var MissingCursorChange = class extends Error {
@@ -2590,9 +2590,9 @@ function findPaginatedResourcePath(responseData) {
2590
2590
  }
2591
2591
  return paginatedResourcePath;
2592
2592
  }
2593
- var deepFindPathToProperty = (object, searchProp, path14 = []) => {
2593
+ var deepFindPathToProperty = (object, searchProp, path15 = []) => {
2594
2594
  for (const key of Object.keys(object)) {
2595
- const currentPath = [...path14, key];
2595
+ const currentPath = [...path15, key];
2596
2596
  const currentValue = object[key];
2597
2597
  if (isObject(currentValue)) {
2598
2598
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -2610,12 +2610,12 @@ var deepFindPathToProperty = (object, searchProp, path14 = []) => {
2610
2610
  }
2611
2611
  return [];
2612
2612
  };
2613
- var get = (object, path14) => {
2614
- return path14.reduce((current, nextProperty) => current[nextProperty], object);
2613
+ var get = (object, path15) => {
2614
+ return path15.reduce((current, nextProperty) => current[nextProperty], object);
2615
2615
  };
2616
- var set = (object, path14, mutator) => {
2617
- const lastProperty = path14[path14.length - 1];
2618
- const parentPath = [...path14].slice(0, -1);
2616
+ var set = (object, path15, mutator) => {
2617
+ const lastProperty = path15[path15.length - 1];
2618
+ const parentPath = [...path15].slice(0, -1);
2619
2619
  const parent = get(object, parentPath);
2620
2620
  if (typeof mutator === "function") {
2621
2621
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -2667,22 +2667,22 @@ var mergeResponses = (response1, response2) => {
2667
2667
  if (Object.keys(response1).length === 0) {
2668
2668
  return Object.assign(response1, response2);
2669
2669
  }
2670
- const path14 = findPaginatedResourcePath(response1);
2671
- const nodesPath = [...path14, "nodes"];
2670
+ const path15 = findPaginatedResourcePath(response1);
2671
+ const nodesPath = [...path15, "nodes"];
2672
2672
  const newNodes = get(response2, nodesPath);
2673
2673
  if (newNodes) {
2674
2674
  set(response1, nodesPath, (values) => {
2675
2675
  return [...values, ...newNodes];
2676
2676
  });
2677
2677
  }
2678
- const edgesPath = [...path14, "edges"];
2678
+ const edgesPath = [...path15, "edges"];
2679
2679
  const newEdges = get(response2, edgesPath);
2680
2680
  if (newEdges) {
2681
2681
  set(response1, edgesPath, (values) => {
2682
2682
  return [...values, ...newEdges];
2683
2683
  });
2684
2684
  }
2685
- const pageInfoPath = [...path14, "pageInfo"];
2685
+ const pageInfoPath = [...path15, "pageInfo"];
2686
2686
  set(response1, pageInfoPath, get(response2, pageInfoPath));
2687
2687
  return response1;
2688
2688
  };
@@ -5103,7 +5103,7 @@ var triggers_notification_paths_default = [
5103
5103
  ];
5104
5104
  function routeMatcher(paths) {
5105
5105
  const regexes = paths.map(
5106
- (path14) => path14.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5106
+ (path15) => path15.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5107
5107
  );
5108
5108
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
5109
5109
  return new RegExp(regex2, "i");
@@ -8378,9 +8378,9 @@ function asBranchUid(s) {
8378
8378
  }
8379
8379
  return s;
8380
8380
  }
8381
- function branchNameFromResourcePath(path14) {
8382
- if (!path14.includes("/branches/")) return null;
8383
- const leaf = path14.split("/branches/").pop();
8381
+ function branchNameFromResourcePath(path15) {
8382
+ if (!path15.includes("/branches/")) return null;
8383
+ const leaf = path15.split("/branches/").pop();
8384
8384
  if (!leaf) return null;
8385
8385
  try {
8386
8386
  return asBranchName(leaf);
@@ -8609,6 +8609,84 @@ function wrap(err, context) {
8609
8609
  }
8610
8610
  throw new GitHubPullRequestError(context);
8611
8611
  }
8612
+ async function getPullRequest(ownerRepo, headBranch) {
8613
+ try {
8614
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8615
+ const ok = await octokit();
8616
+ const { data: pulls } = await ok.rest.pulls.list({
8617
+ owner,
8618
+ repo,
8619
+ state: "open",
8620
+ head: `${owner}:${headBranch}`,
8621
+ per_page: 1
8622
+ });
8623
+ if (pulls.length === 0) return void 0;
8624
+ const { data: pr } = await ok.rest.pulls.get({
8625
+ owner,
8626
+ repo,
8627
+ pull_number: pulls[0].number
8628
+ });
8629
+ if (pr.state !== "open") return void 0;
8630
+ let checks = [];
8631
+ let ciStatus = "pending";
8632
+ const headSha = pr.head?.sha;
8633
+ if (headSha) {
8634
+ try {
8635
+ const { data: checksData } = await ok.rest.checks.listForRef({
8636
+ owner,
8637
+ repo,
8638
+ ref: headSha
8639
+ });
8640
+ const runs = checksData.check_runs || [];
8641
+ checks = runs.map((c) => ({
8642
+ name: c.name || "unknown",
8643
+ status: (c.status || "").toUpperCase(),
8644
+ conclusion: (c.conclusion || "").toUpperCase(),
8645
+ detailsUrl: c.details_url || void 0
8646
+ }));
8647
+ ciStatus = parseCiStatus(runs);
8648
+ } catch {
8649
+ ciStatus = "pending";
8650
+ }
8651
+ }
8652
+ return {
8653
+ number: pr.number,
8654
+ title: pr.title,
8655
+ url: pr.html_url || "",
8656
+ state: (pr.state || "open").toUpperCase(),
8657
+ isDraft: pr.draft || false,
8658
+ ciStatus,
8659
+ checks,
8660
+ mergeable: pr.mergeable,
8661
+ mergeableState: pr.mergeable_state,
8662
+ headBranch: pr.head?.ref || headBranch,
8663
+ baseBranch: pr.base?.ref || "",
8664
+ body: pr.body || void 0,
8665
+ additions: pr.additions,
8666
+ deletions: pr.deletions,
8667
+ changedFiles: pr.changed_files
8668
+ };
8669
+ } catch {
8670
+ return void 0;
8671
+ }
8672
+ }
8673
+ function parseCiStatus(rawChecks) {
8674
+ if (rawChecks.length === 0) return "pending";
8675
+ const latestByName = /* @__PURE__ */ new Map();
8676
+ for (const c of rawChecks) {
8677
+ latestByName.set(c.name || "unknown", c);
8678
+ }
8679
+ const states = Array.from(latestByName.values()).map(
8680
+ (c) => (c.conclusion || c.status || "").toUpperCase()
8681
+ );
8682
+ if (states.some((s) => s === "FAILURE" || s === "ERROR" || s === "ACTION_REQUIRED")) {
8683
+ return "failure";
8684
+ }
8685
+ if (states.every((s) => s === "SUCCESS" || s === "NEUTRAL" || s === "SKIPPED")) {
8686
+ return "success";
8687
+ }
8688
+ return "pending";
8689
+ }
8612
8690
  async function mergePullRequest(args) {
8613
8691
  const method = args.method ?? "merge";
8614
8692
  const deleteRemoteBranch = args.deleteRemoteBranch !== false;
@@ -8739,6 +8817,219 @@ async function getOwnerRepo(cwd) {
8739
8817
  }
8740
8818
  }
8741
8819
 
8820
+ // scripts/util/ci-secrets.ts
8821
+ init_esm_shims();
8822
+ import * as path3 from "path";
8823
+
8824
+ // scripts/github/secrets.ts
8825
+ init_esm_shims();
8826
+ import sodium from "tweetsodium";
8827
+ var GitHubSecretsError = class extends Error {
8828
+ status;
8829
+ constructor(message, status) {
8830
+ super(message);
8831
+ this.name = "GitHubSecretsError";
8832
+ this.status = status;
8833
+ }
8834
+ };
8835
+ async function getOctokit() {
8836
+ const token = await resolveGitHubToken();
8837
+ return new Octokit2({ auth: token });
8838
+ }
8839
+ function wrap2(err, context) {
8840
+ if (err instanceof RequestError) {
8841
+ throw new GitHubSecretsError(`${context}: ${err.message}`, err.status);
8842
+ }
8843
+ if (err instanceof Error) {
8844
+ throw new GitHubSecretsError(`${context}: ${err.message}`);
8845
+ }
8846
+ throw new GitHubSecretsError(context);
8847
+ }
8848
+ function encryptSecret(publicKey, secretValue) {
8849
+ const keyBytes = Buffer.from(publicKey, "base64");
8850
+ const messageBytes = Buffer.from(secretValue);
8851
+ const encryptedBytes = sodium.seal(messageBytes, keyBytes);
8852
+ return Buffer.from(encryptedBytes).toString("base64");
8853
+ }
8854
+ async function setRepoSecret(ownerRepo, secretName, secretValue) {
8855
+ try {
8856
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8857
+ const octokit2 = await getOctokit();
8858
+ const { data: keyData } = await octokit2.rest.actions.getRepoPublicKey({ owner, repo });
8859
+ const encryptedValue = encryptSecret(keyData.key, secretValue);
8860
+ await octokit2.rest.actions.createOrUpdateRepoSecret({
8861
+ owner,
8862
+ repo,
8863
+ secret_name: secretName,
8864
+ encrypted_value: encryptedValue,
8865
+ key_id: keyData.key_id
8866
+ });
8867
+ } catch (err) {
8868
+ if (err instanceof GitHubSecretsError) throw err;
8869
+ wrap2(err, `Failed to set secret ${secretName} on ${ownerRepo}`);
8870
+ }
8871
+ }
8872
+ async function setRepoSecrets(ownerRepo, secrets) {
8873
+ for (const [name, value] of Object.entries(secrets)) {
8874
+ if (!value) {
8875
+ throw new GitHubSecretsError(`Missing value for secret ${name}`);
8876
+ }
8877
+ }
8878
+ for (const [name, value] of Object.entries(secrets)) {
8879
+ await setRepoSecret(ownerRepo, name, value);
8880
+ }
8881
+ }
8882
+ async function listSecretNames(ownerRepo) {
8883
+ try {
8884
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8885
+ const octokit2 = await getOctokit();
8886
+ const { data } = await octokit2.rest.actions.listRepoSecrets({ owner, repo });
8887
+ return data.secrets.map((s) => s.name);
8888
+ } catch {
8889
+ return [];
8890
+ }
8891
+ }
8892
+
8893
+ // scripts/util/ci-secrets.ts
8894
+ var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
8895
+ var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
8896
+ var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
8897
+ function ciTokenComment(ownerRepo) {
8898
+ const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
8899
+ return `GitHub Actions (${repoName})`;
8900
+ }
8901
+ async function missingCiSecrets(ownerRepo) {
8902
+ const present = new Set(await listSecretNames(ownerRepo));
8903
+ return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
8904
+ }
8905
+ async function mintCiToken(args) {
8906
+ try {
8907
+ const raw = await runDatabricks(
8908
+ ["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
8909
+ { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
8910
+ );
8911
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8912
+ const token = parsed.token_value || parsed.token || "";
8913
+ if (token) return token;
8914
+ } catch {
8915
+ }
8916
+ try {
8917
+ const raw = await runDatabricks(["auth", "token", "-o", "json"], {
8918
+ host: args.databricksHost,
8919
+ cwd: args.projectDir,
8920
+ timeout: 3e4
8921
+ });
8922
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8923
+ return parsed.access_token || "";
8924
+ } catch {
8925
+ return "";
8926
+ }
8927
+ }
8928
+ async function syncCiSecrets(args) {
8929
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8930
+ if (!ownerRepo) {
8931
+ throw new Error("Could not resolve GitHub repository from git remote");
8932
+ }
8933
+ if (!args.databricksHost) {
8934
+ throw new Error("syncCiSecrets: databricksHost is required");
8935
+ }
8936
+ if (!args.lakebaseProjectId) {
8937
+ throw new Error("syncCiSecrets: lakebaseProjectId is required");
8938
+ }
8939
+ const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
8940
+ const comment = args.comment ?? ciTokenComment(ownerRepo);
8941
+ const secrets = {
8942
+ DATABRICKS_HOST: args.databricksHost,
8943
+ LAKEBASE_PROJECT_ID: args.lakebaseProjectId
8944
+ };
8945
+ const token = await mintCiToken({
8946
+ databricksHost: args.databricksHost,
8947
+ projectDir: args.projectDir,
8948
+ comment,
8949
+ lifetimeSeconds: lifetime
8950
+ });
8951
+ if (token) secrets.DATABRICKS_TOKEN = token;
8952
+ await setRepoSecrets(ownerRepo, secrets);
8953
+ }
8954
+ async function ciTokenExpiry(args) {
8955
+ const comment = ciTokenComment(args.ownerRepo);
8956
+ let raw;
8957
+ try {
8958
+ raw = await runDatabricks(["tokens", "list", "-o", "json"], {
8959
+ host: args.databricksHost,
8960
+ cwd: args.projectDir,
8961
+ timeout: 3e4
8962
+ });
8963
+ } catch {
8964
+ return null;
8965
+ }
8966
+ let infos;
8967
+ try {
8968
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
8969
+ infos = Array.isArray(parsed) ? parsed : [];
8970
+ } catch {
8971
+ return null;
8972
+ }
8973
+ const expiries = infos.filter((t) => t.comment === comment).map((t) => t.expiry_time === -1 ? Number.POSITIVE_INFINITY : Number(t.expiry_time)).filter((n) => Number.isFinite(n) || n === Number.POSITIVE_INFINITY);
8974
+ if (expiries.length === 0) return null;
8975
+ return Math.max(...expiries);
8976
+ }
8977
+ async function ensureCiSecretsFresh(args) {
8978
+ const now = args.now ?? Date.now;
8979
+ const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
8980
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8981
+ if (!ownerRepo) {
8982
+ throw new Error("Could not resolve GitHub repository from git remote");
8983
+ }
8984
+ const sync = () => syncCiSecrets({
8985
+ projectDir: args.projectDir,
8986
+ databricksHost: args.databricksHost,
8987
+ lakebaseProjectId: args.lakebaseProjectId,
8988
+ ownerRepo
8989
+ });
8990
+ const missing = await missingCiSecrets(ownerRepo);
8991
+ if (missing.length > 0) {
8992
+ await sync();
8993
+ return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
8994
+ }
8995
+ const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
8996
+ if (expiry === null) {
8997
+ await sync();
8998
+ return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
8999
+ }
9000
+ if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
9001
+ await sync();
9002
+ const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
9003
+ return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
9004
+ }
9005
+ return { action: "ok", reason: "CI token is current." };
9006
+ }
9007
+ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
9008
+ const envPath = path3.join(projectDir, ".env");
9009
+ const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
9010
+ const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
9011
+ if (!databricksHost || !lakebaseProjectId) {
9012
+ return {
9013
+ action: "skipped",
9014
+ reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
9015
+ };
9016
+ }
9017
+ try {
9018
+ return await ensureCiSecretsFresh({
9019
+ projectDir,
9020
+ databricksHost,
9021
+ lakebaseProjectId,
9022
+ ownerRepo: opts?.ownerRepo,
9023
+ marginSeconds: opts?.marginSeconds
9024
+ });
9025
+ } catch (err) {
9026
+ return {
9027
+ action: "failed",
9028
+ reason: `CI-auth preflight could not re-mint (${err instanceof Error ? err.message : String(err)}); if CI fails on auth, run lakebase-sync-ci-secrets.`
9029
+ };
9030
+ }
9031
+ }
9032
+
8742
9033
  // scripts/util/poll-until.ts
8743
9034
  init_esm_shims();
8744
9035
 
@@ -8833,11 +9124,11 @@ async function resolveGitBase(parentBranch, cwd) {
8833
9124
  // scripts/lakebase/workflow-drift.ts
8834
9125
  init_esm_shims();
8835
9126
  import * as fs3 from "fs";
8836
- import * as path3 from "path";
9127
+ import * as path4 from "path";
8837
9128
  function findKitTemplatesDir(start) {
8838
9129
  let dir = start;
8839
9130
  for (let i = 0; i < 6; i++) {
8840
- const candidate = path3.join(
9131
+ const candidate = path4.join(
8841
9132
  dir,
8842
9133
  "templates",
8843
9134
  "project",
@@ -8846,7 +9137,7 @@ function findKitTemplatesDir(start) {
8846
9137
  "workflows"
8847
9138
  );
8848
9139
  if (fs3.existsSync(candidate)) return candidate;
8849
- const parent = path3.dirname(dir);
9140
+ const parent = path4.dirname(dir);
8850
9141
  if (parent === dir) break;
8851
9142
  dir = parent;
8852
9143
  }
@@ -8870,13 +9161,13 @@ function unifiedDiff(name, projectContent, templateContent) {
8870
9161
  return out.join("\n");
8871
9162
  }
8872
9163
  function detectWorkflowDrift(args) {
8873
- const projectWorkflowsDir = path3.join(
9164
+ const projectWorkflowsDir = path4.join(
8874
9165
  args.projectDir,
8875
9166
  ".github",
8876
9167
  "workflows"
8877
9168
  );
8878
- const here = path3.dirname(new URL(import.meta.url).pathname);
8879
- const kitWorkflowsDir = args.kitDir ? path3.join(
9169
+ const here = path4.dirname(new URL(import.meta.url).pathname);
9170
+ const kitWorkflowsDir = args.kitDir ? path4.join(
8880
9171
  args.kitDir,
8881
9172
  "templates",
8882
9173
  "project",
@@ -8891,8 +9182,8 @@ function detectWorkflowDrift(args) {
8891
9182
  const files = [];
8892
9183
  for (const name of templateFiles) {
8893
9184
  seen.add(name);
8894
- const projectPath2 = path3.join(projectWorkflowsDir, name);
8895
- const templatePath = path3.join(kitWorkflowsDir, name);
9185
+ const projectPath2 = path4.join(projectWorkflowsDir, name);
9186
+ const templatePath = path4.join(kitWorkflowsDir, name);
8896
9187
  if (!fs3.existsSync(projectPath2)) {
8897
9188
  files.push({ name, status: "missing" });
8898
9189
  continue;
@@ -8929,10 +9220,10 @@ function detectWorkflowDrift(args) {
8929
9220
  function readKitVersion(kitWorkflowsDir) {
8930
9221
  let dir = kitWorkflowsDir;
8931
9222
  for (let i = 0; i < 5; i++) {
8932
- dir = path3.dirname(dir);
9223
+ dir = path4.dirname(dir);
8933
9224
  }
8934
9225
  try {
8935
- const raw = fs3.readFileSync(path3.join(dir, "package.json"), "utf-8");
9226
+ const raw = fs3.readFileSync(path4.join(dir, "package.json"), "utf-8");
8936
9227
  const pkg = JSON.parse(raw);
8937
9228
  return typeof pkg.version === "string" ? pkg.version : "unknown";
8938
9229
  } catch {
@@ -8943,13 +9234,13 @@ function applyPlaceholders(content, version) {
8943
9234
  return content.replace(/\{\{LAKEBASE_SCM_UTILS_VERSION\}\}/g, version);
8944
9235
  }
8945
9236
  function updateWorkflows(args) {
8946
- const projectWorkflowsDir = path3.join(
9237
+ const projectWorkflowsDir = path4.join(
8947
9238
  args.projectDir,
8948
9239
  ".github",
8949
9240
  "workflows"
8950
9241
  );
8951
- const here = path3.dirname(new URL(import.meta.url).pathname);
8952
- const kitWorkflowsDir = args.kitDir ? path3.join(
9242
+ const here = path4.dirname(new URL(import.meta.url).pathname);
9243
+ const kitWorkflowsDir = args.kitDir ? path4.join(
8953
9244
  args.kitDir,
8954
9245
  "templates",
8955
9246
  "project",
@@ -8970,8 +9261,8 @@ function updateWorkflows(args) {
8970
9261
  const files = [];
8971
9262
  for (const name of templateFiles) {
8972
9263
  seen.add(name);
8973
- const projectPath2 = path3.join(projectWorkflowsDir, name);
8974
- const templatePath = path3.join(kitWorkflowsDir, name);
9264
+ const projectPath2 = path4.join(projectWorkflowsDir, name);
9265
+ const templatePath = path4.join(kitWorkflowsDir, name);
8975
9266
  const templateRaw = fs3.readFileSync(templatePath, "utf-8");
8976
9267
  const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
8977
9268
  const existed = fs3.existsSync(projectPath2);
@@ -8992,7 +9283,7 @@ function updateWorkflows(args) {
8992
9283
  if (pruneExtras) {
8993
9284
  for (const name of projectFiles) {
8994
9285
  if (seen.has(name)) continue;
8995
- const projectPath2 = path3.join(projectWorkflowsDir, name);
9286
+ const projectPath2 = path4.join(projectWorkflowsDir, name);
8996
9287
  if (!dryRun) {
8997
9288
  fs3.unlinkSync(projectPath2);
8998
9289
  }
@@ -9013,7 +9304,7 @@ function updateWorkflows(args) {
9013
9304
  // scripts/lakebase/scm-workflow-state.ts
9014
9305
  init_esm_shims();
9015
9306
  import * as fs4 from "fs";
9016
- import * as path4 from "path";
9307
+ import * as path5 from "path";
9017
9308
  import { execFileSync as execFileSync4 } from "child_process";
9018
9309
  function isGitTracked(projectDir, rel) {
9019
9310
  try {
@@ -9032,7 +9323,7 @@ function ensureWorkflowStateUntracked(projectDir) {
9032
9323
  } catch {
9033
9324
  }
9034
9325
  try {
9035
- const gitignore = path4.join(projectDir, ".gitignore");
9326
+ const gitignore = path5.join(projectDir, ".gitignore");
9036
9327
  const existing = fs4.existsSync(gitignore) ? fs4.readFileSync(gitignore, "utf8") : "";
9037
9328
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
9038
9329
  const sep2 = existing === "" || existing.endsWith("\n") ? "" : "\n";
@@ -9060,7 +9351,7 @@ var STATE_INDEX = SCM_STATES.reduce(
9060
9351
  );
9061
9352
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
9062
9353
  function stateFilePath(projectDir) {
9063
- return path4.join(projectDir, STATE_FILE_REL);
9354
+ return path5.join(projectDir, STATE_FILE_REL);
9064
9355
  }
9065
9356
  function readWorkflowState(projectDir) {
9066
9357
  const p = stateFilePath(projectDir);
@@ -9094,7 +9385,7 @@ function writeWorkflowState(projectDir, state) {
9094
9385
  ${summary}`);
9095
9386
  }
9096
9387
  ensureWorkflowStateUntracked(projectDir);
9097
- const dir = path4.join(projectDir, ".lakebase");
9388
+ const dir = path5.join(projectDir, ".lakebase");
9098
9389
  fs4.mkdirSync(dir, { recursive: true });
9099
9390
  const target = stateFilePath(projectDir);
9100
9391
  const tmp = `${target}.tmp`;
@@ -9303,6 +9594,48 @@ function shaMigratePredicate(mergeCommitSha) {
9303
9594
  return !!run.headSha && run.headSha === mergeCommitSha;
9304
9595
  };
9305
9596
  }
9597
+ var PROMOTE_RUNSTATE_CONFLICT = /(^|\/)\.consort\/(features\/[^/]+\/)?pipeline\.json$/;
9598
+ async function reconcilePromoteRunState(projectDir, baseBranch) {
9599
+ const o = { cwd: projectDir, timeout: 3e4 };
9600
+ const dirty = (await exec2("git status --porcelain", o).catch(() => "")).split("\n").map((l) => l.slice(3).trim()).filter(Boolean);
9601
+ const nonRunStateDirty = dirty.filter((p) => !p.startsWith(".consort/"));
9602
+ if (nonRunStateDirty.length > 0) {
9603
+ throw new ScmMergeError(
9604
+ `working tree has uncommitted non-run-state changes (${nonRunStateDirty.slice(0, 5).join(", ")}${nonRunStateDirty.length > 5 ? ", \u2026" : ""}); commit or stash before promoting.`,
9605
+ "promote-conflict"
9606
+ );
9607
+ }
9608
+ if (dirty.length > 0) {
9609
+ await exec2(`git add ${shellEscape(".consort")}`, o);
9610
+ await exec2(`git commit -m ${shellEscape("chore(run): checkpoint run state before promotion")}`, o);
9611
+ }
9612
+ await exec2(`git fetch origin ${shellEscape(baseBranch)}`, o).catch(() => {
9613
+ });
9614
+ let conflicted = false;
9615
+ try {
9616
+ await exec2(`git merge --no-ff -m ${shellEscape(`merge ${baseBranch} for promotion`)} ${shellEscape(`origin/${baseBranch}`)}`, o);
9617
+ } catch {
9618
+ conflicted = true;
9619
+ }
9620
+ if (!conflicted) return { reconciled: false };
9621
+ const u = (await exec2("git diff --name-only --diff-filter=U", o).catch(() => "")).split("\n").map((s) => s.trim()).filter(Boolean);
9622
+ const other = u.filter((p) => !PROMOTE_RUNSTATE_CONFLICT.test(p));
9623
+ if (u.length === 0 || other.length > 0) {
9624
+ await exec2("git merge --abort", o).catch(() => {
9625
+ });
9626
+ throw new ScmMergeError(
9627
+ other.length > 0 ? `promotion conflicts on non-ledger file(s): ${other.join(", ")}. Resolve the real divergence manually, then re-run the promote.` : `promotion merge failed with no resolvable conflicts; resolve manually and re-run.`,
9628
+ "promote-conflict"
9629
+ );
9630
+ }
9631
+ for (const p of u) {
9632
+ await exec2(`git checkout --ours -- ${shellEscape(p)}`, o);
9633
+ await exec2(`git add -- ${shellEscape(p)}`, o);
9634
+ }
9635
+ await exec2(`git commit -m ${shellEscape(`merge ${baseBranch} for promotion (pipeline.json ledger kept at run state)`)}`, o);
9636
+ await pushCurrentBranchForPr({ cwd: projectDir });
9637
+ return { reconciled: true, detail: `reconciled ${u.length} ledger path(s) to the run side + pushed` };
9638
+ }
9306
9639
  async function defaultRefreshPromoteWorkflows(projectDir) {
9307
9640
  const drift = detectWorkflowDrift({ projectDir });
9308
9641
  const touched = drift.files.filter((f) => f.status === "drifted").map((f) => f.name);
@@ -9392,6 +9725,24 @@ async function mergeFeature(args) {
9392
9725
  );
9393
9726
  }
9394
9727
  }
9728
+ {
9729
+ const ensure = args.ensureCiFresh ?? ((repo) => ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo: repo }));
9730
+ try {
9731
+ const r = await ensure(ownerRepo);
9732
+ if (r.action !== "ok" && r.action !== "skipped") preflightNotes.push(`CI-auth preflight: ${r.reason}`);
9733
+ } catch (err) {
9734
+ preflightNotes.push(`CI-auth preflight skipped (${err instanceof Error ? err.message : String(err)}); if the promote CI fails on auth, run lakebase-sync-ci-secrets.`);
9735
+ }
9736
+ }
9737
+ {
9738
+ const fetchState = args.fetchPrState ?? ((o, h) => getPullRequest(o, h));
9739
+ const prState = await fetchState(ownerRepo, current.branch).catch(() => void 0);
9740
+ if (prState?.mergeableState === "dirty") {
9741
+ const reconcile = args.reconcileRunState ?? ((base) => reconcilePromoteRunState(args.projectDir, base));
9742
+ const r = await reconcile(gitBase);
9743
+ if (r.reconciled) preflightNotes.push(`Reconciled a pipeline.json-ledger promotion conflict to the run side${r.detail ? ` (${r.detail})` : ""}.`);
9744
+ }
9745
+ }
9395
9746
  let paired;
9396
9747
  try {
9397
9748
  paired = await mergePairedPullRequest({
@@ -9601,7 +9952,7 @@ function shellEscape(s) {
9601
9952
  // scripts/lakebase/schema-migrate.ts
9602
9953
  init_esm_shims();
9603
9954
  import * as fs11 from "fs";
9604
- import * as path12 from "path";
9955
+ import * as path13 from "path";
9605
9956
 
9606
9957
  // scripts/lakebase/get-connection.ts
9607
9958
  init_esm_shims();
@@ -9621,21 +9972,21 @@ var CONSORT_VERSION_ENV = "CONSORT_VERSION";
9621
9972
  // scripts/lakebase/self-version.ts
9622
9973
  init_esm_shims();
9623
9974
  import * as fs5 from "fs";
9624
- import * as path5 from "path";
9975
+ import * as path6 from "path";
9625
9976
  import { fileURLToPath as fileURLToPath3 } from "url";
9626
9977
  var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
9627
9978
  var cached;
9628
9979
  function substrateSelfVersion() {
9629
9980
  if (cached !== void 0) return cached;
9630
- if ("0.2.47".length > 0) {
9631
- cached = "0.2.47";
9981
+ if ("0.2.49".length > 0) {
9982
+ cached = "0.2.49";
9632
9983
  return cached;
9633
9984
  }
9634
9985
  cached = "unknown";
9635
9986
  try {
9636
- let dir = path5.dirname(fileURLToPath3(import.meta.url));
9987
+ let dir = path6.dirname(fileURLToPath3(import.meta.url));
9637
9988
  for (let i = 0; i < 8; i++) {
9638
- const pkgPath = path5.join(dir, "package.json");
9989
+ const pkgPath = path6.join(dir, "package.json");
9639
9990
  if (fs5.existsSync(pkgPath)) {
9640
9991
  try {
9641
9992
  const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf8"));
@@ -9646,7 +9997,7 @@ function substrateSelfVersion() {
9646
9997
  } catch {
9647
9998
  }
9648
9999
  }
9649
- const parent = path5.dirname(dir);
10000
+ const parent = path6.dirname(dir);
9650
10001
  if (parent === dir) break;
9651
10002
  dir = parent;
9652
10003
  }
@@ -9742,17 +10093,17 @@ init_esm_shims();
9742
10093
  // scripts/lakebase/adapters/alembic-adapter.ts
9743
10094
  init_esm_shims();
9744
10095
  import * as fs7 from "fs";
9745
- import * as path7 from "path";
10096
+ import * as path8 from "path";
9746
10097
 
9747
10098
  // scripts/lakebase/schema-migrate-runners/alembic.ts
9748
10099
  init_esm_shims();
9749
10100
  import { spawn } from "child_process";
9750
10101
  import * as fs6 from "fs";
9751
- import * as path6 from "path";
10102
+ import * as path7 from "path";
9752
10103
  function resolveAlembicBin(projectDir) {
9753
10104
  const candidates = [
9754
- path6.join(projectDir, ".venv", "bin", "alembic"),
9755
- path6.join(projectDir, "venv", "bin", "alembic")
10105
+ path7.join(projectDir, ".venv", "bin", "alembic"),
10106
+ path7.join(projectDir, "venv", "bin", "alembic")
9756
10107
  ];
9757
10108
  for (const candidate of candidates) {
9758
10109
  try {
@@ -9766,7 +10117,7 @@ function spawnAlembic(projectDir, args, dsn) {
9766
10117
  return new Promise((resolve2, reject) => {
9767
10118
  const bin = resolveAlembicBin(projectDir);
9768
10119
  const env = { ...process.env };
9769
- env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path6.delimiter);
10120
+ env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path7.delimiter);
9770
10121
  if (dsn) env.DATABASE_URL = dsn;
9771
10122
  const child = spawn(bin, args, {
9772
10123
  cwd: projectDir,
@@ -9814,10 +10165,10 @@ async function createAlembicRevision(opts) {
9814
10165
  const m = stdout.match(/Generating\s+(\S+\.py)/);
9815
10166
  if (m) return m[1].trim();
9816
10167
  for (const rel of ["migrations/versions", "alembic/versions"]) {
9817
- const dir = path6.join(opts.projectDir, rel);
10168
+ const dir = path7.join(opts.projectDir, rel);
9818
10169
  if (!fs6.existsSync(dir)) continue;
9819
10170
  const hit = fs6.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
9820
- if (hit) return path6.join(dir, hit);
10171
+ if (hit) return path7.join(dir, hit);
9821
10172
  }
9822
10173
  throw new SchemaMigrationError(
9823
10174
  `alembic revision succeeded but the created file could not be located.
@@ -9952,8 +10303,8 @@ async function buildDsn(args) {
9952
10303
  }
9953
10304
  function findVersionsDir(projectDir) {
9954
10305
  const candidates = [
9955
- path7.join(projectDir, "migrations", "versions"),
9956
- path7.join(projectDir, "alembic", "versions")
10306
+ path8.join(projectDir, "migrations", "versions"),
10307
+ path8.join(projectDir, "alembic", "versions")
9957
10308
  ];
9958
10309
  return candidates.find((p) => fs7.existsSync(p));
9959
10310
  }
@@ -9985,9 +10336,9 @@ var AlembicAdapter = {
9985
10336
  * here. Callers can still force-select via project.yaml#migration_tool.
9986
10337
  */
9987
10338
  detect(projectDir) {
9988
- if (fs7.existsSync(path7.join(projectDir, "alembic.ini"))) return true;
9989
- if (fs7.existsSync(path7.join(projectDir, "migrations", "env.py"))) return true;
9990
- if (fs7.existsSync(path7.join(projectDir, "alembic", "env.py"))) return true;
10339
+ if (fs7.existsSync(path8.join(projectDir, "alembic.ini"))) return true;
10340
+ if (fs7.existsSync(path8.join(projectDir, "migrations", "env.py"))) return true;
10341
+ if (fs7.existsSync(path8.join(projectDir, "alembic", "env.py"))) return true;
9991
10342
  return false;
9992
10343
  },
9993
10344
  async apply(args) {
@@ -10093,7 +10444,7 @@ var AlembicAdapter = {
10093
10444
  autogenerate: !!args.autogenerate,
10094
10445
  dsn
10095
10446
  });
10096
- return { status: "ok", version: revId, filename: path7.basename(created), path: created };
10447
+ return { status: "ok", version: revId, filename: path8.basename(created), path: created };
10097
10448
  } catch (err) {
10098
10449
  return {
10099
10450
  status: "error",
@@ -10110,7 +10461,7 @@ var AlembicAdapter = {
10110
10461
  if (heads.length <= 1) return { status: "noop", headsBefore: heads };
10111
10462
  if (args.dryRun) return { status: "ok", headsBefore: heads };
10112
10463
  const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
10113
- const mergeRevision = path7.basename(created).replace(/\.py$/, "").split("_")[0];
10464
+ const mergeRevision = path8.basename(created).replace(/\.py$/, "").split("_")[0];
10114
10465
  return { status: "ok", headsBefore: heads, mergeRevision, path: created };
10115
10466
  } catch (err) {
10116
10467
  return {
@@ -10126,12 +10477,12 @@ registerSchemaMigrationAdapter(AlembicAdapter);
10126
10477
  // scripts/lakebase/adapters/flyway-adapter.ts
10127
10478
  init_esm_shims();
10128
10479
  import * as fs8 from "fs";
10129
- import * as path9 from "path";
10480
+ import * as path10 from "path";
10130
10481
 
10131
10482
  // scripts/lakebase/schema-migrate-runners/flyway.ts
10132
10483
  init_esm_shims();
10133
10484
  import { spawn as spawn2 } from "child_process";
10134
- import * as path8 from "path";
10485
+ import * as path9 from "path";
10135
10486
  function dsnToFlywayEnv(dsn) {
10136
10487
  const u = new URL(dsn);
10137
10488
  const user = decodeURIComponent(u.username);
@@ -10141,7 +10492,7 @@ function dsnToFlywayEnv(dsn) {
10141
10492
  return { url, user, password };
10142
10493
  }
10143
10494
  function migrationsLocation(projectDir) {
10144
- return `filesystem:${path8.join(projectDir, "src", "main", "resources", "db", "migration")}`;
10495
+ return `filesystem:${path9.join(projectDir, "src", "main", "resources", "db", "migration")}`;
10145
10496
  }
10146
10497
  function runFlyway(ctx, args) {
10147
10498
  const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
@@ -10242,7 +10593,7 @@ async function statusFlyway(ctx) {
10242
10593
  if (state === "SUCCESS" || state === "BASELINE") {
10243
10594
  current = m.version;
10244
10595
  } else if (state === "PENDING") {
10245
- const filename = m.filepath ? path8.basename(m.filepath) : `V${m.version}__migration.sql`;
10596
+ const filename = m.filepath ? path9.basename(m.filepath) : `V${m.version}__migration.sql`;
10246
10597
  pending.push({
10247
10598
  version: m.version,
10248
10599
  filename,
@@ -10265,7 +10616,7 @@ async function buildDsn2(args) {
10265
10616
  return result.url;
10266
10617
  }
10267
10618
  function listFlywayFiles(projectDir) {
10268
- const dir = path9.join(projectDir, "src", "main", "resources", "db", "migration");
10619
+ const dir = path10.join(projectDir, "src", "main", "resources", "db", "migration");
10269
10620
  if (!fs8.existsSync(dir)) return [];
10270
10621
  const files = fs8.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
10271
10622
  return files.map((filename) => {
@@ -10290,7 +10641,7 @@ var FlywayAdapter = {
10290
10641
  id: "flyway",
10291
10642
  languages: ["java", "kotlin"],
10292
10643
  detect(projectDir) {
10293
- return fs8.existsSync(path9.join(projectDir, "pom.xml"));
10644
+ return fs8.existsSync(path10.join(projectDir, "pom.xml"));
10294
10645
  },
10295
10646
  async apply(args) {
10296
10647
  const dsn = await buildDsn2(args);
@@ -10348,12 +10699,12 @@ var FlywayAdapter = {
10348
10699
  // optional-protocol shape makes this additive.
10349
10700
  async newMigration(args) {
10350
10701
  try {
10351
- const dir = path9.join(args.projectDir, "src", "main", "resources", "db", "migration");
10702
+ const dir = path10.join(args.projectDir, "src", "main", "resources", "db", "migration");
10352
10703
  fs8.mkdirSync(dir, { recursive: true });
10353
10704
  const version = migrationTimestamp();
10354
10705
  const slug = migrationSlug2(args.slug);
10355
10706
  const filename = `V${version}__${slug}.sql`;
10356
- const full = path9.join(dir, filename);
10707
+ const full = path10.join(dir, filename);
10357
10708
  if (fs8.existsSync(full)) throw new Error(`${filename} already exists`);
10358
10709
  fs8.writeFileSync(
10359
10710
  full,
@@ -10379,17 +10730,17 @@ registerSchemaMigrationAdapter(FlywayAdapter);
10379
10730
  // scripts/lakebase/adapters/knex-adapter.ts
10380
10731
  init_esm_shims();
10381
10732
  import * as fs10 from "fs";
10382
- import * as path11 from "path";
10733
+ import * as path12 from "path";
10383
10734
 
10384
10735
  // scripts/lakebase/schema-migrate-runners/knex.ts
10385
10736
  init_esm_shims();
10386
10737
  import { spawn as spawn3 } from "child_process";
10387
10738
  import * as fs9 from "fs";
10388
- import * as path10 from "path";
10739
+ import * as path11 from "path";
10389
10740
  var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10390
10741
  function findKnexfile(projectDir) {
10391
10742
  for (const name of KNEXFILE_VARIANTS) {
10392
- const p = path10.join(projectDir, name);
10743
+ const p = path11.join(projectDir, name);
10393
10744
  if (fs9.existsSync(p)) return p;
10394
10745
  }
10395
10746
  return void 0;
@@ -10542,7 +10893,7 @@ async function buildDsn3(args) {
10542
10893
  }
10543
10894
  var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10544
10895
  function listKnexFiles(projectDir) {
10545
- const dir = path11.join(projectDir, "migrations");
10896
+ const dir = path12.join(projectDir, "migrations");
10546
10897
  if (!fs10.existsSync(dir)) return [];
10547
10898
  const files = fs10.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
10548
10899
  return files.map((filename) => {
@@ -10564,7 +10915,7 @@ var KnexAdapter = {
10564
10915
  * project.yaml#migration_tool.
10565
10916
  */
10566
10917
  detect(projectDir) {
10567
- return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(path11.join(projectDir, name)));
10918
+ return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(path12.join(projectDir, name)));
10568
10919
  },
10569
10920
  async apply(args) {
10570
10921
  const dsn = await buildDsn3(args);
@@ -10637,9 +10988,9 @@ var KnexAdapter = {
10637
10988
  async newMigration(args) {
10638
10989
  try {
10639
10990
  const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
10640
- const stem = path11.basename(created).replace(/\.(js|ts)$/, "");
10991
+ const stem = path12.basename(created).replace(/\.(js|ts)$/, "");
10641
10992
  const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
10642
- return { status: "ok", version, filename: path11.basename(created), path: created };
10993
+ return { status: "ok", version, filename: path12.basename(created), path: created };
10643
10994
  } catch (err) {
10644
10995
  return {
10645
10996
  status: "error",
@@ -10932,7 +11283,7 @@ async function runScmMergeCli(argv) {
10932
11283
  `);
10933
11284
  return 0;
10934
11285
  }
10935
- const projectDir = path13.resolve(args.projectDir ?? process.cwd());
11286
+ const projectDir = path14.resolve(args.projectDir ?? process.cwd());
10936
11287
  const waitMigrate = args.noWaitMigrate ? false : true;
10937
11288
  const verifyMigrateAuth = waitMigrate && !args.noVerifyMigrateAuth ? async () => {
10938
11289
  try {