@databricks-solutions/lakebase-scm-utils 0.2.48 → 0.2.50

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 (54) 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 +2184 -2054
  4. package/dist/scripts/index.d.cts +3 -2
  5. package/dist/scripts/index.d.ts +3 -2
  6. package/dist/scripts/index.js +259 -136
  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 +2170 -2052
  18. package/dist/scripts/lakebase/index.d.cts +21 -2
  19. package/dist/scripts/lakebase/index.d.ts +21 -2
  20. package/dist/scripts/lakebase/index.js +249 -132
  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-cleanup.cli.cjs +5 -2
  32. package/dist/scripts/lakebase/scm-cleanup.cli.js +5 -2
  33. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  34. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  35. package/dist/scripts/lakebase/scm-merge.cli.cjs +2216 -1994
  36. package/dist/scripts/lakebase/scm-merge.cli.js +296 -74
  37. package/dist/scripts/lakebase/scm-prepare-pr.cli.cjs +479 -86
  38. package/dist/scripts/lakebase/scm-prepare-pr.cli.js +479 -86
  39. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  40. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  41. package/dist/scripts/lakebase/sync-ci-secrets.cli.cjs +56 -30
  42. package/dist/scripts/lakebase/sync-ci-secrets.cli.js +56 -30
  43. package/dist/scripts/util/index.cjs +142 -25
  44. package/dist/scripts/util/index.d.cts +2 -27
  45. package/dist/scripts/util/index.d.ts +2 -27
  46. package/dist/scripts/util/index.js +136 -25
  47. package/package.json +1 -1
  48. package/scripts/lakebase/create-project.ts +2 -2
  49. package/scripts/lakebase/lakebase-project.ts +17 -3
  50. package/scripts/lakebase/scm-merge.ts +21 -0
  51. package/scripts/lakebase/scm-prepare-pr.ts +10 -1
  52. package/scripts/lakebase/sync-ci-secrets.cli.ts +2 -2
  53. package/scripts/util/ci-secrets.ts +212 -26
  54. package/templates/project/common/scripts/create-token-and-sync-secrets.sh +9 -86
@@ -1913,9 +1913,9 @@ function asBranchUid(s) {
1913
1913
  }
1914
1914
  return s;
1915
1915
  }
