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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) 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 +2177 -2052
  4. package/dist/scripts/index.d.cts +2 -1
  5. package/dist/scripts/index.d.ts +2 -1
  6. package/dist/scripts/index.js +253 -134
  7. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
  8. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
  9. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
  10. package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
  11. package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
  12. package/dist/scripts/lakebase/detect-language.cli.js +2 -2
  13. package/dist/scripts/lakebase/doctor.cli.cjs +2 -2
  14. package/dist/scripts/lakebase/doctor.cli.js +2 -2
  15. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  16. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  17. package/dist/scripts/lakebase/index.cjs +2163 -2050
  18. package/dist/scripts/lakebase/index.d.cts +8 -0
  19. package/dist/scripts/lakebase/index.d.ts +8 -0
  20. package/dist/scripts/lakebase/index.js +243 -130
  21. package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
  22. package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
  23. package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
  24. package/dist/scripts/lakebase/new-migration.cli.js +2 -2
  25. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  26. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  27. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
  28. package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
  29. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
  30. package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
  31. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  32. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  33. package/dist/scripts/lakebase/scm-merge.cli.cjs +2216 -1994
  34. package/dist/scripts/lakebase/scm-merge.cli.js +296 -74
  35. package/dist/scripts/lakebase/scm-prepare-pr.cli.cjs +479 -86
  36. package/dist/scripts/lakebase/scm-prepare-pr.cli.js +479 -86
  37. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  38. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  39. package/dist/scripts/lakebase/sync-ci-secrets.cli.cjs +56 -30
  40. package/dist/scripts/lakebase/sync-ci-secrets.cli.js +56 -30
  41. package/dist/scripts/util/index.cjs +142 -25
  42. package/dist/scripts/util/index.d.cts +2 -27
  43. package/dist/scripts/util/index.d.ts +2 -27
  44. package/dist/scripts/util/index.js +136 -25
  45. package/package.json +1 -1
  46. package/scripts/lakebase/create-project.ts +2 -2
  47. package/scripts/lakebase/scm-merge.ts +21 -0
  48. package/scripts/lakebase/scm-prepare-pr.ts +10 -1
  49. package/scripts/lakebase/sync-ci-secrets.cli.ts +2 -2
  50. package/scripts/util/ci-secrets.ts +212 -26
  51. package/templates/project/common/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);
@@ -2518,8 +2518,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
2518
2518
  var cached;
