@biffo/cli 0.58.1 → 0.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core.version CHANGED
@@ -1 +1 @@
1
- 0.58.1
1
+ 0.59.1
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import { Command as Command23 } from "commander";
7
7
  import { Command as Command4 } from "commander";
8
8
 
9
9
  // src/commands/core-diff.ts
10
+ import { existsSync as existsSync3 } from "fs";
10
11
  import { join as join3, resolve } from "path";
11
12
  import chalk2 from "chalk";
12
13
  import { Command } from "commander";
@@ -148,6 +149,7 @@ function computeCoreDiff(templateRoot, instanceRoot, manifest) {
148
149
  }
149
150
 
150
151
  // src/lib/core-version.ts
152
+ import { execFileSync } from "child_process";
151
153
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
152
154
  import { dirname as dirname2, join as join2, parse as parsePath } from "path";
153
155
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -225,6 +227,23 @@ function serializeInstanceCoreVersion(version) {
225
227
  function writeInstanceCoreVersion(cwd, version) {
226
228
  writeFileSync(join2(cwd, INSTANCE_CORE_FILE), serializeInstanceCoreVersion(version));
227
229
  }
230
+ function latestCoreVersionFromTags(repo, git = defaultTagRunner) {
231
+ try {
232
+ git(["-C", repo, "fetch", "--tags", "--quiet"]);
233
+ } catch {
234
+ }
235
+ let out;
236
+ try {
237
+ out = git(["-C", repo, "tag", "--list", "core-v*"]);
238
+ } catch {
239
+ return null;
240
+ }
241
+ const versions = out.split("\n").map((line) => line.trim()).filter((line) => line.startsWith(CORE_TAG_PREFIX)).map((tag) => tag.slice(CORE_TAG_PREFIX.length)).filter((v) => SEMVER.test(v));
242
+ if (versions.length === 0) return null;
243
+ return versions.sort(compareCoreVersions).at(-1) ?? null;
244
+ }
245
+ var CORE_TAG_PREFIX = "core-v";
246
+ var defaultTagRunner = (args) => execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
228
247
 
229
248
  // src/lib/logger.ts
230
249
  import chalk from "chalk";
@@ -257,7 +276,7 @@ var coreDiffCommand = new Command("diff").description(
257
276
  async function runCoreDiff(options) {
258
277
  const templateRoot = options.templateRoot ?? resolveTemplateRoot({ guidance: MISSING_TEMPLATE_ROOT_GUIDANCE });
259
278
  const manifest = readCoreManifest(templateRoot);
260
- const templateVersion = readCoreVersionFile(join3(templateRoot, "core.version"));
279
+ const templateVersion = latestCoreVersionFromTags(templateRoot) ?? (existsSync3(join3(templateRoot, CORE_VERSION_FILE)) ? readCoreVersionFile(join3(templateRoot, CORE_VERSION_FILE)) : "(unreleased)");
261
280
  const instanceVersion = readInstanceCoreVersion(options.cwd);
262
281
  const diff = computeCoreDiff(templateRoot, options.cwd, manifest);
263
282
  const total = diff.added.length + diff.removed.length + diff.modified.length;
@@ -337,6 +356,7 @@ async function runCoreStatus(options) {
337
356
 
338
357
  // src/commands/core-upgrade.ts
339
358
  import { execSync as execSync2 } from "child_process";
359
+ import { existsSync as existsSync10 } from "fs";
340
360
  import { join as join11, resolve as resolve3 } from "path";
341
361
  import chalk4 from "chalk";
342
362
  import { execa as execa3 } from "execa";
@@ -344,7 +364,7 @@ import { Command as Command3 } from "commander";
344
364
 
345
365
  // src/adapters/git/index.ts
346
366
  import { randomUUID } from "crypto";
347
- import { existsSync as existsSync3, mkdtempSync, rmSync } from "fs";
367
+ import { existsSync as existsSync4, mkdtempSync, rmSync } from "fs";
348
368
  import { tmpdir } from "os";
349
369
  import { join as join4 } from "path";
350
370
  import { execa } from "execa";
@@ -383,7 +403,7 @@ var GitAdapter = class {
383
403
  throw new Error(`Failed to clone ${repoUrl}: ${err.message}`);
384
404
  }
385
405
  const gitDir = join4(dir, ".git");
386
- if (existsSync3(gitDir)) rmSync(gitDir, { recursive: true, force: true });
406
+ if (existsSync4(gitDir)) rmSync(gitDir, { recursive: true, force: true });
387
407
  return dir;
388
408
  }
389
409
  /**
@@ -1168,7 +1188,7 @@ var GitHubAdapter = class {
1168
1188
 
1169
1189
  // src/lib/core-migrations.ts
1170
1190
  import { createHash } from "crypto";
1171
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
1191
+ import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
1172
1192
  import { dirname as dirname3, join as join5 } from "path";
1173
1193
  var MIGRATIONS_VERSIONS_DIR = "services/api/migrations/versions";
1174
1194
  var REVISION_RE = /^(revision\b[^=\n]*=\s*)(.+)$/m;
@@ -1208,7 +1228,7 @@ function parseMigration(file, content) {
1208
1228
  return { file, revision, downRevision, content };
1209
1229
  }
1210
1230
  function readMigrations(versionsDir) {
1211
- if (!existsSync4(versionsDir)) return [];
1231
+ if (!existsSync5(versionsDir)) return [];
1212
1232
  return readdirSync2(versionsDir).filter((f) => f.endsWith(".py") && f !== "__init__.py").sort().map((f) => parseMigration(f, readFileSync3(join5(versionsDir, f), "utf8")));
1213
1233
  }
1214
1234
  function rechainMigration(content, revision, downRevision) {
@@ -1444,7 +1464,7 @@ function applyMigrationCarry(instanceDir, plan) {
1444
1464
  const written = [];
1445
1465
  for (const e of plan.entries) {
1446
1466
  const abs = join5(instanceDir, e.path);
1447
- if (existsSync4(abs)) {
1467
+ if (existsSync5(abs)) {
1448
1468
  throw new Error(`Refusing to overwrite an existing migration: ${e.path}`);
1449
1469
  }
1450
1470
  mkdirSync(dirname3(abs), { recursive: true });
@@ -1455,7 +1475,7 @@ function applyMigrationCarry(instanceDir, plan) {
1455
1475
  }
1456
1476
 
1457
1477
  // src/lib/core-upgrade.ts
1458
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
1478
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
1459
1479
  import { tmpdir as tmpdir2 } from "os";
1460
1480
  import { dirname as dirname4, join as join6 } from "path";
1461
1481
  import { execa as execa2 } from "execa";
@@ -1558,7 +1578,7 @@ function applyUpgradePlan(instanceDir, plan) {
1558
1578
  for (const e of plan.entries) {
1559
1579
  const abs = join6(instanceDir, e.path);
1560
1580
  if (e.status === "removed") {
1561
- if (existsSync5(abs)) {
1581
+ if (existsSync6(abs)) {
1562
1582
  rmSync2(abs);
1563
1583
  deleted.push(e.path);
1564
1584
  }
@@ -1585,7 +1605,7 @@ function upgradeBranchName(from, to) {
1585
1605
  }
1586
1606
 
1587
1607
  // src/lib/core-template-trees.ts
1588
- import { execFileSync } from "child_process";
1608
+ import { execFileSync as execFileSync2 } from "child_process";
1589
1609
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync3 } from "fs";
1590
1610
  import { tmpdir as tmpdir3 } from "os";
1591
1611
  import { join as join7 } from "path";
@@ -1593,7 +1613,7 @@ function coreTag(version) {
1593
1613
  parseCoreVersion(version);
1594
1614
  return `core-v${version}`;
1595
1615
  }
1596
- var defaultGit = (args) => execFileSync("git", args, { encoding: "utf8" });
1616
+ var defaultGit = (args) => execFileSync2("git", args, { encoding: "utf8" });
1597
1617
  function tagExists(repo, tag, git) {
1598
1618
  try {
1599
1619
  git(["-C", repo, "rev-parse", "-q", "--verify", `refs/tags/${tag}`]);
@@ -1619,7 +1639,7 @@ function materializeTemplateAtTag(repo, version, git = defaultGit) {
1619
1639
  const tarball = join7(dir, ".tree.tar");
1620
1640
  try {
1621
1641
  git(["-C", repo, "archive", "--format=tar", "-o", tarball, tag]);
1622
- execFileSync("tar", ["-x", "-f", tarball, "-C", dir]);
1642
+ execFileSync2("tar", ["-x", "-f", tarball, "-C", dir]);
1623
1643
  rmSync3(tarball, { force: true });
1624
1644
  } catch (err) {
1625
1645
  rmSync3(dir, { recursive: true, force: true });
@@ -1629,7 +1649,7 @@ function materializeTemplateAtTag(repo, version, git = defaultGit) {
1629
1649
  }
1630
1650
 
1631
1651
  // src/lib/breaking-changes.ts
1632
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1652
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
1633
1653
  import { join as join8 } from "path";
1634
1654
  var UPGRADE_GUIDE_PATH = "docs/guides/core-upgrade.md";
1635
1655
  var SECTION_HEADING = "## Breaking changes by version";
@@ -1656,7 +1676,7 @@ function parseBreakingChanges(guide) {
1656
1676
  }
1657
1677
  function readBreakingChanges(templateRoot) {
1658
1678
  const path = join8(templateRoot, UPGRADE_GUIDE_PATH);
1659
- if (!existsSync6(path)) return [];
1679
+ if (!existsSync7(path)) return [];
1660
1680
  return parseBreakingChanges(readFileSync5(path, "utf8"));
1661
1681
  }
1662
1682
  function breakingChangesBetween(from, to, entries) {
@@ -1674,7 +1694,7 @@ var GLOBAL_DISPATCH_WORKFLOW_PATHS = [
1674
1694
  ];
1675
1695
 
1676
1696
  // src/lib/plugin-terraform-wiring.ts
1677
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
1697
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
1678
1698
  import { join as join9 } from "path";
1679
1699
  var TEMPLATE_MODULE_DIR = "_template";
1680
1700
  var DEFAULT_PLUGIN_HANDLER = "src.lambda.main.handler";
@@ -1705,7 +1725,7 @@ function listPluginModules(cwd) {
1705
1725
  var FIRST_PARTY_TERRAFORM = (name) => `../../../services/_plugins/${name}/terraform`;
1706
1726
  var THIRD_PARTY_TERRAFORM = (name) => `../../../modules/plugins/${name}`;
1707
1727
  function isFirstPartyPlugin(cwd, name) {
1708
- return existsSync7(join9(cwd, "services", "_plugins", name, "terraform", "main.tf"));
1728
+ return existsSync8(join9(cwd, "services", "_plugins", name, "terraform", "main.tf"));
1709
1729
  }
1710
1730
  function pluginModuleSource(cwd, name) {
1711
1731
  return isFirstPartyPlugin(cwd, name) ? FIRST_PARTY_TERRAFORM(name) : THIRD_PARTY_TERRAFORM(name);
@@ -1738,7 +1758,7 @@ function listEnvironments(cwd) {
1738
1758
  return [];
1739
1759
  }
1740
1760
  return entries.filter((e) => {
1741
- if (!e.isDirectory() || !existsSync7(join9(dir, e.name, "main.tf"))) return false;
1761
+ if (!e.isDirectory() || !existsSync8(join9(dir, e.name, "main.tf"))) return false;
1742
1762
  return declaredVariables(join9(dir, e.name)).has("enabled_plugins");
1743
1763
  }).map((e) => e.name).sort();
1744
1764
  }
@@ -1751,7 +1771,7 @@ function listUnwirableEnvironments(cwd) {
1751
1771
  return [];
1752
1772
  }
1753
1773
  return entries.filter(
1754
- (e) => e.isDirectory() && existsSync7(join9(dir, e.name, "main.tf")) && !declaredVariables(join9(dir, e.name)).has("enabled_plugins")
1774
+ (e) => e.isDirectory() && existsSync8(join9(dir, e.name, "main.tf")) && !declaredVariables(join9(dir, e.name)).has("enabled_plugins")
1755
1775
  ).map((e) => e.name).sort();
1756
1776
  }
1757
1777
  function declaredVariables(moduleDir) {
@@ -1860,7 +1880,7 @@ function syncPluginTerraform(cwd) {
1860
1880
  [tfPath, `${relBase}/${GENERATED_TF_FILE}`],
1861
1881
  [tfvarsPath, `${relBase}/${GENERATED_TFVARS_FILE}`]
1862
1882
  ]) {
1863
- if (existsSync7(abs)) {
1883
+ if (existsSync8(abs)) {
1864
1884
  rmSync4(abs);
1865
1885
  changedPaths.push(rel);
1866
1886
  }
@@ -1876,7 +1896,7 @@ function syncPluginTerraform(cwd) {
1876
1896
  }
1877
1897
 
1878
1898
  // src/lib/lockfile-refresh.ts
1879
- import { existsSync as existsSync8 } from "fs";
1899
+ import { existsSync as existsSync9 } from "fs";
1880
1900
  import { join as join10 } from "path";
1881
1901
  var LOCKFILE_TRIGGERS = [
1882
1902
  {
@@ -1900,7 +1920,7 @@ function lockfilesNeedingRefresh(changedPaths, instanceDir, triggers = LOCKFILE_
1900
1920
  const locked = changedPaths.filter((p) => !isForeignManifest(p));
1901
1921
  return triggers.filter((t) => {
1902
1922
  const touched = locked.some((p) => p === t.manifest || p.endsWith(`/${t.manifest}`));
1903
- return touched && existsSync8(join10(instanceDir, t.lockfile));
1923
+ return touched && existsSync9(join10(instanceDir, t.lockfile));
1904
1924
  });
1905
1925
  }
1906
1926
  async function refreshLockfiles(instanceDir, triggers, run) {
@@ -1993,9 +2013,9 @@ async function runCoreUpgradeResolved(options, deps, cleanups) {
1993
2013
  let toVersion;
1994
2014
  if (options.theirsDir) {
1995
2015
  theirsDir = options.theirsDir;
1996
- toVersion = readCoreVersionFile(join11(theirsDir, "core.version"));
2016
+ toVersion = versionOfCheckout(theirsDir, options.toVersion);
1997
2017
  } else {
1998
- const workingVersion = readCoreVersionFile(join11(templateRepo, "core.version"));
2018
+ const workingVersion = latestCoreVersion(templateRepo);
1999
2019
  toVersion = options.toVersion ?? workingVersion;
2000
2020
  if (toVersion === workingVersion) {
2001
2021
  theirsDir = templateRepo;
@@ -2009,7 +2029,7 @@ async function runCoreUpgradeResolved(options, deps, cleanups) {
2009
2029
  let fromVersion;
2010
2030
  if (options.baseDir) {
2011
2031
  baseDir = options.baseDir;
2012
- fromVersion = readCoreVersionFile(join11(baseDir, "core.version"));
2032
+ fromVersion = versionOfCheckout(baseDir, void 0);
2013
2033
  } else {
2014
2034
  if (instanceVersion === null) {
2015
2035
  throw new Error(
@@ -2293,6 +2313,23 @@ function printBreakingChanges(breaking, applying) {
2293
2313
  );
2294
2314
  }
2295
2315
  }
2316
+ function versionOfCheckout(dir, explicit) {
2317
+ if (explicit) return explicit;
2318
+ const file = join11(dir, CORE_VERSION_FILE);
2319
+ if (existsSync10(file)) return readCoreVersionFile(file);
2320
+ throw new Error(
2321
+ `Cannot determine the core version of ${dir}: it has no ${CORE_VERSION_FILE}, and a checkout supplied explicitly is not resolved from a tag. Pass --to to state which version this tree is.`
2322
+ );
2323
+ }
2324
+ function latestCoreVersion(repo) {
2325
+ const fromTags = latestCoreVersionFromTags(repo);
2326
+ if (fromTags) return fromTags;
2327
+ const file = join11(repo, CORE_VERSION_FILE);
2328
+ if (existsSync10(file)) return readCoreVersionFile(file);
2329
+ throw new Error(
2330
+ `Cannot determine the template's core version: ${repo} has no core-v* tags and no ${CORE_VERSION_FILE}. Fetch tags (\`git fetch --tags\`) or pass --to explicitly.`
2331
+ );
2332
+ }
2296
2333
 
2297
2334
  // src/commands/core.ts
2298
2335
  var coreCommand = new Command4("core").description(
@@ -2306,7 +2343,7 @@ coreCommand.addCommand(coreUpgradeCommand);
2306
2343
  import { Command as Command8 } from "commander";
2307
2344
 
2308
2345
  // src/commands/data-apply.ts
2309
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
2346
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
2310
2347
  import { resolve as resolve4 } from "path";
2311
2348
  import chalk5 from "chalk";
2312
2349
  import { Command as Command5 } from "commander";
@@ -2757,7 +2794,7 @@ function isTemplatePlaceholderConfig(raw) {
2757
2794
 
2758
2795
  // src/lib/session.ts
2759
2796
  import {
2760
- existsSync as existsSync9,
2797
+ existsSync as existsSync11,
2761
2798
  mkdirSync as mkdirSync4,
2762
2799
  readdirSync as readdirSync4,
2763
2800
  readFileSync as readFileSync7,
@@ -2782,7 +2819,7 @@ function sessionPath(projectName) {
2782
2819
  }
2783
2820
  function loadSession(projectName) {
2784
2821
  const path = sessionPath(projectName);
2785
- if (!existsSync9(path)) return null;
2822
+ if (!existsSync11(path)) return null;
2786
2823
  try {
2787
2824
  return JSON.parse(readFileSync7(path, "utf8"));
2788
2825
  } catch {
@@ -2791,12 +2828,12 @@ function loadSession(projectName) {
2791
2828
  }
2792
2829
  function findLatestSession() {
2793
2830
  const dir = sessionsDir();
2794
- if (!existsSync9(dir)) return null;
2831
+ if (!existsSync11(dir)) return null;
2795
2832
  const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
2796
2833
  if (files.length === 0) return null;
2797
2834
  const sorted = files.map((f) => {
2798
2835
  const fullPath = join12(dir, f);
2799
- const mtime = existsSync9(fullPath) ? statSync(fullPath).mtimeMs : -1;
2836
+ const mtime = existsSync11(fullPath) ? statSync(fullPath).mtimeMs : -1;
2800
2837
  return { f, mtime };
2801
2838
  }).sort((a, b) => b.mtime - a.mtime);
2802
2839
  try {
@@ -2807,7 +2844,7 @@ function findLatestSession() {
2807
2844
  }
2808
2845
  function saveSession(session) {
2809
2846
  const dir = sessionsDir();
2810
- if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
2847
+ if (!existsSync11(dir)) mkdirSync4(dir, { recursive: true });
2811
2848
  const name = session.config.project?.name ?? "unknown";
2812
2849
  const prior = loadSession(name);
2813
2850
  if (prior) {
@@ -2829,19 +2866,19 @@ function markStepComplete(session, step) {
2829
2866
  }
2830
2867
  function deleteSession(projectName) {
2831
2868
  const path = sessionPath(projectName);
2832
- if (existsSync9(path)) rmSync5(path);
2869
+ if (existsSync11(path)) rmSync5(path);
2833
2870
  }
2834
2871
  function projectsDir() {
2835
2872
  return process.env["BIFFO_PROJECTS_DIR"] ?? join12(homedir(), ".biffo", "projects");
2836
2873
  }
2837
2874
  function saveProjectConfig(config) {
2838
2875
  const dir = projectsDir();
2839
- if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
2876
+ if (!existsSync11(dir)) mkdirSync4(dir, { recursive: true });
2840
2877
  writeFileSync5(join12(dir, `${config.project.name}.json`), JSON.stringify(config, null, 2));
2841
2878
  }
2842
2879
  function loadProjectConfig(name) {
2843
2880
  const path = join12(projectsDir(), `${name}.json`);
2844
- if (!existsSync9(path)) return null;
2881
+ if (!existsSync11(path)) return null;
2845
2882
  try {
2846
2883
  const result = BiffoConfigSchema.safeParse(JSON.parse(readFileSync7(path, "utf8")));
2847
2884
  return result.success ? result.data : null;
@@ -2851,11 +2888,11 @@ function loadProjectConfig(name) {
2851
2888
  }
2852
2889
  function deleteProjectConfig(name) {
2853
2890
  const path = join12(projectsDir(), `${name}.json`);
2854
- if (existsSync9(path)) rmSync5(path);
2891
+ if (existsSync11(path)) rmSync5(path);
2855
2892
  }
2856
2893
  function listProjectConfigs() {
2857
2894
  const dir = projectsDir();
2858
- if (!existsSync9(dir)) return [];
2895
+ if (!existsSync11(dir)) return [];
2859
2896
  return readdirSync4(dir).filter((f) => f.endsWith(".json")).flatMap((f) => {
2860
2897
  try {
2861
2898
  const result = BiffoConfigSchema.safeParse(JSON.parse(readFileSync7(join12(dir, f), "utf8")));
@@ -2947,7 +2984,7 @@ async function resolveConfig(options) {
2947
2984
  return cfg;
2948
2985
  }
2949
2986
  const localConfigPath = resolve4(process.cwd(), "biffo.config.json");
2950
- if (existsSync10(localConfigPath)) {
2987
+ if (existsSync12(localConfigPath)) {
2951
2988
  const raw = JSON.parse(readFileSync8(localConfigPath, "utf8"));
2952
2989
  const result = BiffoConfigSchema.safeParse(raw);
2953
2990
  if (result.success) return result.data;
@@ -2994,7 +3031,7 @@ async function resolveConfig(options) {
2994
3031
 
2995
3032
  // src/commands/data-import.ts
2996
3033
  import { execSync as execSync3 } from "child_process";
2997
- import { cpSync, existsSync as existsSync11, mkdirSync as mkdirSync5, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
3034
+ import { cpSync, existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
2998
3035
  import { join as join13, resolve as resolve5 } from "path";
2999
3036
  import chalk6 from "chalk";
3000
3037
  import { Command as Command6 } from "commander";
@@ -3036,18 +3073,18 @@ async function runDataImport(name, options, deps) {
3036
3073
  );
3037
3074
  }
3038
3075
  const servicesDir = join13(options.cwd, "services");
3039
- if (!existsSync11(servicesDir)) {
3076
+ if (!existsSync13(servicesDir)) {
3040
3077
  throw new Error(
3041
3078
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
3042
3079
  );
3043
3080
  }
3044
3081
  const targetDir = join13(options.cwd, "db", "imports", name);
3045
- if (existsSync11(targetDir)) {
3082
+ if (existsSync13(targetDir)) {
3046
3083
  throw new Error(
3047
3084
  `DDL import '${name}' is already present at db/imports/${name}/. Remove it first to re-import.`
3048
3085
  );
3049
3086
  }
3050
- const isLocalDir = existsSync11(options.source) && statSync2(options.source).isDirectory();
3087
+ const isLocalDir = existsSync13(options.source) && statSync2(options.source).isDirectory();
3051
3088
  let sourceDir;
3052
3089
  let cleanupClone = null;
3053
3090
  if (isLocalDir) {
@@ -3062,7 +3099,7 @@ async function runDataImport(name, options, deps) {
3062
3099
  sourceDir = options.path ? join13(tmpDir, options.path) : tmpDir;
3063
3100
  }
3064
3101
  try {
3065
- if (!existsSync11(sourceDir)) {
3102
+ if (!existsSync13(sourceDir)) {
3066
3103
  throw new Error(`Source directory does not exist: ${sourceDir}`);
3067
3104
  }
3068
3105
  const sqlFiles = readdirSync5(sourceDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".sql")).map((entry) => entry.name).sort();
@@ -3139,7 +3176,7 @@ function printDryRun(name, sqlFiles) {
3139
3176
  }
3140
3177
 
3141
3178
  // src/commands/data-list.ts
3142
- import { existsSync as existsSync12, readdirSync as readdirSync6 } from "fs";
3179
+ import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
3143
3180
  import { join as join14, resolve as resolve6 } from "path";
3144
3181
  import chalk7 from "chalk";
3145
3182
  import { Command as Command7 } from "commander";
@@ -3154,7 +3191,7 @@ var dataListCommand = new Command7("list").description("List DDL imports vendore
3154
3191
  });
3155
3192
  async function runDataList(options) {
3156
3193
  const importsDir = join14(options.cwd, "db", "imports");
3157
- if (!existsSync12(importsDir)) {
3194
+ if (!existsSync14(importsDir)) {
3158
3195
  console.log(chalk7.dim("\n No DDL imports in this checkout.\n"));
3159
3196
  return;
3160
3197
  }
@@ -3191,7 +3228,7 @@ dataCommand.addCommand(dataListCommand);
3191
3228
 
3192
3229
  // src/commands/deploy.ts
3193
3230
  import { execSync as execSync4 } from "child_process";
3194
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
3231
+ import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
3195
3232
  import { resolve as resolve7 } from "path";
3196
3233
  import chalk8 from "chalk";
3197
3234
  import { Command as Command9 } from "commander";
@@ -3565,7 +3602,7 @@ async function resolveConfig2(options) {
3565
3602
  return cfg;
3566
3603
  }
3567
3604
  const localConfigPath = resolve7(process.cwd(), "biffo.config.json");
3568
- if (existsSync13(localConfigPath)) {
3605
+ if (existsSync15(localConfigPath)) {
3569
3606
  const raw = JSON.parse(readFileSync9(localConfigPath, "utf8"));
3570
3607
  const result = BiffoConfigSchema.safeParse(raw);
3571
3608
  if (result.success) return result.data;
@@ -4117,7 +4154,7 @@ import { Command as Command12 } from "commander";
4117
4154
  import inquirer5 from "inquirer";
4118
4155
 
4119
4156
  // src/lib/build-freshness.ts
4120
- import { existsSync as existsSync14, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
4157
+ import { existsSync as existsSync16, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
4121
4158
  import { dirname as dirname5, join as join15, relative as relative2, sep as sep2 } from "path";
4122
4159
  import { fileURLToPath as fileURLToPath3 } from "url";
4123
4160
  var SKIP_ENV_VAR = "BIFFO_SKIP_BUILD_FRESHNESS_CHECK";
@@ -4141,7 +4178,7 @@ function checkBuildFreshness(options = {}) {
4141
4178
  };
4142
4179
  }
4143
4180
  const srcDir = join15(packageRoot, "src");
4144
- if (!existsSync14(srcDir)) {
4181
+ if (!existsSync16(srcDir)) {
4145
4182
  return {
4146
4183
  status: "skipped",
4147
4184
  reason: "no src/ alongside dist/ \u2014 this is a shipped package",
@@ -4149,7 +4186,7 @@ function checkBuildFreshness(options = {}) {
4149
4186
  };
4150
4187
  }
4151
4188
  const entry = join15(distDir, "index.js");
4152
- if (!existsSync14(entry)) {
4189
+ if (!existsSync16(entry)) {
4153
4190
  return { status: "skipped", reason: `${entry} not found`, newerSources: [] };
4154
4191
  }
4155
4192
  const builtAt = statSync3(entry).mtimeMs;
@@ -4212,7 +4249,7 @@ function collectSourceFiles(srcDir) {
4212
4249
  function findPackageRoot(from) {
4213
4250
  let dir = from;
4214
4251
  for (; ; ) {
4215
- if (existsSync14(join15(dir, "package.json"))) return dir;
4252
+ if (existsSync16(join15(dir, "package.json"))) return dir;
4216
4253
  const parent = dirname5(dir);
4217
4254
  if (parent === dir) return null;
4218
4255
  dir = parent;
@@ -4226,7 +4263,7 @@ function isInside(parent, child) {
4226
4263
 
4227
4264
  // src/lib/credentials.ts
4228
4265
  import { execSync as execSync6 } from "child_process";
4229
- import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
4266
+ import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
4230
4267
  import { homedir as homedir2 } from "os";
4231
4268
  import { join as join16 } from "path";
4232
4269
  import { GetCallerIdentityCommand as GetCallerIdentityCommand2, STSClient as STSClient2 } from "@aws-sdk/client-sts";
@@ -4410,7 +4447,7 @@ function discoverAwsProfiles() {
4410
4447
  const files = [join16(homedir2(), ".aws", "credentials"), join16(homedir2(), ".aws", "config")];
4411
4448
  const profiles = /* @__PURE__ */ new Set();
4412
4449
  for (const file of files) {
4413
- if (!existsSync15(file)) continue;
4450
+ if (!existsSync17(file)) continue;
4414
4451
  const content = readFileSync11(file, "utf8");
4415
4452
  for (const match of content.matchAll(/^\s*\[([^\]]+)\]\s*$/gm)) {
4416
4453
  const section = match[1]?.trim();
@@ -4501,7 +4538,7 @@ var SiblingConfigSchema = z4.object({
4501
4538
 
4502
4539
  // src/lib/sibling-session.ts
4503
4540
  import {
4504
- existsSync as existsSync16,
4541
+ existsSync as existsSync18,
4505
4542
  mkdirSync as mkdirSync6,
4506
4543
  readdirSync as readdirSync8,
4507
4544
  readFileSync as readFileSync12,
@@ -4519,7 +4556,7 @@ function sessionPath2(projectName) {
4519
4556
  }
4520
4557
  function loadSiblingSession(projectName) {
4521
4558
  const path = sessionPath2(projectName);
4522
- if (!existsSync16(path)) return null;
4559
+ if (!existsSync18(path)) return null;
4523
4560
  try {
4524
4561
  return JSON.parse(readFileSync12(path, "utf8"));
4525
4562
  } catch {
@@ -4528,7 +4565,7 @@ function loadSiblingSession(projectName) {
4528
4565
  }
4529
4566
  function saveSiblingSession(session) {
4530
4567
  const dir = sessionsDir2();
4531
- if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
4568
+ if (!existsSync18(dir)) mkdirSync6(dir, { recursive: true });
4532
4569
  const name = session.config.project?.name ?? "unknown";
4533
4570
  const prior = loadSiblingSession(name);
4534
4571
  if (prior) {
@@ -4550,11 +4587,11 @@ function markSiblingStepComplete(session, step) {
4550
4587
  }
4551
4588
  function deleteSiblingSession(projectName) {
4552
4589
  const path = sessionPath2(projectName);
4553
- if (existsSync16(path)) rmSync6(path);
4590
+ if (existsSync18(path)) rmSync6(path);
4554
4591
  }
4555
4592
 
4556
4593
  // src/commands/sibling-create.ts
4557
- import { cpSync as cpSync2, existsSync as existsSync17, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
4594
+ import { cpSync as cpSync2, existsSync as existsSync19, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
4558
4595
  import { tmpdir as tmpdir4 } from "os";
4559
4596
  import { dirname as dirname6, join as join19, resolve as resolve9 } from "path";
4560
4597
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -4618,7 +4655,7 @@ async function runSiblingCreateCommand(name, options) {
4618
4655
  printDryRun2(config, coreConfig, options.templateRoot);
4619
4656
  return;
4620
4657
  }
4621
- if (!existsSync17(options.templateRoot)) {
4658
+ if (!existsSync19(options.templateRoot)) {
4622
4659
  throw new Error(`Sibling template not found at ${options.templateRoot}`);
4623
4660
  }
4624
4661
  let session = null;
@@ -4892,7 +4929,7 @@ async function pushSkeleton(git, skeletonRoot, cloneUrl, config, coreConfig, git
4892
4929
  }
4893
4930
  }
4894
4931
  function writeSiblingTemplate(templateRoot, targetDir, config, context) {
4895
- if (!existsSync17(templateRoot)) {
4932
+ if (!existsSync19(templateRoot)) {
4896
4933
  throw new Error(`Sibling template not found at ${templateRoot}`);
4897
4934
  }
4898
4935
  cpSync2(templateRoot, targetDir, { recursive: true });
@@ -5098,7 +5135,7 @@ function defaultSiblingTemplateRoot() {
5098
5135
  let dir = start;
5099
5136
  for (; ; ) {
5100
5137
  const candidate = join19(dir, "_skeletons", "sibling-template");
5101
- if (existsSync17(candidate)) return candidate;
5138
+ if (existsSync19(candidate)) return candidate;
5102
5139
  const parent = dirname6(dir);
5103
5140
  if (parent === dir) break;
5104
5141
  dir = parent;
@@ -5555,14 +5592,14 @@ async function promptForConfig(awsAccountId, awsRegion, awsProfile) {
5555
5592
  import { Command as Command20 } from "commander";
5556
5593
 
5557
5594
  // src/commands/plugin-create.ts
5558
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
5595
+ import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
5559
5596
  import { dirname as dirname8, join as join22, resolve as resolve11 } from "path";
5560
5597
  import { fileURLToPath as fileURLToPath5 } from "url";
5561
5598
  import chalk13 from "chalk";
5562
5599
  import { Command as Command13 } from "commander";
5563
5600
 
5564
5601
  // src/lib/plugin-locations.ts
5565
- import { existsSync as existsSync18, readdirSync as readdirSync10 } from "fs";
5602
+ import { existsSync as existsSync20, readdirSync as readdirSync10 } from "fs";
5566
5603
  import { join as join20 } from "path";
5567
5604
  var FIRST_PARTY_PLUGINS_DIR = "_plugins";
5568
5605
  var PLUGIN_MANIFEST_FILE = "biffo.plugin.json";
@@ -5570,13 +5607,13 @@ function pluginDir(name, channel) {
5570
5607
  return channel === "first-party" ? `services/${FIRST_PARTY_PLUGINS_DIR}/${name}` : `services/${name}`;
5571
5608
  }
5572
5609
  function scanDir(absDir, relDir, channel) {
5573
- if (!existsSync18(absDir)) return [];
5610
+ if (!existsSync20(absDir)) return [];
5574
5611
  const found = [];
5575
5612
  for (const entry of readdirSync10(absDir, { withFileTypes: true })) {
5576
5613
  if (!entry.isDirectory()) continue;
5577
5614
  if (channel === "third-party" && entry.name === FIRST_PARTY_PLUGINS_DIR) continue;
5578
5615
  const manifestPath = join20(absDir, entry.name, PLUGIN_MANIFEST_FILE);
5579
- if (!existsSync18(manifestPath)) continue;
5616
+ if (!existsSync20(manifestPath)) continue;
5580
5617
  found.push({
5581
5618
  dirName: entry.name,
5582
5619
  relDir: `${relDir}/${entry.name}`,
@@ -5751,7 +5788,7 @@ function validateManifest(raw) {
5751
5788
  // src/lib/plugin-scaffold.ts
5752
5789
  import {
5753
5790
  copyFileSync,
5754
- existsSync as existsSync19,
5791
+ existsSync as existsSync21,
5755
5792
  mkdirSync as mkdirSync8,
5756
5793
  readFileSync as readFileSync15,
5757
5794
  readdirSync as readdirSync11,
@@ -5810,10 +5847,10 @@ function applySubstitutions(text, names) {
5810
5847
  }
5811
5848
  var BINARY_EXTENSIONS = /\.(png|jpe?g|gif|ico|woff2?|ttf|zip|gz)$/i;
5812
5849
  function scaffoldPlugin(skeletonRoot, destDir, names) {
5813
- if (!existsSync19(skeletonRoot)) {
5850
+ if (!existsSync21(skeletonRoot)) {
5814
5851
  throw new Error(`Plugin skeleton not found at ${skeletonRoot}`);
5815
5852
  }
5816
- if (!existsSync19(join21(skeletonRoot, "terraform"))) {
5853
+ if (!existsSync21(join21(skeletonRoot, "terraform"))) {
5817
5854
  throw new Error(
5818
5855
  `Plugin skeleton at ${skeletonRoot} has no terraform/ directory. Refusing to scaffold a plugin that cannot receive events (issue #194) \u2014 the skeleton is broken.`
5819
5856
  );
@@ -5861,7 +5898,7 @@ function findSkeletonRoot(startDir, skeleton) {
5861
5898
  let dir = startDir;
5862
5899
  for (; ; ) {
5863
5900
  const candidate = join21(dir, "_skeletons", skeleton);
5864
- if (existsSync19(candidate)) return candidate;
5901
+ if (existsSync21(candidate)) return candidate;
5865
5902
  const parent = dirname7(dir);
5866
5903
  if (parent === dir) return null;
5867
5904
  dir = parent;
@@ -5898,7 +5935,7 @@ var pluginCreateCommand = new Command13("create").description("Scaffold a new pl
5898
5935
  );
5899
5936
  async function runPluginCreate(name, options, deps) {
5900
5937
  const names = deriveNames(name);
5901
- const isInstance = existsSync20(join22(options.cwd, INSTANCE_CORE_FILE));
5938
+ const isInstance = existsSync22(join22(options.cwd, INSTANCE_CORE_FILE));
5902
5939
  if (options.firstParty && isInstance) {
5903
5940
  throw new Error(
5904
5941
  `--first-party scaffolds into services/_plugins/, which is template-owned: \`biffo core upgrade\` three-way-merges it against the template on every upgrade, and the template has no '${names.slug}'. This checkout is a Biffo instance (${INSTANCE_CORE_FILE} is present), so your plugin belongs in the user-owned ${pluginDir(names.slug, "third-party")}/ \u2014 re-run without --first-party.`
@@ -5908,17 +5945,17 @@ async function runPluginCreate(name, options, deps) {
5908
5945
  const relDir = pluginDir(names.slug, channel);
5909
5946
  const destDir = join22(options.cwd, relDir);
5910
5947
  const servicesDir = join22(options.cwd, "services");
5911
- if (!existsSync20(servicesDir)) {
5948
+ if (!existsSync22(servicesDir)) {
5912
5949
  throw new Error(
5913
5950
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
5914
5951
  );
5915
5952
  }
5916
- if (existsSync20(destDir)) {
5953
+ if (existsSync22(destDir)) {
5917
5954
  throw new Error(`${relDir}/ already exists. Choose a different name, or remove it first.`);
5918
5955
  }
5919
5956
  const here = dirname8(fileURLToPath5(import.meta.url));
5920
5957
  const skeletonRoot = options.skeletonRoot ?? findSkeletonRoot(here, "plugin-template") ?? join22(options.cwd, "_skeletons", "plugin-template");
5921
- if (!existsSync20(skeletonRoot)) {
5958
+ if (!existsSync22(skeletonRoot)) {
5922
5959
  throw new Error(
5923
5960
  `Could not find the plugin skeleton (_skeletons/plugin-template/). Pass --skeleton <path> to point at it explicitly.`
5924
5961
  );
@@ -6124,7 +6161,7 @@ function printEntry(entry) {
6124
6161
  }
6125
6162
 
6126
6163
  // src/commands/plugin-install.ts
6127
- import { cpSync as cpSync3, existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync17, statSync as statSync5 } from "fs";
6164
+ import { cpSync as cpSync3, existsSync as existsSync23, mkdirSync as mkdirSync9, readFileSync as readFileSync17, statSync as statSync5 } from "fs";
6128
6165
  import { basename, join as join24, relative as relative3, resolve as resolve12 } from "path";
6129
6166
  import chalk15 from "chalk";
6130
6167
  import { Command as Command15 } from "commander";
@@ -6213,14 +6250,14 @@ var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
6213
6250
  ".terraform"
6214
6251
  ]);
6215
6252
  function resolveLocalPlugin(localPath) {
6216
- if (!existsSync21(localPath)) {
6253
+ if (!existsSync23(localPath)) {
6217
6254
  throw new Error(`--local path does not exist: ${localPath}`);
6218
6255
  }
6219
6256
  if (!statSync5(localPath).isDirectory()) {
6220
6257
  throw new Error(`--local path is not a directory: ${localPath}`);
6221
6258
  }
6222
6259
  const manifestPath = join24(localPath, "biffo.plugin.json");
6223
- if (!existsSync21(manifestPath)) {
6260
+ if (!existsSync23(manifestPath)) {
6224
6261
  throw new Error(
6225
6262
  `${localPath} does not contain a biffo.plugin.json manifest at its root \u2014 is it a plugin directory? (Scaffold one with \`biffo plugin create <name>\`.)`
6226
6263
  );
@@ -6247,7 +6284,7 @@ async function cloneAndValidatePlugin(entry, git) {
6247
6284
  const tmpDir = await git.cloneToTemp(entry.repo, `biffo-plugin-${entry.name}`);
6248
6285
  try {
6249
6286
  const manifestPath = join24(tmpDir, "biffo.plugin.json");
6250
- if (!existsSync21(manifestPath)) {
6287
+ if (!existsSync23(manifestPath)) {
6251
6288
  throw new Error(
6252
6289
  `Plugin repo ${entry.repo} does not contain a biffo.plugin.json manifest at its root.`
6253
6290
  );
@@ -6276,7 +6313,7 @@ async function runPluginInstall(target, options, deps) {
6276
6313
  );
6277
6314
  }
6278
6315
  const servicesDir = join24(options.cwd, "services");
6279
- if (!existsSync21(servicesDir)) {
6316
+ if (!existsSync23(servicesDir)) {
6280
6317
  throw new Error(
6281
6318
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
6282
6319
  );
@@ -6297,7 +6334,7 @@ async function runPluginInstall(target, options, deps) {
6297
6334
  const targetDir = join24(options.cwd, relTargetDir);
6298
6335
  const modulesDir = join24(options.cwd, "modules", "plugins", pluginName);
6299
6336
  const inTreeSource = options.local !== void 0 && resolve12(options.local) === resolve12(targetDir);
6300
- if (existsSync21(targetDir) && !inTreeSource) {
6337
+ if (existsSync23(targetDir) && !inTreeSource) {
6301
6338
  throw new Error(
6302
6339
  `Plugin '${pluginName}' is already installed at ${relTargetDir}/. Remove it first, or wait for a future 'biffo plugin upgrade' command.`
6303
6340
  );
@@ -6341,7 +6378,7 @@ async function runPluginInstall(target, options, deps) {
6341
6378
  }
6342
6379
  const stagePaths = [relTargetDir];
6343
6380
  const tfSourceDir = join24(targetDir, "terraform");
6344
- if (existsSync21(tfSourceDir)) {
6381
+ if (existsSync23(tfSourceDir)) {
6345
6382
  mkdirSync9(modulesDir, { recursive: true });
6346
6383
  cpSync3(tfSourceDir, modulesDir, { recursive: true });
6347
6384
  stagePaths.push(`modules/plugins/${pluginName}`);
@@ -6435,7 +6472,7 @@ function printDryRun4(entry, source, relTargetDir, inTreeSource) {
6435
6472
  }
6436
6473
 
6437
6474
  // src/commands/plugin-list.ts
6438
- import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
6475
+ import { existsSync as existsSync24, readFileSync as readFileSync18 } from "fs";
6439
6476
  import { join as join25, resolve as resolve13 } from "path";
6440
6477
  import chalk16 from "chalk";
6441
6478
  import { Command as Command16 } from "commander";
@@ -6450,7 +6487,7 @@ var pluginListCommand = new Command16("list").description("List plugins installe
6450
6487
  });
6451
6488
  async function runPluginList(options) {
6452
6489
  const servicesDir = join25(options.cwd, "services");
6453
- if (!existsSync22(servicesDir)) {
6490
+ if (!existsSync24(servicesDir)) {
6454
6491
  throw new Error(
6455
6492
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
6456
6493
  );
@@ -6495,7 +6532,7 @@ async function runPluginList(options) {
6495
6532
  }
6496
6533
 
6497
6534
  // src/commands/plugin-sync-migrations.ts
6498
- import { existsSync as existsSync23 } from "fs";
6535
+ import { existsSync as existsSync25 } from "fs";
6499
6536
  import { join as join26, relative as relative4, resolve as resolve14 } from "path";
6500
6537
  import chalk17 from "chalk";
6501
6538
  import { Command as Command17 } from "commander";
@@ -6518,10 +6555,10 @@ var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
6518
6555
  );
6519
6556
  async function runPluginSyncMigrations(name, options, deps) {
6520
6557
  const servicesDir = join26(options.cwd, "services");
6521
- if (!existsSync23(servicesDir)) {
6558
+ if (!existsSync25(servicesDir)) {
6522
6559
  throw new Error(`${servicesDir} does not exist \u2014 is ${options.cwd} a Biffo project checkout?`);
6523
6560
  }
6524
- if (name && !existsSync23(join26(servicesDir, name, "biffo.plugin.json"))) {
6561
+ if (name && !existsSync25(join26(servicesDir, name, "biffo.plugin.json"))) {
6525
6562
  throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
6526
6563
  }
6527
6564
  if (options.dryRun) {
@@ -6557,7 +6594,7 @@ async function runPluginSyncMigrations(name, options, deps) {
6557
6594
  }
6558
6595
 
6559
6596
  // src/commands/plugin-uninstall.ts
6560
- import { existsSync as existsSync24, readFileSync as readFileSync19, rmSync as rmSync7 } from "fs";
6597
+ import { existsSync as existsSync26, readFileSync as readFileSync19, rmSync as rmSync7 } from "fs";
6561
6598
  import { join as join27, resolve as resolve15 } from "path";
6562
6599
  import chalk18 from "chalk";
6563
6600
  import { Command as Command18 } from "commander";
@@ -6591,15 +6628,15 @@ async function runPluginUninstall(name, options, deps) {
6591
6628
  throw new Error(`Invalid plugin name '${name}'. Expected a lowercase kebab-case slug.`);
6592
6629
  }
6593
6630
  const servicesDir = join27(options.cwd, "services");
6594
- if (!existsSync24(servicesDir)) {
6631
+ if (!existsSync26(servicesDir)) {
6595
6632
  throw new Error(
6596
6633
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
6597
6634
  );
6598
6635
  }
6599
6636
  const targetDir = join27(servicesDir, name);
6600
- if (!existsSync24(targetDir)) {
6637
+ if (!existsSync26(targetDir)) {
6601
6638
  const firstParty = join27(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
6602
- if (existsSync24(firstParty)) {
6639
+ if (existsSync26(firstParty)) {
6603
6640
  throw new Error(
6604
6641
  `Plugin '${name}' is a first-party plugin at ${pluginDir(name, "first-party")}/, which is template-owned \u2014 \`biffo core upgrade\` would restore it on the next upgrade. Disable it instead by removing '${name}' from \`enabled_plugins\` in infra/environments/<env>/main.tf and re-applying.`
6605
6642
  );
@@ -6609,7 +6646,7 @@ async function runPluginUninstall(name, options, deps) {
6609
6646
  const version = readInstalledVersion(targetDir);
6610
6647
  const modulesDir = join27(options.cwd, "modules", "plugins", name);
6611
6648
  const stagePaths = [`services/${name}`];
6612
- if (existsSync24(modulesDir)) {
6649
+ if (existsSync26(modulesDir)) {
6613
6650
  stagePaths.push(`modules/plugins/${name}`);
6614
6651
  }
6615
6652
  if (options.dryRun) {
@@ -6631,7 +6668,7 @@ async function runPluginUninstall(name, options, deps) {
6631
6668
  }
6632
6669
  rmSync7(targetDir, { recursive: true, force: true });
6633
6670
  log.success(`Removed services/${name}/`);
6634
- if (existsSync24(modulesDir)) {
6671
+ if (existsSync26(modulesDir)) {
6635
6672
  rmSync7(modulesDir, { recursive: true, force: true });
6636
6673
  log.success(`Removed modules/plugins/${name}/`);
6637
6674
  const wiring = syncPluginTerraform(options.cwd);
@@ -6669,7 +6706,7 @@ async function runPluginUninstall(name, options, deps) {
6669
6706
  }
6670
6707
  function readInstalledVersion(targetDir) {
6671
6708
  const manifestPath = join27(targetDir, "biffo.plugin.json");
6672
- if (!existsSync24(manifestPath)) return void 0;
6709
+ if (!existsSync26(manifestPath)) return void 0;
6673
6710
  try {
6674
6711
  return validateManifest(JSON.parse(readFileSync19(manifestPath, "utf8"))).version;
6675
6712
  } catch {
@@ -6704,7 +6741,7 @@ function printDryRun5(name, version, stagePaths, keepData) {
6704
6741
  }
6705
6742
 
6706
6743
  // src/commands/plugin-upgrade.ts
6707
- import { cpSync as cpSync4, existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync20, rmSync as rmSync8 } from "fs";
6744
+ import { cpSync as cpSync4, existsSync as existsSync27, mkdirSync as mkdirSync10, readFileSync as readFileSync20, rmSync as rmSync8 } from "fs";
6708
6745
  import { join as join28, relative as relative5, resolve as resolve16 } from "path";
6709
6746
  import chalk19 from "chalk";
6710
6747
  import { Command as Command19 } from "commander";
@@ -6731,13 +6768,13 @@ var pluginUpgradeCommand = new Command19("upgrade").description(
6731
6768
  async function runPluginUpgrade(target, options, deps) {
6732
6769
  const { name, minor } = parsePluginTarget(target);
6733
6770
  const servicesDir = join28(options.cwd, "services");
6734
- if (!existsSync25(servicesDir)) {
6771
+ if (!existsSync27(servicesDir)) {
6735
6772
  throw new Error(
6736
6773
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
6737
6774
  );
6738
6775
  }
6739
6776
  const targetDir = join28(servicesDir, name);
6740
- if (!existsSync25(targetDir)) {
6777
+ if (!existsSync27(targetDir)) {
6741
6778
  throw new Error(
6742
6779
  `Plugin '${name}' is not installed at services/${name}/. Use 'biffo plugin install ${name}@${minor}' instead.`
6743
6780
  );
@@ -6784,11 +6821,11 @@ async function runPluginUpgrade(target, options, deps) {
6784
6821
  cpSync4(tmpDir, targetDir, { recursive: true });
6785
6822
  log.success(`Upgraded plugin source at services/${entry.name}/`);
6786
6823
  const stagePaths = [`services/${entry.name}`];
6787
- if (existsSync25(modulesDir)) {
6824
+ if (existsSync27(modulesDir)) {
6788
6825
  rmSync8(modulesDir, { recursive: true, force: true });
6789
6826
  }
6790
6827
  const tfSourceDir = join28(targetDir, "terraform");
6791
- if (existsSync25(tfSourceDir)) {
6828
+ if (existsSync27(tfSourceDir)) {
6792
6829
  mkdirSync10(modulesDir, { recursive: true });
6793
6830
  cpSync4(tfSourceDir, modulesDir, { recursive: true });
6794
6831
  stagePaths.push(`modules/plugins/${entry.name}`);
@@ -6823,7 +6860,7 @@ async function runPluginUpgrade(target, options, deps) {
6823
6860
  }
6824
6861
  function readInstalledVersion2(targetDir) {
6825
6862
  const manifestPath = join28(targetDir, "biffo.plugin.json");
6826
- if (!existsSync25(manifestPath)) return void 0;
6863
+ if (!existsSync27(manifestPath)) return void 0;
6827
6864
  try {
6828
6865
  return validateManifest(JSON.parse(readFileSync20(manifestPath, "utf8"))).version;
6829
6866
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.58.1",
3
+ "version": "0.59.1",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",