@databricks-solutions/lakebase-scm-utils 0.2.44 → 0.2.45

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 (39) hide show
  1. package/dist/scripts/index.cjs +795 -758
  2. package/dist/scripts/index.d.cts +1 -1
  3. package/dist/scripts/index.d.ts +1 -1
  4. package/dist/scripts/index.js +794 -758
  5. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
  6. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
  7. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
  8. package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
  9. package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
  10. package/dist/scripts/lakebase/detect-language.cli.js +2 -2
  11. package/dist/scripts/lakebase/doctor.cli.cjs +3 -3
  12. package/dist/scripts/lakebase/doctor.cli.js +3 -3
  13. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  14. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  15. package/dist/scripts/lakebase/index.cjs +463 -395
  16. package/dist/scripts/lakebase/index.d.cts +33 -1
  17. package/dist/scripts/lakebase/index.d.ts +33 -1
  18. package/dist/scripts/lakebase/index.js +462 -395
  19. package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
  20. package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
  21. package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
  22. package/dist/scripts/lakebase/new-migration.cli.js +2 -2
  23. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  24. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  25. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
  26. package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
  27. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
  28. package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
  29. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  30. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  31. package/dist/scripts/lakebase/scm-merge.cli.cjs +2284 -2033
  32. package/dist/scripts/lakebase/scm-merge.cli.js +339 -88
  33. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  34. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  35. package/dist/scripts/util/index.cjs +2 -2
  36. package/dist/scripts/util/index.js +2 -2
  37. package/package.json +1 -1
  38. package/scripts/lakebase/doctor.ts +1 -1
  39. package/scripts/lakebase/scm-merge.ts +80 -1
