@biffo/cli 0.103.0 → 0.103.2
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/dist/index.js +203 -80
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6627,8 +6627,8 @@ function printEntry(entry) {
|
|
|
6627
6627
|
}
|
|
6628
6628
|
|
|
6629
6629
|
// src/commands/plugin-install.ts
|
|
6630
|
-
import { cpSync as cpSync3, existsSync as
|
|
6631
|
-
import { basename, join as
|
|
6630
|
+
import { cpSync as cpSync3, existsSync as existsSync25, mkdirSync as mkdirSync9, readFileSync as readFileSync19, statSync as statSync6 } from "fs";
|
|
6631
|
+
import { basename, join as join26, relative as relative3, resolve as resolve12 } from "path";
|
|
6632
6632
|
import chalk15 from "chalk";
|
|
6633
6633
|
import { Command as Command15 } from "commander";
|
|
6634
6634
|
|
|
@@ -6674,6 +6674,120 @@ var PluginMigrationsAdapter = class {
|
|
|
6674
6674
|
}
|
|
6675
6675
|
};
|
|
6676
6676
|
|
|
6677
|
+
// src/lib/plugin-workspace-sources.ts
|
|
6678
|
+
import { existsSync as existsSync24, readdirSync as readdirSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
|
|
6679
|
+
import { join as join25 } from "path";
|
|
6680
|
+
function readTomlStringArray(text, key) {
|
|
6681
|
+
const open = new RegExp(`^${key}\\s*=\\s*\\[`, "m").exec(text);
|
|
6682
|
+
if (!open) return [];
|
|
6683
|
+
const start = open.index + open[0].length;
|
|
6684
|
+
let depth = 1;
|
|
6685
|
+
let inString = false;
|
|
6686
|
+
let quote = "";
|
|
6687
|
+
let end = -1;
|
|
6688
|
+
for (let i = start; i < text.length; i++) {
|
|
6689
|
+
const c = text[i];
|
|
6690
|
+
if (inString) {
|
|
6691
|
+
if (c === quote) inString = false;
|
|
6692
|
+
} else if (c === '"' || c === "'") {
|
|
6693
|
+
inString = true;
|
|
6694
|
+
quote = c;
|
|
6695
|
+
} else if (c === "[") {
|
|
6696
|
+
depth++;
|
|
6697
|
+
} else if (c === "]") {
|
|
6698
|
+
depth--;
|
|
6699
|
+
if (depth === 0) {
|
|
6700
|
+
end = i;
|
|
6701
|
+
break;
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
if (end === -1) return [];
|
|
6706
|
+
const body = text.slice(start, end);
|
|
6707
|
+
return [...body.matchAll(/["']([^"']+)["']/g)].map((m) => m[1]);
|
|
6708
|
+
}
|
|
6709
|
+
function readProjectName(text) {
|
|
6710
|
+
let inProject = false;
|
|
6711
|
+
for (const line of text.split("\n")) {
|
|
6712
|
+
const trimmed = line.trim();
|
|
6713
|
+
if (trimmed.startsWith("[")) {
|
|
6714
|
+
inProject = trimmed === "[project]";
|
|
6715
|
+
continue;
|
|
6716
|
+
}
|
|
6717
|
+
if (inProject) {
|
|
6718
|
+
const m = /^name\s*=\s*["']([^"']+)["']/.exec(trimmed);
|
|
6719
|
+
if (m) return m[1];
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
return null;
|
|
6723
|
+
}
|
|
6724
|
+
function readDependencyNames(text) {
|
|
6725
|
+
return readTomlStringArray(text, "dependencies").map((dep) => /^\s*([A-Za-z0-9._-]+)/.exec(dep)?.[1] ?? "").filter(Boolean);
|
|
6726
|
+
}
|
|
6727
|
+
function workspaceMemberNames(instanceRoot) {
|
|
6728
|
+
const rootPyproject = join25(instanceRoot, "pyproject.toml");
|
|
6729
|
+
if (!existsSync24(rootPyproject)) return /* @__PURE__ */ new Set();
|
|
6730
|
+
const text = readFileSync18(rootPyproject, "utf8");
|
|
6731
|
+
const members = readTomlStringArray(text, "members");
|
|
6732
|
+
const excluded = new Set(readTomlStringArray(text, "exclude"));
|
|
6733
|
+
const dirs = [];
|
|
6734
|
+
for (const member of members) {
|
|
6735
|
+
if (member.endsWith("/*")) {
|
|
6736
|
+
const base = member.slice(0, -2);
|
|
6737
|
+
let entries;
|
|
6738
|
+
try {
|
|
6739
|
+
entries = readdirSync12(join25(instanceRoot, base), { withFileTypes: true });
|
|
6740
|
+
} catch {
|
|
6741
|
+
continue;
|
|
6742
|
+
}
|
|
6743
|
+
for (const entry of entries) {
|
|
6744
|
+
const rel = `${base}/${entry.name}`;
|
|
6745
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && !excluded.has(rel)) dirs.push(rel);
|
|
6746
|
+
}
|
|
6747
|
+
} else if (!excluded.has(member)) {
|
|
6748
|
+
dirs.push(member);
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
const names = /* @__PURE__ */ new Set();
|
|
6752
|
+
for (const dir of dirs) {
|
|
6753
|
+
const pp = join25(instanceRoot, dir, "pyproject.toml");
|
|
6754
|
+
if (!existsSync24(pp)) continue;
|
|
6755
|
+
const name = readProjectName(readFileSync18(pp, "utf8"));
|
|
6756
|
+
if (name) names.add(name);
|
|
6757
|
+
}
|
|
6758
|
+
return names;
|
|
6759
|
+
}
|
|
6760
|
+
function existingWorkspaceSources(text) {
|
|
6761
|
+
return new Set(
|
|
6762
|
+
[...text.matchAll(/^\s*([A-Za-z0-9._-]+)\s*=\s*\{[^}]*\bworkspace\b/gm)].map((m) => m[1])
|
|
6763
|
+
);
|
|
6764
|
+
}
|
|
6765
|
+
function ensureWorkspaceSources(pluginPyprojectPath, memberNames) {
|
|
6766
|
+
if (!existsSync24(pluginPyprojectPath) || memberNames.size === 0) return [];
|
|
6767
|
+
const text = readFileSync18(pluginPyprojectPath, "utf8");
|
|
6768
|
+
const already = existingWorkspaceSources(text);
|
|
6769
|
+
const toAdd = readDependencyNames(text).filter((n) => memberNames.has(n) && !already.has(n));
|
|
6770
|
+
if (toAdd.length === 0) return [];
|
|
6771
|
+
const lines = toAdd.map((n) => `${n} = { workspace = true }`);
|
|
6772
|
+
const header = /^\[tool\.uv\.sources\]\s*$/m.exec(text);
|
|
6773
|
+
let updated;
|
|
6774
|
+
if (header) {
|
|
6775
|
+
const insertAt = header.index + header[0].length;
|
|
6776
|
+
updated = `${text.slice(0, insertAt)}
|
|
6777
|
+
${lines.join("\n")}${text.slice(insertAt)}`;
|
|
6778
|
+
} else {
|
|
6779
|
+
const sep4 = text.endsWith("\n") ? "" : "\n";
|
|
6780
|
+
updated = `${text}${sep4}
|
|
6781
|
+
# Vendored into this instance by \`biffo plugin install\`: resolve dependencies the
|
|
6782
|
+
# instance's uv workspace provides as members from the workspace, not PyPI.
|
|
6783
|
+
[tool.uv.sources]
|
|
6784
|
+
${lines.join("\n")}
|
|
6785
|
+
`;
|
|
6786
|
+
}
|
|
6787
|
+
writeFileSync9(pluginPyprojectPath, updated);
|
|
6788
|
+
return toAdd;
|
|
6789
|
+
}
|
|
6790
|
+
|
|
6677
6791
|
// src/commands/plugin-install.ts
|
|
6678
6792
|
var TARGET_PATTERN = /^([a-z][a-z0-9-]*)@(\d+\.\d+)$/;
|
|
6679
6793
|
var pluginInstallCommand = new Command15("install").description(
|
|
@@ -6716,14 +6830,14 @@ var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
|
6716
6830
|
".terraform"
|
|
6717
6831
|
]);
|
|
6718
6832
|
function resolveLocalPlugin(localPath) {
|
|
6719
|
-
if (!
|
|
6833
|
+
if (!existsSync25(localPath)) {
|
|
6720
6834
|
throw new Error(`--local path does not exist: ${localPath}`);
|
|
6721
6835
|
}
|
|
6722
6836
|
if (!statSync6(localPath).isDirectory()) {
|
|
6723
6837
|
throw new Error(`--local path is not a directory: ${localPath}`);
|
|
6724
6838
|
}
|
|
6725
|
-
const manifestPath =
|
|
6726
|
-
if (!
|
|
6839
|
+
const manifestPath = join26(localPath, "biffo.plugin.json");
|
|
6840
|
+
if (!existsSync25(manifestPath)) {
|
|
6727
6841
|
throw new Error(
|
|
6728
6842
|
`${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>\`.)`
|
|
6729
6843
|
);
|
|
@@ -6749,8 +6863,8 @@ function parsePluginTarget(target) {
|
|
|
6749
6863
|
async function cloneAndValidatePlugin(entry, git) {
|
|
6750
6864
|
const tmpDir = await git.cloneToTemp(entry.repo, `biffo-plugin-${entry.name}`);
|
|
6751
6865
|
try {
|
|
6752
|
-
const manifestPath =
|
|
6753
|
-
if (!
|
|
6866
|
+
const manifestPath = join26(tmpDir, "biffo.plugin.json");
|
|
6867
|
+
if (!existsSync25(manifestPath)) {
|
|
6754
6868
|
throw new Error(
|
|
6755
6869
|
`Plugin repo ${entry.repo} does not contain a biffo.plugin.json manifest at its root.`
|
|
6756
6870
|
);
|
|
@@ -6778,8 +6892,8 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6778
6892
|
`Nothing to install. Pass a registry target (e.g. \`biffo plugin install acme-crm@1.0\`) or a local plugin directory (\`biffo plugin install --local services/acme-crm\`).`
|
|
6779
6893
|
);
|
|
6780
6894
|
}
|
|
6781
|
-
const servicesDir =
|
|
6782
|
-
if (!
|
|
6895
|
+
const servicesDir = join26(options.cwd, "services");
|
|
6896
|
+
if (!existsSync25(servicesDir)) {
|
|
6783
6897
|
throw new Error(
|
|
6784
6898
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
6785
6899
|
);
|
|
@@ -6797,10 +6911,10 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6797
6911
|
}
|
|
6798
6912
|
const pluginName = entry ? entry.name : source.name;
|
|
6799
6913
|
const relTargetDir = pluginDir(pluginName, "third-party");
|
|
6800
|
-
const targetDir =
|
|
6801
|
-
const modulesDir =
|
|
6914
|
+
const targetDir = join26(options.cwd, relTargetDir);
|
|
6915
|
+
const modulesDir = join26(options.cwd, "modules", "plugins", pluginName);
|
|
6802
6916
|
const inTreeSource = options.local !== void 0 && resolve12(options.local) === resolve12(targetDir);
|
|
6803
|
-
if (
|
|
6917
|
+
if (existsSync25(targetDir) && !inTreeSource) {
|
|
6804
6918
|
throw new Error(
|
|
6805
6919
|
`Plugin '${pluginName}' is already installed at ${relTargetDir}/. Remove it first, or wait for a future 'biffo plugin upgrade' command.`
|
|
6806
6920
|
);
|
|
@@ -6842,9 +6956,18 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6842
6956
|
});
|
|
6843
6957
|
log.success(`Installed plugin source at ${relTargetDir}/`);
|
|
6844
6958
|
}
|
|
6959
|
+
const pluginPyproject = join26(targetDir, "pyproject.toml");
|
|
6960
|
+
if (existsSync25(pluginPyproject)) {
|
|
6961
|
+
const sourced = ensureWorkspaceSources(pluginPyproject, workspaceMemberNames(options.cwd));
|
|
6962
|
+
if (sourced.length > 0) {
|
|
6963
|
+
log.info(
|
|
6964
|
+
`Sourced ${sourced.join(", ")} from the workspace in ${relTargetDir}/pyproject.toml (the instance provides it as a workspace member).`
|
|
6965
|
+
);
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6845
6968
|
const stagePaths = [relTargetDir];
|
|
6846
|
-
const tfSourceDir =
|
|
6847
|
-
if (
|
|
6969
|
+
const tfSourceDir = join26(targetDir, "terraform");
|
|
6970
|
+
if (existsSync25(tfSourceDir)) {
|
|
6848
6971
|
mkdirSync9(modulesDir, { recursive: true });
|
|
6849
6972
|
cpSync3(tfSourceDir, modulesDir, { recursive: true });
|
|
6850
6973
|
stagePaths.push(`modules/plugins/${pluginName}`);
|
|
@@ -6923,7 +7046,7 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6923
7046
|
}
|
|
6924
7047
|
function parseManifestFile(path) {
|
|
6925
7048
|
try {
|
|
6926
|
-
return JSON.parse(
|
|
7049
|
+
return JSON.parse(readFileSync19(path, "utf8"));
|
|
6927
7050
|
} catch (err) {
|
|
6928
7051
|
throw new Error(`Could not parse ${path} as JSON: ${err.message}`);
|
|
6929
7052
|
}
|
|
@@ -6960,8 +7083,8 @@ function printDryRun4(entry, source, relTargetDir, inTreeSource) {
|
|
|
6960
7083
|
}
|
|
6961
7084
|
|
|
6962
7085
|
// src/commands/plugin-list.ts
|
|
6963
|
-
import { existsSync as
|
|
6964
|
-
import { join as
|
|
7086
|
+
import { existsSync as existsSync26, readFileSync as readFileSync20 } from "fs";
|
|
7087
|
+
import { join as join27, resolve as resolve13 } from "path";
|
|
6965
7088
|
import chalk16 from "chalk";
|
|
6966
7089
|
import { Command as Command16 } from "commander";
|
|
6967
7090
|
var pluginListCommand = new Command16("list").description("List plugins installed in this project checkout").option("--cwd <path>", "Project root to scan (defaults to the current directory)").action(async (options) => {
|
|
@@ -6974,8 +7097,8 @@ var pluginListCommand = new Command16("list").description("List plugins installe
|
|
|
6974
7097
|
}
|
|
6975
7098
|
});
|
|
6976
7099
|
async function runPluginList(options) {
|
|
6977
|
-
const servicesDir =
|
|
6978
|
-
if (!
|
|
7100
|
+
const servicesDir = join27(options.cwd, "services");
|
|
7101
|
+
if (!existsSync26(servicesDir)) {
|
|
6979
7102
|
throw new Error(
|
|
6980
7103
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
6981
7104
|
);
|
|
@@ -6983,7 +7106,7 @@ async function runPluginList(options) {
|
|
|
6983
7106
|
const plugins = [];
|
|
6984
7107
|
for (const location of findInstalledPlugins(options.cwd)) {
|
|
6985
7108
|
try {
|
|
6986
|
-
const manifest = validateManifest(JSON.parse(
|
|
7109
|
+
const manifest = validateManifest(JSON.parse(readFileSync20(location.manifestPath, "utf8")));
|
|
6987
7110
|
plugins.push({
|
|
6988
7111
|
name: manifest.name,
|
|
6989
7112
|
version: manifest.version,
|
|
@@ -7020,8 +7143,8 @@ async function runPluginList(options) {
|
|
|
7020
7143
|
}
|
|
7021
7144
|
|
|
7022
7145
|
// src/commands/plugin-sync-migrations.ts
|
|
7023
|
-
import { existsSync as
|
|
7024
|
-
import { join as
|
|
7146
|
+
import { existsSync as existsSync27 } from "fs";
|
|
7147
|
+
import { join as join28, relative as relative4, resolve as resolve14 } from "path";
|
|
7025
7148
|
import chalk17 from "chalk";
|
|
7026
7149
|
import { Command as Command17 } from "commander";
|
|
7027
7150
|
var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
@@ -7042,11 +7165,11 @@ var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
|
7042
7165
|
}
|
|
7043
7166
|
);
|
|
7044
7167
|
async function runPluginSyncMigrations(name, options, deps) {
|
|
7045
|
-
const servicesDir =
|
|
7046
|
-
if (!
|
|
7168
|
+
const servicesDir = join28(options.cwd, "services");
|
|
7169
|
+
if (!existsSync27(servicesDir)) {
|
|
7047
7170
|
throw new Error(`${servicesDir} does not exist \u2014 is ${options.cwd} a Biffo project checkout?`);
|
|
7048
7171
|
}
|
|
7049
|
-
if (name && !
|
|
7172
|
+
if (name && !existsSync27(join28(servicesDir, name, "biffo.plugin.json"))) {
|
|
7050
7173
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
7051
7174
|
}
|
|
7052
7175
|
if (options.dryRun) {
|
|
@@ -7082,8 +7205,8 @@ async function runPluginSyncMigrations(name, options, deps) {
|
|
|
7082
7205
|
}
|
|
7083
7206
|
|
|
7084
7207
|
// src/commands/plugin-uninstall.ts
|
|
7085
|
-
import { existsSync as
|
|
7086
|
-
import { join as
|
|
7208
|
+
import { existsSync as existsSync28, readFileSync as readFileSync21, rmSync as rmSync8 } from "fs";
|
|
7209
|
+
import { join as join29, resolve as resolve15 } from "path";
|
|
7087
7210
|
import chalk18 from "chalk";
|
|
7088
7211
|
import { Command as Command18 } from "commander";
|
|
7089
7212
|
import inquirer6 from "inquirer";
|
|
@@ -7115,16 +7238,16 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7115
7238
|
if (!NAME_PATTERN2.test(name)) {
|
|
7116
7239
|
throw new Error(`Invalid plugin name '${name}'. Expected a lowercase kebab-case slug.`);
|
|
7117
7240
|
}
|
|
7118
|
-
const servicesDir =
|
|
7119
|
-
if (!
|
|
7241
|
+
const servicesDir = join29(options.cwd, "services");
|
|
7242
|
+
if (!existsSync28(servicesDir)) {
|
|
7120
7243
|
throw new Error(
|
|
7121
7244
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
7122
7245
|
);
|
|
7123
7246
|
}
|
|
7124
|
-
const targetDir =
|
|
7125
|
-
if (!
|
|
7126
|
-
const firstParty =
|
|
7127
|
-
if (
|
|
7247
|
+
const targetDir = join29(servicesDir, name);
|
|
7248
|
+
if (!existsSync28(targetDir)) {
|
|
7249
|
+
const firstParty = join29(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
|
|
7250
|
+
if (existsSync28(firstParty)) {
|
|
7128
7251
|
throw new Error(
|
|
7129
7252
|
`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.`
|
|
7130
7253
|
);
|
|
@@ -7132,9 +7255,9 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7132
7255
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
7133
7256
|
}
|
|
7134
7257
|
const version = readInstalledVersion(targetDir);
|
|
7135
|
-
const modulesDir =
|
|
7258
|
+
const modulesDir = join29(options.cwd, "modules", "plugins", name);
|
|
7136
7259
|
const stagePaths = [`services/${name}`];
|
|
7137
|
-
if (
|
|
7260
|
+
if (existsSync28(modulesDir)) {
|
|
7138
7261
|
stagePaths.push(`modules/plugins/${name}`);
|
|
7139
7262
|
}
|
|
7140
7263
|
if (options.dryRun) {
|
|
@@ -7156,7 +7279,7 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7156
7279
|
}
|
|
7157
7280
|
rmSync8(targetDir, { recursive: true, force: true });
|
|
7158
7281
|
log.success(`Removed services/${name}/`);
|
|
7159
|
-
if (
|
|
7282
|
+
if (existsSync28(modulesDir)) {
|
|
7160
7283
|
rmSync8(modulesDir, { recursive: true, force: true });
|
|
7161
7284
|
log.success(`Removed modules/plugins/${name}/`);
|
|
7162
7285
|
const wiring = syncPluginTerraform(options.cwd);
|
|
@@ -7193,10 +7316,10 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7193
7316
|
}
|
|
7194
7317
|
}
|
|
7195
7318
|
function readInstalledVersion(targetDir) {
|
|
7196
|
-
const manifestPath =
|
|
7197
|
-
if (!
|
|
7319
|
+
const manifestPath = join29(targetDir, "biffo.plugin.json");
|
|
7320
|
+
if (!existsSync28(manifestPath)) return void 0;
|
|
7198
7321
|
try {
|
|
7199
|
-
return validateManifest(JSON.parse(
|
|
7322
|
+
return validateManifest(JSON.parse(readFileSync21(manifestPath, "utf8"))).version;
|
|
7200
7323
|
} catch {
|
|
7201
7324
|
return void 0;
|
|
7202
7325
|
}
|
|
@@ -7229,8 +7352,8 @@ function printDryRun5(name, version, stagePaths, keepData) {
|
|
|
7229
7352
|
}
|
|
7230
7353
|
|
|
7231
7354
|
// src/commands/plugin-upgrade.ts
|
|
7232
|
-
import { cpSync as cpSync4, existsSync as
|
|
7233
|
-
import { join as
|
|
7355
|
+
import { cpSync as cpSync4, existsSync as existsSync29, mkdirSync as mkdirSync10, readFileSync as readFileSync22, rmSync as rmSync9 } from "fs";
|
|
7356
|
+
import { join as join30, relative as relative5, resolve as resolve16 } from "path";
|
|
7234
7357
|
import chalk19 from "chalk";
|
|
7235
7358
|
import { Command as Command19 } from "commander";
|
|
7236
7359
|
import inquirer7 from "inquirer";
|
|
@@ -7255,14 +7378,14 @@ var pluginUpgradeCommand = new Command19("upgrade").description(
|
|
|
7255
7378
|
});
|
|
7256
7379
|
async function runPluginUpgrade(target, options, deps) {
|
|
7257
7380
|
const { name, minor } = parsePluginTarget(target);
|
|
7258
|
-
const servicesDir =
|
|
7259
|
-
if (!
|
|
7381
|
+
const servicesDir = join30(options.cwd, "services");
|
|
7382
|
+
if (!existsSync29(servicesDir)) {
|
|
7260
7383
|
throw new Error(
|
|
7261
7384
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
7262
7385
|
);
|
|
7263
7386
|
}
|
|
7264
|
-
const targetDir =
|
|
7265
|
-
if (!
|
|
7387
|
+
const targetDir = join30(servicesDir, name);
|
|
7388
|
+
if (!existsSync29(targetDir)) {
|
|
7266
7389
|
throw new Error(
|
|
7267
7390
|
`Plugin '${name}' is not installed at services/${name}/. Use 'biffo plugin install ${name}@${minor}' instead.`
|
|
7268
7391
|
);
|
|
@@ -7276,7 +7399,7 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7276
7399
|
`Plugin declares required_core_version '${entry.required_core_version}'. The CLI cannot verify this against your deployment \u2014 the Core API exposes no version endpoint and services/api/pyproject.toml's version is a static placeholder, not a real release marker. Confirm compatibility yourself before deploying.`
|
|
7277
7400
|
);
|
|
7278
7401
|
}
|
|
7279
|
-
const modulesDir =
|
|
7402
|
+
const modulesDir = join30(options.cwd, "modules", "plugins", entry.name);
|
|
7280
7403
|
if (options.dryRun) {
|
|
7281
7404
|
printDryRun6(entry, currentVersion);
|
|
7282
7405
|
return;
|
|
@@ -7309,11 +7432,11 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7309
7432
|
cpSync4(tmpDir, targetDir, { recursive: true });
|
|
7310
7433
|
log.success(`Upgraded plugin source at services/${entry.name}/`);
|
|
7311
7434
|
const stagePaths = [`services/${entry.name}`];
|
|
7312
|
-
if (
|
|
7435
|
+
if (existsSync29(modulesDir)) {
|
|
7313
7436
|
rmSync9(modulesDir, { recursive: true, force: true });
|
|
7314
7437
|
}
|
|
7315
|
-
const tfSourceDir =
|
|
7316
|
-
if (
|
|
7438
|
+
const tfSourceDir = join30(targetDir, "terraform");
|
|
7439
|
+
if (existsSync29(tfSourceDir)) {
|
|
7317
7440
|
mkdirSync10(modulesDir, { recursive: true });
|
|
7318
7441
|
cpSync4(tfSourceDir, modulesDir, { recursive: true });
|
|
7319
7442
|
stagePaths.push(`modules/plugins/${entry.name}`);
|
|
@@ -7347,10 +7470,10 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7347
7470
|
}
|
|
7348
7471
|
}
|
|
7349
7472
|
function readInstalledVersion2(targetDir) {
|
|
7350
|
-
const manifestPath =
|
|
7351
|
-
if (!
|
|
7473
|
+
const manifestPath = join30(targetDir, "biffo.plugin.json");
|
|
7474
|
+
if (!existsSync29(manifestPath)) return void 0;
|
|
7352
7475
|
try {
|
|
7353
|
-
return validateManifest(JSON.parse(
|
|
7476
|
+
return validateManifest(JSON.parse(readFileSync22(manifestPath, "utf8"))).version;
|
|
7354
7477
|
} catch {
|
|
7355
7478
|
return void 0;
|
|
7356
7479
|
}
|
|
@@ -7379,14 +7502,14 @@ function printDryRun6(entry, currentVersion) {
|
|
|
7379
7502
|
}
|
|
7380
7503
|
|
|
7381
7504
|
// src/commands/plugin-wire.ts
|
|
7382
|
-
import { existsSync as
|
|
7505
|
+
import { existsSync as existsSync31, readFileSync as readFileSync24 } from "fs";
|
|
7383
7506
|
import { resolve as resolve17 } from "path";
|
|
7384
7507
|
import chalk20 from "chalk";
|
|
7385
7508
|
import { Command as Command20 } from "commander";
|
|
7386
7509
|
|
|
7387
7510
|
// src/lib/plugin-origin.ts
|
|
7388
|
-
import { existsSync as
|
|
7389
|
-
import { join as
|
|
7511
|
+
import { existsSync as existsSync30, readFileSync as readFileSync23, writeFileSync as writeFileSync10 } from "fs";
|
|
7512
|
+
import { join as join31 } from "path";
|
|
7390
7513
|
var PLUGIN_API_TFVARS = "plugin-apis.auto.tfvars.json";
|
|
7391
7514
|
var SIBLINGS_TFVARS = "siblings.auto.tfvars.json";
|
|
7392
7515
|
function upsertPluginApiOrigin(existing, entry) {
|
|
@@ -7396,9 +7519,9 @@ function serializePluginApiRegistry(origins) {
|
|
|
7396
7519
|
return JSON.stringify({ plugin_api_origins: origins }, null, 2) + "\n";
|
|
7397
7520
|
}
|
|
7398
7521
|
function readArray(path, key) {
|
|
7399
|
-
if (!
|
|
7522
|
+
if (!existsSync30(path)) return [];
|
|
7400
7523
|
try {
|
|
7401
|
-
const parsed = JSON.parse(
|
|
7524
|
+
const parsed = JSON.parse(readFileSync23(path, "utf8"));
|
|
7402
7525
|
const arr = parsed[key];
|
|
7403
7526
|
return Array.isArray(arr) ? arr : [];
|
|
7404
7527
|
} catch {
|
|
@@ -7406,19 +7529,19 @@ function readArray(path, key) {
|
|
|
7406
7529
|
}
|
|
7407
7530
|
}
|
|
7408
7531
|
function registerUserFacingPlugin(cwd, environment, reg) {
|
|
7409
|
-
const envDir =
|
|
7410
|
-
const apiPath =
|
|
7411
|
-
const siblingPath =
|
|
7532
|
+
const envDir = join31(cwd, "infra", "environments", environment);
|
|
7533
|
+
const apiPath = join31(envDir, PLUGIN_API_TFVARS);
|
|
7534
|
+
const siblingPath = join31(envDir, SIBLINGS_TFVARS);
|
|
7412
7535
|
const apis = upsertPluginApiOrigin(readArray(apiPath, "plugin_api_origins"), {
|
|
7413
7536
|
name: reg.name,
|
|
7414
7537
|
function_url_domain: reg.functionUrlDomain
|
|
7415
7538
|
});
|
|
7416
|
-
|
|
7539
|
+
writeFileSync10(apiPath, serializePluginApiRegistry(apis));
|
|
7417
7540
|
const siblings = upsertSiblingOrigin(readArray(siblingPath, "sibling_origins"), {
|
|
7418
7541
|
name: reg.name,
|
|
7419
7542
|
bucket_regional_domain: reg.bucketRegionalDomain
|
|
7420
7543
|
});
|
|
7421
|
-
|
|
7544
|
+
writeFileSync10(siblingPath, serializeRegistry(siblings));
|
|
7422
7545
|
return [
|
|
7423
7546
|
`infra/environments/${environment}/${PLUGIN_API_TFVARS}`,
|
|
7424
7547
|
`infra/environments/${environment}/${SIBLINGS_TFVARS}`
|
|
@@ -7499,7 +7622,7 @@ var pluginWireCommand = new Command20("wire").description(
|
|
|
7499
7622
|
);
|
|
7500
7623
|
async function resolveConfig4(options) {
|
|
7501
7624
|
if (options.config) {
|
|
7502
|
-
const raw = JSON.parse(
|
|
7625
|
+
const raw = JSON.parse(readFileSync24(resolve17(options.config), "utf8"));
|
|
7503
7626
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7504
7627
|
if (!result.success) {
|
|
7505
7628
|
log.error(`Invalid config at ${options.config}:`);
|
|
@@ -7519,8 +7642,8 @@ async function resolveConfig4(options) {
|
|
|
7519
7642
|
return cfg;
|
|
7520
7643
|
}
|
|
7521
7644
|
const localConfigPath = resolve17(process.cwd(), "biffo.config.json");
|
|
7522
|
-
if (
|
|
7523
|
-
const raw = JSON.parse(
|
|
7645
|
+
if (existsSync31(localConfigPath)) {
|
|
7646
|
+
const raw = JSON.parse(readFileSync24(localConfigPath, "utf8"));
|
|
7524
7647
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7525
7648
|
if (result.success) return result.data;
|
|
7526
7649
|
if (isTemplatePlaceholderConfig(raw)) {
|
|
@@ -7555,7 +7678,7 @@ pluginCommand.addCommand(pluginInfoCommand);
|
|
|
7555
7678
|
import { Command as Command23 } from "commander";
|
|
7556
7679
|
|
|
7557
7680
|
// src/commands/sibling-check-identity.ts
|
|
7558
|
-
import { existsSync as
|
|
7681
|
+
import { existsSync as existsSync32, readFileSync as readFileSync25 } from "fs";
|
|
7559
7682
|
import { resolve as resolve18 } from "path";
|
|
7560
7683
|
import chalk21 from "chalk";
|
|
7561
7684
|
import { Command as Command22 } from "commander";
|
|
@@ -7749,7 +7872,7 @@ async function fetchPublishedIdentity(portalUrl) {
|
|
|
7749
7872
|
}
|
|
7750
7873
|
async function resolveConfig5(options) {
|
|
7751
7874
|
if (options.config) {
|
|
7752
|
-
const raw = JSON.parse(
|
|
7875
|
+
const raw = JSON.parse(readFileSync25(resolve18(options.config), "utf8"));
|
|
7753
7876
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7754
7877
|
if (!result.success) {
|
|
7755
7878
|
log.error(`Invalid config at ${options.config}:`);
|
|
@@ -7769,8 +7892,8 @@ async function resolveConfig5(options) {
|
|
|
7769
7892
|
return cfg;
|
|
7770
7893
|
}
|
|
7771
7894
|
const localConfigPath = resolve18(process.cwd(), "biffo.config.json");
|
|
7772
|
-
if (
|
|
7773
|
-
const raw = JSON.parse(
|
|
7895
|
+
if (existsSync32(localConfigPath)) {
|
|
7896
|
+
const raw = JSON.parse(readFileSync25(localConfigPath, "utf8"));
|
|
7774
7897
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7775
7898
|
if (result.success) return result.data;
|
|
7776
7899
|
if (isTemplatePlaceholderConfig(raw)) {
|
|
@@ -7839,8 +7962,8 @@ async function runOwnershipCheck(argv) {
|
|
|
7839
7962
|
const { stdout } = await execa5("git", ["diff", "--cached", "--name-status"], { cwd: root });
|
|
7840
7963
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
7841
7964
|
if (messageFile) {
|
|
7842
|
-
const { readFileSync:
|
|
7843
|
-
if (
|
|
7965
|
+
const { readFileSync: readFileSync27, existsSync: existsSync34 } = await import("fs");
|
|
7966
|
+
if (existsSync34(messageFile)) commitMessage = readFileSync27(messageFile, "utf8");
|
|
7844
7967
|
}
|
|
7845
7968
|
} else {
|
|
7846
7969
|
const base = process.env["GITHUB_BASE_REF"] ?? args[0];
|
|
@@ -7944,8 +8067,8 @@ ${BOLD}If the divergence is deliberate${OFF}
|
|
|
7944
8067
|
import { execa as execa6 } from "execa";
|
|
7945
8068
|
|
|
7946
8069
|
// src/lib/plugin-terraform-guard.ts
|
|
7947
|
-
import { existsSync as
|
|
7948
|
-
import { dirname as dirname9, join as
|
|
8070
|
+
import { existsSync as existsSync33, readFileSync as readFileSync26, readdirSync as readdirSync13 } from "fs";
|
|
8071
|
+
import { dirname as dirname9, join as join32, relative as relative6, sep as sep3 } from "path";
|
|
7949
8072
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
|
|
7950
8073
|
var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
|
|
7951
8074
|
function findPluginManifests(root) {
|
|
@@ -7953,16 +8076,16 @@ function findPluginManifests(root) {
|
|
|
7953
8076
|
const walk = (dir) => {
|
|
7954
8077
|
let entries;
|
|
7955
8078
|
try {
|
|
7956
|
-
entries =
|
|
8079
|
+
entries = readdirSync13(dir, { withFileTypes: true });
|
|
7957
8080
|
} catch {
|
|
7958
8081
|
return;
|
|
7959
8082
|
}
|
|
7960
8083
|
for (const entry of entries) {
|
|
7961
8084
|
if (entry.isDirectory()) {
|
|
7962
8085
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
7963
|
-
walk(
|
|
8086
|
+
walk(join32(dir, entry.name));
|
|
7964
8087
|
} else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
|
|
7965
|
-
found.push(relative6(root,
|
|
8088
|
+
found.push(relative6(root, join32(dir, entry.name)).split(sep3).join("/"));
|
|
7966
8089
|
}
|
|
7967
8090
|
}
|
|
7968
8091
|
};
|
|
@@ -7972,7 +8095,7 @@ function findPluginManifests(root) {
|
|
|
7972
8095
|
function readSubscriptions(absManifestPath) {
|
|
7973
8096
|
let parsed;
|
|
7974
8097
|
try {
|
|
7975
|
-
parsed = JSON.parse(
|
|
8098
|
+
parsed = JSON.parse(readFileSync26(absManifestPath, "utf8"));
|
|
7976
8099
|
} catch {
|
|
7977
8100
|
return null;
|
|
7978
8101
|
}
|
|
@@ -7987,14 +8110,14 @@ function readSubscriptions(absManifestPath) {
|
|
|
7987
8110
|
}
|
|
7988
8111
|
function checkPluginTerraform(root) {
|
|
7989
8112
|
const violations = [];
|
|
7990
|
-
const coreManifest =
|
|
8113
|
+
const coreManifest = existsSync33(join32(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
|
|
7991
8114
|
for (const manifest of findPluginManifests(root)) {
|
|
7992
8115
|
if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
|
|
7993
|
-
const absManifest =
|
|
8116
|
+
const absManifest = join32(root, manifest);
|
|
7994
8117
|
const subscriptions = readSubscriptions(absManifest);
|
|
7995
8118
|
if (subscriptions === null) continue;
|
|
7996
8119
|
const pluginDir2 = dirname9(absManifest);
|
|
7997
|
-
if (
|
|
8120
|
+
if (existsSync33(join32(pluginDir2, "terraform"))) continue;
|
|
7998
8121
|
const relPluginDir = relative6(root, pluginDir2).split(sep3).join("/");
|
|
7999
8122
|
violations.push({
|
|
8000
8123
|
manifest,
|