1916
- function branchNameFromResourcePath(path32) {
1917
- if (!path32.includes("/branches/")) return null;
1918
- const leaf = path32.split("/branches/").pop();
1916
+ function branchNameFromResourcePath(path33) {
1917
+ if (!path33.includes("/branches/")) return null;
1918
+ const leaf = path33.split("/branches/").pop();
1919
1919
  if (!leaf) return null;
1920
1920
  try {
1921
1921
  return asBranchName(leaf);
@@ -2210,9 +2210,12 @@ function assertCreatedProjectReady(projectId, verified, reportedState) {
2210
2210
  }
2211
2211
  return { uid: verified.uid, name: verified.name, state: verified.state ?? "READY" };
2212
2212
  }
2213
+ function deleteProjectArgs(projectId) {
2214
+ const name = projectId.startsWith("projects/") ? projectId : `projects/${projectId}`;
2215
+ return ["postgres", "delete-project", name, "--purge", "-o", "json"];
2216
+ }
2213
2217
  async function deleteLakebaseProject(args) {
2214
- const name = args.projectId.startsWith("projects/") ? args.projectId : `projects/${args.projectId}`;
2215
- await dbcli2(["postgres", "delete-project", name, "-o", "json"], args.host);
2218
+ await dbcli2(deleteProjectArgs(args.projectId), args.host);
2216
2219
  }
2217
2220
  function findDefaultBranchName(items) {
2218
2221
  const def = items.find((b) => b.status?.default === true || b.is_default === true);
@@ -2518,8 +2521,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
2518
2521
  var cached;
2519
2522
  function substrateSelfVersion() {
2520
2523
  if (cached !== void 0) return cached;
2521
- if ("0.2.48".length > 0) {
2522
- cached = "0.2.48";
2524
+ if ("0.2.50".length > 0) {
2525
+ cached = "0.2.50";
2523
2526
  return cached;
2524
2527
  }
2525
2528
  cached = "unknown";
@@ -5059,7 +5062,7 @@ paginateRest.VERSION = VERSION5;
5059
5062
 
5060
5063
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
5061
5064
  init_esm_shims();
5062
- var generateMessage = (path32, cursorValue) => `The cursor at "${path32.join(
5065
+ var generateMessage = (path33, cursorValue) => `The cursor at "${path33.join(
5063
5066
  ","
5064
5067
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
5065
5068
  var MissingCursorChange = class extends Error {
@@ -5100,9 +5103,9 @@ function findPaginatedResourcePath(responseData) {
5100
5103
  }
5101
5104
  return paginatedResourcePath;
5102
5105
  }
5103
- var deepFindPathToProperty = (object, searchProp, path32 = []) => {
5106
+ var deepFindPathToProperty = (object, searchProp, path33 = []) => {
5104
5107
  for (const key of Object.keys(object)) {
5105
- const currentPath = [...path32, key];
5108
+ const currentPath = [...path33, key];
5106
5109
  const currentValue = object[key];
5107
5110
  if (isObject(currentValue)) {
5108
5111
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -5120,12 +5123,12 @@ var deepFindPathToProperty = (object, searchProp, path32 = []) => {
5120
5123
  }
5121
5124
  return [];
5122
5125
  };
5123
- var get = (object, path32) => {
5124
- return path32.reduce((current, nextProperty) => current[nextProperty], object);
5126
+ var get = (object, path33) => {
5127
+ return path33.reduce((current, nextProperty) => current[nextProperty], object);
5125
5128
  };
5126
- var set = (object, path32, mutator) => {
5127
- const lastProperty = path32[path32.length - 1];
5128
- const parentPath = [...path32].slice(0, -1);
5129
+ var set = (object, path33, mutator) => {
5130
+ const lastProperty = path33[path33.length - 1];
5131
+ const parentPath = [...path33].slice(0, -1);
5129
5132
  const parent = get(object, parentPath);
5130
5133
  if (typeof mutator === "function") {
5131
5134
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -5177,22 +5180,22 @@ var mergeResponses = (response1, response2) => {
5177
5180
  if (Object.keys(response1).length === 0) {
5178
5181
  return Object.assign(response1, response2);
5179
5182
  }
5180
- const path32 = findPaginatedResourcePath(response1);
5181
- const nodesPath = [...path32, "nodes"];
5183
+ const path33 = findPaginatedResourcePath(response1);
5184
+ const nodesPath = [...path33, "nodes"];
5182
5185
  const newNodes = get(response2, nodesPath);
5183
5186
  if (newNodes) {
5184
5187
  set(response1, nodesPath, (values) => {
5185
5188
  return [...values, ...newNodes];
5186
5189
  });
5187
5190
  }
5188
- const edgesPath = [...path32, "edges"];
5191
+ const edgesPath = [...path33, "edges"];
5189
5192
  const newEdges = get(response2, edgesPath);
5190
5193
  if (newEdges) {
5191
5194
  set(response1, edgesPath, (values) => {
5192
5195
  return [...values, ...newEdges];
5193
5196
  });
5194
5197
  }
5195
- const pageInfoPath = [...path32, "pageInfo"];
5198
+ const pageInfoPath = [...path33, "pageInfo"];
5196
5199
  set(response1, pageInfoPath, get(response2, pageInfoPath));
5197
5200
  return response1;
5198
5201
  };
@@ -7613,7 +7616,7 @@ var triggers_notification_paths_default = [
7613
7616
  ];
7614
7617
  function routeMatcher(paths) {
7615
7618
  const regexes = paths.map(
7616
- (path32) => path32.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
7619
+ (path33) => path33.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
7617
7620
  );
7618
7621
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
7619
7622
  return new RegExp(regex2, "i");
@@ -10941,16 +10944,16 @@ function isAllSchemas(schema) {
10941
10944
  }
10942
10945
  function buildSchemaQuery(schema) {
10943
10946
  const cols = "c.table_schema, c.table_name, c.column_name, c.data_type";
10944
- const join33 = "FROM information_schema.columns c JOIN pg_tables t ON c.table_name = t.tablename AND c.table_schema = t.schemaname ";
10947
+ const join34 = "FROM information_schema.columns c JOIN pg_tables t ON c.table_name = t.tablename AND c.table_schema = t.schemaname ";
10945
10948
  if (isAllSchemas(schema)) {
10946
10949
  return {
10947
- text: `SELECT ${cols} ` + join33 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
10950
+ text: `SELECT ${cols} ` + join34 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
10948
10951
  values: []
10949
10952
  };
10950
10953
  }
10951
10954
  const one = (schema ?? "").trim() || "public";
10952
10955
  return {
10953
- text: `SELECT ${cols} ` + join33 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
10956
+ text: `SELECT ${cols} ` + join34 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
10954
10957
  values: [one]
10955
10958
  };
10956
10959
  }
@@ -11111,7 +11114,7 @@ async function withLakebaseRollback(opts, fn) {
11111
11114
  // scripts/lakebase/create-project.ts
11112
11115
  init_esm_shims();
11113
11116
  import * as fs18 from "fs";
11114
- import * as path17 from "path";
11117
+ import * as path18 from "path";
11115
11118
 
11116
11119
  // scripts/lakebase/project-verify.ts
11117
11120
  init_esm_shims();
@@ -12865,6 +12868,7 @@ async function removeRunner(args) {
12865
12868
 
12866
12869
  // scripts/util/ci-secrets.ts
12867
12870
  init_esm_shims();
12871
+ import * as path16 from "path";
12868
12872
 
12869
12873
  // scripts/github/secrets.ts
12870
12874
  init_esm_shims();
@@ -12974,13 +12978,40 @@ async function getOwnerRepo(cwd) {
12974
12978
 
12975
12979
  // scripts/util/ci-secrets.ts
12976
12980
  var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
12981
+ var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
12982
+ var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
12983
+ function ciTokenComment(ownerRepo) {
12984
+ const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
12985
+ return `GitHub Actions (${repoName})`;
12986
+ }
12977
12987
  async function missingCiSecrets(ownerRepo) {
12978
12988
  const present = new Set(await listSecretNames(ownerRepo));
12979
12989
  return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
12980
12990
  }
12991
+ async function mintCiToken(args) {
12992
+ try {
12993
+ const raw = await runDatabricks(
12994
+ ["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
12995
+ { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
12996
+ );
12997
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
12998
+ const token = parsed.token_value || parsed.token || "";
12999
+ if (token) return token;
13000
+ } catch {
13001
+ }
13002
+ try {
13003
+ const raw = await runDatabricks(["auth", "token", "-o", "json"], {
13004
+ host: args.databricksHost,
13005
+ cwd: args.projectDir,
13006
+ timeout: 3e4
13007
+ });
13008
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
13009
+ return parsed.access_token || "";
13010
+ } catch {
13011
+ return "";
13012
+ }
13013
+ }
12981
13014
  async function syncCiSecrets(args) {
12982
- const lifetime = args.lifetimeSeconds ?? 86400;
12983
- const comment = args.comment ?? "GitHub Actions CI";
12984
13015
  const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
12985
13016
  if (!ownerRepo) {
12986
13017
  throw new Error("Could not resolve GitHub repository from git remote");
@@ -12991,27 +13022,104 @@ async function syncCiSecrets(args) {
12991
13022
  if (!args.lakebaseProjectId) {
12992
13023
  throw new Error("syncCiSecrets: lakebaseProjectId is required");
12993
13024
  }
13025
+ const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
13026
+ const comment = args.comment ?? ciTokenComment(ownerRepo);
12994
13027
  const secrets = {
12995
13028
  DATABRICKS_HOST: args.databricksHost,
12996
13029
  LAKEBASE_PROJECT_ID: args.lakebaseProjectId
12997
13030
  };
13031
+ const token = await mintCiToken({
13032
+ databricksHost: args.databricksHost,
13033
+ projectDir: args.projectDir,
13034
+ comment,
13035
+ lifetimeSeconds: lifetime
13036
+ });
13037
+ if (token) secrets.DATABRICKS_TOKEN = token;
13038
+ await setRepoSecrets(ownerRepo, secrets);
13039
+ }
13040
+ async function ciTokenExpiry(args) {
13041
+ const comment = ciTokenComment(args.ownerRepo);
13042
+ let raw;
12998
13043
  try {
12999
- const tokenRaw = await runDatabricks(
13000
- ["tokens", "create", "--comment", comment, "--lifetime-seconds", String(lifetime), "-o", "json"],
13001
- { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
13002
- );
13003
- const parsed = JSON.parse(tokenRaw);
13004
- const token = parsed.token_value || parsed.token || "";
13005
- if (token) secrets.DATABRICKS_TOKEN = token;
13044
+ raw = await runDatabricks(["tokens", "list", "-o", "json"], {
13045
+ host: args.databricksHost,
13046
+ cwd: args.projectDir,
13047
+ timeout: 3e4
13048
+ });
13006
13049
  } catch {
13050
+ return null;
13051
+ }
13052
+ let infos;
13053
+ try {
13054
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
13055
+ infos = Array.isArray(parsed) ? parsed : [];
13056
+ } catch {
13057
+ return null;
13058
+ }
13059
+ 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);
13060
+ if (expiries.length === 0) return null;
13061
+ return Math.max(...expiries);
13062
+ }
13063
+ async function ensureCiSecretsFresh(args) {
13064
+ const now = args.now ?? Date.now;
13065
+ const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
13066
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
13067
+ if (!ownerRepo) {
13068
+ throw new Error("Could not resolve GitHub repository from git remote");
13069
+ }
13070
+ const sync = () => syncCiSecrets({
13071
+ projectDir: args.projectDir,
13072
+ databricksHost: args.databricksHost,
13073
+ lakebaseProjectId: args.lakebaseProjectId,
13074
+ ownerRepo
13075
+ });
13076
+ const missing = await missingCiSecrets(ownerRepo);
13077
+ if (missing.length > 0) {
13078
+ await sync();
13079
+ return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
13080
+ }
13081
+ const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
13082
+ if (expiry === null) {
13083
+ await sync();
13084
+ return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
13085
+ }
13086
+ if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
13087
+ await sync();
13088
+ const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
13089
+ return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
13090
+ }
13091
+ return { action: "ok", reason: "CI token is current." };
13092
+ }
13093
+ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
13094
+ const envPath = path16.join(projectDir, ".env");
13095
+ const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
13096
+ const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
13097
+ if (!databricksHost || !lakebaseProjectId) {
13098
+ return {
13099
+ action: "skipped",
13100
+ reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
13101
+ };
13102
+ }
13103
+ try {
13104
+ return await ensureCiSecretsFresh({
13105
+ projectDir,
13106
+ databricksHost,
13107
+ lakebaseProjectId,
13108
+ ownerRepo: opts?.ownerRepo,
13109
+ marginSeconds: opts?.marginSeconds
13110
+ });
13111
+ } catch (err) {
13112
+ return {
13113
+ action: "failed",
13114
+ 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.`
13115
+ };
13007
13116
  }
13008
- await setRepoSecrets(ownerRepo, secrets);
13009
13117
  }
13010
13118
 
13011
13119
  // scripts/lakebase/scm-workflow-state.ts
13012
13120
  init_esm_shims();
13013
13121
  import * as fs17 from "fs";
13014
- import * as path16 from "path";
13122
+ import * as path17 from "path";
13015
13123
  import { execFileSync as execFileSync6 } from "child_process";
13016
13124
  function isGitTracked(projectDir, rel) {
13017
13125
  try {
@@ -13030,7 +13138,7 @@ function ensureWorkflowStateUntracked(projectDir) {
13030
13138
  } catch {
13031
13139
  }
13032
13140
  try {
13033
- const gitignore = path16.join(projectDir, ".gitignore");
13141
+ const gitignore = path17.join(projectDir, ".gitignore");
13034
13142
  const existing = fs17.existsSync(gitignore) ? fs17.readFileSync(gitignore, "utf8") : "";
13035
13143
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
13036
13144
  const sep4 = existing === "" || existing.endsWith("\n") ? "" : "\n";
@@ -13058,7 +13166,7 @@ var STATE_INDEX = SCM_STATES.reduce(
13058
13166
  );
13059
13167
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
13060
13168
  function stateFilePath(projectDir) {
13061
- return path16.join(projectDir, STATE_FILE_REL);
13169
+ return path17.join(projectDir, STATE_FILE_REL);
13062
13170
  }
13063
13171
  function readWorkflowState(projectDir) {
13064
13172
  const p = stateFilePath(projectDir);
@@ -13098,7 +13206,7 @@ function writeWorkflowState(projectDir, state) {
13098
13206
  ${summary}`);
13099
13207
  }
13100
13208
  ensureWorkflowStateUntracked(projectDir);
13101
- const dir = path16.join(projectDir, ".lakebase");
13209
+ const dir = path17.join(projectDir, ".lakebase");
13102
13210
  fs17.mkdirSync(dir, { recursive: true });
13103
13211
  const target = stateFilePath(projectDir);
13104
13212
  const tmp = `${target}.tmp`;
@@ -13329,7 +13437,7 @@ function orderForOutput(state) {
13329
13437
  async function createProject(input, progress) {
13330
13438
  const report = progress ?? (() => {
13331
13439
  });
13332
- const projectDir = path17.join(input.parentDir, input.projectName);
13440
+ const projectDir = path18.join(input.parentDir, input.projectName);
13333
13441
  const lakebaseProjectId = input.projectName;
13334
13442
  const host = input.databricksHost.replace(/\/+$/, "");
13335
13443
  const useGithub = input.createGithubRepo !== false;
@@ -13490,8 +13598,6 @@ Last probe error:
13490
13598
  projectDir,
13491
13599
  databricksHost: host,
13492
13600
  lakebaseProjectId,
13493
- comment: "GitHub Actions CI",
13494
- lifetimeSeconds: 86400,
13495
13601
  ownerRepo: fullRepoName
13496
13602
  });
13497
13603
  const missing = await missingCiSecrets(fullRepoName);
@@ -13558,9 +13664,9 @@ Last probe error:
13558
13664
  const scmRef = envRef || (ver !== "unknown" ? `v${ver}` : "");
13559
13665
  if (scmRef) {
13560
13666
  try {
13561
- const dir = path17.join(projectDir, ".lakebase");
13667
+ const dir = path18.join(projectDir, ".lakebase");
13562
13668
  fs18.mkdirSync(dir, { recursive: true });
13563
- fs18.writeFileSync(path17.join(dir, "scm-utils-ref"), `${scmRef}
13669
+ fs18.writeFileSync(path18.join(dir, "scm-utils-ref"), `${scmRef}
13564
13670
  `, "utf8");
13565
13671
  } catch (err) {
13566
13672
  warnings.push(`Substrate ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
@@ -13571,9 +13677,9 @@ Last probe error:
13571
13677
  const kitRef = process.env.LAKEBASE_KIT_REF?.trim();
13572
13678
  if (kitRef) {
13573
13679
  try {
13574
- const dir = path17.join(projectDir, ".lakebase");
13680
+ const dir = path18.join(projectDir, ".lakebase");
13575
13681
  fs18.mkdirSync(dir, { recursive: true });
13576
- fs18.writeFileSync(path17.join(dir, "kit-ref"), `${kitRef}
13682
+ fs18.writeFileSync(path18.join(dir, "kit-ref"), `${kitRef}
13577
13683
  `, "utf8");
13578
13684
  } catch (err) {
13579
13685
  warnings.push(`Kit ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
@@ -13655,7 +13761,7 @@ Last probe error:
13655
13761
  init_esm_shims();
13656
13762
  import * as cp5 from "child_process";
13657
13763
  import * as fs19 from "fs";
13658
- import * as path18 from "path";
13764
+ import * as path19 from "path";
13659
13765
  async function adoptLakebaseProject(args) {
13660
13766
  const warnings = [];
13661
13767
  const filesWritten = [];
@@ -13664,7 +13770,7 @@ async function adoptLakebaseProject(args) {
13664
13770
  if (!fs19.existsSync(args.projectDir)) {
13665
13771
  throw new Error(`adoptLakebaseProject: project directory does not exist: ${args.projectDir}`);
13666
13772
  }
13667
- if (!fs19.existsSync(path18.join(args.projectDir, ".git"))) {
13773
+ if (!fs19.existsSync(path19.join(args.projectDir, ".git"))) {
13668
13774
  throw new Error(
13669
13775
  `adoptLakebaseProject: ${args.projectDir} is not a git repo. Run \`git init\` first, or pass an existing repo path.`
13670
13776
  );
@@ -13730,7 +13836,7 @@ async function adoptLakebaseProject(args) {
13730
13836
  };
13731
13837
  }
13732
13838
  function assertEnvCompatibility(projectDir, expectedProjectId) {
13733
- const envPath = path18.join(projectDir, ".env");
13839
+ const envPath = path19.join(projectDir, ".env");
13734
13840
  if (!fs19.existsSync(envPath)) return;
13735
13841
  const content = fs19.readFileSync(envPath, "utf8");
13736
13842
  const match = content.match(/^LAKEBASE_PROJECT_ID\s*=\s*(.+?)\s*$/m);
@@ -13746,7 +13852,7 @@ function assertAdoptionPreflight(args) {
13746
13852
  if (!fs19.existsSync(args.projectDir)) {
13747
13853
  throw new Error(`assertAdoptionPreflight: project directory does not exist: ${args.projectDir}`);
13748
13854
  }
13749
- if (!fs19.existsSync(path18.join(args.projectDir, ".git"))) {
13855
+ if (!fs19.existsSync(path19.join(args.projectDir, ".git"))) {
13750
13856
  throw new Error(
13751
13857
  `assertAdoptionPreflight: ${args.projectDir} is not a git repo.`
13752
13858
  );
@@ -13760,7 +13866,7 @@ function _testMakeBrownfieldFixture(opts) {
13760
13866
  cp5.execSync("git init --quiet", { cwd: opts.dir, stdio: "pipe" });
13761
13867
  if (opts.packageJson) {
13762
13868
  fs19.writeFileSync(
13763
- path18.join(opts.dir, "package.json"),
13869
+ path19.join(opts.dir, "package.json"),
13764
13870
  JSON.stringify(opts.packageJson, null, 2) + "\n"
13765
13871
  );
13766
13872
  }
@@ -13769,7 +13875,7 @@ function _testMakeBrownfieldFixture(opts) {
13769
13875
  // scripts/lakebase/infra-runner.ts
13770
13876
  init_esm_shims();
13771
13877
  import * as fs27 from "fs";
13772
- import * as path27 from "path";
13878
+ import * as path28 from "path";
13773
13879
 
13774
13880
  // scripts/lakebase/schema-diff.ts
13775
13881
  init_esm_shims();
@@ -13966,12 +14072,12 @@ function dbcli6(args) {
13966
14072
  // scripts/lakebase/schema-migrate.ts
13967
14073
  init_esm_shims();
13968
14074
  import * as fs26 from "fs";
13969
- import * as path26 from "path";
14075
+ import * as path27 from "path";
13970
14076
 
13971
14077
  // scripts/lakebase/migration-layout.ts
13972
14078
  init_esm_shims();
13973
14079
  import * as fs20 from "fs";
13974
- import * as path19 from "path";
14080
+ import * as path20 from "path";
13975
14081
  var MIGRATION_LANGUAGES = [
13976
14082
  "java",
13977
14083
  "kotlin",
@@ -13987,13 +14093,13 @@ var MIGRATION_DEFAULTS = {
13987
14093
  unknown: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" }
13988
14094
  };
13989
14095
  function detectLanguageAt(dir) {
13990
- if (fs20.existsSync(path19.join(dir, "pom.xml"))) {
13991
- const kotlinDir = path19.join(dir, "src", "main", "kotlin");
14096
+ if (fs20.existsSync(path20.join(dir, "pom.xml"))) {
14097
+ const kotlinDir = path20.join(dir, "src", "main", "kotlin");
13992
14098
  if (fs20.existsSync(kotlinDir)) {
13993
14099
  return "kotlin";
13994
14100
  }
13995
14101
  try {
13996
- const pom = fs20.readFileSync(path19.join(dir, "pom.xml"), "utf-8");
14102
+ const pom = fs20.readFileSync(path20.join(dir, "pom.xml"), "utf-8");
13997
14103
  if (pom.includes("kotlin-maven-plugin")) {
13998
14104
  return "kotlin";
13999
14105
  }
@@ -14001,10 +14107,10 @@ function detectLanguageAt(dir) {
14001
14107
  }
14002
14108
  return "java";
14003
14109
  }
14004
- if (fs20.existsSync(path19.join(dir, "pyproject.toml")) || fs20.existsSync(path19.join(dir, "requirements.txt")) || fs20.existsSync(path19.join(dir, "alembic.ini"))) {
14110
+ if (fs20.existsSync(path20.join(dir, "pyproject.toml")) || fs20.existsSync(path20.join(dir, "requirements.txt")) || fs20.existsSync(path20.join(dir, "alembic.ini"))) {
14005
14111
  return "python";
14006
14112
  }
14007
- if (fs20.existsSync(path19.join(dir, "package.json"))) {
14113
+ if (fs20.existsSync(path20.join(dir, "package.json"))) {
14008
14114
  return "nodejs";
14009
14115
  }
14010
14116
  return "unknown";
@@ -14025,14 +14131,14 @@ function resolveMigrationLanguage(projectDir, configuredMigrationPath, override)
14025
14131
  if (!rel) {
14026
14132
  return "unknown";
14027
14133
  }
14028
- const rootResolved = path19.resolve(projectDir);
14029
- let dir = path19.resolve(projectDir, rel);
14030
- while (dir === rootResolved || dir.startsWith(rootResolved + path19.sep)) {
14134
+ const rootResolved = path20.resolve(projectDir);
14135
+ let dir = path20.resolve(projectDir, rel);
14136
+ while (dir === rootResolved || dir.startsWith(rootResolved + path20.sep)) {
14031
14137
  const lang = detectLanguageAt(dir);
14032
14138
  if (lang !== "unknown") {
14033
14139
  return lang;
14034
14140
  }
14035
- const parent = path19.dirname(dir);
14141
+ const parent = path20.dirname(dir);
14036
14142
  if (parent === dir) {
14037
14143
  break;
14038
14144
  }
@@ -14066,17 +14172,17 @@ function resolveMigrationLayout(args) {
14066
14172
  // scripts/lakebase/adapters/alembic-adapter.ts
14067
14173
  init_esm_shims();
14068
14174
  import * as fs22 from "fs";
14069
- import * as path21 from "path";
14175
+ import * as path22 from "path";
14070
14176
 
14071
14177
  // scripts/lakebase/schema-migrate-runners/alembic.ts
14072
14178
  init_esm_shims();
14073
14179
  import { spawn as spawn5 } from "child_process";
14074
14180
  import * as fs21 from "fs";
14075
- import * as path20 from "path";
14181
+ import * as path21 from "path";
14076
14182
  function resolveAlembicBin(projectDir) {
14077
14183
  const candidates = [
14078
- path20.join(projectDir, ".venv", "bin", "alembic"),
14079
- path20.join(projectDir, "venv", "bin", "alembic")
14184
+ path21.join(projectDir, ".venv", "bin", "alembic"),
14185
+ path21.join(projectDir, "venv", "bin", "alembic")
14080
14186
  ];
14081
14187
  for (const candidate of candidates) {
14082
14188
  try {
@@ -14090,7 +14196,7 @@ function spawnAlembic(projectDir, args, dsn) {
14090
14196
  return new Promise((resolve2, reject) => {
14091
14197
  const bin = resolveAlembicBin(projectDir);
14092
14198
  const env = { ...process.env };
14093
- env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path20.delimiter);
14199
+ env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path21.delimiter);
14094
14200
  if (dsn) env.DATABASE_URL = dsn;
14095
14201
  const child = spawn5(bin, args, {
14096
14202
  cwd: projectDir,
@@ -14138,10 +14244,10 @@ async function createAlembicRevision(opts) {
14138
14244
  const m = stdout.match(/Generating\s+(\S+\.py)/);
14139
14245
  if (m) return m[1].trim();
14140
14246
  for (const rel of ["migrations/versions", "alembic/versions"]) {
14141
- const dir = path20.join(opts.projectDir, rel);
14247
+ const dir = path21.join(opts.projectDir, rel);
14142
14248
  if (!fs21.existsSync(dir)) continue;
14143
14249
  const hit = fs21.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
14144
- if (hit) return path20.join(dir, hit);
14250
+ if (hit) return path21.join(dir, hit);
14145
14251
  }
14146
14252
  throw new SchemaMigrationError(
14147
14253
  `alembic revision succeeded but the created file could not be located.
@@ -14276,8 +14382,8 @@ async function buildDsn2(args) {
14276
14382
  }
14277
14383
  function findVersionsDir(projectDir) {
14278
14384
  const candidates = [
14279
- path21.join(projectDir, "migrations", "versions"),
14280
- path21.join(projectDir, "alembic", "versions")
14385
+ path22.join(projectDir, "migrations", "versions"),
14386
+ path22.join(projectDir, "alembic", "versions")
14281
14387
  ];
14282
14388
  return candidates.find((p) => fs22.existsSync(p));
14283
14389
  }
@@ -14309,9 +14415,9 @@ var AlembicAdapter = {
14309
14415
  * here. Callers can still force-select via project.yaml#migration_tool.
14310
14416
  */
14311
14417
  detect(projectDir) {
14312
- if (fs22.existsSync(path21.join(projectDir, "alembic.ini"))) return true;
14313
- if (fs22.existsSync(path21.join(projectDir, "migrations", "env.py"))) return true;
14314
- if (fs22.existsSync(path21.join(projectDir, "alembic", "env.py"))) return true;
14418
+ if (fs22.existsSync(path22.join(projectDir, "alembic.ini"))) return true;
14419
+ if (fs22.existsSync(path22.join(projectDir, "migrations", "env.py"))) return true;
14420
+ if (fs22.existsSync(path22.join(projectDir, "alembic", "env.py"))) return true;
14315
14421
  return false;
14316
14422
  },
14317
14423
  async apply(args) {
@@ -14417,7 +14523,7 @@ var AlembicAdapter = {
14417
14523
  autogenerate: !!args.autogenerate,
14418
14524
  dsn
14419
14525
  });
14420
- return { status: "ok", version: revId, filename: path21.basename(created), path: created };
14526
+ return { status: "ok", version: revId, filename: path22.basename(created), path: created };
14421
14527
  } catch (err) {
14422
14528
  return {
14423
14529
  status: "error",
@@ -14434,7 +14540,7 @@ var AlembicAdapter = {
14434
14540
  if (heads.length <= 1) return { status: "noop", headsBefore: heads };
14435
14541
  if (args.dryRun) return { status: "ok", headsBefore: heads };
14436
14542
  const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
14437
- const mergeRevision = path21.basename(created).replace(/\.py$/, "").split("_")[0];
14543
+ const mergeRevision = path22.basename(created).replace(/\.py$/, "").split("_")[0];
14438
14544
  return { status: "ok", headsBefore: heads, mergeRevision, path: created };
14439
14545
  } catch (err) {
14440
14546
  return {
@@ -14450,12 +14556,12 @@ registerSchemaMigrationAdapter(AlembicAdapter);
14450
14556
  // scripts/lakebase/adapters/flyway-adapter.ts
14451
14557
  init_esm_shims();
14452
14558
  import * as fs23 from "fs";
14453
- import * as path23 from "path";
14559
+ import * as path24 from "path";
14454
14560
 
14455
14561
  // scripts/lakebase/schema-migrate-runners/flyway.ts
14456
14562
  init_esm_shims();
14457
14563
  import { spawn as spawn6 } from "child_process";
14458
- import * as path22 from "path";
14564
+ import * as path23 from "path";
14459
14565
  function dsnToFlywayEnv(dsn) {
14460
14566
  const u = new URL(dsn);
14461
14567
  const user = decodeURIComponent(u.username);
@@ -14465,7 +14571,7 @@ function dsnToFlywayEnv(dsn) {
14465
14571
  return { url, user, password };
14466
14572
  }
14467
14573
  function migrationsLocation(projectDir) {
14468
- return `filesystem:${path22.join(projectDir, "src", "main", "resources", "db", "migration")}`;
14574
+ return `filesystem:${path23.join(projectDir, "src", "main", "resources", "db", "migration")}`;
14469
14575
  }
14470
14576
  function runFlyway(ctx, args) {
14471
14577
  const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
@@ -14566,7 +14672,7 @@ async function statusFlyway(ctx) {
14566
14672
  if (state === "SUCCESS" || state === "BASELINE") {
14567
14673
  current = m.version;
14568
14674
  } else if (state === "PENDING") {
14569
- const filename = m.filepath ? path22.basename(m.filepath) : `V${m.version}__migration.sql`;
14675
+ const filename = m.filepath ? path23.basename(m.filepath) : `V${m.version}__migration.sql`;
14570
14676
  pending.push({
14571
14677
  version: m.version,
14572
14678
  filename,
@@ -14589,7 +14695,7 @@ async function buildDsn3(args) {
14589
14695
  return result.url;
14590
14696
  }
14591
14697
  function listFlywayFiles(projectDir) {
14592
- const dir = path23.join(projectDir, "src", "main", "resources", "db", "migration");
14698
+ const dir = path24.join(projectDir, "src", "main", "resources", "db", "migration");
14593
14699
  if (!fs23.existsSync(dir)) return [];
14594
14700
  const files = fs23.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
14595
14701
  return files.map((filename) => {
@@ -14614,7 +14720,7 @@ var FlywayAdapter = {
14614
14720
  id: "flyway",
14615
14721
  languages: ["java", "kotlin"],
14616
14722
  detect(projectDir) {
14617
- return fs23.existsSync(path23.join(projectDir, "pom.xml"));
14723
+ return fs23.existsSync(path24.join(projectDir, "pom.xml"));
14618
14724
  },
14619
14725
  async apply(args) {
14620
14726
  const dsn = await buildDsn3(args);
@@ -14672,12 +14778,12 @@ var FlywayAdapter = {
14672
14778
  // optional-protocol shape makes this additive.
14673
14779
  async newMigration(args) {
14674
14780
  try {
14675
- const dir = path23.join(args.projectDir, "src", "main", "resources", "db", "migration");
14781
+ const dir = path24.join(args.projectDir, "src", "main", "resources", "db", "migration");
14676
14782
  fs23.mkdirSync(dir, { recursive: true });
14677
14783
  const version = migrationTimestamp();
14678
14784
  const slug = migrationSlug2(args.slug);
14679
14785
  const filename = `V${version}__${slug}.sql`;
14680
- const full = path23.join(dir, filename);
14786
+ const full = path24.join(dir, filename);
14681
14787
  if (fs23.existsSync(full)) throw new Error(`${filename} already exists`);
14682
14788
  fs23.writeFileSync(
14683
14789
  full,
@@ -14703,17 +14809,17 @@ registerSchemaMigrationAdapter(FlywayAdapter);
14703
14809
  // scripts/lakebase/adapters/knex-adapter.ts
14704
14810
  init_esm_shims();
14705
14811
  import * as fs25 from "fs";
14706
- import * as path25 from "path";
14812
+ import * as path26 from "path";
14707
14813
 
14708
14814
  // scripts/lakebase/schema-migrate-runners/knex.ts
14709
14815
  init_esm_shims();
14710
14816
  import { spawn as spawn7 } from "child_process";
14711
14817
  import * as fs24 from "fs";
14712
- import * as path24 from "path";
14818
+ import * as path25 from "path";
14713
14819
  var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
14714
14820
  function findKnexfile(projectDir) {
14715
14821
  for (const name of KNEXFILE_VARIANTS) {
14716
- const p = path24.join(projectDir, name);
14822
+ const p = path25.join(projectDir, name);
14717
14823
  if (fs24.existsSync(p)) return p;
14718
14824
  }
14719
14825
  return void 0;
@@ -14866,7 +14972,7 @@ async function buildDsn4(args) {
14866
14972
  }
14867
14973
  var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
14868
14974
  function listKnexFiles(projectDir) {
14869
- const dir = path25.join(projectDir, "migrations");
14975
+ const dir = path26.join(projectDir, "migrations");
14870
14976
  if (!fs25.existsSync(dir)) return [];
14871
14977
  const files = fs25.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
14872
14978
  return files.map((filename) => {
@@ -14888,7 +14994,7 @@ var KnexAdapter = {
14888
14994
  * project.yaml#migration_tool.
14889
14995
  */
14890
14996
  detect(projectDir) {
14891
- return KNEXFILE_VARIANTS2.some((name) => fs25.existsSync(path25.join(projectDir, name)));
14997
+ return KNEXFILE_VARIANTS2.some((name) => fs25.existsSync(path26.join(projectDir, name)));
14892
14998
  },
14893
14999
  async apply(args) {
14894
15000
  const dsn = await buildDsn4(args);
@@ -14961,9 +15067,9 @@ var KnexAdapter = {
14961
15067
  async newMigration(args) {
14962
15068
  try {
14963
15069
  const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
14964
- const stem = path25.basename(created).replace(/\.(js|ts)$/, "");
15070
+ const stem = path26.basename(created).replace(/\.(js|ts)$/, "");
14965
15071
  const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
14966
- return { status: "ok", version, filename: path25.basename(created), path: created };
15072
+ return { status: "ok", version, filename: path26.basename(created), path: created };
14967
15073
  } catch (err) {
14968
15074
  return {
14969
15075
  status: "error",
@@ -15020,7 +15126,7 @@ function listSchemaMigrations(args = {}) {
15020
15126
  }
15021
15127
  }
15022
15128
  function listFlywayMigrations(projectDir) {
15023
- const dir = path26.join(projectDir, "src", "main", "resources", "db", "migration");
15129
+ const dir = path27.join(projectDir, "src", "main", "resources", "db", "migration");
15024
15130
  if (!fs26.existsSync(dir)) return [];
15025
15131
  const files = fs26.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
15026
15132
  return files.map((filename) => {
@@ -15032,8 +15138,8 @@ function listFlywayMigrations(projectDir) {
15032
15138
  }
15033
15139
  function listAlembicMigrations(projectDir) {
15034
15140
  const candidates = [
15035
- path26.join(projectDir, "migrations", "versions"),
15036
- path26.join(projectDir, "alembic", "versions")
15141
+ path27.join(projectDir, "migrations", "versions"),
15142
+ path27.join(projectDir, "alembic", "versions")
15037
15143
  ];
15038
15144
  const dir = candidates.find((p) => fs26.existsSync(p));
15039
15145
  if (!dir) return [];
@@ -15047,7 +15153,7 @@ function listAlembicMigrations(projectDir) {
15047
15153
  }).sort((a, b) => a.filename.localeCompare(b.filename));
15048
15154
  }
15049
15155
  function listKnexMigrations(projectDir) {
15050
- const dir = path26.join(projectDir, "migrations");
15156
+ const dir = path27.join(projectDir, "migrations");
15051
15157
  if (!fs26.existsSync(dir)) return [];
15052
15158
  const files = fs26.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
15053
15159
  return files.map((filename) => {
@@ -15225,7 +15331,7 @@ async function runInfraSuite(args) {
15225
15331
  duration_ms: Date.now() - start
15226
15332
  };
15227
15333
  if (args.junitOutput) {
15228
- fs27.mkdirSync(path27.dirname(args.junitOutput), { recursive: true });
15334
+ fs27.mkdirSync(path28.dirname(args.junitOutput), { recursive: true });
15229
15335
  fs27.writeFileSync(args.junitOutput, formatJUnit(result), "utf8");
15230
15336
  }
15231
15337
  return result;
@@ -15273,7 +15379,7 @@ function escapeXml(s) {
15273
15379
  // scripts/lakebase/scm-claim-feature.ts
15274
15380
  init_esm_shims();
15275
15381
  import * as fs28 from "fs";
15276
- import * as path28 from "path";
15382
+ import * as path29 from "path";
15277
15383
  var ScmClaimError = class extends Error {
15278
15384
  constructor(message, code) {
15279
15385
  super(message);
@@ -15330,7 +15436,7 @@ async function claimFeatureBranch(args) {
15330
15436
  const current = readWorkflowState(args.projectDir);
15331
15437
  if (!current) {
15332
15438
  throw new ScmClaimError(
15333
- `No SCM workflow state found at ${path28.join(args.projectDir, ".lakebase/workflow-state.json")}. Run lakebase-create-project to scaffold, or re-seed via the substrate.`,
15439
+ `No SCM workflow state found at ${path29.join(args.projectDir, ".lakebase/workflow-state.json")}. Run lakebase-create-project to scaffold, or re-seed via the substrate.`,
15334
15440
  "no-state-file"
15335
15441
  );
15336
15442
  }
@@ -15435,7 +15541,7 @@ function alreadyClaimedSentinel(state) {
15435
15541
  }
15436
15542
  function workflowStateFileExists(projectDir) {
15437
15543
  return fs28.existsSync(
15438
- path28.join(projectDir, ".lakebase/workflow-state.json")
15544
+ path29.join(projectDir, ".lakebase/workflow-state.json")
15439
15545
  );
15440
15546
  }
15441
15547
 
@@ -15699,6 +15805,7 @@ async function preparePr(args) {
15699
15805
  "no-github-remote"
15700
15806
  );
15701
15807
  }
15808
+ const ciFreshness = await ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo });
15702
15809
  const now = (args.now ?? (() => /* @__PURE__ */ new Date()))();
15703
15810
  let prUrl = args.prUrlOverride ?? "";
15704
15811
  let prCreated = false;
@@ -15743,7 +15850,7 @@ async function preparePr(args) {
15743
15850
  pushed_at: now.toISOString()
15744
15851
  };
15745
15852
  writeWorkflowState(args.projectDir, next);
15746
- return { state: next, prUrl, prCreated };
15853
+ return { state: next, prUrl, prCreated, ciFreshness };
15747
15854
  }
15748
15855
  async function ensureAheadOfParent(cwd, branch, parent) {
15749
15856
  try {
@@ -15923,11 +16030,11 @@ async function pushCurrentBranchForPr(args) {
15923
16030
  // scripts/lakebase/workflow-drift.ts
15924
16031
  init_esm_shims();
15925
16032
  import * as fs29 from "fs";
15926
- import * as path29 from "path";
16033
+ import * as path30 from "path";
15927
16034
  function findKitTemplatesDir(start) {
15928
16035
  let dir = start;
15929
16036
  for (let i = 0; i < 6; i++) {
15930
- const candidate = path29.join(
16037
+ const candidate = path30.join(
15931
16038
  dir,
15932
16039
  "templates",
15933
16040
  "project",
@@ -15936,7 +16043,7 @@ function findKitTemplatesDir(start) {
15936
16043
  "workflows"
15937
16044
  );
15938
16045
  if (fs29.existsSync(candidate)) return candidate;
15939
- const parent = path29.dirname(dir);
16046
+ const parent = path30.dirname(dir);
15940
16047
  if (parent === dir) break;
15941
16048
  dir = parent;
15942
16049
  }
@@ -15960,13 +16067,13 @@ function unifiedDiff(name, projectContent, templateContent) {
15960
16067
  return out.join("\n");
15961
16068
  }
15962
16069
  function detectWorkflowDrift(args) {
15963
- const projectWorkflowsDir = path29.join(
16070
+ const projectWorkflowsDir = path30.join(
15964
16071
  args.projectDir,
15965
16072
  ".github",
15966
16073
  "workflows"
15967
16074
  );
15968
- const here = path29.dirname(new URL(import.meta.url).pathname);
15969
- const kitWorkflowsDir = args.kitDir ? path29.join(
16075
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16076
+ const kitWorkflowsDir = args.kitDir ? path30.join(
15970
16077
  args.kitDir,
15971
16078
  "templates",
15972
16079
  "project",
@@ -15981,8 +16088,8 @@ function detectWorkflowDrift(args) {
15981
16088
  const files = [];
15982
16089
  for (const name of templateFiles) {
15983
16090
  seen.add(name);
15984
- const projectPath2 = path29.join(projectWorkflowsDir, name);
15985
- const templatePath = path29.join(kitWorkflowsDir, name);
16091
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16092
+ const templatePath = path30.join(kitWorkflowsDir, name);
15986
16093
  if (!fs29.existsSync(projectPath2)) {
15987
16094
  files.push({ name, status: "missing" });
15988
16095
  continue;
@@ -16019,10 +16126,10 @@ function detectWorkflowDrift(args) {
16019
16126
  function readKitVersion(kitWorkflowsDir) {
16020
16127
  let dir = kitWorkflowsDir;
16021
16128
  for (let i = 0; i < 5; i++) {
16022
- dir = path29.dirname(dir);
16129
+ dir = path30.dirname(dir);
16023
16130
  }
16024
16131
  try {
16025
- const raw = fs29.readFileSync(path29.join(dir, "package.json"), "utf-8");
16132
+ const raw = fs29.readFileSync(path30.join(dir, "package.json"), "utf-8");
16026
16133
  const pkg = JSON.parse(raw);
16027
16134
  return typeof pkg.version === "string" ? pkg.version : "unknown";
16028
16135
  } catch {
@@ -16039,7 +16146,7 @@ var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
16039
16146
  function findKitCommandsDir(start) {
16040
16147
  let dir = start;
16041
16148
  for (let i = 0; i < 6; i++) {
16042
- const candidate = path29.join(
16149
+ const candidate = path30.join(
16043
16150
  dir,
16044
16151
  "templates",
16045
16152
  "project",
@@ -16048,7 +16155,7 @@ function findKitCommandsDir(start) {
16048
16155
  "commands"
16049
16156
  );
16050
16157
  if (fs29.existsSync(candidate)) return candidate;
16051
- const parent = path29.dirname(dir);
16158
+ const parent = path30.dirname(dir);
16052
16159
  if (parent === dir) break;
16053
16160
  dir = parent;
16054
16161
  }
@@ -16061,9 +16168,9 @@ function parsePinnedVersion(content) {
16061
16168
  return m ? m[1] : void 0;
16062
16169
  }
16063
16170
  function detectCommandDrift(args) {
16064
- const projectCommandsDir = path29.join(args.projectDir, ".claude", "commands");
16065
- const here = path29.dirname(new URL(import.meta.url).pathname);
16066
- const kitCommandsDir = args.kitDir ? path29.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
16171
+ const projectCommandsDir = path30.join(args.projectDir, ".claude", "commands");
16172
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16173
+ const kitCommandsDir = args.kitDir ? path30.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
16067
16174
  const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
16068
16175
  const templateFiles = fs29.existsSync(kitCommandsDir) ? fs29.readdirSync(kitCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
16069
16176
  const projectFiles = fs29.existsSync(projectCommandsDir) ? fs29.readdirSync(projectCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
@@ -16071,8 +16178,8 @@ function detectCommandDrift(args) {
16071
16178
  const files = [];
16072
16179
  for (const name of templateFiles) {
16073
16180
  seen.add(name);
16074
- const projectPath2 = path29.join(projectCommandsDir, name);
16075
- const templatePath = path29.join(kitCommandsDir, name);
16181
+ const projectPath2 = path30.join(projectCommandsDir, name);
16182
+ const templatePath = path30.join(kitCommandsDir, name);
16076
16183
  const templateRaw = fs29.readFileSync(templatePath, "utf8");
16077
16184
  if (!fs29.existsSync(projectPath2)) {
16078
16185
  files.push({ name, status: "missing", kit_version: kitVersion });
@@ -16116,10 +16223,10 @@ function detectCommandDrift(args) {
16116
16223
  function readKitVersionFromCommandsDir(kitCommandsDir) {
16117
16224
  let dir = kitCommandsDir;
16118
16225
  for (let i = 0; i < 5; i++) {
16119
- dir = path29.dirname(dir);
16226
+ dir = path30.dirname(dir);
16120
16227
  }
16121
16228
  try {
16122
- const raw = fs29.readFileSync(path29.join(dir, "package.json"), "utf-8");
16229
+ const raw = fs29.readFileSync(path30.join(dir, "package.json"), "utf-8");
16123
16230
  const pkg = JSON.parse(raw);
16124
16231
  return typeof pkg.version === "string" ? pkg.version : "unknown";
16125
16232
  } catch {
@@ -16136,13 +16243,13 @@ function detectScaffoldedDrift(args) {
16136
16243
  };
16137
16244
  }
16138
16245
  function updateWorkflows(args) {
16139
- const projectWorkflowsDir = path29.join(
16246
+ const projectWorkflowsDir = path30.join(
16140
16247
  args.projectDir,
16141
16248
  ".github",
16142
16249
  "workflows"
16143
16250
  );
16144
- const here = path29.dirname(new URL(import.meta.url).pathname);
16145
- const kitWorkflowsDir = args.kitDir ? path29.join(
16251
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16252
+ const kitWorkflowsDir = args.kitDir ? path30.join(
16146
16253
  args.kitDir,
16147
16254
  "templates",
16148
16255
  "project",
@@ -16163,8 +16270,8 @@ function updateWorkflows(args) {
16163
16270
  const files = [];
16164
16271
  for (const name of templateFiles) {
16165
16272
  seen.add(name);
16166
- const projectPath2 = path29.join(projectWorkflowsDir, name);
16167
- const templatePath = path29.join(kitWorkflowsDir, name);
16273
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16274
+ const templatePath = path30.join(kitWorkflowsDir, name);
16168
16275
  const templateRaw = fs29.readFileSync(templatePath, "utf-8");
16169
16276
  const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
16170
16277
  const existed = fs29.existsSync(projectPath2);
@@ -16185,7 +16292,7 @@ function updateWorkflows(args) {
16185
16292
  if (pruneExtras) {
16186
16293
  for (const name of projectFiles) {
16187
16294
  if (seen.has(name)) continue;
16188
- const projectPath2 = path29.join(projectWorkflowsDir, name);
16295
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16189
16296
  if (!dryRun) {
16190
16297
  fs29.unlinkSync(projectPath2);
16191
16298
  }
@@ -16372,6 +16479,15 @@ async function mergeFeature(args) {
16372
16479
  );
16373
16480
  }
16374
16481
  }
16482
+ {
16483
+ const ensure = args.ensureCiFresh ?? ((repo) => ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo: repo }));
16484
+ try {
16485
+ const r = await ensure(ownerRepo);
16486
+ if (r.action !== "ok" && r.action !== "skipped") preflightNotes.push(`CI-auth preflight: ${r.reason}`);
16487
+ } catch (err) {
16488
+ 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.`);
16489
+ }
16490
+ }
16375
16491
  {
16376
16492
  const fetchState = args.fetchPrState ?? ((o, h) => getPullRequest(o, h));
16377
16493
  const prState = await fetchState(ownerRepo, current.branch).catch(() => void 0);
@@ -16777,11 +16893,11 @@ function parentForTopology(t, defaultLeaf) {
16777
16893
  // scripts/lakebase/scm-doctor.ts
16778
16894
  init_esm_shims();
16779
16895
  import * as fs30 from "fs";
16780
- import * as path30 from "path";
16896
+ import * as path31 from "path";
16781
16897
  var FEATURE_PREFIX = "feature/";
16782
16898
  var TIER_LEAFS2 = DEFAULT_PROTECTED_TIER_NAMES;
16783
16899
  function readEnv(projectDir) {
16784
- const envPath = path30.join(projectDir, ".env");
16900
+ const envPath = path31.join(projectDir, ".env");
16785
16901
  const out = /* @__PURE__ */ new Map();
16786
16902
  if (!fs30.existsSync(envPath)) return out;
16787
16903
  const lines = fs30.readFileSync(envPath, "utf8").split("\n");
@@ -16839,7 +16955,7 @@ async function runDoctor(args, deps = {}) {
16839
16955
  }
16840
16956
  for (const wf of ["pr.yml", "merge.yml"]) {
16841
16957
  try {
16842
- const p = path30.join(projectDir, ".github", "workflows", wf);
16958
+ const p = path31.join(projectDir, ".github", "workflows", wf);
16843
16959
  if (!fs30.existsSync(p)) continue;
16844
16960
  const body = fs30.readFileSync(p, "utf8");
16845
16961
  if (/lakebase-scm-utils#v\d/.test(body)) {
@@ -17056,7 +17172,7 @@ async function fixFinding(args) {
17056
17172
  );
17057
17173
  }
17058
17174
  const sanitized = sanitizeBranchName(branch);
17059
- const envFile = path30.join(args.projectDir, ".env");
17175
+ const envFile = path31.join(args.projectDir, ".env");
17060
17176
  updateEnvConnection({
17061
17177
  envPath: envFile,
17062
17178
  projectId: readEnvVar(envFile, "LAKEBASE_PROJECT_ID") ?? "",
@@ -17159,10 +17275,10 @@ function shellEscape3(s) {
17159
17275
  // scripts/lakebase/doctor.ts
17160
17276
  init_esm_shims();
17161
17277
  import * as fs31 from "fs";
17162
- import * as path31 from "path";
17278
+ import * as path32 from "path";
17163
17279
  import * as cp6 from "child_process";
17164
17280
  function readEnvFile(projectDir) {
17165
- const envPath = path31.join(projectDir, ".env");
17281
+ const envPath = path32.join(projectDir, ".env");
17166
17282
  if (!fs31.existsSync(envPath)) return {};
17167
17283
  const out = {};
17168
17284
  for (const line of fs31.readFileSync(envPath, "utf8").split("\n")) {
@@ -17420,7 +17536,7 @@ function checkEnv(projectDir) {
17420
17536
  name: "env-file",
17421
17537
  status: "warn",
17422
17538
  message: ".env not found",
17423
- detail: { projectDir, envPath: path31.join(projectDir, ".env") },
17539
+ detail: { projectDir, envPath: path32.join(projectDir, ".env") },
17424
17540
  hint: "Run `lakebase-branch sync-env`, or `git checkout <branch>` so the post-checkout hook writes .env (or copy .env.example). The kit stores connection METADATA only , no DB token (the app mints a short-lived credential at runtime)."
17425
17541
  };
17426
17542
  }
@@ -17906,6 +18022,7 @@ export {
17906
18022
  deleteBranch,
17907
18023
  deleteLakebaseProject,
17908
18024
  deletePairedBranch,
18025
+ deleteProjectArgs,
17909
18026
  deployClaudeAgents,
17910
18027
  deployClaudeCommands,
17911
18028
  deployClaudeSettings,