2519
2519
  function substrateSelfVersion() {
2520
2520
  if (cached !== void 0) return cached;
2521
- if ("0.2.48".length > 0) {
2522
- cached = "0.2.48";
2521
+ if ("0.2.49".length > 0) {
2522
+ cached = "0.2.49";
2523
2523
  return cached;
2524
2524
  }
2525
2525
  cached = "unknown";
@@ -5059,7 +5059,7 @@ paginateRest.VERSION = VERSION5;
5059
5059
 
5060
5060
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
5061
5061
  init_esm_shims();
5062
- var generateMessage = (path32, cursorValue) => `The cursor at "${path32.join(
5062
+ var generateMessage = (path33, cursorValue) => `The cursor at "${path33.join(
5063
5063
  ","
5064
5064
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
5065
5065
  var MissingCursorChange = class extends Error {
@@ -5100,9 +5100,9 @@ function findPaginatedResourcePath(responseData) {
5100
5100
  }
5101
5101
  return paginatedResourcePath;
5102
5102
  }
5103
- var deepFindPathToProperty = (object, searchProp, path32 = []) => {
5103
+ var deepFindPathToProperty = (object, searchProp, path33 = []) => {
5104
5104
  for (const key of Object.keys(object)) {
5105
- const currentPath = [...path32, key];
5105
+ const currentPath = [...path33, key];
5106
5106
  const currentValue = object[key];
5107
5107
  if (isObject(currentValue)) {
5108
5108
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -5120,12 +5120,12 @@ var deepFindPathToProperty = (object, searchProp, path32 = []) => {
5120
5120
  }
5121
5121
  return [];
5122
5122
  };
5123
- var get = (object, path32) => {
5124
- return path32.reduce((current, nextProperty) => current[nextProperty], object);
5123
+ var get = (object, path33) => {
5124
+ return path33.reduce((current, nextProperty) => current[nextProperty], object);
5125
5125
  };
5126
- var set = (object, path32, mutator) => {
5127
- const lastProperty = path32[path32.length - 1];
5128
- const parentPath = [...path32].slice(0, -1);
5126
+ var set = (object, path33, mutator) => {
5127
+ const lastProperty = path33[path33.length - 1];
5128
+ const parentPath = [...path33].slice(0, -1);
5129
5129
  const parent = get(object, parentPath);
5130
5130
  if (typeof mutator === "function") {
5131
5131
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -5177,22 +5177,22 @@ var mergeResponses = (response1, response2) => {
5177
5177
  if (Object.keys(response1).length === 0) {
5178
5178
  return Object.assign(response1, response2);
5179
5179
  }
5180
- const path32 = findPaginatedResourcePath(response1);
5181
- const nodesPath = [...path32, "nodes"];
5180
+ const path33 = findPaginatedResourcePath(response1);
5181
+ const nodesPath = [...path33, "nodes"];
5182
5182
  const newNodes = get(response2, nodesPath);
5183
5183
  if (newNodes) {
5184
5184
  set(response1, nodesPath, (values) => {
5185
5185
  return [...values, ...newNodes];
5186
5186
  });
5187
5187
  }
5188
- const edgesPath = [...path32, "edges"];
5188
+ const edgesPath = [...path33, "edges"];
5189
5189
  const newEdges = get(response2, edgesPath);
5190
5190
  if (newEdges) {
5191
5191
  set(response1, edgesPath, (values) => {
5192
5192
  return [...values, ...newEdges];
5193
5193
  });
5194
5194
  }
5195
- const pageInfoPath = [...path32, "pageInfo"];
5195
+ const pageInfoPath = [...path33, "pageInfo"];
5196
5196
  set(response1, pageInfoPath, get(response2, pageInfoPath));
5197
5197
  return response1;
5198
5198
  };
@@ -7613,7 +7613,7 @@ var triggers_notification_paths_default = [
7613
7613
  ];
7614
7614
  function routeMatcher(paths) {
7615
7615
  const regexes = paths.map(
7616
- (path32) => path32.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
7616
+ (path33) => path33.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
7617
7617
  );
7618
7618
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
7619
7619
  return new RegExp(regex2, "i");
@@ -10941,16 +10941,16 @@ function isAllSchemas(schema) {
10941
10941
  }
10942
10942
  function buildSchemaQuery(schema) {
10943
10943
  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 ";
10944
+ const join34 = "FROM information_schema.columns c JOIN pg_tables t ON c.table_name = t.tablename AND c.table_schema = t.schemaname ";
10945
10945
  if (isAllSchemas(schema)) {
10946
10946
  return {
10947
- text: `SELECT ${cols} ` + join33 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
10947
+ text: `SELECT ${cols} ` + join34 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
10948
10948
  values: []
10949
10949
  };
10950
10950
  }
10951
10951
  const one = (schema ?? "").trim() || "public";
10952
10952
  return {
10953
- text: `SELECT ${cols} ` + join33 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
10953
+ text: `SELECT ${cols} ` + join34 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
10954
10954
  values: [one]
10955
10955
  };
10956
10956
  }
@@ -11111,7 +11111,7 @@ async function withLakebaseRollback(opts, fn) {
11111
11111
  // scripts/lakebase/create-project.ts
11112
11112
  init_esm_shims();
11113
11113
  import * as fs18 from "fs";
11114
- import * as path17 from "path";
11114
+ import * as path18 from "path";
11115
11115
 
11116
11116
  // scripts/lakebase/project-verify.ts
11117
11117
  init_esm_shims();
@@ -12865,6 +12865,7 @@ async function removeRunner(args) {
12865
12865
 
12866
12866
  // scripts/util/ci-secrets.ts
12867
12867
  init_esm_shims();
12868
+ import * as path16 from "path";
12868
12869
 
12869
12870
  // scripts/github/secrets.ts
12870
12871
  init_esm_shims();
@@ -12974,13 +12975,40 @@ async function getOwnerRepo(cwd) {
12974
12975
 
12975
12976
  // scripts/util/ci-secrets.ts
12976
12977
  var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
12978
+ var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
12979
+ var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
12980
+ function ciTokenComment(ownerRepo) {
12981
+ const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
12982
+ return `GitHub Actions (${repoName})`;
12983
+ }
12977
12984
  async function missingCiSecrets(ownerRepo) {
12978
12985
  const present = new Set(await listSecretNames(ownerRepo));
12979
12986
  return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
12980
12987
  }
12988
+ async function mintCiToken(args) {
12989
+ try {
12990
+ const raw = await runDatabricks(
12991
+ ["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
12992
+ { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
12993
+ );
12994
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
12995
+ const token = parsed.token_value || parsed.token || "";
12996
+ if (token) return token;
12997
+ } catch {
12998
+ }
12999
+ try {
13000
+ const raw = await runDatabricks(["auth", "token", "-o", "json"], {
13001
+ host: args.databricksHost,
13002
+ cwd: args.projectDir,
13003
+ timeout: 3e4
13004
+ });
13005
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
13006
+ return parsed.access_token || "";
13007
+ } catch {
13008
+ return "";
13009
+ }
13010
+ }
12981
13011
  async function syncCiSecrets(args) {
12982
- const lifetime = args.lifetimeSeconds ?? 86400;
12983
- const comment = args.comment ?? "GitHub Actions CI";
12984
13012
  const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
12985
13013
  if (!ownerRepo) {
12986
13014
  throw new Error("Could not resolve GitHub repository from git remote");
@@ -12991,27 +13019,104 @@ async function syncCiSecrets(args) {
12991
13019
  if (!args.lakebaseProjectId) {
12992
13020
  throw new Error("syncCiSecrets: lakebaseProjectId is required");
12993
13021
  }
13022
+ const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
13023
+ const comment = args.comment ?? ciTokenComment(ownerRepo);
12994
13024
  const secrets = {
12995
13025
  DATABRICKS_HOST: args.databricksHost,
12996
13026
  LAKEBASE_PROJECT_ID: args.lakebaseProjectId
12997
13027
  };
13028
+ const token = await mintCiToken({
13029
+ databricksHost: args.databricksHost,
13030
+ projectDir: args.projectDir,
13031
+ comment,
13032
+ lifetimeSeconds: lifetime
13033
+ });
13034
+ if (token) secrets.DATABRICKS_TOKEN = token;
13035
+ await setRepoSecrets(ownerRepo, secrets);
13036
+ }
13037
+ async function ciTokenExpiry(args) {
13038
+ const comment = ciTokenComment(args.ownerRepo);
13039
+ let raw;
12998
13040
  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;
13041
+ raw = await runDatabricks(["tokens", "list", "-o", "json"], {
13042
+ host: args.databricksHost,
13043
+ cwd: args.projectDir,
13044
+ timeout: 3e4
13045
+ });
13006
13046
  } catch {
13047
+ return null;
13048
+ }
13049
+ let infos;
13050
+ try {
13051
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
13052
+ infos = Array.isArray(parsed) ? parsed : [];
13053
+ } catch {
13054
+ return null;
13055
+ }
13056
+ 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);
13057
+ if (expiries.length === 0) return null;
13058
+ return Math.max(...expiries);
13059
+ }
13060
+ async function ensureCiSecretsFresh(args) {
13061
+ const now = args.now ?? Date.now;
13062
+ const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
13063
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
13064
+ if (!ownerRepo) {
13065
+ throw new Error("Could not resolve GitHub repository from git remote");
13066
+ }
13067
+ const sync = () => syncCiSecrets({
13068
+ projectDir: args.projectDir,
13069
+ databricksHost: args.databricksHost,
13070
+ lakebaseProjectId: args.lakebaseProjectId,
13071
+ ownerRepo
13072
+ });
13073
+ const missing = await missingCiSecrets(ownerRepo);
13074
+ if (missing.length > 0) {
13075
+ await sync();
13076
+ return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
13077
+ }
13078
+ const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
13079
+ if (expiry === null) {
13080
+ await sync();
13081
+ return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
13082
+ }
13083
+ if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
13084
+ await sync();
13085
+ const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
13086
+ return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
13087
+ }
13088
+ return { action: "ok", reason: "CI token is current." };
13089
+ }
13090
+ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
13091
+ const envPath = path16.join(projectDir, ".env");
13092
+ const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
13093
+ const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
13094
+ if (!databricksHost || !lakebaseProjectId) {
13095
+ return {
13096
+ action: "skipped",
13097
+ reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
13098
+ };
13099
+ }
13100
+ try {
13101
+ return await ensureCiSecretsFresh({
13102
+ projectDir,
13103
+ databricksHost,
13104
+ lakebaseProjectId,
13105
+ ownerRepo: opts?.ownerRepo,
13106
+ marginSeconds: opts?.marginSeconds
13107
+ });
13108
+ } catch (err) {
13109
+ return {
13110
+ action: "failed",
13111
+ 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.`
13112
+ };
13007
13113
  }
13008
- await setRepoSecrets(ownerRepo, secrets);
13009
13114
  }
13010
13115
 
13011
13116
  // scripts/lakebase/scm-workflow-state.ts
13012
13117
  init_esm_shims();
13013
13118
  import * as fs17 from "fs";
13014
- import * as path16 from "path";
13119
+ import * as path17 from "path";
13015
13120
  import { execFileSync as execFileSync6 } from "child_process";
13016
13121
  function isGitTracked(projectDir, rel) {
13017
13122
  try {
@@ -13030,7 +13135,7 @@ function ensureWorkflowStateUntracked(projectDir) {
13030
13135
  } catch {
13031
13136
  }
13032
13137
  try {
13033
- const gitignore = path16.join(projectDir, ".gitignore");
13138
+ const gitignore = path17.join(projectDir, ".gitignore");
13034
13139
  const existing = fs17.existsSync(gitignore) ? fs17.readFileSync(gitignore, "utf8") : "";
13035
13140
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
13036
13141
  const sep4 = existing === "" || existing.endsWith("\n") ? "" : "\n";
@@ -13058,7 +13163,7 @@ var STATE_INDEX = SCM_STATES.reduce(
13058
13163
  );
13059
13164
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
13060
13165
  function stateFilePath(projectDir) {
13061
- return path16.join(projectDir, STATE_FILE_REL);
13166
+ return path17.join(projectDir, STATE_FILE_REL);
13062
13167
  }
13063
13168
  function readWorkflowState(projectDir) {
13064
13169
  const p = stateFilePath(projectDir);
@@ -13098,7 +13203,7 @@ function writeWorkflowState(projectDir, state) {
13098
13203
  ${summary}`);
13099
13204
  }
13100
13205
  ensureWorkflowStateUntracked(projectDir);
13101
- const dir = path16.join(projectDir, ".lakebase");
13206
+ const dir = path17.join(projectDir, ".lakebase");
13102
13207
  fs17.mkdirSync(dir, { recursive: true });
13103
13208
  const target = stateFilePath(projectDir);
13104
13209
  const tmp = `${target}.tmp`;
@@ -13329,7 +13434,7 @@ function orderForOutput(state) {
13329
13434
  async function createProject(input, progress) {
13330
13435
  const report = progress ?? (() => {
13331
13436
  });
13332
- const projectDir = path17.join(input.parentDir, input.projectName);
13437
+ const projectDir = path18.join(input.parentDir, input.projectName);
13333
13438
  const lakebaseProjectId = input.projectName;
13334
13439
  const host = input.databricksHost.replace(/\/+$/, "");
13335
13440
  const useGithub = input.createGithubRepo !== false;
@@ -13490,8 +13595,6 @@ Last probe error:
13490
13595
  projectDir,
13491
13596
  databricksHost: host,
13492
13597
  lakebaseProjectId,
13493
- comment: "GitHub Actions CI",
13494
- lifetimeSeconds: 86400,
13495
13598
  ownerRepo: fullRepoName
13496
13599
  });
13497
13600
  const missing = await missingCiSecrets(fullRepoName);
@@ -13558,9 +13661,9 @@ Last probe error:
13558
13661
  const scmRef = envRef || (ver !== "unknown" ? `v${ver}` : "");
13559
13662
  if (scmRef) {
13560
13663
  try {
13561
- const dir = path17.join(projectDir, ".lakebase");
13664
+ const dir = path18.join(projectDir, ".lakebase");
13562
13665
  fs18.mkdirSync(dir, { recursive: true });
13563
- fs18.writeFileSync(path17.join(dir, "scm-utils-ref"), `${scmRef}
13666
+ fs18.writeFileSync(path18.join(dir, "scm-utils-ref"), `${scmRef}
13564
13667
  `, "utf8");
13565
13668
  } catch (err) {
13566
13669
  warnings.push(`Substrate ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
@@ -13571,9 +13674,9 @@ Last probe error:
13571
13674
  const kitRef = process.env.LAKEBASE_KIT_REF?.trim();
13572
13675
  if (kitRef) {
13573
13676
  try {
13574
- const dir = path17.join(projectDir, ".lakebase");
13677
+ const dir = path18.join(projectDir, ".lakebase");
13575
13678
  fs18.mkdirSync(dir, { recursive: true });
13576
- fs18.writeFileSync(path17.join(dir, "kit-ref"), `${kitRef}
13679
+ fs18.writeFileSync(path18.join(dir, "kit-ref"), `${kitRef}
13577
13680
  `, "utf8");
13578
13681
  } catch (err) {
13579
13682
  warnings.push(`Kit ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
@@ -13655,7 +13758,7 @@ Last probe error:
13655
13758
  init_esm_shims();
13656
13759
  import * as cp5 from "child_process";
13657
13760
  import * as fs19 from "fs";
13658
- import * as path18 from "path";
13761
+ import * as path19 from "path";
13659
13762
  async function adoptLakebaseProject(args) {
13660
13763
  const warnings = [];
13661
13764
  const filesWritten = [];
@@ -13664,7 +13767,7 @@ async function adoptLakebaseProject(args) {
13664
13767
  if (!fs19.existsSync(args.projectDir)) {
13665
13768
  throw new Error(`adoptLakebaseProject: project directory does not exist: ${args.projectDir}`);
13666
13769
  }
13667
- if (!fs19.existsSync(path18.join(args.projectDir, ".git"))) {
13770
+ if (!fs19.existsSync(path19.join(args.projectDir, ".git"))) {
13668
13771
  throw new Error(
13669
13772
  `adoptLakebaseProject: ${args.projectDir} is not a git repo. Run \`git init\` first, or pass an existing repo path.`
13670
13773
  );
@@ -13730,7 +13833,7 @@ async function adoptLakebaseProject(args) {
13730
13833
  };
13731
13834
  }
13732
13835
  function assertEnvCompatibility(projectDir, expectedProjectId) {
13733
- const envPath = path18.join(projectDir, ".env");
13836
+ const envPath = path19.join(projectDir, ".env");
13734
13837
  if (!fs19.existsSync(envPath)) return;
13735
13838
  const content = fs19.readFileSync(envPath, "utf8");
13736
13839
  const match = content.match(/^LAKEBASE_PROJECT_ID\s*=\s*(.+?)\s*$/m);
@@ -13746,7 +13849,7 @@ function assertAdoptionPreflight(args) {
13746
13849
  if (!fs19.existsSync(args.projectDir)) {
13747
13850
  throw new Error(`assertAdoptionPreflight: project directory does not exist: ${args.projectDir}`);
13748
13851
  }
13749
- if (!fs19.existsSync(path18.join(args.projectDir, ".git"))) {
13852
+ if (!fs19.existsSync(path19.join(args.projectDir, ".git"))) {
13750
13853
  throw new Error(
13751
13854
  `assertAdoptionPreflight: ${args.projectDir} is not a git repo.`
13752
13855
  );
@@ -13760,7 +13863,7 @@ function _testMakeBrownfieldFixture(opts) {
13760
13863
  cp5.execSync("git init --quiet", { cwd: opts.dir, stdio: "pipe" });
13761
13864
  if (opts.packageJson) {
13762
13865
  fs19.writeFileSync(
13763
- path18.join(opts.dir, "package.json"),
13866
+ path19.join(opts.dir, "package.json"),
13764
13867
  JSON.stringify(opts.packageJson, null, 2) + "\n"
13765
13868
  );
13766
13869
  }
@@ -13769,7 +13872,7 @@ function _testMakeBrownfieldFixture(opts) {
13769
13872
  // scripts/lakebase/infra-runner.ts
13770
13873
  init_esm_shims();
13771
13874
  import * as fs27 from "fs";
13772
- import * as path27 from "path";
13875
+ import * as path28 from "path";
13773
13876
 
13774
13877
  // scripts/lakebase/schema-diff.ts
13775
13878
  init_esm_shims();
@@ -13966,12 +14069,12 @@ function dbcli6(args) {
13966
14069
  // scripts/lakebase/schema-migrate.ts
13967
14070
  init_esm_shims();
13968
14071
  import * as fs26 from "fs";
13969
- import * as path26 from "path";
14072
+ import * as path27 from "path";
13970
14073
 
13971
14074
  // scripts/lakebase/migration-layout.ts
13972
14075
  init_esm_shims();
13973
14076
  import * as fs20 from "fs";
13974
- import * as path19 from "path";
14077
+ import * as path20 from "path";
13975
14078
  var MIGRATION_LANGUAGES = [
13976
14079
  "java",
13977
14080
  "kotlin",
@@ -13987,13 +14090,13 @@ var MIGRATION_DEFAULTS = {
13987
14090
  unknown: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" }
13988
14091
  };
13989
14092
  function detectLanguageAt(dir) {
13990
- if (fs20.existsSync(path19.join(dir, "pom.xml"))) {
13991
- const kotlinDir = path19.join(dir, "src", "main", "kotlin");
14093
+ if (fs20.existsSync(path20.join(dir, "pom.xml"))) {
14094
+ const kotlinDir = path20.join(dir, "src", "main", "kotlin");
13992
14095
  if (fs20.existsSync(kotlinDir)) {
13993
14096
  return "kotlin";
13994
14097
  }
13995
14098
  try {
13996
- const pom = fs20.readFileSync(path19.join(dir, "pom.xml"), "utf-8");
14099
+ const pom = fs20.readFileSync(path20.join(dir, "pom.xml"), "utf-8");
13997
14100
  if (pom.includes("kotlin-maven-plugin")) {
13998
14101
  return "kotlin";
13999
14102
  }
@@ -14001,10 +14104,10 @@ function detectLanguageAt(dir) {
14001
14104
  }
14002
14105
  return "java";
14003
14106
  }
14004
- if (fs20.existsSync(path19.join(dir, "pyproject.toml")) || fs20.existsSync(path19.join(dir, "requirements.txt")) || fs20.existsSync(path19.join(dir, "alembic.ini"))) {
14107
+ if (fs20.existsSync(path20.join(dir, "pyproject.toml")) || fs20.existsSync(path20.join(dir, "requirements.txt")) || fs20.existsSync(path20.join(dir, "alembic.ini"))) {
14005
14108
  return "python";
14006
14109
  }
14007
- if (fs20.existsSync(path19.join(dir, "package.json"))) {
14110
+ if (fs20.existsSync(path20.join(dir, "package.json"))) {
14008
14111
  return "nodejs";
14009
14112
  }
14010
14113
  return "unknown";
@@ -14025,14 +14128,14 @@ function resolveMigrationLanguage(projectDir, configuredMigrationPath, override)
14025
14128
  if (!rel) {
14026
14129
  return "unknown";
14027
14130
  }
14028
- const rootResolved = path19.resolve(projectDir);
14029
- let dir = path19.resolve(projectDir, rel);
14030
- while (dir === rootResolved || dir.startsWith(rootResolved + path19.sep)) {
14131
+ const rootResolved = path20.resolve(projectDir);
14132
+ let dir = path20.resolve(projectDir, rel);
14133
+ while (dir === rootResolved || dir.startsWith(rootResolved + path20.sep)) {
14031
14134
  const lang = detectLanguageAt(dir);
14032
14135
  if (lang !== "unknown") {
14033
14136
  return lang;
14034
14137
  }
14035
- const parent = path19.dirname(dir);
14138
+ const parent = path20.dirname(dir);
14036
14139
  if (parent === dir) {
14037
14140
  break;
14038
14141
  }
@@ -14066,17 +14169,17 @@ function resolveMigrationLayout(args) {
14066
14169
  // scripts/lakebase/adapters/alembic-adapter.ts
14067
14170
  init_esm_shims();
14068
14171
  import * as fs22 from "fs";
14069
- import * as path21 from "path";
14172
+ import * as path22 from "path";
14070
14173
 
14071
14174
  // scripts/lakebase/schema-migrate-runners/alembic.ts
14072
14175
  init_esm_shims();
14073
14176
  import { spawn as spawn5 } from "child_process";
14074
14177
  import * as fs21 from "fs";
14075
- import * as path20 from "path";
14178
+ import * as path21 from "path";
14076
14179
  function resolveAlembicBin(projectDir) {
14077
14180
  const candidates = [
14078
- path20.join(projectDir, ".venv", "bin", "alembic"),
14079
- path20.join(projectDir, "venv", "bin", "alembic")
14181
+ path21.join(projectDir, ".venv", "bin", "alembic"),
14182
+ path21.join(projectDir, "venv", "bin", "alembic")
14080
14183
  ];
14081
14184
  for (const candidate of candidates) {
14082
14185
  try {
@@ -14090,7 +14193,7 @@ function spawnAlembic(projectDir, args, dsn) {
14090
14193
  return new Promise((resolve2, reject) => {
14091
14194
  const bin = resolveAlembicBin(projectDir);
14092
14195
  const env = { ...process.env };
14093
- env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path20.delimiter);
14196
+ env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path21.delimiter);
14094
14197
  if (dsn) env.DATABASE_URL = dsn;
14095
14198
  const child = spawn5(bin, args, {
14096
14199
  cwd: projectDir,
@@ -14138,10 +14241,10 @@ async function createAlembicRevision(opts) {
14138
14241
  const m = stdout.match(/Generating\s+(\S+\.py)/);
14139
14242
  if (m) return m[1].trim();
14140
14243
  for (const rel of ["migrations/versions", "alembic/versions"]) {
14141
- const dir = path20.join(opts.projectDir, rel);
14244
+ const dir = path21.join(opts.projectDir, rel);
14142
14245
  if (!fs21.existsSync(dir)) continue;
14143
14246
  const hit = fs21.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
14144
- if (hit) return path20.join(dir, hit);
14247
+ if (hit) return path21.join(dir, hit);
14145
14248
  }
14146
14249
  throw new SchemaMigrationError(
14147
14250
  `alembic revision succeeded but the created file could not be located.
@@ -14276,8 +14379,8 @@ async function buildDsn2(args) {
14276
14379
  }
14277
14380
  function findVersionsDir(projectDir) {
14278
14381
  const candidates = [
14279
- path21.join(projectDir, "migrations", "versions"),
14280
- path21.join(projectDir, "alembic", "versions")
14382
+ path22.join(projectDir, "migrations", "versions"),
14383
+ path22.join(projectDir, "alembic", "versions")
14281
14384
  ];
14282
14385
  return candidates.find((p) => fs22.existsSync(p));
14283
14386
  }
@@ -14309,9 +14412,9 @@ var AlembicAdapter = {
14309
14412
  * here. Callers can still force-select via project.yaml#migration_tool.
14310
14413
  */
14311
14414
  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;
14415
+ if (fs22.existsSync(path22.join(projectDir, "alembic.ini"))) return true;
14416
+ if (fs22.existsSync(path22.join(projectDir, "migrations", "env.py"))) return true;
14417
+ if (fs22.existsSync(path22.join(projectDir, "alembic", "env.py"))) return true;
14315
14418
  return false;
14316
14419
  },
14317
14420
  async apply(args) {
@@ -14417,7 +14520,7 @@ var AlembicAdapter = {
14417
14520
  autogenerate: !!args.autogenerate,
14418
14521
  dsn
14419
14522
  });
14420
- return { status: "ok", version: revId, filename: path21.basename(created), path: created };
14523
+ return { status: "ok", version: revId, filename: path22.basename(created), path: created };
14421
14524
  } catch (err) {
14422
14525
  return {
14423
14526
  status: "error",
@@ -14434,7 +14537,7 @@ var AlembicAdapter = {
14434
14537
  if (heads.length <= 1) return { status: "noop", headsBefore: heads };
14435
14538
  if (args.dryRun) return { status: "ok", headsBefore: heads };
14436
14539
  const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
14437
- const mergeRevision = path21.basename(created).replace(/\.py$/, "").split("_")[0];
14540
+ const mergeRevision = path22.basename(created).replace(/\.py$/, "").split("_")[0];
14438
14541
  return { status: "ok", headsBefore: heads, mergeRevision, path: created };
14439
14542
  } catch (err) {
14440
14543
  return {
@@ -14450,12 +14553,12 @@ registerSchemaMigrationAdapter(AlembicAdapter);
14450
14553
  // scripts/lakebase/adapters/flyway-adapter.ts
14451
14554
  init_esm_shims();
14452
14555
  import * as fs23 from "fs";
14453
- import * as path23 from "path";
14556
+ import * as path24 from "path";
14454
14557
 
14455
14558
  // scripts/lakebase/schema-migrate-runners/flyway.ts
14456
14559
  init_esm_shims();
14457
14560
  import { spawn as spawn6 } from "child_process";
14458
- import * as path22 from "path";
14561
+ import * as path23 from "path";
14459
14562
  function dsnToFlywayEnv(dsn) {
14460
14563
  const u = new URL(dsn);
14461
14564
  const user = decodeURIComponent(u.username);
@@ -14465,7 +14568,7 @@ function dsnToFlywayEnv(dsn) {
14465
14568
  return { url, user, password };
14466
14569
  }
14467
14570
  function migrationsLocation(projectDir) {
14468
- return `filesystem:${path22.join(projectDir, "src", "main", "resources", "db", "migration")}`;
14571
+ return `filesystem:${path23.join(projectDir, "src", "main", "resources", "db", "migration")}`;
14469
14572
  }
14470
14573
  function runFlyway(ctx, args) {
14471
14574
  const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
@@ -14566,7 +14669,7 @@ async function statusFlyway(ctx) {
14566
14669
  if (state === "SUCCESS" || state === "BASELINE") {
14567
14670
  current = m.version;
14568
14671
  } else if (state === "PENDING") {
14569
- const filename = m.filepath ? path22.basename(m.filepath) : `V${m.version}__migration.sql`;
14672
+ const filename = m.filepath ? path23.basename(m.filepath) : `V${m.version}__migration.sql`;
14570
14673
  pending.push({
14571
14674
  version: m.version,
14572
14675
  filename,
@@ -14589,7 +14692,7 @@ async function buildDsn3(args) {
14589
14692
  return result.url;
14590
14693
  }
14591
14694
  function listFlywayFiles(projectDir) {
14592
- const dir = path23.join(projectDir, "src", "main", "resources", "db", "migration");
14695
+ const dir = path24.join(projectDir, "src", "main", "resources", "db", "migration");
14593
14696
  if (!fs23.existsSync(dir)) return [];
14594
14697
  const files = fs23.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
14595
14698
  return files.map((filename) => {
@@ -14614,7 +14717,7 @@ var FlywayAdapter = {
14614
14717
  id: "flyway",
14615
14718
  languages: ["java", "kotlin"],
14616
14719
  detect(projectDir) {
14617
- return fs23.existsSync(path23.join(projectDir, "pom.xml"));
14720
+ return fs23.existsSync(path24.join(projectDir, "pom.xml"));
14618
14721
  },
14619
14722
  async apply(args) {
14620
14723
  const dsn = await buildDsn3(args);
@@ -14672,12 +14775,12 @@ var FlywayAdapter = {
14672
14775
  // optional-protocol shape makes this additive.
14673
14776
  async newMigration(args) {
14674
14777
  try {
14675
- const dir = path23.join(args.projectDir, "src", "main", "resources", "db", "migration");
14778
+ const dir = path24.join(args.projectDir, "src", "main", "resources", "db", "migration");
14676
14779
  fs23.mkdirSync(dir, { recursive: true });
14677
14780
  const version = migrationTimestamp();
14678
14781
  const slug = migrationSlug2(args.slug);
14679
14782
  const filename = `V${version}__${slug}.sql`;
14680
- const full = path23.join(dir, filename);
14783
+ const full = path24.join(dir, filename);
14681
14784
  if (fs23.existsSync(full)) throw new Error(`${filename} already exists`);
14682
14785
  fs23.writeFileSync(
14683
14786
  full,
@@ -14703,17 +14806,17 @@ registerSchemaMigrationAdapter(FlywayAdapter);
14703
14806
  // scripts/lakebase/adapters/knex-adapter.ts
14704
14807
  init_esm_shims();
14705
14808
  import * as fs25 from "fs";
14706
- import * as path25 from "path";
14809
+ import * as path26 from "path";
14707
14810
 
14708
14811
  // scripts/lakebase/schema-migrate-runners/knex.ts
14709
14812
  init_esm_shims();
14710
14813
  import { spawn as spawn7 } from "child_process";
14711
14814
  import * as fs24 from "fs";
14712
- import * as path24 from "path";
14815
+ import * as path25 from "path";
14713
14816
  var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
14714
14817
  function findKnexfile(projectDir) {
14715
14818
  for (const name of KNEXFILE_VARIANTS) {
14716
- const p = path24.join(projectDir, name);
14819
+ const p = path25.join(projectDir, name);
14717
14820
  if (fs24.existsSync(p)) return p;
14718
14821
  }
14719
14822
  return void 0;
@@ -14866,7 +14969,7 @@ async function buildDsn4(args) {
14866
14969
  }
14867
14970
  var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
14868
14971
  function listKnexFiles(projectDir) {
14869
- const dir = path25.join(projectDir, "migrations");
14972
+ const dir = path26.join(projectDir, "migrations");
14870
14973
  if (!fs25.existsSync(dir)) return [];
14871
14974
  const files = fs25.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
14872
14975
  return files.map((filename) => {
@@ -14888,7 +14991,7 @@ var KnexAdapter = {
14888
14991
  * project.yaml#migration_tool.
14889
14992
  */
14890
14993
  detect(projectDir) {
14891
- return KNEXFILE_VARIANTS2.some((name) => fs25.existsSync(path25.join(projectDir, name)));
14994
+ return KNEXFILE_VARIANTS2.some((name) => fs25.existsSync(path26.join(projectDir, name)));
14892
14995
  },
14893
14996
  async apply(args) {
14894
14997
  const dsn = await buildDsn4(args);
@@ -14961,9 +15064,9 @@ var KnexAdapter = {
14961
15064
  async newMigration(args) {
14962
15065
  try {
14963
15066
  const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
14964
- const stem = path25.basename(created).replace(/\.(js|ts)$/, "");
15067
+ const stem = path26.basename(created).replace(/\.(js|ts)$/, "");
14965
15068
  const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
14966
- return { status: "ok", version, filename: path25.basename(created), path: created };
15069
+ return { status: "ok", version, filename: path26.basename(created), path: created };
14967
15070
  } catch (err) {
14968
15071
  return {
14969
15072
  status: "error",
@@ -15020,7 +15123,7 @@ function listSchemaMigrations(args = {}) {
15020
15123
  }
15021
15124
  }
15022
15125
  function listFlywayMigrations(projectDir) {
15023
- const dir = path26.join(projectDir, "src", "main", "resources", "db", "migration");
15126
+ const dir = path27.join(projectDir, "src", "main", "resources", "db", "migration");
15024
15127
  if (!fs26.existsSync(dir)) return [];
15025
15128
  const files = fs26.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
15026
15129
  return files.map((filename) => {
@@ -15032,8 +15135,8 @@ function listFlywayMigrations(projectDir) {
15032
15135
  }
15033
15136
  function listAlembicMigrations(projectDir) {
15034
15137
  const candidates = [
15035
- path26.join(projectDir, "migrations", "versions"),
15036
- path26.join(projectDir, "alembic", "versions")
15138
+ path27.join(projectDir, "migrations", "versions"),
15139
+ path27.join(projectDir, "alembic", "versions")
15037
15140
  ];
15038
15141
  const dir = candidates.find((p) => fs26.existsSync(p));
15039
15142
  if (!dir) return [];
@@ -15047,7 +15150,7 @@ function listAlembicMigrations(projectDir) {
15047
15150
  }).sort((a, b) => a.filename.localeCompare(b.filename));
15048
15151
  }
15049
15152
  function listKnexMigrations(projectDir) {
15050
- const dir = path26.join(projectDir, "migrations");
15153
+ const dir = path27.join(projectDir, "migrations");
15051
15154
  if (!fs26.existsSync(dir)) return [];
15052
15155
  const files = fs26.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
15053
15156
  return files.map((filename) => {
@@ -15225,7 +15328,7 @@ async function runInfraSuite(args) {
15225
15328
  duration_ms: Date.now() - start
15226
15329
  };
15227
15330
  if (args.junitOutput) {
15228
- fs27.mkdirSync(path27.dirname(args.junitOutput), { recursive: true });
15331
+ fs27.mkdirSync(path28.dirname(args.junitOutput), { recursive: true });
15229
15332
  fs27.writeFileSync(args.junitOutput, formatJUnit(result), "utf8");
15230
15333
  }
15231
15334
  return result;
@@ -15273,7 +15376,7 @@ function escapeXml(s) {
15273
15376
  // scripts/lakebase/scm-claim-feature.ts
15274
15377
  init_esm_shims();
15275
15378
  import * as fs28 from "fs";
15276
- import * as path28 from "path";
15379
+ import * as path29 from "path";
15277
15380
  var ScmClaimError = class extends Error {
15278
15381
  constructor(message, code) {
15279
15382
  super(message);
@@ -15330,7 +15433,7 @@ async function claimFeatureBranch(args) {
15330
15433
  const current = readWorkflowState(args.projectDir);
15331
15434
  if (!current) {
15332
15435
  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.`,
15436
+ `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
15437
  "no-state-file"
15335
15438
  );
15336
15439
  }
@@ -15435,7 +15538,7 @@ function alreadyClaimedSentinel(state) {
15435
15538
  }
15436
15539
  function workflowStateFileExists(projectDir) {
15437
15540
  return fs28.existsSync(
15438
- path28.join(projectDir, ".lakebase/workflow-state.json")
15541
+ path29.join(projectDir, ".lakebase/workflow-state.json")
15439
15542
  );
15440
15543
  }
15441
15544
 
@@ -15699,6 +15802,7 @@ async function preparePr(args) {
15699
15802
  "no-github-remote"
15700
15803
  );
15701
15804
  }
15805
+ const ciFreshness = await ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo });
15702
15806
  const now = (args.now ?? (() => /* @__PURE__ */ new Date()))();
15703
15807
  let prUrl = args.prUrlOverride ?? "";
15704
15808
  let prCreated = false;
@@ -15743,7 +15847,7 @@ async function preparePr(args) {
15743
15847
  pushed_at: now.toISOString()
15744
15848
  };
15745
15849
  writeWorkflowState(args.projectDir, next);
15746
- return { state: next, prUrl, prCreated };
15850
+ return { state: next, prUrl, prCreated, ciFreshness };
15747
15851
  }
15748
15852
  async function ensureAheadOfParent(cwd, branch, parent) {
15749
15853
  try {
@@ -15923,11 +16027,11 @@ async function pushCurrentBranchForPr(args) {
15923
16027
  // scripts/lakebase/workflow-drift.ts
15924
16028
  init_esm_shims();
15925
16029
  import * as fs29 from "fs";
15926
- import * as path29 from "path";
16030
+ import * as path30 from "path";
15927
16031
  function findKitTemplatesDir(start) {
15928
16032
  let dir = start;
15929
16033
  for (let i = 0; i < 6; i++) {
15930
- const candidate = path29.join(
16034
+ const candidate = path30.join(
15931
16035
  dir,
15932
16036
  "templates",
15933
16037
  "project",
@@ -15936,7 +16040,7 @@ function findKitTemplatesDir(start) {
15936
16040
  "workflows"
15937
16041
  );
15938
16042
  if (fs29.existsSync(candidate)) return candidate;
15939
- const parent = path29.dirname(dir);
16043
+ const parent = path30.dirname(dir);
15940
16044
  if (parent === dir) break;
15941
16045
  dir = parent;
15942
16046
  }
@@ -15960,13 +16064,13 @@ function unifiedDiff(name, projectContent, templateContent) {
15960
16064
  return out.join("\n");
15961
16065
  }
15962
16066
  function detectWorkflowDrift(args) {
15963
- const projectWorkflowsDir = path29.join(
16067
+ const projectWorkflowsDir = path30.join(
15964
16068
  args.projectDir,
15965
16069
  ".github",
15966
16070
  "workflows"
15967
16071
  );
15968
- const here = path29.dirname(new URL(import.meta.url).pathname);
15969
- const kitWorkflowsDir = args.kitDir ? path29.join(
16072
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16073
+ const kitWorkflowsDir = args.kitDir ? path30.join(
15970
16074
  args.kitDir,
15971
16075
  "templates",
15972
16076
  "project",
@@ -15981,8 +16085,8 @@ function detectWorkflowDrift(args) {
15981
16085
  const files = [];
15982
16086
  for (const name of templateFiles) {
15983
16087
  seen.add(name);
15984
- const projectPath2 = path29.join(projectWorkflowsDir, name);
15985
- const templatePath = path29.join(kitWorkflowsDir, name);
16088
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16089
+ const templatePath = path30.join(kitWorkflowsDir, name);
15986
16090
  if (!fs29.existsSync(projectPath2)) {
15987
16091
  files.push({ name, status: "missing" });
15988
16092
  continue;
@@ -16019,10 +16123,10 @@ function detectWorkflowDrift(args) {
16019
16123
  function readKitVersion(kitWorkflowsDir) {
16020
16124
  let dir = kitWorkflowsDir;
16021
16125
  for (let i = 0; i < 5; i++) {
16022
- dir = path29.dirname(dir);
16126
+ dir = path30.dirname(dir);
16023
16127
  }
16024
16128
  try {
16025
- const raw = fs29.readFileSync(path29.join(dir, "package.json"), "utf-8");
16129
+ const raw = fs29.readFileSync(path30.join(dir, "package.json"), "utf-8");
16026
16130
  const pkg = JSON.parse(raw);
16027
16131
  return typeof pkg.version === "string" ? pkg.version : "unknown";
16028
16132
  } catch {
@@ -16039,7 +16143,7 @@ var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
16039
16143
  function findKitCommandsDir(start) {
16040
16144
  let dir = start;
16041
16145
  for (let i = 0; i < 6; i++) {
16042
- const candidate = path29.join(
16146
+ const candidate = path30.join(
16043
16147
  dir,
16044
16148
  "templates",
16045
16149
  "project",
@@ -16048,7 +16152,7 @@ function findKitCommandsDir(start) {
16048
16152
  "commands"
16049
16153
  );
16050
16154
  if (fs29.existsSync(candidate)) return candidate;
16051
- const parent = path29.dirname(dir);
16155
+ const parent = path30.dirname(dir);
16052
16156
  if (parent === dir) break;
16053
16157
  dir = parent;
16054
16158
  }
@@ -16061,9 +16165,9 @@ function parsePinnedVersion(content) {
16061
16165
  return m ? m[1] : void 0;
16062
16166
  }
16063
16167
  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);
16168
+ const projectCommandsDir = path30.join(args.projectDir, ".claude", "commands");
16169
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16170
+ const kitCommandsDir = args.kitDir ? path30.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
16067
16171
  const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
16068
16172
  const templateFiles = fs29.existsSync(kitCommandsDir) ? fs29.readdirSync(kitCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
16069
16173
  const projectFiles = fs29.existsSync(projectCommandsDir) ? fs29.readdirSync(projectCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
@@ -16071,8 +16175,8 @@ function detectCommandDrift(args) {
16071
16175
  const files = [];
16072
16176
  for (const name of templateFiles) {
16073
16177
  seen.add(name);
16074
- const projectPath2 = path29.join(projectCommandsDir, name);
16075
- const templatePath = path29.join(kitCommandsDir, name);
16178
+ const projectPath2 = path30.join(projectCommandsDir, name);
16179
+ const templatePath = path30.join(kitCommandsDir, name);
16076
16180
  const templateRaw = fs29.readFileSync(templatePath, "utf8");
16077
16181
  if (!fs29.existsSync(projectPath2)) {
16078
16182
  files.push({ name, status: "missing", kit_version: kitVersion });
@@ -16116,10 +16220,10 @@ function detectCommandDrift(args) {
16116
16220
  function readKitVersionFromCommandsDir(kitCommandsDir) {
16117
16221
  let dir = kitCommandsDir;
16118
16222
  for (let i = 0; i < 5; i++) {
16119
- dir = path29.dirname(dir);
16223
+ dir = path30.dirname(dir);
16120
16224
  }
16121
16225
  try {
16122
- const raw = fs29.readFileSync(path29.join(dir, "package.json"), "utf-8");
16226
+ const raw = fs29.readFileSync(path30.join(dir, "package.json"), "utf-8");
16123
16227
  const pkg = JSON.parse(raw);
16124
16228
  return typeof pkg.version === "string" ? pkg.version : "unknown";
16125
16229
  } catch {
@@ -16136,13 +16240,13 @@ function detectScaffoldedDrift(args) {
16136
16240
  };
16137
16241
  }
16138
16242
  function updateWorkflows(args) {
16139
- const projectWorkflowsDir = path29.join(
16243
+ const projectWorkflowsDir = path30.join(
16140
16244
  args.projectDir,
16141
16245
  ".github",
16142
16246
  "workflows"
16143
16247
  );
16144
- const here = path29.dirname(new URL(import.meta.url).pathname);
16145
- const kitWorkflowsDir = args.kitDir ? path29.join(
16248
+ const here = path30.dirname(new URL(import.meta.url).pathname);
16249
+ const kitWorkflowsDir = args.kitDir ? path30.join(
16146
16250
  args.kitDir,
16147
16251
  "templates",
16148
16252
  "project",
@@ -16163,8 +16267,8 @@ function updateWorkflows(args) {
16163
16267
  const files = [];
16164
16268
  for (const name of templateFiles) {
16165
16269
  seen.add(name);
16166
- const projectPath2 = path29.join(projectWorkflowsDir, name);
16167
- const templatePath = path29.join(kitWorkflowsDir, name);
16270
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16271
+ const templatePath = path30.join(kitWorkflowsDir, name);
16168
16272
  const templateRaw = fs29.readFileSync(templatePath, "utf-8");
16169
16273
  const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
16170
16274
  const existed = fs29.existsSync(projectPath2);
@@ -16185,7 +16289,7 @@ function updateWorkflows(args) {
16185
16289
  if (pruneExtras) {
16186
16290
  for (const name of projectFiles) {
16187
16291
  if (seen.has(name)) continue;
16188
- const projectPath2 = path29.join(projectWorkflowsDir, name);
16292
+ const projectPath2 = path30.join(projectWorkflowsDir, name);
16189
16293
  if (!dryRun) {
16190
16294
  fs29.unlinkSync(projectPath2);
16191
16295
  }
@@ -16372,6 +16476,15 @@ async function mergeFeature(args) {
16372
16476
  );
16373
16477
  }
16374
16478
  }
16479
+ {
16480
+ const ensure = args.ensureCiFresh ?? ((repo) => ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo: repo }));
16481
+ try {
16482
+ const r = await ensure(ownerRepo);
16483
+ if (r.action !== "ok" && r.action !== "skipped") preflightNotes.push(`CI-auth preflight: ${r.reason}`);
16484
+ } catch (err) {
16485
+ 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.`);
16486
+ }
16487
+ }
16375
16488
  {
16376
16489
  const fetchState = args.fetchPrState ?? ((o, h) => getPullRequest(o, h));
16377
16490
  const prState = await fetchState(ownerRepo, current.branch).catch(() => void 0);
@@ -16777,11 +16890,11 @@ function parentForTopology(t, defaultLeaf) {
16777
16890
  // scripts/lakebase/scm-doctor.ts
16778
16891
  init_esm_shims();
16779
16892
  import * as fs30 from "fs";
16780
- import * as path30 from "path";
16893
+ import * as path31 from "path";
16781
16894
  var FEATURE_PREFIX = "feature/";
16782
16895
  var TIER_LEAFS2 = DEFAULT_PROTECTED_TIER_NAMES;
16783
16896
  function readEnv(projectDir) {
16784
- const envPath = path30.join(projectDir, ".env");
16897
+ const envPath = path31.join(projectDir, ".env");
16785
16898
  const out = /* @__PURE__ */ new Map();
16786
16899
  if (!fs30.existsSync(envPath)) return out;
16787
16900
  const lines = fs30.readFileSync(envPath, "utf8").split("\n");
@@ -16839,7 +16952,7 @@ async function runDoctor(args, deps = {}) {
16839
16952
  }
16840
16953
  for (const wf of ["pr.yml", "merge.yml"]) {
16841
16954
  try {
16842
- const p = path30.join(projectDir, ".github", "workflows", wf);
16955
+ const p = path31.join(projectDir, ".github", "workflows", wf);
16843
16956
  if (!fs30.existsSync(p)) continue;
16844
16957
  const body = fs30.readFileSync(p, "utf8");
16845
16958
  if (/lakebase-scm-utils#v\d/.test(body)) {
@@ -17056,7 +17169,7 @@ async function fixFinding(args) {
17056
17169
  );
17057
17170
  }
17058
17171
  const sanitized = sanitizeBranchName(branch);
17059
- const envFile = path30.join(args.projectDir, ".env");
17172
+ const envFile = path31.join(args.projectDir, ".env");
17060
17173
  updateEnvConnection({
17061
17174
  envPath: envFile,
17062
17175
  projectId: readEnvVar(envFile, "LAKEBASE_PROJECT_ID") ?? "",
@@ -17159,10 +17272,10 @@ function shellEscape3(s) {
17159
17272
  // scripts/lakebase/doctor.ts
17160
17273
  init_esm_shims();
17161
17274
  import * as fs31 from "fs";
17162
- import * as path31 from "path";
17275
+ import * as path32 from "path";
17163
17276
  import * as cp6 from "child_process";
17164
17277
  function readEnvFile(projectDir) {
17165
- const envPath = path31.join(projectDir, ".env");
17278
+ const envPath = path32.join(projectDir, ".env");
17166
17279
  if (!fs31.existsSync(envPath)) return {};
17167
17280
  const out = {};
17168
17281
  for (const line of fs31.readFileSync(envPath, "utf8").split("\n")) {
@@ -17420,7 +17533,7 @@ function checkEnv(projectDir) {
17420
17533
  name: "env-file",
17421
17534
  status: "warn",
17422
17535
  message: ".env not found",
17423
- detail: { projectDir, envPath: path31.join(projectDir, ".env") },
17536
+ detail: { projectDir, envPath: path32.join(projectDir, ".env") },
17424
17537
  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
17538
  };
17426
17539
  }