@@ -78993,6 +78993,7 @@ __export(lakebase_exports, {
78993
78993
  createUatPairedBranch: () => createUatPairedBranch,
78994
78994
  cutBackup: () => cutBackup,
78995
78995
  databricksAuthPrereqMessage: () => databricksAuthPrereqMessage,
78996
+ defaultRefreshPromoteWorkflows: () => defaultRefreshPromoteWorkflows,
78996
78997
  deleteAppEndpoint: () => deleteAppEndpoint,
78997
78998
  deleteBranch: () => deleteBranch,
78998
78999
  deleteLakebaseProject: () => deleteLakebaseProject,
@@ -81587,8 +81588,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
81587
81588
  var cached;
81588
81589
  function substrateSelfVersion() {
81589
81590
  if (cached !== void 0) return cached;
81590
- if ("0.2.44".length > 0) {
81591
- cached = "0.2.44";
81591
+ if ("0.2.45".length > 0) {
81592
+ cached = "0.2.45";
81592
81593
  return cached;
81593
81594
  }
81594
81595
  cached = "unknown";
@@ -81816,6 +81817,14 @@ async function getCredential(args) {
81816
81817
 
81817
81818
  // scripts/git/status.ts
81818
81819
  init_cjs_shims();
81820
+ async function hasUpstream(args) {
81821
+ try {
81822
+ await exec2("git rev-parse --abbrev-ref @{u}", { cwd: args.cwd });
81823
+ return true;
81824
+ } catch {
81825
+ return false;
81826
+ }
81827
+ }
81819
81828
  async function getAheadBehind(args) {
81820
81829
  const { cwd } = args;
81821
81830
  try {
@@ -94919,118 +94928,461 @@ function pickRunUrl(pr) {
94919
94928
 
94920
94929
  // scripts/lakebase/scm-merge.ts
94921
94930
  init_cjs_shims();
94922
- async function reconcileTierToOrigin(args) {
94923
- const { cwd, tier } = args;
94931
+
94932
+ // scripts/git/sync.ts
94933
+ init_cjs_shims();
94934
+ async function currentBranchName(cwd) {
94924
94935
  try {
94925
- const head = await getCurrentBranch({ cwd });
94926
- if (head === tier) {
94927
- await exec2(`git pull --ff-only`, { cwd, timeout: 3e4 });
94928
- } else {
94929
- await exec2(`git fetch origin ${shellEscape2(`${tier}:${tier}`)}`, { cwd, timeout: 3e4 });
94930
- }
94931
- return null;
94932
- } catch (err) {
94933
- return `local reconcile of ${tier} to origin/${tier} failed: ${err instanceof Error ? err.message : String(err)}. Reconcile it by hand (git checkout ${tier} && git pull --ff-only).`;
94936
+ return await exec2("git rev-parse --abbrev-ref HEAD", { cwd });
94937
+ } catch {
94938
+ return "";
94934
94939
  }
94935
94940
  }
94936
- var ScmMergeError = class extends Error {
94937
- constructor(message, code) {
94938
- super(message);
94939
- this.code = code;
94940
- this.name = "ScmMergeError";
94941
+ async function pushCurrentBranchForPr(args) {
94942
+ const remote = args.remote ?? "origin";
94943
+ const branch = await currentBranchName(args.cwd);
94944
+ if (!branch) throw new Error("No current branch");
94945
+ const upstreamSet = await hasUpstream({ cwd: args.cwd });
94946
+ if (!upstreamSet) {
94947
+ await exec2(`git push -u ${remote} ${shq(branch)}`, {
94948
+ cwd: args.cwd
94949
+ });
94950
+ } else {
94951
+ await exec2("git push", { cwd: args.cwd });
94941
94952
  }
94942
- code;
94943
- };
94944
- var DEFAULT_MIGRATE_TIMEOUT_MS = 30 * 60 * 1e3;
94945
- var DEFAULT_MIGRATE_POLL_MS = 30 * 1e3;
94946
- function defaultMigratePredicate(run, mergedAt) {
94947
- if (!run.createdAt) return false;
94948
- const created = Date.parse(run.createdAt);
94949
- if (!Number.isFinite(created)) return false;
94950
- if (run.event && run.event !== "push") return false;
94951
- return created >= mergedAt.getTime() - 5e3;
94952
- }
94953
- function shaMigratePredicate(mergeCommitSha) {
94954
- return (run) => {
94955
- if (run.event && run.event !== "push") return false;
94956
- return !!run.headSha && run.headSha === mergeCommitSha;
94957
- };
94958
94953
  }
94959
- async function mergeFeature(args) {
94960
- const current = readWorkflowState(args.projectDir);
94961
- if (!current) {
94962
- throw new ScmMergeError(
94963
- "No SCM workflow state. wait-ci first.",
94964
- "no-state-file"
94954
+
94955
+ // scripts/lakebase/workflow-drift.ts
94956
+ init_cjs_shims();
94957
+ var fs30 = __toESM(require("fs"), 1);
94958
+ var path28 = __toESM(require("path"), 1);
94959
+ function findKitTemplatesDir(start) {
94960
+ let dir = start;
94961
+ for (let i2 = 0; i2 < 6; i2++) {
94962
+ const candidate = path28.join(
94963
+ dir,
94964
+ "templates",
94965
+ "project",
94966
+ "common",
94967
+ ".github",
94968
+ "workflows"
94965
94969
  );
94970
+ if (fs30.existsSync(candidate)) return candidate;
94971
+ const parent = path28.dirname(dir);
94972
+ if (parent === dir) break;
94973
+ dir = parent;
94966
94974
  }
94967
- if (current.state !== "ci-green") {
94968
- throw new ScmMergeError(
94969
- `merge refuses state "${current.state}". Allowed predecessor: ci-green.`,
94970
- "bad-precondition"
94971
- );
94975
+ throw new Error(
94976
+ `Could not locate templates/project/common/.github/workflows/ relative to ${start}. Pass explicit kitDir.`
94977
+ );
94978
+ }
94979
+ function unifiedDiff(name, projectContent, templateContent) {
94980
+ if (projectContent === templateContent) return "";
94981
+ const a = projectContent.split("\n");
94982
+ const b = templateContent.split("\n");
94983
+ const out = [`--- project/${name}`, `+++ template/${name}`];
94984
+ const max = Math.max(a.length, b.length);
94985
+ for (let i2 = 0; i2 < max; i2++) {
94986
+ const av = a[i2];
94987
+ const bv = b[i2];
94988
+ if (av === bv) continue;
94989
+ if (av !== void 0) out.push(`-${i2 + 1}: ${av}`);
94990
+ if (bv !== void 0) out.push(`+${i2 + 1}: ${bv}`);
94972
94991
  }
94973
- if (!current.pr_url) {
94974
- throw new ScmMergeError(
94975
- "ci-green row is missing pr_url; cannot resolve the PR to merge.",
94976
- "no-pr-url"
94977
- );
94992
+ return out.join("\n");
94993
+ }
94994
+ function detectWorkflowDrift(args) {
94995
+ const projectWorkflowsDir = path28.join(
94996
+ args.projectDir,
94997
+ ".github",
94998
+ "workflows"
94999
+ );
95000
+ const here = path28.dirname(new URL(importMetaUrl).pathname);
95001
+ const kitWorkflowsDir = args.kitDir ? path28.join(
95002
+ args.kitDir,
95003
+ "templates",
95004
+ "project",
95005
+ "common",
95006
+ ".github",
95007
+ "workflows"
95008
+ ) : findKitTemplatesDir(here);
95009
+ const templateFiles = fs30.existsSync(kitWorkflowsDir) ? fs30.readdirSync(kitWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95010
+ const projectFiles = fs30.existsSync(projectWorkflowsDir) ? fs30.readdirSync(projectWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95011
+ const version = readKitVersion(kitWorkflowsDir);
95012
+ const seen = /* @__PURE__ */ new Set();
95013
+ const files = [];
95014
+ for (const name of templateFiles) {
95015
+ seen.add(name);
95016
+ const projectPath2 = path28.join(projectWorkflowsDir, name);
95017
+ const templatePath = path28.join(kitWorkflowsDir, name);
95018
+ if (!fs30.existsSync(projectPath2)) {
95019
+ files.push({ name, status: "missing" });
95020
+ continue;
95021
+ }
95022
+ const projectContent = fs30.readFileSync(projectPath2, "utf8");
95023
+ const templateContent = applyPlaceholders(fs30.readFileSync(templatePath, "utf8"), version);
95024
+ if (projectContent === templateContent) {
95025
+ files.push({ name, status: "unchanged" });
95026
+ } else {
95027
+ files.push({
95028
+ name,
95029
+ status: "drifted",
95030
+ diff: unifiedDiff(name, projectContent, templateContent)
95031
+ });
95032
+ }
94978
95033
  }
94979
- if (!current.branch || !current.parent_branch) {
94980
- throw new ScmMergeError(
94981
- "ci-green row missing branch / parent_branch; refusing to merge.",
94982
- "bad-precondition"
94983
- );
95034
+ for (const name of projectFiles) {
95035
+ if (seen.has(name)) continue;
95036
+ files.push({ name, status: "extra" });
94984
95037
  }
94985
- const ownerRepo = await getOwnerRepo(args.projectDir);
94986
- if (!ownerRepo) {
94987
- throw new ScmMergeError(
94988
- "No GitHub remote found at origin.",
94989
- "no-github-remote"
94990
- );
95038
+ const order = {
95039
+ drifted: 0,
95040
+ missing: 1,
95041
+ extra: 2,
95042
+ unchanged: 3
95043
+ };
95044
+ files.sort((a, b) => order[a.status] - order[b.status] || a.name.localeCompare(b.name));
95045
+ const hasDrift = files.some((f3) => f3.status === "drifted" || f3.status === "missing");
95046
+ return {
95047
+ overall: hasDrift ? "drift" : "ok",
95048
+ files
95049
+ };
95050
+ }
95051
+ function readKitVersion(kitWorkflowsDir) {
95052
+ let dir = kitWorkflowsDir;
95053
+ for (let i2 = 0; i2 < 5; i2++) {
95054
+ dir = path28.dirname(dir);
94991
95055
  }
94992
- const pullNumber = extractPullNumber(current.pr_url);
94993
- if (!pullNumber) {
94994
- throw new ScmMergeError(
94995
- `Could not extract PR number from URL: ${current.pr_url}`,
94996
- "bad-pr-url"
95056
+ try {
95057
+ const raw = fs30.readFileSync(path28.join(dir, "package.json"), "utf-8");
95058
+ const pkg = JSON.parse(raw);
95059
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
95060
+ } catch {
95061
+ return "unknown";
95062
+ }
95063
+ }
95064
+ function applyPlaceholders(content, version) {
95065
+ return content.replace(/\{\{LAKEBASE_SCM_UTILS_VERSION\}\}/g, version);
95066
+ }
95067
+ function applyCommandPlaceholders(content, version) {
95068
+ return content.replace(/\$\{KIT_VERSION_AT_SCAFFOLD\}/g, version);
95069
+ }
95070
+ var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
95071
+ function findKitCommandsDir(start) {
95072
+ let dir = start;
95073
+ for (let i2 = 0; i2 < 6; i2++) {
95074
+ const candidate = path28.join(
95075
+ dir,
95076
+ "templates",
95077
+ "project",
95078
+ "common",
95079
+ ".claude",
95080
+ "commands"
94997
95081
  );
95082
+ if (fs30.existsSync(candidate)) return candidate;
95083
+ const parent = path28.dirname(dir);
95084
+ if (parent === dir) break;
95085
+ dir = parent;
94998
95086
  }
94999
- const instance = args.instance ?? current.project_id;
95000
- const gitBase = await resolveGitBase(current.parent_branch, args.projectDir);
95001
- const wantMigrate = args.waitMigrate !== false;
95002
- let authVerified = false;
95003
- if (wantMigrate && args.verifyMigrateAuth) {
95004
- const probe = await args.verifyMigrateAuth();
95005
- if (!probe.ok) {
95006
- throw new ScmMergeError(
95007
- `Migrate-auth precondition failed: ${probe.detail ?? "the Databricks credential is not usable"}. Refusing to merge: the downstream migrate would promote git without applying the schema. Refresh your credential (databricks auth login), then re-run.`,
95008
- "migrate-auth"
95009
- );
95087
+ throw new Error(
95088
+ `Could not locate templates/project/common/.claude/commands/ relative to ${start}. Pass explicit kitDir.`
95089
+ );
95090
+ }
95091
+ function parsePinnedVersion(content) {
95092
+ const m2 = content.match(/^\s*[*_>`\s]*pinned\s+to\s*:\s*[`*_]*([^\s`*_]+)[`*_]*\s*$/im);
95093
+ return m2 ? m2[1] : void 0;
95094
+ }
95095
+ function detectCommandDrift(args) {
95096
+ const projectCommandsDir = path28.join(args.projectDir, ".claude", "commands");
95097
+ const here = path28.dirname(new URL(importMetaUrl).pathname);
95098
+ const kitCommandsDir = args.kitDir ? path28.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
95099
+ const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
95100
+ const templateFiles = fs30.existsSync(kitCommandsDir) ? fs30.readdirSync(kitCommandsDir).filter((f3) => f3.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f3)) : [];
95101
+ const projectFiles = fs30.existsSync(projectCommandsDir) ? fs30.readdirSync(projectCommandsDir).filter((f3) => f3.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f3)) : [];
95102
+ const seen = /* @__PURE__ */ new Set();
95103
+ const files = [];
95104
+ for (const name of templateFiles) {
95105
+ seen.add(name);
95106
+ const projectPath2 = path28.join(projectCommandsDir, name);
95107
+ const templatePath = path28.join(kitCommandsDir, name);
95108
+ const templateRaw = fs30.readFileSync(templatePath, "utf8");
95109
+ if (!fs30.existsSync(projectPath2)) {
95110
+ files.push({ name, status: "missing", kit_version: kitVersion });
95111
+ continue;
95112
+ }
95113
+ const projectContent = fs30.readFileSync(projectPath2, "utf8");
95114
+ const pinned = parsePinnedVersion(projectContent);
95115
+ const versionForCompare = pinned ?? kitVersion;
95116
+ const templateContent = applyCommandPlaceholders(templateRaw, versionForCompare);
95117
+ if (projectContent === templateContent) {
95118
+ files.push({
95119
+ name,
95120
+ status: "unchanged",
95121
+ pinned_version: pinned,
95122
+ kit_version: kitVersion
95123
+ });
95124
+ } else {
95125
+ files.push({
95126
+ name,
95127
+ status: "drifted",
95128
+ pinned_version: pinned,
95129
+ kit_version: kitVersion,
95130
+ diff: unifiedDiff(name, projectContent, templateContent)
95131
+ });
95010
95132
  }
95011
- authVerified = true;
95012
95133
  }
95013
- let paired;
95014
- try {
95015
- paired = await mergePairedPullRequest({
95016
- ownerRepo,
95017
- pullNumber,
95018
- lakebaseInstance: instance,
95019
- method: args.method ?? "squash"
95020
- });
95021
- } catch (err) {
95022
- throw new ScmMergeError(
95023
- `mergePairedPullRequest failed: ${err instanceof Error ? err.message : String(err)}`,
95024
- "merge-failed"
95025
- );
95134
+ for (const name of projectFiles) {
95135
+ if (seen.has(name)) continue;
95136
+ files.push({ name, status: "extra", kit_version: kitVersion });
95026
95137
  }
95027
- const warnings = [...paired.warnings];
95028
- let localBranchDeleted = false;
95029
- let headAfter = current.branch;
95030
- if (!args.skipLocalCleanup) {
95031
- const switchTo = args.switchTo ?? gitBase;
95032
- const head = await getCurrentBranch({ cwd: args.projectDir });
95033
- if (head === current.branch) {
95138
+ const order = {
95139
+ drifted: 0,
95140
+ missing: 1,
95141
+ extra: 2,
95142
+ unchanged: 3
95143
+ };
95144
+ files.sort((a, b) => order[a.status] - order[b.status] || a.name.localeCompare(b.name));
95145
+ const hasDrift = files.some((f3) => f3.status === "drifted" || f3.status === "missing");
95146
+ return { overall: hasDrift ? "drift" : "ok", files };
95147
+ }
95148
+ function readKitVersionFromCommandsDir(kitCommandsDir) {
95149
+ let dir = kitCommandsDir;
95150
+ for (let i2 = 0; i2 < 5; i2++) {
95151
+ dir = path28.dirname(dir);
95152
+ }
95153
+ try {
95154
+ const raw = fs30.readFileSync(path28.join(dir, "package.json"), "utf-8");
95155
+ const pkg = JSON.parse(raw);
95156
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
95157
+ } catch {
95158
+ return "unknown";
95159
+ }
95160
+ }
95161
+ function detectScaffoldedDrift(args) {
95162
+ const workflows = detectWorkflowDrift(args);
95163
+ const commands = detectCommandDrift(args);
95164
+ return {
95165
+ overall: workflows.overall === "drift" || commands.overall === "drift" ? "drift" : "ok",
95166
+ workflows,
95167
+ commands
95168
+ };
95169
+ }
95170
+ function updateWorkflows(args) {
95171
+ const projectWorkflowsDir = path28.join(
95172
+ args.projectDir,
95173
+ ".github",
95174
+ "workflows"
95175
+ );
95176
+ const here = path28.dirname(new URL(importMetaUrl).pathname);
95177
+ const kitWorkflowsDir = args.kitDir ? path28.join(
95178
+ args.kitDir,
95179
+ "templates",
95180
+ "project",
95181
+ "common",
95182
+ ".github",
95183
+ "workflows"
95184
+ ) : findKitTemplatesDir(here);
95185
+ const substitute = args.substitute !== false;
95186
+ const dryRun = args.dryRun === true;
95187
+ const pruneExtras = args.pruneExtras === true;
95188
+ const templateFiles = fs30.existsSync(kitWorkflowsDir) ? fs30.readdirSync(kitWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95189
+ const projectFiles = fs30.existsSync(projectWorkflowsDir) ? fs30.readdirSync(projectWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95190
+ if (!dryRun && templateFiles.length > 0 && !fs30.existsSync(projectWorkflowsDir)) {
95191
+ fs30.mkdirSync(projectWorkflowsDir, { recursive: true });
95192
+ }
95193
+ const version = substitute ? readKitVersion(kitWorkflowsDir) : "";
95194
+ const seen = /* @__PURE__ */ new Set();
95195
+ const files = [];
95196
+ for (const name of templateFiles) {
95197
+ seen.add(name);
95198
+ const projectPath2 = path28.join(projectWorkflowsDir, name);
95199
+ const templatePath = path28.join(kitWorkflowsDir, name);
95200
+ const templateRaw = fs30.readFileSync(templatePath, "utf-8");
95201
+ const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
95202
+ const existed = fs30.existsSync(projectPath2);
95203
+ const current = existed ? fs30.readFileSync(projectPath2, "utf-8") : "";
95204
+ let outcome;
95205
+ if (!existed) {
95206
+ outcome = "added";
95207
+ } else if (current === desired) {
95208
+ outcome = "unchanged";
95209
+ } else {
95210
+ outcome = "updated";
95211
+ }
95212
+ if (!dryRun && outcome !== "unchanged") {
95213
+ fs30.writeFileSync(projectPath2, desired);
95214
+ }
95215
+ files.push({ name, outcome });
95216
+ }
95217
+ if (pruneExtras) {
95218
+ for (const name of projectFiles) {
95219
+ if (seen.has(name)) continue;
95220
+ const projectPath2 = path28.join(projectWorkflowsDir, name);
95221
+ if (!dryRun) {
95222
+ fs30.unlinkSync(projectPath2);
95223
+ }
95224
+ files.push({ name, outcome: "removed" });
95225
+ }
95226
+ }
95227
+ const order = {
95228
+ added: 0,
95229
+ updated: 1,
95230
+ removed: 2,
95231
+ unchanged: 3
95232
+ };
95233
+ files.sort((a, b) => order[a.outcome] - order[b.outcome] || a.name.localeCompare(b.name));
95234
+ const changed = files.some((f3) => f3.outcome !== "unchanged");
95235
+ return { files, changed };
95236
+ }
95237
+
95238
+ // scripts/lakebase/scm-merge.ts
95239
+ async function reconcileTierToOrigin(args) {
95240
+ const { cwd, tier } = args;
95241
+ try {
95242
+ const head = await getCurrentBranch({ cwd });
95243
+ if (head === tier) {
95244
+ await exec2(`git pull --ff-only`, { cwd, timeout: 3e4 });
95245
+ } else {
95246
+ await exec2(`git fetch origin ${shellEscape2(`${tier}:${tier}`)}`, { cwd, timeout: 3e4 });
95247
+ }
95248
+ return null;
95249
+ } catch (err) {
95250
+ return `local reconcile of ${tier} to origin/${tier} failed: ${err instanceof Error ? err.message : String(err)}. Reconcile it by hand (git checkout ${tier} && git pull --ff-only).`;
95251
+ }
95252
+ }
95253
+ var ScmMergeError = class extends Error {
95254
+ constructor(message, code) {
95255
+ super(message);
95256
+ this.code = code;
95257
+ this.name = "ScmMergeError";
95258
+ }
95259
+ code;
95260
+ };
95261
+ var DEFAULT_MIGRATE_TIMEOUT_MS = 30 * 60 * 1e3;
95262
+ var DEFAULT_MIGRATE_POLL_MS = 30 * 1e3;
95263
+ function defaultMigratePredicate(run, mergedAt) {
95264
+ if (!run.createdAt) return false;
95265
+ const created = Date.parse(run.createdAt);
95266
+ if (!Number.isFinite(created)) return false;
95267
+ if (run.event && run.event !== "push") return false;
95268
+ return created >= mergedAt.getTime() - 5e3;
95269
+ }
95270
+ function shaMigratePredicate(mergeCommitSha) {
95271
+ return (run) => {
95272
+ if (run.event && run.event !== "push") return false;
95273
+ return !!run.headSha && run.headSha === mergeCommitSha;
95274
+ };
95275
+ }
95276
+ async function defaultRefreshPromoteWorkflows(projectDir) {
95277
+ const drift = detectWorkflowDrift({ projectDir });
95278
+ const touched = drift.files.filter((f3) => f3.status === "drifted").map((f3) => f3.name);
95279
+ if (touched.length === 0) return { refreshed: false };
95280
+ const result = updateWorkflows({ projectDir });
95281
+ if (!result.changed) return { refreshed: false };
95282
+ await exec2(`git add ${shellEscape2(".github/workflows")}`, { cwd: projectDir, timeout: 1e4 });
95283
+ const staged = await exec2("git diff --cached --name-only -- .github/workflows", {
95284
+ cwd: projectDir,
95285
+ timeout: 1e4
95286
+ });
95287
+ if (!staged.trim()) return { refreshed: false };
95288
+ await exec2(
95289
+ `git commit -m ${shellEscape2(
95290
+ "chore(ci): refresh scaffolded workflows to pinned substrate (promote uses apply-tier)"
95291
+ )} -- .github/workflows`,
95292
+ { cwd: projectDir, timeout: 15e3 }
95293
+ );
95294
+ await pushCurrentBranchForPr({ cwd: projectDir });
95295
+ return { refreshed: true, detail: `refreshed + pushed ${touched.join(", ") || "workflow(s)"} onto the PR head` };
95296
+ }
95297
+ async function mergeFeature(args) {
95298
+ const current = readWorkflowState(args.projectDir);
95299
+ if (!current) {
95300
+ throw new ScmMergeError(
95301
+ "No SCM workflow state. wait-ci first.",
95302
+ "no-state-file"
95303
+ );
95304
+ }
95305
+ if (current.state !== "ci-green") {
95306
+ throw new ScmMergeError(
95307
+ `merge refuses state "${current.state}". Allowed predecessor: ci-green.`,
95308
+ "bad-precondition"
95309
+ );
95310
+ }
95311
+ if (!current.pr_url) {
95312
+ throw new ScmMergeError(
95313
+ "ci-green row is missing pr_url; cannot resolve the PR to merge.",
95314
+ "no-pr-url"
95315
+ );
95316
+ }
95317
+ if (!current.branch || !current.parent_branch) {
95318
+ throw new ScmMergeError(
95319
+ "ci-green row missing branch / parent_branch; refusing to merge.",
95320
+ "bad-precondition"
95321
+ );
95322
+ }
95323
+ const ownerRepo = await getOwnerRepo(args.projectDir);
95324
+ if (!ownerRepo) {
95325
+ throw new ScmMergeError(
95326
+ "No GitHub remote found at origin.",
95327
+ "no-github-remote"
95328
+ );
95329
+ }
95330
+ const pullNumber = extractPullNumber(current.pr_url);
95331
+ if (!pullNumber) {
95332
+ throw new ScmMergeError(
95333
+ `Could not extract PR number from URL: ${current.pr_url}`,
95334
+ "bad-pr-url"
95335
+ );
95336
+ }
95337
+ const instance = args.instance ?? current.project_id;
95338
+ const gitBase = await resolveGitBase(current.parent_branch, args.projectDir);
95339
+ const wantMigrate = args.waitMigrate !== false;
95340
+ let authVerified = false;
95341
+ if (wantMigrate && args.verifyMigrateAuth) {
95342
+ const probe = await args.verifyMigrateAuth();
95343
+ if (!probe.ok) {
95344
+ throw new ScmMergeError(
95345
+ `Migrate-auth precondition failed: ${probe.detail ?? "the Databricks credential is not usable"}. Refusing to merge: the downstream migrate would promote git without applying the schema. Refresh your credential (databricks auth login), then re-run.`,
95346
+ "migrate-auth"
95347
+ );
95348
+ }
95349
+ authVerified = true;
95350
+ }
95351
+ const preflightNotes = [];
95352
+ {
95353
+ const refresh = args.refreshWorkflows ?? (() => defaultRefreshPromoteWorkflows(args.projectDir));
95354
+ try {
95355
+ const r2 = await refresh();
95356
+ if (r2.refreshed) {
95357
+ preflightNotes.push(`Refreshed stale CI workflows before merge${r2.detail ? ` (${r2.detail})` : ""}.`);
95358
+ }
95359
+ } catch (err) {
95360
+ preflightNotes.push(
95361
+ `Workflow self-heal skipped (${err instanceof Error ? err.message : String(err)}); if the promote's migrate-target fails on the tier guard, refresh .github/workflows (merge.yml must call 'lakebase-schema-migrate apply-tier').`
95362
+ );
95363
+ }
95364
+ }
95365
+ let paired;
95366
+ try {
95367
+ paired = await mergePairedPullRequest({
95368
+ ownerRepo,
95369
+ pullNumber,
95370
+ lakebaseInstance: instance,
95371
+ method: args.method ?? "squash"
95372
+ });
95373
+ } catch (err) {
95374
+ throw new ScmMergeError(
95375
+ `mergePairedPullRequest failed: ${err instanceof Error ? err.message : String(err)}`,
95376
+ "merge-failed"
95377
+ );
95378
+ }
95379
+ const warnings = [...preflightNotes, ...paired.warnings];
95380
+ let localBranchDeleted = false;
95381
+ let headAfter = current.branch;
95382
+ if (!args.skipLocalCleanup) {
95383
+ const switchTo = args.switchTo ?? gitBase;
95384
+ const head = await getCurrentBranch({ cwd: args.projectDir });
95385
+ if (head === current.branch) {
95034
95386
  try {
95035
95387
  await exec2(`git checkout ${shellEscape2(switchTo)}`, {
95036
95388
  cwd: args.projectDir,
@@ -95221,7 +95573,7 @@ init_cjs_shims();
95221
95573
 
95222
95574
  // scripts/git/branches.ts
95223
95575
  init_cjs_shims();
95224
- async function currentBranchName(cwd) {
95576
+ async function currentBranchName2(cwd) {
95225
95577
  try {
95226
95578
  return await exec2("git rev-parse --abbrev-ref HEAD", { cwd });
95227
95579
  } catch {
@@ -95240,7 +95592,7 @@ async function listLocalBranches(args) {
95240
95592
  return [];
95241
95593
  }
95242
95594
  if (!raw) return [];
95243
- const current = await currentBranchName(cwd);
95595
+ const current = await currentBranchName2(cwd);
95244
95596
  return raw.split("\n").filter(Boolean).map((line) => {
95245
95597
  const [name, tracking, trackInfo] = line.split("|");
95246
95598
  let ahead = 0;
@@ -95405,15 +95757,15 @@ function parentForTopology(t2, defaultLeaf) {
95405
95757
 
95406
95758
  // scripts/lakebase/scm-doctor.ts
95407
95759
  init_cjs_shims();
95408
- var fs30 = __toESM(require("fs"), 1);
95409
- var path28 = __toESM(require("path"), 1);
95760
+ var fs31 = __toESM(require("fs"), 1);
95761
+ var path29 = __toESM(require("path"), 1);
95410
95762
  var FEATURE_PREFIX = "feature/";
95411
95763
  var TIER_LEAFS2 = DEFAULT_PROTECTED_TIER_NAMES;
95412
95764
  function readEnv(projectDir) {
95413
- const envPath = path28.join(projectDir, ".env");
95765
+ const envPath = path29.join(projectDir, ".env");
95414
95766
  const out = /* @__PURE__ */ new Map();
95415
- if (!fs30.existsSync(envPath)) return out;
95416
- const lines = fs30.readFileSync(envPath, "utf8").split("\n");
95767
+ if (!fs31.existsSync(envPath)) return out;
95768
+ const lines = fs31.readFileSync(envPath, "utf8").split("\n");
95417
95769
  for (const line of lines) {
95418
95770
  const m2 = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.+?)\s*$/);
95419
95771
  if (m2) out.set(m2[1], m2[2].replace(/^["']|["']$/g, ""));
@@ -95468,9 +95820,9 @@ async function runDoctor(args, deps = {}) {
95468
95820
  }
95469
95821
  for (const wf of ["pr.yml", "merge.yml"]) {
95470
95822
  try {
95471
- const p = path28.join(projectDir, ".github", "workflows", wf);
95472
- if (!fs30.existsSync(p)) continue;
95473
- const body = fs30.readFileSync(p, "utf8");
95823
+ const p = path29.join(projectDir, ".github", "workflows", wf);
95824
+ if (!fs31.existsSync(p)) continue;
95825
+ const body = fs31.readFileSync(p, "utf8");
95474
95826
  if (/lakebase-scm-utils#v\d/.test(body)) {
95475
95827
  findings.push({
95476
95828
  id: "ci-workflow-substrate-pin",
@@ -95685,7 +96037,7 @@ async function fixFinding(args) {
95685
96037
  );
95686
96038
  }
95687
96039
  const sanitized = sanitizeBranchName(branch);
95688
- const envFile = path28.join(args.projectDir, ".env");
96040
+ const envFile = path29.join(args.projectDir, ".env");
95689
96041
  updateEnvConnection({
95690
96042
  envPath: envFile,
95691
96043
  projectId: readEnvVar(envFile, "LAKEBASE_PROJECT_ID") ?? "",
@@ -95790,291 +96142,6 @@ init_cjs_shims();
95790
96142
  var fs32 = __toESM(require("fs"), 1);
95791
96143
  var path30 = __toESM(require("path"), 1);
95792
96144
  var cp6 = __toESM(require("child_process"), 1);
95793
-
95794
- // scripts/lakebase/workflow-drift.ts
95795
- init_cjs_shims();
95796
- var fs31 = __toESM(require("fs"), 1);
95797
- var path29 = __toESM(require("path"), 1);
95798
- function findKitTemplatesDir(start) {
95799
- let dir = start;
95800
- for (let i2 = 0; i2 < 6; i2++) {
95801
- const candidate = path29.join(
95802
- dir,
95803
- "templates",
95804
- "project",
95805
- "common",
95806
- ".github",
95807
- "workflows"
95808
- );
95809
- if (fs31.existsSync(candidate)) return candidate;
95810
- const parent = path29.dirname(dir);
95811
- if (parent === dir) break;
95812
- dir = parent;
95813
- }
95814
- throw new Error(
95815
- `Could not locate templates/project/common/.github/workflows/ relative to ${start}. Pass explicit kitDir.`
95816
- );
95817
- }
95818
- function unifiedDiff(name, projectContent, templateContent) {
95819
- if (projectContent === templateContent) return "";
95820
- const a = projectContent.split("\n");
95821
- const b = templateContent.split("\n");
95822
- const out = [`--- project/${name}`, `+++ template/${name}`];
95823
- const max = Math.max(a.length, b.length);
95824
- for (let i2 = 0; i2 < max; i2++) {
95825
- const av = a[i2];
95826
- const bv = b[i2];
95827
- if (av === bv) continue;
95828
- if (av !== void 0) out.push(`-${i2 + 1}: ${av}`);
95829
- if (bv !== void 0) out.push(`+${i2 + 1}: ${bv}`);
95830
- }
95831
- return out.join("\n");
95832
- }
95833
- function detectWorkflowDrift(args) {
95834
- const projectWorkflowsDir = path29.join(
95835
- args.projectDir,
95836
- ".github",
95837
- "workflows"
95838
- );
95839
- const here = path29.dirname(new URL(importMetaUrl).pathname);
95840
- const kitWorkflowsDir = args.kitDir ? path29.join(
95841
- args.kitDir,
95842
- "templates",
95843
- "project",
95844
- "common",
95845
- ".github",
95846
- "workflows"
95847
- ) : findKitTemplatesDir(here);
95848
- const templateFiles = fs31.existsSync(kitWorkflowsDir) ? fs31.readdirSync(kitWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95849
- const projectFiles = fs31.existsSync(projectWorkflowsDir) ? fs31.readdirSync(projectWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
95850
- const version = readKitVersion(kitWorkflowsDir);
95851
- const seen = /* @__PURE__ */ new Set();
95852
- const files = [];
95853
- for (const name of templateFiles) {
95854
- seen.add(name);
95855
- const projectPath2 = path29.join(projectWorkflowsDir, name);
95856
- const templatePath = path29.join(kitWorkflowsDir, name);
95857
- if (!fs31.existsSync(projectPath2)) {
95858
- files.push({ name, status: "missing" });
95859
- continue;
95860
- }
95861
- const projectContent = fs31.readFileSync(projectPath2, "utf8");
95862
- const templateContent = applyPlaceholders(fs31.readFileSync(templatePath, "utf8"), version);
95863
- if (projectContent === templateContent) {
95864
- files.push({ name, status: "unchanged" });
95865
- } else {
95866
- files.push({
95867
- name,
95868
- status: "drifted",
95869
- diff: unifiedDiff(name, projectContent, templateContent)
95870
- });
95871
- }
95872
- }
95873
- for (const name of projectFiles) {
95874
- if (seen.has(name)) continue;
95875
- files.push({ name, status: "extra" });
95876
- }
95877
- const order = {
95878
- drifted: 0,
95879
- missing: 1,
95880
- extra: 2,
95881
- unchanged: 3
95882
- };
95883
- files.sort((a, b) => order[a.status] - order[b.status] || a.name.localeCompare(b.name));
95884
- const hasDrift = files.some((f3) => f3.status === "drifted" || f3.status === "missing");
95885
- return {
95886
- overall: hasDrift ? "drift" : "ok",
95887
- files
95888
- };
95889
- }
95890
- function readKitVersion(kitWorkflowsDir) {
95891
- let dir = kitWorkflowsDir;
95892
- for (let i2 = 0; i2 < 5; i2++) {
95893
- dir = path29.dirname(dir);
95894
- }
95895
- try {
95896
- const raw = fs31.readFileSync(path29.join(dir, "package.json"), "utf-8");
95897
- const pkg = JSON.parse(raw);
95898
- return typeof pkg.version === "string" ? pkg.version : "unknown";
95899
- } catch {
95900
- return "unknown";
95901
- }
95902
- }
95903
- function applyPlaceholders(content, version) {
95904
- return content.replace(/\{\{LAKEBASE_SCM_UTILS_VERSION\}\}/g, version);
95905
- }
95906
- function applyCommandPlaceholders(content, version) {
95907
- return content.replace(/\$\{KIT_VERSION_AT_SCAFFOLD\}/g, version);
95908
- }
95909
- var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
95910
- function findKitCommandsDir(start) {
95911
- let dir = start;
95912
- for (let i2 = 0; i2 < 6; i2++) {
95913
- const candidate = path29.join(
95914
- dir,
95915
- "templates",
95916
- "project",
95917
- "common",
95918
- ".claude",
95919
- "commands"
95920
- );
95921
- if (fs31.existsSync(candidate)) return candidate;
95922
- const parent = path29.dirname(dir);
95923
- if (parent === dir) break;
95924
- dir = parent;
95925
- }
95926
- throw new Error(
95927
- `Could not locate templates/project/common/.claude/commands/ relative to ${start}. Pass explicit kitDir.`
95928
- );
95929
- }
95930
- function parsePinnedVersion(content) {
95931
- const m2 = content.match(/^\s*[*_>`\s]*pinned\s+to\s*:\s*[`*_]*([^\s`*_]+)[`*_]*\s*$/im);
95932
- return m2 ? m2[1] : void 0;
95933
- }
95934
- function detectCommandDrift(args) {
95935
- const projectCommandsDir = path29.join(args.projectDir, ".claude", "commands");
95936
- const here = path29.dirname(new URL(importMetaUrl).pathname);
95937
- const kitCommandsDir = args.kitDir ? path29.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
95938
- const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
95939
- const templateFiles = fs31.existsSync(kitCommandsDir) ? fs31.readdirSync(kitCommandsDir).filter((f3) => f3.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f3)) : [];
95940
- const projectFiles = fs31.existsSync(projectCommandsDir) ? fs31.readdirSync(projectCommandsDir).filter((f3) => f3.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f3)) : [];
95941
- const seen = /* @__PURE__ */ new Set();
95942
- const files = [];
95943
- for (const name of templateFiles) {
95944
- seen.add(name);
95945
- const projectPath2 = path29.join(projectCommandsDir, name);
95946
- const templatePath = path29.join(kitCommandsDir, name);
95947
- const templateRaw = fs31.readFileSync(templatePath, "utf8");
95948
- if (!fs31.existsSync(projectPath2)) {
95949
- files.push({ name, status: "missing", kit_version: kitVersion });
95950
- continue;
95951
- }
95952
- const projectContent = fs31.readFileSync(projectPath2, "utf8");
95953
- const pinned = parsePinnedVersion(projectContent);
95954
- const versionForCompare = pinned ?? kitVersion;
95955
- const templateContent = applyCommandPlaceholders(templateRaw, versionForCompare);
95956
- if (projectContent === templateContent) {
95957
- files.push({
95958
- name,
95959
- status: "unchanged",
95960
- pinned_version: pinned,
95961
- kit_version: kitVersion
95962
- });
95963
- } else {
95964
- files.push({
95965
- name,
95966
- status: "drifted",
95967
- pinned_version: pinned,
95968
- kit_version: kitVersion,
95969
- diff: unifiedDiff(name, projectContent, templateContent)
95970
- });
95971
- }
95972
- }
95973
- for (const name of projectFiles) {
95974
- if (seen.has(name)) continue;
95975
- files.push({ name, status: "extra", kit_version: kitVersion });
95976
- }
95977
- const order = {
95978
- drifted: 0,
95979
- missing: 1,
95980
- extra: 2,
95981
- unchanged: 3
95982
- };
95983
- files.sort((a, b) => order[a.status] - order[b.status] || a.name.localeCompare(b.name));
95984
- const hasDrift = files.some((f3) => f3.status === "drifted" || f3.status === "missing");
95985
- return { overall: hasDrift ? "drift" : "ok", files };
95986
- }
95987
- function readKitVersionFromCommandsDir(kitCommandsDir) {
95988
- let dir = kitCommandsDir;
95989
- for (let i2 = 0; i2 < 5; i2++) {
95990
- dir = path29.dirname(dir);
95991
- }
95992
- try {
95993
- const raw = fs31.readFileSync(path29.join(dir, "package.json"), "utf-8");
95994
- const pkg = JSON.parse(raw);
95995
- return typeof pkg.version === "string" ? pkg.version : "unknown";
95996
- } catch {
95997
- return "unknown";
95998
- }
95999
- }
96000
- function detectScaffoldedDrift(args) {
96001
- const workflows = detectWorkflowDrift(args);
96002
- const commands = detectCommandDrift(args);
96003
- return {
96004
- overall: workflows.overall === "drift" || commands.overall === "drift" ? "drift" : "ok",
96005
- workflows,
96006
- commands
96007
- };
96008
- }
96009
- function updateWorkflows(args) {
96010
- const projectWorkflowsDir = path29.join(
96011
- args.projectDir,
96012
- ".github",
96013
- "workflows"
96014
- );
96015
- const here = path29.dirname(new URL(importMetaUrl).pathname);
96016
- const kitWorkflowsDir = args.kitDir ? path29.join(
96017
- args.kitDir,
96018
- "templates",
96019
- "project",
96020
- "common",
96021
- ".github",
96022
- "workflows"
96023
- ) : findKitTemplatesDir(here);
96024
- const substitute = args.substitute !== false;
96025
- const dryRun = args.dryRun === true;
96026
- const pruneExtras = args.pruneExtras === true;
96027
- const templateFiles = fs31.existsSync(kitWorkflowsDir) ? fs31.readdirSync(kitWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
96028
- const projectFiles = fs31.existsSync(projectWorkflowsDir) ? fs31.readdirSync(projectWorkflowsDir).filter((f3) => f3.endsWith(".yml")) : [];
96029
- if (!dryRun && templateFiles.length > 0 && !fs31.existsSync(projectWorkflowsDir)) {
96030
- fs31.mkdirSync(projectWorkflowsDir, { recursive: true });
96031
- }
96032
- const version = substitute ? readKitVersion(kitWorkflowsDir) : "";
96033
- const seen = /* @__PURE__ */ new Set();
96034
- const files = [];
96035
- for (const name of templateFiles) {
96036
- seen.add(name);
96037
- const projectPath2 = path29.join(projectWorkflowsDir, name);
96038
- const templatePath = path29.join(kitWorkflowsDir, name);
96039
- const templateRaw = fs31.readFileSync(templatePath, "utf-8");
96040
- const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
96041
- const existed = fs31.existsSync(projectPath2);
96042
- const current = existed ? fs31.readFileSync(projectPath2, "utf-8") : "";
96043
- let outcome;
96044
- if (!existed) {
96045
- outcome = "added";
96046
- } else if (current === desired) {
96047
- outcome = "unchanged";
96048
- } else {
96049
- outcome = "updated";
96050
- }
96051
- if (!dryRun && outcome !== "unchanged") {
96052
- fs31.writeFileSync(projectPath2, desired);
96053
- }
96054
- files.push({ name, outcome });
96055
- }
96056
- if (pruneExtras) {
96057
- for (const name of projectFiles) {
96058
- if (seen.has(name)) continue;
96059
- const projectPath2 = path29.join(projectWorkflowsDir, name);
96060
- if (!dryRun) {
96061
- fs31.unlinkSync(projectPath2);
96062
- }
96063
- files.push({ name, outcome: "removed" });
96064
- }
96065
- }
96066
- const order = {
96067
- added: 0,
96068
- updated: 1,
96069
- removed: 2,
96070
- unchanged: 3
96071
- };
96072
- files.sort((a, b) => order[a.outcome] - order[b.outcome] || a.name.localeCompare(b.name));
96073
- const changed = files.some((f3) => f3.outcome !== "unchanged");
96074
- return { files, changed };
96075
- }
96076
-
96077
- // scripts/lakebase/doctor.ts
96078
96145
  function readEnvFile(projectDir) {
96079
96146
  const envPath = path30.join(projectDir, ".env");
96080
96147
  if (!fs32.existsSync(envPath)) return {};
@@ -96507,7 +96574,7 @@ function checkWorkflowDrift(projectDir) {
96507
96574
  status: "warn",
96508
96575
  message: `Scaffolded workflows drift from kit: ${drifted} drifted, ${missing} missing`,
96509
96576
  detail: { files: report.files.map((f3) => ({ name: f3.name, status: f3.status })) },
96510
- hint: "Inspect via the lakebase_workflow_drift MCP tool (or detectWorkflowDrift import). Refresh manually until updateWorkflows lands."
96577
+ hint: "Refresh with updateWorkflows (or the lakebase_workflow_drift MCP tool). A stale merge.yml calling 'lakebase-schema-migrate apply' (not 'apply-tier') makes the promote's migrate-target fail on the tier guard; the scm-merge promote also self-heals drifted workflows onto the PR head before merging."
96511
96578
  };
96512
96579
  } catch (err) {
96513
96580
  return {
@@ -96816,6 +96883,7 @@ function isUcMissingError(msg) {
96816
96883
  createUatPairedBranch,
96817
96884
  cutBackup,
96818
96885
  databricksAuthPrereqMessage,
96886
+ defaultRefreshPromoteWorkflows,
96819
96887
  deleteAppEndpoint,
96820
96888
  deleteBranch,
96821
96889
  deleteLakebaseProject,