@saptools/bruno 0.3.2 → 0.3.3
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/cli.js +92 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.js +53 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -716,14 +716,12 @@ function pickSpace(org) {
|
|
|
716
716
|
function pickApp(space) {
|
|
717
717
|
return space.apps.map((a) => ({ value: a.name, name: a.name }));
|
|
718
718
|
}
|
|
719
|
-
async function
|
|
720
|
-
const deps = options.deps ?? defaultCfInfoDeps;
|
|
721
|
-
const log = options.log ?? (() => void 0);
|
|
719
|
+
async function selectRegion(prompts, deps) {
|
|
722
720
|
const regions = await listRegionsWithContent(deps);
|
|
723
721
|
if (regions.length === 0) {
|
|
724
722
|
throw new Error("No CF regions with orgs are cached. Run `cf-sync sync` first.");
|
|
725
723
|
}
|
|
726
|
-
const regionKey = await
|
|
724
|
+
const regionKey = await prompts.selectRegion(pickRegion(regions));
|
|
727
725
|
const regionView = await deps.readRegionView(regionKey);
|
|
728
726
|
if (!regionView) {
|
|
729
727
|
throw new Error(`Region ${regionKey} is not cached. Run \`cf-sync region ${regionKey}\` or \`cf-sync sync\` first.`);
|
|
@@ -732,7 +730,10 @@ async function setupApp(options) {
|
|
|
732
730
|
if (region.orgs.length === 0) {
|
|
733
731
|
throw new Error(`Region ${regionKey} has no accessible orgs.`);
|
|
734
732
|
}
|
|
735
|
-
|
|
733
|
+
return { regionKey, region };
|
|
734
|
+
}
|
|
735
|
+
async function selectOrg(prompts, region, regionKey) {
|
|
736
|
+
const orgName = await prompts.selectOrg(pickOrg(region));
|
|
736
737
|
const org = region.orgs.find((o) => o.name === orgName);
|
|
737
738
|
if (!org) {
|
|
738
739
|
throw new Error(`Org ${orgName} not found in region ${regionKey}`);
|
|
@@ -740,7 +741,10 @@ async function setupApp(options) {
|
|
|
740
741
|
if (org.spaces.length === 0) {
|
|
741
742
|
throw new Error(`Org ${orgName} has no spaces.`);
|
|
742
743
|
}
|
|
743
|
-
|
|
744
|
+
return { orgName, org };
|
|
745
|
+
}
|
|
746
|
+
async function selectSpace(prompts, org, orgName) {
|
|
747
|
+
const spaceName = await prompts.selectSpace(pickSpace(org));
|
|
744
748
|
const space = org.spaces.find((s) => s.name === spaceName);
|
|
745
749
|
if (!space) {
|
|
746
750
|
throw new Error(`Space ${spaceName} not found in org ${orgName}`);
|
|
@@ -748,24 +752,25 @@ async function setupApp(options) {
|
|
|
748
752
|
if (space.apps.length === 0) {
|
|
749
753
|
throw new Error(`Space ${spaceName} has no apps.`);
|
|
750
754
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
755
|
+
return { spaceName, space };
|
|
756
|
+
}
|
|
757
|
+
async function selectCfAppRef(prompts, deps) {
|
|
758
|
+
const { regionKey, region } = await selectRegion(prompts, deps);
|
|
759
|
+
const { orgName, org } = await selectOrg(prompts, region, regionKey);
|
|
760
|
+
const { spaceName, space } = await selectSpace(prompts, org, orgName);
|
|
761
|
+
const appName = await prompts.selectApp(pickApp(space));
|
|
762
|
+
return { region: regionKey, org: orgName, space: spaceName, app: appName };
|
|
763
|
+
}
|
|
764
|
+
function appPathFor(root, ref) {
|
|
765
|
+
return join4(
|
|
766
|
+
root,
|
|
767
|
+
regionFolderName(ref.region),
|
|
768
|
+
orgFolderName(ref.org),
|
|
769
|
+
spaceFolderName(ref.space),
|
|
770
|
+
ref.app
|
|
759
771
|
);
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
return { ref, appPath, environments: [], created: false };
|
|
763
|
-
}
|
|
764
|
-
await mkdir(appPath, { recursive: true });
|
|
765
|
-
await ensureCollectionConfig(appPath);
|
|
766
|
-
const existingEnvs = await listExistingEnvs(appPath);
|
|
767
|
-
const common = [...COMMON_ENVIRONMENTS];
|
|
768
|
-
const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });
|
|
772
|
+
}
|
|
773
|
+
function normalizeEnvironmentNames(selected) {
|
|
769
774
|
const merged = [];
|
|
770
775
|
for (const name of selected) {
|
|
771
776
|
const trimmed = name.trim();
|
|
@@ -778,12 +783,36 @@ async function setupApp(options) {
|
|
|
778
783
|
if (merged.length === 0) {
|
|
779
784
|
throw new Error("At least one environment is required.");
|
|
780
785
|
}
|
|
786
|
+
return merged;
|
|
787
|
+
}
|
|
788
|
+
async function selectEnvironmentNames(appPath, prompts) {
|
|
789
|
+
const existingEnvs = await listExistingEnvs(appPath);
|
|
790
|
+
const common = [...COMMON_ENVIRONMENTS];
|
|
791
|
+
const selected = await prompts.selectEnvironments({ common, existing: existingEnvs });
|
|
792
|
+
return normalizeEnvironmentNames(selected);
|
|
793
|
+
}
|
|
794
|
+
async function createEnvironmentFiles(appPath, envNames, ref, log) {
|
|
781
795
|
const created = [];
|
|
782
|
-
for (const envName of
|
|
796
|
+
for (const envName of envNames) {
|
|
783
797
|
const path = await ensureEnvFile(appPath, envName, ref);
|
|
784
798
|
created.push(path);
|
|
785
799
|
log(`\u2022 ${path}`);
|
|
786
800
|
}
|
|
801
|
+
return created;
|
|
802
|
+
}
|
|
803
|
+
async function setupApp(options) {
|
|
804
|
+
const deps = options.deps ?? defaultCfInfoDeps;
|
|
805
|
+
const log = options.log ?? (() => void 0);
|
|
806
|
+
const ref = await selectCfAppRef(options.prompts, deps);
|
|
807
|
+
const appPath = appPathFor(options.root, ref);
|
|
808
|
+
const confirmed = await options.prompts.confirmCreate(appPath);
|
|
809
|
+
if (!confirmed) {
|
|
810
|
+
return { ref, appPath, environments: [], created: false };
|
|
811
|
+
}
|
|
812
|
+
await mkdir(appPath, { recursive: true });
|
|
813
|
+
await ensureCollectionConfig(appPath);
|
|
814
|
+
const envNames = await selectEnvironmentNames(appPath, options.prompts);
|
|
815
|
+
const created = await createEnvironmentFiles(appPath, envNames, ref, log);
|
|
787
816
|
return { ref, appPath, environments: created, created: true };
|
|
788
817
|
}
|
|
789
818
|
async function listExistingEnvs(appPath) {
|
|
@@ -1000,16 +1029,18 @@ function resolveCollectionDir(explicitCollection, explicitRoot) {
|
|
|
1000
1029
|
}
|
|
1001
1030
|
return process2.cwd();
|
|
1002
1031
|
}
|
|
1003
|
-
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1032
|
+
function resolveProgramCollectionDir(program) {
|
|
1033
|
+
const opts = program.opts();
|
|
1034
|
+
return resolveCollectionDir(opts.collection, opts.root);
|
|
1035
|
+
}
|
|
1036
|
+
function writeLine(message) {
|
|
1037
|
+
process2.stdout.write(`${message}
|
|
1038
|
+
`);
|
|
1039
|
+
}
|
|
1040
|
+
function registerSetupAppCommand(program) {
|
|
1006
1041
|
program.command("setup-app").description("Interactively scaffold a bruno app folder and seed __cf_* variables").action(async () => {
|
|
1007
|
-
const collectionDir = resolveCollectionDir(
|
|
1008
|
-
program.opts().collection,
|
|
1009
|
-
program.opts().root
|
|
1010
|
-
);
|
|
1011
1042
|
const result = await setupApp({
|
|
1012
|
-
root:
|
|
1043
|
+
root: resolveProgramCollectionDir(program),
|
|
1013
1044
|
prompts: {
|
|
1014
1045
|
selectRegion: async (choices) => await select({ message: "Select region", choices: [...choices] }),
|
|
1015
1046
|
selectOrg: async (choices) => await select({ message: "Select org", choices: [...choices] }),
|
|
@@ -1018,46 +1049,41 @@ async function main(argv) {
|
|
|
1018
1049
|
confirmCreate: async (path) => await confirm({ message: `Create ${path}?`, default: true }),
|
|
1019
1050
|
selectEnvironments: async (opts) => await promptForEnvironments(opts)
|
|
1020
1051
|
},
|
|
1021
|
-
log:
|
|
1022
|
-
process2.stdout.write(`${msg}
|
|
1023
|
-
`);
|
|
1024
|
-
}
|
|
1052
|
+
log: writeLine
|
|
1025
1053
|
});
|
|
1026
1054
|
if (!result.created) {
|
|
1027
|
-
|
|
1055
|
+
writeLine("Aborted.");
|
|
1028
1056
|
return;
|
|
1029
1057
|
}
|
|
1030
|
-
|
|
1031
|
-
`);
|
|
1058
|
+
writeLine(`\u2714 App folder ready at ${result.appPath}`);
|
|
1032
1059
|
});
|
|
1060
|
+
}
|
|
1061
|
+
async function resolveRunTarget(target) {
|
|
1062
|
+
if (target) {
|
|
1063
|
+
return target;
|
|
1064
|
+
}
|
|
1065
|
+
const ctx = await readContext();
|
|
1066
|
+
if (!ctx) {
|
|
1067
|
+
throw new Error(
|
|
1068
|
+
"No target specified and no default context is set. Run `saptools-bruno use <region/org/space/app>` first."
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
return `${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}`;
|
|
1072
|
+
}
|
|
1073
|
+
function registerRunCommand(program) {
|
|
1033
1074
|
program.command("run").description("Run a bruno request or folder, auto-injecting an XSUAA token").argument("[target]", "Shorthand path (region/org/space/app[/folder/file.bru]) or real path").option("-e, --env <name>", "Environment name (default: context or first)").action(
|
|
1034
1075
|
async (target, opts) => {
|
|
1035
|
-
const collectionDir = resolveCollectionDir(
|
|
1036
|
-
program.opts().collection,
|
|
1037
|
-
program.opts().root
|
|
1038
|
-
);
|
|
1039
|
-
let effectiveTarget = target;
|
|
1040
|
-
if (!effectiveTarget) {
|
|
1041
|
-
const ctx = await readContext();
|
|
1042
|
-
if (!ctx) {
|
|
1043
|
-
throw new Error(
|
|
1044
|
-
"No target specified and no default context is set. Run `saptools-bruno use <region/org/space/app>` first."
|
|
1045
|
-
);
|
|
1046
|
-
}
|
|
1047
|
-
effectiveTarget = `${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}`;
|
|
1048
|
-
}
|
|
1049
1076
|
const result = await runBruno({
|
|
1050
|
-
root:
|
|
1051
|
-
target:
|
|
1077
|
+
root: resolveProgramCollectionDir(program),
|
|
1078
|
+
target: await resolveRunTarget(target),
|
|
1052
1079
|
...opts.env ? { environment: opts.env } : {},
|
|
1053
|
-
log:
|
|
1054
|
-
process2.stdout.write(`${msg}
|
|
1055
|
-
`);
|
|
1056
|
-
}
|
|
1080
|
+
log: writeLine
|
|
1057
1081
|
});
|
|
1058
1082
|
process2.exit(result.code);
|
|
1059
1083
|
}
|
|
1060
1084
|
);
|
|
1085
|
+
}
|
|
1086
|
+
function registerUseCommand(program) {
|
|
1061
1087
|
program.command("use").description("Set the default CF context (region/org/space/app) for future `run` calls").argument("<shorthand>", "region/org/space/app").option("--no-verify", "Skip verifying the context against the cached CF structure").action(async (shorthand, opts) => {
|
|
1062
1088
|
const ctx = await useContext({
|
|
1063
1089
|
shorthand,
|
|
@@ -1066,6 +1092,13 @@ async function main(argv) {
|
|
|
1066
1092
|
process2.stdout.write(`\u2714 Default context set to ${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}
|
|
1067
1093
|
`);
|
|
1068
1094
|
});
|
|
1095
|
+
}
|
|
1096
|
+
async function main(argv) {
|
|
1097
|
+
const program = new Command();
|
|
1098
|
+
program.name("saptools-bruno").description("Smart runner for Bruno with CF-aware env metadata and automatic token injection").addOption(new Option("--collection <dir>", "Bruno collection directory (default: SAPTOOLS_BRUNO_COLLECTION or cwd)")).addOption(new Option("--root <dir>", "Legacy alias for --collection").hideHelp());
|
|
1099
|
+
registerSetupAppCommand(program);
|
|
1100
|
+
registerRunCommand(program);
|
|
1101
|
+
registerUseCommand(program);
|
|
1069
1102
|
await program.parseAsync([...argv]);
|
|
1070
1103
|
}
|
|
1071
1104
|
try {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/main.ts","../src/commands/run.ts","../src/bruno/parser.ts","../src/bruno/writer.ts","../src/cf/meta.ts","../src/collection/folder-scan.ts","../src/collection/paths.ts","../src/commands/setup-app.ts","../src/cf/info.ts","../src/state/context.ts","../src/commands/use.ts","../src/prompts/app-search.ts","../src/prompts/environment.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { confirm, select } from \"@inquirer/prompts\";\nimport { Command, Option } from \"commander\";\n\nimport { runBruno } from \"../commands/run.js\";\nimport { setupApp } from \"../commands/setup-app.js\";\nimport { useContext } from \"../commands/use.js\";\nimport { promptForAppSelection } from \"../prompts/app-search.js\";\nimport { promptForEnvironments } from \"../prompts/environment.js\";\nimport { readContext } from \"../state/context.js\";\n\nfunction resolveCollectionDir(explicitCollection: string | undefined, explicitRoot: string | undefined): string {\n if (explicitCollection) {\n return explicitCollection;\n }\n if (explicitRoot) {\n return explicitRoot;\n }\n if (process.env[\"SAPTOOLS_BRUNO_COLLECTION\"]) {\n return process.env[\"SAPTOOLS_BRUNO_COLLECTION\"];\n }\n if (process.env[\"SAPTOOLS_BRUNO_ROOT\"]) {\n return process.env[\"SAPTOOLS_BRUNO_ROOT\"];\n }\n return process.cwd();\n}\n\nexport async function main(argv: readonly string[]): Promise<void> {\n const program = new Command();\n\n program\n .name(\"saptools-bruno\")\n .description(\"Smart runner for Bruno with CF-aware env metadata and automatic token injection\")\n .addOption(new Option(\"--collection <dir>\", \"Bruno collection directory (default: SAPTOOLS_BRUNO_COLLECTION or cwd)\"))\n .addOption(new Option(\"--root <dir>\", \"Legacy alias for --collection\").hideHelp());\n\n program\n .command(\"setup-app\")\n .description(\"Interactively scaffold a bruno app folder and seed __cf_* variables\")\n .action(async (): Promise<void> => {\n const collectionDir = resolveCollectionDir(\n program.opts<{ collection?: string; root?: string }>().collection,\n program.opts<{ collection?: string; root?: string }>().root,\n );\n const result = await setupApp({\n root: collectionDir,\n prompts: {\n selectRegion: async (choices) => await select({ message: \"Select region\", choices: [...choices] }),\n selectOrg: async (choices) => await select({ message: \"Select org\", choices: [...choices] }),\n selectSpace: async (choices) => await select({ message: \"Select space\", choices: [...choices] }),\n selectApp: async (choices) => await promptForAppSelection(choices),\n confirmCreate: async (path) => await confirm({ message: `Create ${path}?`, default: true }),\n selectEnvironments: async (opts) => await promptForEnvironments(opts),\n },\n log: (msg) => {\n process.stdout.write(`${msg}\\n`);\n },\n });\n if (!result.created) {\n process.stdout.write(\"Aborted.\\n\");\n return;\n }\n process.stdout.write(`✔ App folder ready at ${result.appPath}\\n`);\n });\n\n program\n .command(\"run\")\n .description(\"Run a bruno request or folder, auto-injecting an XSUAA token\")\n .argument(\"[target]\", \"Shorthand path (region/org/space/app[/folder/file.bru]) or real path\")\n .option(\"-e, --env <name>\", \"Environment name (default: context or first)\")\n .action(\n async (\n target: string | undefined,\n opts: { env?: string },\n ): Promise<void> => {\n const collectionDir = resolveCollectionDir(\n program.opts<{ collection?: string; root?: string }>().collection,\n program.opts<{ collection?: string; root?: string }>().root,\n );\n let effectiveTarget = target;\n\n if (!effectiveTarget) {\n const ctx = await readContext();\n if (!ctx) {\n throw new Error(\n \"No target specified and no default context is set. Run `saptools-bruno use <region/org/space/app>` first.\",\n );\n }\n effectiveTarget = `${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}`;\n }\n\n const result = await runBruno({\n root: collectionDir,\n target: effectiveTarget,\n ...(opts.env ? { environment: opts.env } : {}),\n log: (msg) => {\n process.stdout.write(`${msg}\\n`);\n },\n });\n process.exit(result.code);\n },\n );\n\n program\n .command(\"use\")\n .description(\"Set the default CF context (region/org/space/app) for future `run` calls\")\n .argument(\"<shorthand>\", \"region/org/space/app\")\n .option(\"--no-verify\", \"Skip verifying the context against the cached CF structure\")\n .action(async (shorthand: string, opts: { verify?: boolean }): Promise<void> => {\n const ctx = await useContext({\n shorthand,\n verify: opts.verify !== false,\n });\n process.stdout.write(`✔ Default context set to ${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}\\n`);\n });\n\n await program.parseAsync([...argv]);\n}\n\ntry {\n await main(process.argv);\n} catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`Error: ${msg}\\n`);\n process.exit(1);\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\n\nimport type { AppRef } from \"@saptools/cf-xsuaa\";\nimport { getTokenCached as getTokenCachedApi } from \"@saptools/cf-xsuaa\";\n\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { readCfMetaFromFile } from \"../cf/meta.js\";\nimport type { ShorthandRef } from \"../collection/folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"../collection/folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\n\nexport type GetTokenCachedFn = (ref: AppRef) => Promise<string>;\n\nexport interface RunSpawnResult {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type SpawnBruFn = (\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n) => Promise<RunSpawnResult>;\n\nexport interface RunOptions {\n readonly root: string;\n readonly target: string;\n readonly environment?: string;\n readonly extraArgs?: readonly string[];\n readonly getTokenCached?: GetTokenCachedFn;\n readonly spawnBru?: SpawnBruFn;\n readonly log?: (msg: string) => void;\n}\n\nexport interface RunPlan {\n readonly filePath: string;\n readonly environment: string;\n readonly envFile: string;\n readonly meta: { readonly region: string; readonly org: string; readonly space: string; readonly app: string };\n readonly token: string;\n readonly bruArgs: readonly string[];\n readonly cwd: string;\n}\n\nexport interface RunResult extends RunPlan {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nconst require = createRequire(import.meta.url);\n\nexport interface BruRuntime {\n readonly command: string;\n readonly argsPrefix: readonly string[];\n}\n\nexport interface ResolveBruRuntimeDeps {\n readonly findOnPath?: (command: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;\n readonly readTextFile?: (path: string) => Promise<string>;\n readonly resolvePackageJsonPath?: () => string;\n}\n\nfunction pathEntries(env: NodeJS.ProcessEnv): readonly string[] {\n const value = env[\"PATH\"] ?? process.env[\"PATH\"] ?? \"\";\n return value.split(delimiter).filter((entry) => entry.length > 0);\n}\n\nfunction pathCandidates(command: string, env: NodeJS.ProcessEnv): readonly string[] {\n if (process.platform !== \"win32\" || command.includes(\".\")) {\n return [command];\n }\n const pathExt =\n env[\"PATHEXT\"]?.split(\";\").filter((entry) => entry.length > 0) ?? [\".COM\", \".EXE\", \".BAT\", \".CMD\"];\n return [command, ...pathExt.map((ext) => `${command}${ext}`)];\n}\n\nasync function findCommandOnPath(command: string, env: NodeJS.ProcessEnv): Promise<string | undefined> {\n const candidates = pathCandidates(command, env);\n for (const entry of pathEntries(env)) {\n for (const candidate of candidates) {\n const fullPath = join(entry, candidate);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction bruBinRelativePath(value: unknown): string | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const bin = value[\"bin\"];\n if (typeof bin === \"string\") {\n return bin;\n }\n if (!isRecord(bin)) {\n return undefined;\n }\n const bru = bin[\"bru\"];\n return typeof bru === \"string\" ? bru : undefined;\n}\n\nfunction defaultResolvePackageJsonPath(): string {\n return require.resolve(\"@usebruno/cli/package.json\");\n}\n\nasync function defaultReadTextFile(path: string): Promise<string> {\n return await readFile(path, \"utf8\");\n}\n\nasync function resolveBundledBruBinPath(\n deps: ResolveBruRuntimeDeps,\n): Promise<string | undefined> {\n try {\n const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();\n const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);\n const binPath = bruBinRelativePath(JSON.parse(raw) as unknown);\n if (!binPath) {\n return undefined;\n }\n return resolve(dirname(packageJsonPath), binPath);\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveBruRuntime(\n env: NodeJS.ProcessEnv = process.env,\n deps: ResolveBruRuntimeDeps = {},\n): Promise<BruRuntime> {\n const onPath = await (deps.findOnPath ?? findCommandOnPath)(\"bru\", env);\n if (onPath) {\n return { command: onPath, argsPrefix: [] };\n }\n const bundledBin = await resolveBundledBruBinPath(deps);\n if (bundledBin) {\n return { command: process.execPath, argsPrefix: [bundledBin] };\n }\n throw new Error(\n \"Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH.\",\n );\n}\n\nasync function defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n const runtime = await resolveBruRuntime(env);\n return await new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: \"pipe\" });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n process.stderr.write(chunk);\n });\n child.on(\"error\", rejectPromise);\n child.on(\"close\", (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\n });\n });\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveTarget(\n root: string,\n target: string,\n): Promise<{ readonly filePath: string; readonly shorthand: ShorthandRef | undefined }> {\n const direct = isAbsolute(target) ? target : resolve(process.cwd(), target);\n if (await exists(direct)) {\n return { filePath: direct, shorthand: undefined };\n }\n\n const shorthand = parseShorthandPath(target);\n if (!shorthand) {\n throw new Error(`Target not found: ${target}`);\n }\n\n const { region, org, space, app, filePath } = shorthand;\n const appDir = join(\n root,\n regionFolderName(region),\n orgFolderName(org),\n spaceFolderName(space),\n app,\n );\n\n if (!filePath) {\n return { filePath: appDir, shorthand };\n }\n\n const candidate = join(appDir, filePath);\n if (await exists(candidate)) {\n return { filePath: candidate, shorthand };\n }\n\n const withExt = candidate.endsWith(\".bru\") ? candidate : `${candidate}.bru`;\n if (await exists(withExt)) {\n return { filePath: withExt, shorthand };\n }\n\n throw new Error(`File not found: ${candidate}`);\n}\n\nasync function chooseEnvironmentFile(\n appDir: string,\n environment: string | undefined,\n): Promise<{ readonly envFile: string; readonly environment: string }> {\n if (environment) {\n const envFile = join(appDir, ENVIRONMENTS_DIR, `${environment}.bru`);\n if (!(await exists(envFile))) {\n throw new Error(`Environment file not found: ${envFile}`);\n }\n return { envFile, environment };\n }\n\n const collection = await scanCollection(resolve(appDir, \"..\", \"..\", \"..\", \"..\"));\n for (const region of collection.regions) {\n for (const org of region.orgs) {\n for (const space of org.spaces) {\n for (const app of space.apps) {\n if (app.path === appDir && app.environments.length > 0) {\n const first = app.environments[0];\n if (first) {\n return { envFile: first.path, environment: first.name };\n }\n }\n }\n }\n }\n }\n throw new Error(`No environment files found under ${appDir}/${ENVIRONMENTS_DIR}`);\n}\n\nfunction findAppDirFromFile(filePath: string, root: string): string {\n const rel = relative(root, filePath).split(sep);\n if (rel.length < 4) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n const [regionDir, orgDir, spaceDir, appDir] = rel;\n if (!regionDir || !orgDir || !spaceDir || !appDir) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n return join(root, regionDir, orgDir, spaceDir, appDir);\n}\n\nasync function persistAccessToken(envFile: string, token: string): Promise<void> {\n const raw = await readFile(envFile, \"utf8\");\n const { content, changed } = upsertVars(raw, new Map([[\"accessToken\", token]]));\n if (changed) {\n await writeFile(envFile, content, \"utf8\");\n }\n}\n\nexport async function buildRunPlan(options: RunOptions): Promise<RunPlan> {\n const { filePath } = await resolveTarget(options.root, options.target);\n const stats = await stat(filePath);\n\n let appDir: string;\n let requestFile: string | undefined;\n\n if (stats.isDirectory()) {\n appDir = filePath;\n requestFile = undefined;\n } else {\n appDir = findAppDirFromFile(filePath, options.root);\n requestFile = filePath;\n }\n\n const { envFile, environment } = await chooseEnvironmentFile(appDir, options.environment);\n\n const meta = await readCfMetaFromFile(envFile);\n if (!meta) {\n throw new Error(\n `Missing __cf_region/__cf_org/__cf_space/__cf_app in ${envFile}. Run \\`saptools-bruno setup-app\\` first.`,\n );\n }\n\n const getToken = options.getTokenCached ?? getTokenCachedApi;\n const token = await getToken(meta);\n await persistAccessToken(envFile, token);\n\n const bruArgs: string[] = [\"run\"];\n if (requestFile) {\n bruArgs.push(relative(appDir, requestFile) || \".\");\n }\n bruArgs.push(\"--env\", environment, \"--env-var\", `accessToken=${token}`);\n if (options.extraArgs) {\n bruArgs.push(...options.extraArgs);\n }\n\n return {\n filePath,\n environment,\n envFile,\n meta,\n token,\n bruArgs,\n cwd: appDir,\n };\n}\n\nexport async function runBruno(options: RunOptions): Promise<RunResult> {\n const plan = await buildRunPlan(options);\n const spawnFn = options.spawnBru ?? defaultSpawnBru;\n const env: NodeJS.ProcessEnv = { ...process.env, SAPTOOLS_ACCESS_TOKEN: plan.token };\n options.log?.(`▶ bru ${plan.bruArgs.join(\" \")} (cwd=${plan.cwd})`);\n const result = await spawnFn(plan.bruArgs, env, plan.cwd);\n return { ...plan, ...result };\n}\n","import type { BruVarsBlock } from \"../types.js\";\n\ninterface BlockRange {\n readonly header: string;\n readonly start: number;\n readonly end: number;\n readonly bodyStart: number;\n readonly bodyEnd: number;\n readonly open: \"{\" | \"[\";\n readonly close: \"}\" | \"]\";\n}\n\nconst HEADER_REGEX = /(^|\\n)[^\\S\\n]*([a-zA-Z][a-zA-Z0-9:_-]*)[^\\S\\n]*([{[])/g;\n\nfunction findMatchingClose(raw: string, open: \"{\" | \"[\", openIdx: number): number {\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 1;\n let i = openIdx + 1;\n while (i < raw.length) {\n const ch = raw[i];\n if (ch === open) {\n depth++;\n } else if (ch === close) {\n depth--;\n if (depth === 0) {\n return i;\n }\n }\n i++;\n }\n return -1;\n}\n\nexport function listBlocks(raw: string): readonly BlockRange[] {\n const blocks: BlockRange[] = [];\n HEADER_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = HEADER_REGEX.exec(raw)) !== null) {\n const leadingNewline = match[1] ?? \"\";\n const header = match[2];\n const open = match[3];\n if (header === undefined || (open !== \"{\" && open !== \"[\")) {\n continue;\n }\n const headerStart = match.index + leadingNewline.length;\n const openIdx = match.index + match[0].length - 1;\n const closeIdx = findMatchingClose(raw, open, openIdx);\n if (closeIdx === -1) {\n continue;\n }\n blocks.push({\n header,\n start: headerStart,\n end: closeIdx + 1,\n bodyStart: openIdx + 1,\n bodyEnd: closeIdx,\n open,\n close: open === \"{\" ? \"}\" : \"]\",\n });\n }\n return blocks;\n}\n\nexport function parseKeyValueBody(body: string): Map<string, string> {\n const entries = new Map<string, string>();\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n const colon = line.indexOf(\":\");\n if (colon === -1) {\n continue;\n }\n const key = line.slice(0, colon).trim();\n const value = line.slice(colon + 1).trim();\n if (key.length > 0) {\n entries.set(key, value);\n }\n }\n return entries;\n}\n\nexport function parseListBody(body: string): string[] {\n const items: string[] = [];\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n items.push(line);\n }\n return items;\n}\n\nexport interface ParsedBruEnv {\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport function parseBruEnvFile(raw: string): ParsedBruEnv {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n const entries = varsBlock\n ? parseKeyValueBody(raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd))\n : new Map<string, string>();\n const secrets = secretsBlock\n ? parseListBody(raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd))\n : [];\n\n return { vars: { entries }, secrets };\n}\n","import { listBlocks, parseKeyValueBody } from \"./parser.js\";\n\nexport interface UpsertResult {\n readonly content: string;\n readonly changed: boolean;\n}\n\nfunction formatVarsBlock(entries: ReadonlyMap<string, string>): string {\n const lines: string[] = [];\n for (const [key, value] of entries) {\n lines.push(` ${key}: ${value}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function upsertVars(\n raw: string,\n updates: ReadonlyMap<string, string>,\n): UpsertResult {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n\n if (!varsBlock) {\n const newBlock = `vars {\\n${formatVarsBlock(updates)}\\n}\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: updates.size > 0 };\n }\n\n const body = raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd);\n const existing = parseKeyValueBody(body);\n let changed = false;\n for (const [k, v] of updates) {\n if (existing.get(k) !== v) {\n existing.set(k, v);\n changed = true;\n }\n }\n\n if (!changed) {\n return { content: raw, changed: false };\n }\n\n const rebuilt = `\\n${formatVarsBlock(existing)}\\n`;\n const before = raw.slice(0, varsBlock.bodyStart);\n const after = raw.slice(varsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n\nexport function ensureSecretEntry(raw: string, secretName: string): UpsertResult {\n const blocks = listBlocks(raw);\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n if (!secretsBlock) {\n const newBlock = `vars:secret [\\n ${secretName}\\n]\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: true };\n }\n\n const body = raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd);\n const items = body\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\"//\"));\n if (items.includes(secretName)) {\n return { content: raw, changed: false };\n }\n items.push(secretName);\n const rebuilt = `\\n ${items.join(\"\\n \")}\\n`;\n const before = raw.slice(0, secretsBlock.bodyStart);\n const after = raw.slice(secretsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { CF_META_KEYS } from \"../types.js\";\nimport type { CfAppRef, CfMetaKey } from \"../types.js\";\n\nexport interface CfMeta {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport function readCfMetaFromVars(vars: ReadonlyMap<string, string>): CfMeta | undefined {\n const region = vars.get(\"__cf_region\");\n const org = vars.get(\"__cf_org\");\n const space = vars.get(\"__cf_space\");\n const app = vars.get(\"__cf_app\");\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport function buildCfMetaUpdates(ref: CfAppRef, baseUrl?: string): Map<string, string> {\n const updates = new Map<string, string>();\n const pairs: readonly [CfMetaKey, string][] = [\n [\"__cf_region\", ref.region],\n [\"__cf_org\", ref.org],\n [\"__cf_space\", ref.space],\n [\"__cf_app\", ref.app],\n ];\n for (const [k, v] of pairs) {\n updates.set(k, v);\n }\n if (baseUrl !== undefined) {\n updates.set(\"baseUrl\", baseUrl);\n }\n return updates;\n}\n\nexport function hasCfMeta(vars: ReadonlyMap<string, string>): boolean {\n return CF_META_KEYS.every((k) => {\n const v = vars.get(k);\n return v !== undefined && v.length > 0;\n });\n}\n\nexport async function readCfMetaFromFile(path: string): Promise<CfMeta | undefined> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return readCfMetaFromVars(parsed.vars.entries);\n}\n\nexport async function writeCfMetaToFile(\n path: string,\n ref: CfAppRef,\n baseUrl?: string,\n): Promise<boolean> {\n const raw = await readFile(path, \"utf8\");\n const updates = buildCfMetaUpdates(ref, baseUrl);\n const { content, changed } = upsertVars(raw, updates);\n if (changed) {\n await writeFile(path, content, \"utf8\");\n }\n return changed;\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"../types.js\";\n\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\n\nasync function safeReaddir(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function listFiles(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isFile()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function loadEnvFile(path: string, name: string): Promise<BruEnvFile> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return {\n path,\n name: name.replace(/\\.bru$/, \"\"),\n raw,\n vars: parsed.vars,\n secrets: parsed.secrets,\n };\n}\n\nasync function scanAppEnvironments(appPath: string): Promise<readonly BruEnvFile[]> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n const files = await listFiles(envDir);\n const bruFiles = files.filter((f) => f.endsWith(\".bru\"));\n const loaded: BruEnvFile[] = [];\n for (const file of bruFiles) {\n loaded.push(await loadEnvFile(join(envDir, file), file));\n }\n return loaded;\n}\n\nasync function scanApp(spacePath: string, name: string): Promise<AppFolder> {\n const appPath = join(spacePath, name);\n const environments = await scanAppEnvironments(appPath);\n return { path: appPath, name, environments };\n}\n\nasync function scanSpace(orgPath: string, dirName: string): Promise<SpaceFolder | undefined> {\n const name = parsePrefixedName(dirName, SPACE_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const spacePath = join(orgPath, dirName);\n const appDirs = await safeReaddir(spacePath);\n const apps: AppFolder[] = [];\n for (const appDir of appDirs) {\n apps.push(await scanApp(spacePath, appDir));\n }\n return { path: spacePath, name, apps };\n}\n\nasync function scanOrg(regionPath: string, dirName: string): Promise<OrgFolder | undefined> {\n const name = parsePrefixedName(dirName, ORG_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const orgPath = join(regionPath, dirName);\n const spaceDirs = await safeReaddir(orgPath);\n const spaces: SpaceFolder[] = [];\n for (const spaceDir of spaceDirs) {\n const space = await scanSpace(orgPath, spaceDir);\n if (space) {\n spaces.push(space);\n }\n }\n return { path: orgPath, name, spaces };\n}\n\nasync function scanRegion(root: string, dirName: string): Promise<RegionFolder | undefined> {\n const key = parsePrefixedName(dirName, REGION_FOLDER_PREFIX);\n if (key === undefined) {\n return undefined;\n }\n const regionPath = join(root, dirName);\n const orgDirs = await safeReaddir(regionPath);\n const orgs: OrgFolder[] = [];\n for (const orgDir of orgDirs) {\n const org = await scanOrg(regionPath, orgDir);\n if (org) {\n orgs.push(org);\n }\n }\n return { path: regionPath, key, orgs };\n}\n\nexport async function scanCollection(root: string): Promise<BrunoCollection> {\n const regionDirs = await safeReaddir(root);\n const regions: RegionFolder[] = [];\n for (const dir of regionDirs) {\n const region = await scanRegion(root, dir);\n if (region) {\n regions.push(region);\n }\n }\n return { root, regions };\n}\n\nexport interface ShorthandRef {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly environment?: string;\n readonly filePath?: string;\n}\n\nexport function parseShorthandPath(shorthand: string): ShorthandRef | undefined {\n const cleaned = shorthand.replace(/^[./]+/, \"\").replace(/\\\\/g, \"/\");\n const segs = cleaned.split(\"/\").filter((s) => s.length > 0);\n if (segs.length < 4) {\n return undefined;\n }\n const [region, org, space, app, ...rest] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n if (rest.length === 0) {\n return { region, org, space, app };\n }\n const filePath = rest.join(\"/\");\n const last = rest[rest.length - 1] ?? \"\";\n const environment = last.endsWith(\".bru\") ? last.replace(/\\.bru$/, \"\") : undefined;\n return environment\n ? { region, org, space, app, environment, filePath }\n : { region, org, space, app, filePath };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const SAPTOOLS_DIR_NAME = \".saptools\";\nexport const BRUNO_CONTEXT_FILENAME = \"bruno-context.json\";\n\nexport const REGION_FOLDER_PREFIX = \"region__\";\nexport const ORG_FOLDER_PREFIX = \"org__\";\nexport const SPACE_FOLDER_PREFIX = \"space__\";\nexport const ENVIRONMENTS_DIR = \"environments\";\n\nexport function saptoolsDir(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nexport function brunoContextPath(): string {\n return join(saptoolsDir(), BRUNO_CONTEXT_FILENAME);\n}\n\nexport function regionFolderName(key: string): string {\n return `${REGION_FOLDER_PREFIX}${key}`;\n}\n\nexport function orgFolderName(name: string): string {\n return `${ORG_FOLDER_PREFIX}${name}`;\n}\n\nexport function spaceFolderName(name: string): string {\n return `${SPACE_FOLDER_PREFIX}${name}`;\n}\n\nexport function parsePrefixedName(\n dirName: string,\n prefix: string,\n): string | undefined {\n if (!dirName.startsWith(prefix)) {\n return undefined;\n }\n return dirName.slice(prefix.length);\n}\n","import { mkdir, readdir, writeFile } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport type { OrgNode, RegionKey, RegionNode, SpaceNode } from \"@saptools/cf-sync\";\n\nimport type { CfInfoDeps } from \"../cf/info.js\";\nimport { defaultCfInfoDeps, listRegionsWithContent } from \"../cf/info.js\";\nimport { writeCfMetaToFile } from \"../cf/meta.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\nimport type { CfAppRef } from \"../types.js\";\n\nexport interface EnvironmentSelection {\n readonly common: readonly string[];\n readonly existing: readonly string[];\n}\n\nexport interface SetupAppPrompts {\n readonly selectRegion: (choices: readonly { value: RegionKey; name: string }[]) => Promise<RegionKey>;\n readonly selectOrg: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectSpace: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectApp: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly confirmCreate: (path: string) => Promise<boolean>;\n readonly selectEnvironments: (opts: EnvironmentSelection) => Promise<readonly string[]>;\n}\n\nexport interface SetupAppOptions {\n readonly root: string;\n readonly prompts: SetupAppPrompts;\n readonly deps?: CfInfoDeps;\n readonly log?: (msg: string) => void;\n}\n\nexport interface SetupAppResult {\n readonly ref: CfAppRef;\n readonly appPath: string;\n readonly environments: readonly string[];\n readonly created: boolean;\n}\n\nexport const COMMON_ENVIRONMENTS = [\"local\", \"dev\", \"staging\", \"prod\"] as const;\nconst BRUNO_COLLECTION_CONFIG_FILENAME = \"bruno.json\";\n\nexport const ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nexport function assertValidEnvName(name: string): void {\n if (!ENV_NAME_PATTERN.test(name)) {\n throw new Error(\n `Invalid environment name '${name}': only letters, digits, dot, underscore, and dash are allowed.`,\n );\n }\n}\n\nfunction emptyEnvContent(envName: string, ref: CfAppRef): string {\n const lines = [\n \"vars {\",\n ` __cf_region: ${ref.region}`,\n ` __cf_org: ${ref.org}`,\n ` __cf_space: ${ref.space}`,\n ` __cf_app: ${ref.app}`,\n ` environment: ${envName}`,\n \" baseUrl: \",\n \"}\",\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nfunction normalizeCollectionName(root: string): string {\n const candidate = basename(root).replace(/^\\.+/, \"\").trim();\n return candidate.length > 0 ? candidate : \"bruno-collection\";\n}\n\nfunction defaultBrunoConfig(root: string): string {\n return `${JSON.stringify(\n {\n version: \"1\",\n name: normalizeCollectionName(root),\n type: \"collection\",\n ignore: [\"node_modules\", \".git\"],\n },\n null,\n 2,\n )}\\n`;\n}\n\nasync function ensureCollectionConfig(root: string): Promise<void> {\n const filePath = join(root, BRUNO_COLLECTION_CONFIG_FILENAME);\n try {\n await writeFile(filePath, defaultBrunoConfig(root), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n }\n}\n\nasync function ensureEnvFile(appPath: string, envName: string, ref: CfAppRef): Promise<string> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n await mkdir(envDir, { recursive: true });\n const filePath = join(envDir, `${envName}.bru`);\n try {\n await writeFile(filePath, emptyEnvContent(envName, ref), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n await writeCfMetaToFile(filePath, ref);\n }\n return filePath;\n}\n\nfunction pickRegion(regions: readonly { key: RegionKey; label: string; orgCount: number }[]): readonly {\n readonly value: RegionKey;\n readonly name: string;\n}[] {\n return regions.map((r) => ({ value: r.key, name: `${r.key} — ${r.label} (${r.orgCount.toString()} org${r.orgCount === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickOrg(region: RegionNode): readonly { value: string; name: string }[] {\n return region.orgs.map((o) => ({ value: o.name, name: `${o.name} (${o.spaces.length.toString()} space${o.spaces.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickSpace(org: OrgNode): readonly { value: string; name: string }[] {\n return org.spaces.map((s) => ({ value: s.name, name: `${s.name} (${s.apps.length.toString()} app${s.apps.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickApp(space: SpaceNode): readonly { value: string; name: string }[] {\n return space.apps.map((a) => ({ value: a.name, name: a.name }));\n}\n\nexport async function setupApp(options: SetupAppOptions): Promise<SetupAppResult> {\n const deps = options.deps ?? defaultCfInfoDeps;\n const log = options.log ?? ((): void => undefined);\n\n const regions = await listRegionsWithContent(deps);\n if (regions.length === 0) {\n throw new Error(\"No CF regions with orgs are cached. Run `cf-sync sync` first.\");\n }\n\n const regionKey = await options.prompts.selectRegion(pickRegion(regions));\n const regionView = await deps.readRegionView(regionKey);\n if (!regionView) {\n throw new Error(`Region ${regionKey} is not cached. Run \\`cf-sync region ${regionKey}\\` or \\`cf-sync sync\\` first.`);\n }\n const region = regionView.region;\n\n if (region.orgs.length === 0) {\n throw new Error(`Region ${regionKey} has no accessible orgs.`);\n }\n\n const orgName = await options.prompts.selectOrg(pickOrg(region));\n const org = region.orgs.find((o) => o.name === orgName);\n if (!org) {\n throw new Error(`Org ${orgName} not found in region ${regionKey}`);\n }\n if (org.spaces.length === 0) {\n throw new Error(`Org ${orgName} has no spaces.`);\n }\n\n const spaceName = await options.prompts.selectSpace(pickSpace(org));\n const space = org.spaces.find((s) => s.name === spaceName);\n if (!space) {\n throw new Error(`Space ${spaceName} not found in org ${orgName}`);\n }\n if (space.apps.length === 0) {\n throw new Error(`Space ${spaceName} has no apps.`);\n }\n\n const appName = await options.prompts.selectApp(pickApp(space));\n const ref: CfAppRef = { region: regionKey, org: orgName, space: spaceName, app: appName };\n\n const appPath = join(\n options.root,\n regionFolderName(regionKey),\n orgFolderName(orgName),\n spaceFolderName(spaceName),\n appName,\n );\n\n const confirmed = await options.prompts.confirmCreate(appPath);\n if (!confirmed) {\n return { ref, appPath, environments: [], created: false };\n }\n\n await mkdir(appPath, { recursive: true });\n await ensureCollectionConfig(appPath);\n\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const merged: string[] = [];\n for (const name of selected) {\n const trimmed = name.trim();\n if (trimmed.length === 0 || merged.includes(trimmed)) {\n continue;\n }\n assertValidEnvName(trimmed);\n merged.push(trimmed);\n }\n if (merged.length === 0) {\n throw new Error(\"At least one environment is required.\");\n }\n\n const created: string[] = [];\n for (const envName of merged) {\n const path = await ensureEnvFile(appPath, envName, ref);\n created.push(path);\n log(`• ${path}`);\n }\n\n return { ref, appPath, environments: created, created: true };\n}\n\nasync function listExistingEnvs(appPath: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(join(appPath, ENVIRONMENTS_DIR), { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".bru\"))\n .map((e) => e.name.replace(/\\.bru$/, \"\"));\n } catch {\n return [];\n }\n}\n","import type {\n CfStructure,\n OrgNode,\n RegionKey,\n RegionNode,\n RegionsView,\n RegionView,\n SpaceNode,\n StructureView,\n} from \"@saptools/cf-sync\";\nimport {\n getRegionView as getRegionViewApi,\n readRegionsView,\n readRegionView,\n readStructureView,\n REGION_KEYS,\n} from \"@saptools/cf-sync\";\n\nexport interface CfInfoDeps {\n readonly readStructureView: () => Promise<StructureView | undefined>;\n readonly readRegionsView: () => Promise<RegionsView>;\n readonly readRegionView: (key: RegionKey) => Promise<RegionView | undefined>;\n readonly getRegionView: (opts: {\n readonly regionKey: RegionKey;\n readonly email?: string;\n readonly password?: string;\n readonly refreshIfMissing?: boolean;\n }) => Promise<RegionView | undefined>;\n}\n\nexport const defaultCfInfoDeps: CfInfoDeps = {\n readStructureView,\n readRegionsView,\n readRegionView,\n getRegionView: getRegionViewApi,\n};\n\nexport function isValidRegionKey(value: string): value is RegionKey {\n return (REGION_KEYS as readonly string[]).includes(value);\n}\n\nexport interface StructureSnapshot {\n readonly source: \"runtime\" | \"stable\" | \"empty\";\n readonly structure: CfStructure | undefined;\n readonly stale: boolean;\n readonly message: string | undefined;\n}\n\nexport async function getStructureSnapshot(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<StructureSnapshot> {\n const view = await deps.readStructureView();\n if (!view) {\n return {\n source: \"empty\",\n structure: undefined,\n stale: true,\n message: \"No CF structure cached. Run `cf-sync sync` first.\",\n };\n }\n\n const stale = view.source === \"runtime\" && view.metadata?.status === \"running\";\n return {\n source: view.source,\n structure: view.structure,\n stale,\n message: stale ? \"A CF sync is still running — showing partial data.\" : undefined,\n };\n}\n\nexport interface RegionSuggestion {\n readonly key: RegionKey;\n readonly label: string;\n readonly orgCount: number;\n}\n\nexport async function listRegionsWithContent(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<readonly RegionSuggestion[]> {\n const snapshot = await getStructureSnapshot(deps);\n if (!snapshot.structure) {\n return [];\n }\n return snapshot.structure.regions\n .filter((r) => r.accessible && r.orgs.length > 0)\n .map((r) => ({ key: r.key, label: r.label, orgCount: r.orgs.length }));\n}\n\nexport async function getRegion(\n key: RegionKey,\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<RegionNode | undefined> {\n const view = await deps.readRegionView(key);\n return view?.region;\n}\n\nexport function findOrg(region: RegionNode, orgName: string): OrgNode | undefined {\n return region.orgs.find((o) => o.name === orgName);\n}\n\nexport function findSpace(org: OrgNode, spaceName: string): SpaceNode | undefined {\n return org.spaces.find((s) => s.name === spaceName);\n}\n\nexport function findApp(space: SpaceNode, appName: string): { readonly name: string } | undefined {\n return space.apps.find((a) => a.name === appName);\n}\n\nexport interface ResolvedRef {\n readonly region: RegionNode;\n readonly org: OrgNode;\n readonly space: SpaceNode;\n readonly app: { readonly name: string };\n}\n\nexport async function resolveRef(\n ref: {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n },\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<ResolvedRef | undefined> {\n const region = await getRegion(ref.region, deps);\n if (!region) {\n return undefined;\n }\n const org = findOrg(region, ref.org);\n if (!org) {\n return undefined;\n }\n const space = findSpace(org, ref.space);\n if (!space) {\n return undefined;\n }\n const app = findApp(space, ref.app);\n if (!app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"../collection/paths.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport async function readContext(): Promise<BrunoContext | undefined> {\n try {\n const raw = await readFile(brunoContextPath(), \"utf8\");\n return JSON.parse(raw) as BrunoContext;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport async function writeContext(ctx: Omit<BrunoContext, \"updatedAt\">): Promise<BrunoContext> {\n const updated: BrunoContext = { ...ctx, updatedAt: new Date().toISOString() };\n const path = brunoContextPath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n return updated;\n}\n","import type { CfInfoDeps } from \"../cf/info.js\";\nimport { isValidRegionKey, resolveRef } from \"../cf/info.js\";\nimport { writeContext } from \"../state/context.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport function parseContextShorthand(shorthand: string): {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n} | undefined {\n const segs = shorthand.split(\"/\").filter((s) => s.length > 0);\n if (segs.length !== 4) {\n return undefined;\n }\n const [region, org, space, app] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport interface UseOptions {\n readonly shorthand: string;\n readonly deps?: CfInfoDeps;\n readonly verify?: boolean;\n}\n\nexport async function useContext(options: UseOptions): Promise<BrunoContext> {\n const parsed = parseContextShorthand(options.shorthand);\n if (!parsed) {\n throw new Error(\n `Invalid context shorthand: ${options.shorthand}. Expected <region>/<org>/<space>/<app>.`,\n );\n }\n\n if (!isValidRegionKey(parsed.region)) {\n throw new Error(`Unknown region key: ${parsed.region}`);\n }\n\n if (options.verify !== false) {\n const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);\n if (!resolved) {\n throw new Error(\n `Could not verify ${options.shorthand} against the cached CF structure. Run \\`cf-sync sync\\` first.`,\n );\n }\n }\n\n return await writeContext(parsed);\n}\n","import { search } from \"@inquirer/prompts\";\n\nexport interface AppChoice {\n readonly value: string;\n readonly name: string;\n}\n\ninterface SearchResultChoice extends AppChoice {\n readonly disabled?: boolean | string;\n}\n\ninterface AppSearchPromptConfig {\n readonly message: string;\n readonly pageSize: number;\n readonly source: (\n term: string | undefined,\n opt: { signal: AbortSignal },\n ) => Promise<readonly SearchResultChoice[]>;\n readonly validate: (value: string) => boolean | string | Promise<boolean | string>;\n}\n\ninterface AppSearchPromptDeps {\n readonly searchPrompt?: (config: AppSearchPromptConfig) => Promise<string>;\n}\n\nconst DEFAULT_PAGE_SIZE = 12;\nconst NO_MATCHING_APP = \"__saptools_no_matching_app__\";\n\nfunction normalizeTerm(term: string | undefined): string {\n return term?.trim().toLowerCase() ?? \"\";\n}\n\nfunction scoreChoice(choice: AppChoice, normalizedTerm: string): number {\n const name = choice.name.toLowerCase();\n const value = choice.value.toLowerCase();\n\n if (name === normalizedTerm || value === normalizedTerm) {\n return 0;\n }\n if (name.startsWith(normalizedTerm) || value.startsWith(normalizedTerm)) {\n return 1;\n }\n if (name.includes(normalizedTerm) || value.includes(normalizedTerm)) {\n return 2;\n }\n return Number.POSITIVE_INFINITY;\n}\n\nfunction noMatchChoice(term: string | undefined): SearchResultChoice {\n const label = term?.trim() ?? \"\";\n return {\n value: NO_MATCHING_APP,\n name: `No apps match \"${label}\"`,\n disabled: \"Type a different search term\",\n };\n}\n\nfunction buildAppSearchChoices(\n choices: readonly AppChoice[],\n term: string | undefined,\n): readonly SearchResultChoice[] {\n const normalizedTerm = normalizeTerm(term);\n if (normalizedTerm.length === 0) {\n return [...choices];\n }\n\n const rankedMatches = choices\n .map((choice, index) => ({ choice, index, score: scoreChoice(choice, normalizedTerm) }))\n .filter((item) => Number.isFinite(item.score))\n .sort((left, right) => left.score - right.score || left.index - right.index)\n .map((item) => item.choice);\n\n if (rankedMatches.length > 0) {\n return rankedMatches;\n }\n\n return [noMatchChoice(term)];\n}\n\nexport async function promptForAppSelection(\n choices: readonly AppChoice[],\n deps: AppSearchPromptDeps = {},\n): Promise<string> {\n const searchPrompt = deps.searchPrompt ?? search;\n return await searchPrompt({\n message: \"Select app\",\n pageSize: DEFAULT_PAGE_SIZE,\n source: (term) => Promise.resolve(buildAppSearchChoices(choices, term)),\n validate: (value) => (value === NO_MATCHING_APP ? \"Select a real app.\" : true),\n });\n}\n\nexport const appSearchPromptTestHelpers = {\n buildAppSearchChoices,\n};\n","import { Separator, checkbox, input } from \"@inquirer/prompts\";\n\nimport type { EnvironmentSelection } from \"../commands/setup-app.js\";\nimport { assertValidEnvName } from \"../commands/setup-app.js\";\n\nconst ADD_CUSTOM_ENVIRONMENT = \"__saptools_add_custom_environment__\";\n\ninterface EnvironmentChoice {\n readonly value: string;\n readonly name: string;\n readonly checked?: boolean;\n readonly description?: string;\n}\n\ninterface CheckboxChoiceState {\n readonly value: string;\n}\n\ninterface EnvironmentPromptDeps {\n readonly checkboxPrompt?: (config: {\n message: string;\n choices: readonly (Separator | EnvironmentChoice)[];\n validate: (choices: readonly CheckboxChoiceState[]) => boolean | string;\n }) => Promise<string[]>;\n readonly inputPrompt?: (config: {\n message: string;\n default: string;\n validate: (value: string) => boolean | string;\n }) => Promise<string>;\n}\n\nfunction uniqueNames(names: readonly string[]): string[] {\n const merged: string[] = [];\n for (const name of names) {\n if (!merged.includes(name)) {\n merged.push(name);\n }\n }\n return merged;\n}\n\nfunction validateEnvironmentSelection(choices: readonly CheckboxChoiceState[]): boolean | string {\n const selected = choices.map((choice) => choice.value);\n const hasEnvironment = selected.some((value) => value !== ADD_CUSTOM_ENVIRONMENT);\n if (hasEnvironment || selected.includes(ADD_CUSTOM_ENVIRONMENT)) {\n return true;\n }\n return 'Select at least one environment, or choose \"Add custom environment\".';\n}\n\nfunction buildEnvironmentChoices(\n names: readonly string[],\n selected: ReadonlySet<string>,\n): readonly (Separator | EnvironmentChoice)[] {\n return [\n ...names.map((name) => ({\n value: name,\n name,\n checked: selected.has(name),\n })),\n new Separator(),\n {\n value: ADD_CUSTOM_ENVIRONMENT,\n name: \"Add custom environment\",\n description: \"Create another environment name and return to this menu\",\n },\n ];\n}\n\nfunction validateCustomEnvironmentName(value: string): boolean | string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n return true;\n }\n\n try {\n assertValidEnvName(trimmed);\n return true;\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n}\n\nexport async function promptForEnvironments(\n opts: EnvironmentSelection,\n deps: EnvironmentPromptDeps = {},\n): Promise<readonly string[]> {\n const checkboxPrompt = deps.checkboxPrompt ?? checkbox;\n const inputPrompt = deps.inputPrompt ?? input;\n const selected = new Set<string>(opts.existing);\n const customNames: string[] = [];\n\n for (;;) {\n const names = uniqueNames([...opts.common, ...opts.existing, ...customNames]);\n const answers = await checkboxPrompt({\n message: \"Environments to create (space to toggle, enter to continue)\",\n choices: buildEnvironmentChoices(names, selected),\n validate: validateEnvironmentSelection,\n });\n\n selected.clear();\n for (const name of answers) {\n if (name !== ADD_CUSTOM_ENVIRONMENT) {\n selected.add(name);\n }\n }\n\n if (!answers.includes(ADD_CUSTOM_ENVIRONMENT)) {\n return [...selected];\n }\n\n const custom = (await inputPrompt({\n message: \"Custom environment name (leave empty to go back)\",\n default: \"\",\n validate: validateCustomEnvironmentName,\n })).trim();\n\n if (custom.length === 0) {\n continue;\n }\n\n if (!customNames.includes(custom) && !names.includes(custom)) {\n customNames.push(custom);\n }\n selected.add(custom);\n }\n}\n\nexport const environmentPromptTestHelpers = {\n buildEnvironmentChoices,\n validateEnvironmentSelection,\n validateCustomEnvironmentName,\n};\n"],"mappings":"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","names":["process","readFile","writeFile","join","sep","readFile","join","readFile","join","require","join","readFile","writeFile","readdir","writeFile","join","join","writeFile","readdir","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","process"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/main.ts","../src/commands/run.ts","../src/bruno/parser.ts","../src/bruno/writer.ts","../src/cf/meta.ts","../src/collection/folder-scan.ts","../src/collection/paths.ts","../src/commands/setup-app.ts","../src/cf/info.ts","../src/state/context.ts","../src/commands/use.ts","../src/prompts/app-search.ts","../src/prompts/environment.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { confirm, select } from \"@inquirer/prompts\";\nimport { Command, Option } from \"commander\";\n\nimport { runBruno } from \"../commands/run.js\";\nimport { setupApp } from \"../commands/setup-app.js\";\nimport { useContext } from \"../commands/use.js\";\nimport { promptForAppSelection } from \"../prompts/app-search.js\";\nimport { promptForEnvironments } from \"../prompts/environment.js\";\nimport { readContext } from \"../state/context.js\";\n\nfunction resolveCollectionDir(explicitCollection: string | undefined, explicitRoot: string | undefined): string {\n if (explicitCollection) {\n return explicitCollection;\n }\n if (explicitRoot) {\n return explicitRoot;\n }\n if (process.env[\"SAPTOOLS_BRUNO_COLLECTION\"]) {\n return process.env[\"SAPTOOLS_BRUNO_COLLECTION\"];\n }\n if (process.env[\"SAPTOOLS_BRUNO_ROOT\"]) {\n return process.env[\"SAPTOOLS_BRUNO_ROOT\"];\n }\n return process.cwd();\n}\n\nfunction resolveProgramCollectionDir(program: Command): string {\n const opts = program.opts<{ collection?: string; root?: string }>();\n return resolveCollectionDir(opts.collection, opts.root);\n}\n\nfunction writeLine(message: string): void {\n process.stdout.write(`${message}\\n`);\n}\n\nfunction registerSetupAppCommand(program: Command): void {\n program\n .command(\"setup-app\")\n .description(\"Interactively scaffold a bruno app folder and seed __cf_* variables\")\n .action(async (): Promise<void> => {\n const result = await setupApp({\n root: resolveProgramCollectionDir(program),\n prompts: {\n selectRegion: async (choices) => await select({ message: \"Select region\", choices: [...choices] }),\n selectOrg: async (choices) => await select({ message: \"Select org\", choices: [...choices] }),\n selectSpace: async (choices) => await select({ message: \"Select space\", choices: [...choices] }),\n selectApp: async (choices) => await promptForAppSelection(choices),\n confirmCreate: async (path) => await confirm({ message: `Create ${path}?`, default: true }),\n selectEnvironments: async (opts) => await promptForEnvironments(opts),\n },\n log: writeLine,\n });\n if (!result.created) {\n writeLine(\"Aborted.\");\n return;\n }\n writeLine(`✔ App folder ready at ${result.appPath}`);\n });\n}\n\nasync function resolveRunTarget(target: string | undefined): Promise<string> {\n if (target) {\n return target;\n }\n\n const ctx = await readContext();\n if (!ctx) {\n throw new Error(\n \"No target specified and no default context is set. Run `saptools-bruno use <region/org/space/app>` first.\",\n );\n }\n return `${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}`;\n}\n\nfunction registerRunCommand(program: Command): void {\n program\n .command(\"run\")\n .description(\"Run a bruno request or folder, auto-injecting an XSUAA token\")\n .argument(\"[target]\", \"Shorthand path (region/org/space/app[/folder/file.bru]) or real path\")\n .option(\"-e, --env <name>\", \"Environment name (default: context or first)\")\n .action(\n async (\n target: string | undefined,\n opts: { env?: string },\n ): Promise<void> => {\n const result = await runBruno({\n root: resolveProgramCollectionDir(program),\n target: await resolveRunTarget(target),\n ...(opts.env ? { environment: opts.env } : {}),\n log: writeLine,\n });\n process.exit(result.code);\n },\n );\n}\n\nfunction registerUseCommand(program: Command): void {\n program\n .command(\"use\")\n .description(\"Set the default CF context (region/org/space/app) for future `run` calls\")\n .argument(\"<shorthand>\", \"region/org/space/app\")\n .option(\"--no-verify\", \"Skip verifying the context against the cached CF structure\")\n .action(async (shorthand: string, opts: { verify?: boolean }): Promise<void> => {\n const ctx = await useContext({\n shorthand,\n verify: opts.verify !== false,\n });\n process.stdout.write(`✔ Default context set to ${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}\\n`);\n });\n}\n\nexport async function main(argv: readonly string[]): Promise<void> {\n const program = new Command();\n\n program\n .name(\"saptools-bruno\")\n .description(\"Smart runner for Bruno with CF-aware env metadata and automatic token injection\")\n .addOption(new Option(\"--collection <dir>\", \"Bruno collection directory (default: SAPTOOLS_BRUNO_COLLECTION or cwd)\"))\n .addOption(new Option(\"--root <dir>\", \"Legacy alias for --collection\").hideHelp());\n\n registerSetupAppCommand(program);\n registerRunCommand(program);\n registerUseCommand(program);\n\n await program.parseAsync([...argv]);\n}\n\ntry {\n await main(process.argv);\n} catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`Error: ${msg}\\n`);\n process.exit(1);\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\n\nimport type { AppRef } from \"@saptools/cf-xsuaa\";\nimport { getTokenCached as getTokenCachedApi } from \"@saptools/cf-xsuaa\";\n\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { readCfMetaFromFile } from \"../cf/meta.js\";\nimport type { ShorthandRef } from \"../collection/folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"../collection/folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\n\nexport type GetTokenCachedFn = (ref: AppRef) => Promise<string>;\n\nexport interface RunSpawnResult {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type SpawnBruFn = (\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n) => Promise<RunSpawnResult>;\n\nexport interface RunOptions {\n readonly root: string;\n readonly target: string;\n readonly environment?: string;\n readonly extraArgs?: readonly string[];\n readonly getTokenCached?: GetTokenCachedFn;\n readonly spawnBru?: SpawnBruFn;\n readonly log?: (msg: string) => void;\n}\n\nexport interface RunPlan {\n readonly filePath: string;\n readonly environment: string;\n readonly envFile: string;\n readonly meta: { readonly region: string; readonly org: string; readonly space: string; readonly app: string };\n readonly token: string;\n readonly bruArgs: readonly string[];\n readonly cwd: string;\n}\n\nexport interface RunResult extends RunPlan {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nconst require = createRequire(import.meta.url);\n\nexport interface BruRuntime {\n readonly command: string;\n readonly argsPrefix: readonly string[];\n}\n\nexport interface ResolveBruRuntimeDeps {\n readonly findOnPath?: (command: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;\n readonly readTextFile?: (path: string) => Promise<string>;\n readonly resolvePackageJsonPath?: () => string;\n}\n\nfunction pathEntries(env: NodeJS.ProcessEnv): readonly string[] {\n const value = env[\"PATH\"] ?? process.env[\"PATH\"] ?? \"\";\n return value.split(delimiter).filter((entry) => entry.length > 0);\n}\n\nfunction pathCandidates(command: string, env: NodeJS.ProcessEnv): readonly string[] {\n if (process.platform !== \"win32\" || command.includes(\".\")) {\n return [command];\n }\n const pathExt =\n env[\"PATHEXT\"]?.split(\";\").filter((entry) => entry.length > 0) ?? [\".COM\", \".EXE\", \".BAT\", \".CMD\"];\n return [command, ...pathExt.map((ext) => `${command}${ext}`)];\n}\n\nasync function findCommandOnPath(command: string, env: NodeJS.ProcessEnv): Promise<string | undefined> {\n const candidates = pathCandidates(command, env);\n for (const entry of pathEntries(env)) {\n for (const candidate of candidates) {\n const fullPath = join(entry, candidate);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction bruBinRelativePath(value: unknown): string | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const bin = value[\"bin\"];\n if (typeof bin === \"string\") {\n return bin;\n }\n if (!isRecord(bin)) {\n return undefined;\n }\n const bru = bin[\"bru\"];\n return typeof bru === \"string\" ? bru : undefined;\n}\n\nfunction defaultResolvePackageJsonPath(): string {\n return require.resolve(\"@usebruno/cli/package.json\");\n}\n\nasync function defaultReadTextFile(path: string): Promise<string> {\n return await readFile(path, \"utf8\");\n}\n\nasync function resolveBundledBruBinPath(\n deps: ResolveBruRuntimeDeps,\n): Promise<string | undefined> {\n try {\n const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();\n const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);\n const binPath = bruBinRelativePath(JSON.parse(raw) as unknown);\n if (!binPath) {\n return undefined;\n }\n return resolve(dirname(packageJsonPath), binPath);\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveBruRuntime(\n env: NodeJS.ProcessEnv = process.env,\n deps: ResolveBruRuntimeDeps = {},\n): Promise<BruRuntime> {\n const onPath = await (deps.findOnPath ?? findCommandOnPath)(\"bru\", env);\n if (onPath) {\n return { command: onPath, argsPrefix: [] };\n }\n const bundledBin = await resolveBundledBruBinPath(deps);\n if (bundledBin) {\n return { command: process.execPath, argsPrefix: [bundledBin] };\n }\n throw new Error(\n \"Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH.\",\n );\n}\n\nasync function defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n const runtime = await resolveBruRuntime(env);\n return await new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: \"pipe\" });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n process.stderr.write(chunk);\n });\n child.on(\"error\", rejectPromise);\n child.on(\"close\", (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\n });\n });\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveTarget(\n root: string,\n target: string,\n): Promise<{ readonly filePath: string; readonly shorthand: ShorthandRef | undefined }> {\n const direct = isAbsolute(target) ? target : resolve(process.cwd(), target);\n if (await exists(direct)) {\n return { filePath: direct, shorthand: undefined };\n }\n\n const shorthand = parseShorthandPath(target);\n if (!shorthand) {\n throw new Error(`Target not found: ${target}`);\n }\n\n const { region, org, space, app, filePath } = shorthand;\n const appDir = join(\n root,\n regionFolderName(region),\n orgFolderName(org),\n spaceFolderName(space),\n app,\n );\n\n if (!filePath) {\n return { filePath: appDir, shorthand };\n }\n\n const candidate = join(appDir, filePath);\n if (await exists(candidate)) {\n return { filePath: candidate, shorthand };\n }\n\n const withExt = candidate.endsWith(\".bru\") ? candidate : `${candidate}.bru`;\n if (await exists(withExt)) {\n return { filePath: withExt, shorthand };\n }\n\n throw new Error(`File not found: ${candidate}`);\n}\n\nasync function chooseEnvironmentFile(\n appDir: string,\n environment: string | undefined,\n): Promise<{ readonly envFile: string; readonly environment: string }> {\n if (environment) {\n const envFile = join(appDir, ENVIRONMENTS_DIR, `${environment}.bru`);\n if (!(await exists(envFile))) {\n throw new Error(`Environment file not found: ${envFile}`);\n }\n return { envFile, environment };\n }\n\n const collection = await scanCollection(resolve(appDir, \"..\", \"..\", \"..\", \"..\"));\n for (const region of collection.regions) {\n for (const org of region.orgs) {\n for (const space of org.spaces) {\n for (const app of space.apps) {\n if (app.path === appDir && app.environments.length > 0) {\n const first = app.environments[0];\n if (first) {\n return { envFile: first.path, environment: first.name };\n }\n }\n }\n }\n }\n }\n throw new Error(`No environment files found under ${appDir}/${ENVIRONMENTS_DIR}`);\n}\n\nfunction findAppDirFromFile(filePath: string, root: string): string {\n const rel = relative(root, filePath).split(sep);\n if (rel.length < 4) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n const [regionDir, orgDir, spaceDir, appDir] = rel;\n if (!regionDir || !orgDir || !spaceDir || !appDir) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n return join(root, regionDir, orgDir, spaceDir, appDir);\n}\n\nasync function persistAccessToken(envFile: string, token: string): Promise<void> {\n const raw = await readFile(envFile, \"utf8\");\n const { content, changed } = upsertVars(raw, new Map([[\"accessToken\", token]]));\n if (changed) {\n await writeFile(envFile, content, \"utf8\");\n }\n}\n\nexport async function buildRunPlan(options: RunOptions): Promise<RunPlan> {\n const { filePath } = await resolveTarget(options.root, options.target);\n const stats = await stat(filePath);\n\n let appDir: string;\n let requestFile: string | undefined;\n\n if (stats.isDirectory()) {\n appDir = filePath;\n requestFile = undefined;\n } else {\n appDir = findAppDirFromFile(filePath, options.root);\n requestFile = filePath;\n }\n\n const { envFile, environment } = await chooseEnvironmentFile(appDir, options.environment);\n\n const meta = await readCfMetaFromFile(envFile);\n if (!meta) {\n throw new Error(\n `Missing __cf_region/__cf_org/__cf_space/__cf_app in ${envFile}. Run \\`saptools-bruno setup-app\\` first.`,\n );\n }\n\n const getToken = options.getTokenCached ?? getTokenCachedApi;\n const token = await getToken(meta);\n await persistAccessToken(envFile, token);\n\n const bruArgs: string[] = [\"run\"];\n if (requestFile) {\n bruArgs.push(relative(appDir, requestFile) || \".\");\n }\n bruArgs.push(\"--env\", environment, \"--env-var\", `accessToken=${token}`);\n if (options.extraArgs) {\n bruArgs.push(...options.extraArgs);\n }\n\n return {\n filePath,\n environment,\n envFile,\n meta,\n token,\n bruArgs,\n cwd: appDir,\n };\n}\n\nexport async function runBruno(options: RunOptions): Promise<RunResult> {\n const plan = await buildRunPlan(options);\n const spawnFn = options.spawnBru ?? defaultSpawnBru;\n const env: NodeJS.ProcessEnv = { ...process.env, SAPTOOLS_ACCESS_TOKEN: plan.token };\n options.log?.(`▶ bru ${plan.bruArgs.join(\" \")} (cwd=${plan.cwd})`);\n const result = await spawnFn(plan.bruArgs, env, plan.cwd);\n return { ...plan, ...result };\n}\n","import type { BruVarsBlock } from \"../types.js\";\n\ninterface BlockRange {\n readonly header: string;\n readonly start: number;\n readonly end: number;\n readonly bodyStart: number;\n readonly bodyEnd: number;\n readonly open: \"{\" | \"[\";\n readonly close: \"}\" | \"]\";\n}\n\nconst HEADER_REGEX = /(^|\\n)[^\\S\\n]*([a-zA-Z][a-zA-Z0-9:_-]*)[^\\S\\n]*([{[])/g;\n\nfunction findMatchingClose(raw: string, open: \"{\" | \"[\", openIdx: number): number {\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 1;\n let i = openIdx + 1;\n while (i < raw.length) {\n const ch = raw[i];\n if (ch === open) {\n depth++;\n } else if (ch === close) {\n depth--;\n if (depth === 0) {\n return i;\n }\n }\n i++;\n }\n return -1;\n}\n\nexport function listBlocks(raw: string): readonly BlockRange[] {\n const blocks: BlockRange[] = [];\n HEADER_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = HEADER_REGEX.exec(raw)) !== null) {\n const leadingNewline = match[1] ?? \"\";\n const header = match[2];\n const open = match[3];\n if (header === undefined || (open !== \"{\" && open !== \"[\")) {\n continue;\n }\n const headerStart = match.index + leadingNewline.length;\n const openIdx = match.index + match[0].length - 1;\n const closeIdx = findMatchingClose(raw, open, openIdx);\n if (closeIdx === -1) {\n continue;\n }\n blocks.push({\n header,\n start: headerStart,\n end: closeIdx + 1,\n bodyStart: openIdx + 1,\n bodyEnd: closeIdx,\n open,\n close: open === \"{\" ? \"}\" : \"]\",\n });\n }\n return blocks;\n}\n\nexport function parseKeyValueBody(body: string): Map<string, string> {\n const entries = new Map<string, string>();\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n const colon = line.indexOf(\":\");\n if (colon === -1) {\n continue;\n }\n const key = line.slice(0, colon).trim();\n const value = line.slice(colon + 1).trim();\n if (key.length > 0) {\n entries.set(key, value);\n }\n }\n return entries;\n}\n\nexport function parseListBody(body: string): string[] {\n const items: string[] = [];\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n items.push(line);\n }\n return items;\n}\n\nexport interface ParsedBruEnv {\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport function parseBruEnvFile(raw: string): ParsedBruEnv {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n const entries = varsBlock\n ? parseKeyValueBody(raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd))\n : new Map<string, string>();\n const secrets = secretsBlock\n ? parseListBody(raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd))\n : [];\n\n return { vars: { entries }, secrets };\n}\n","import { listBlocks, parseKeyValueBody } from \"./parser.js\";\n\nexport interface UpsertResult {\n readonly content: string;\n readonly changed: boolean;\n}\n\nfunction formatVarsBlock(entries: ReadonlyMap<string, string>): string {\n const lines: string[] = [];\n for (const [key, value] of entries) {\n lines.push(` ${key}: ${value}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function upsertVars(\n raw: string,\n updates: ReadonlyMap<string, string>,\n): UpsertResult {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n\n if (!varsBlock) {\n const newBlock = `vars {\\n${formatVarsBlock(updates)}\\n}\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: updates.size > 0 };\n }\n\n const body = raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd);\n const existing = parseKeyValueBody(body);\n let changed = false;\n for (const [k, v] of updates) {\n if (existing.get(k) !== v) {\n existing.set(k, v);\n changed = true;\n }\n }\n\n if (!changed) {\n return { content: raw, changed: false };\n }\n\n const rebuilt = `\\n${formatVarsBlock(existing)}\\n`;\n const before = raw.slice(0, varsBlock.bodyStart);\n const after = raw.slice(varsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n\nexport function ensureSecretEntry(raw: string, secretName: string): UpsertResult {\n const blocks = listBlocks(raw);\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n if (!secretsBlock) {\n const newBlock = `vars:secret [\\n ${secretName}\\n]\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: true };\n }\n\n const body = raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd);\n const items = body\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\"//\"));\n if (items.includes(secretName)) {\n return { content: raw, changed: false };\n }\n items.push(secretName);\n const rebuilt = `\\n ${items.join(\"\\n \")}\\n`;\n const before = raw.slice(0, secretsBlock.bodyStart);\n const after = raw.slice(secretsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { CF_META_KEYS } from \"../types.js\";\nimport type { CfAppRef, CfMetaKey } from \"../types.js\";\n\nexport interface CfMeta {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport function readCfMetaFromVars(vars: ReadonlyMap<string, string>): CfMeta | undefined {\n const region = vars.get(\"__cf_region\");\n const org = vars.get(\"__cf_org\");\n const space = vars.get(\"__cf_space\");\n const app = vars.get(\"__cf_app\");\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport function buildCfMetaUpdates(ref: CfAppRef, baseUrl?: string): Map<string, string> {\n const updates = new Map<string, string>();\n const pairs: readonly [CfMetaKey, string][] = [\n [\"__cf_region\", ref.region],\n [\"__cf_org\", ref.org],\n [\"__cf_space\", ref.space],\n [\"__cf_app\", ref.app],\n ];\n for (const [k, v] of pairs) {\n updates.set(k, v);\n }\n if (baseUrl !== undefined) {\n updates.set(\"baseUrl\", baseUrl);\n }\n return updates;\n}\n\nexport function hasCfMeta(vars: ReadonlyMap<string, string>): boolean {\n return CF_META_KEYS.every((k) => {\n const v = vars.get(k);\n return v !== undefined && v.length > 0;\n });\n}\n\nexport async function readCfMetaFromFile(path: string): Promise<CfMeta | undefined> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return readCfMetaFromVars(parsed.vars.entries);\n}\n\nexport async function writeCfMetaToFile(\n path: string,\n ref: CfAppRef,\n baseUrl?: string,\n): Promise<boolean> {\n const raw = await readFile(path, \"utf8\");\n const updates = buildCfMetaUpdates(ref, baseUrl);\n const { content, changed } = upsertVars(raw, updates);\n if (changed) {\n await writeFile(path, content, \"utf8\");\n }\n return changed;\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"../types.js\";\n\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\n\nasync function safeReaddir(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function listFiles(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isFile()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function loadEnvFile(path: string, name: string): Promise<BruEnvFile> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return {\n path,\n name: name.replace(/\\.bru$/, \"\"),\n raw,\n vars: parsed.vars,\n secrets: parsed.secrets,\n };\n}\n\nasync function scanAppEnvironments(appPath: string): Promise<readonly BruEnvFile[]> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n const files = await listFiles(envDir);\n const bruFiles = files.filter((f) => f.endsWith(\".bru\"));\n const loaded: BruEnvFile[] = [];\n for (const file of bruFiles) {\n loaded.push(await loadEnvFile(join(envDir, file), file));\n }\n return loaded;\n}\n\nasync function scanApp(spacePath: string, name: string): Promise<AppFolder> {\n const appPath = join(spacePath, name);\n const environments = await scanAppEnvironments(appPath);\n return { path: appPath, name, environments };\n}\n\nasync function scanSpace(orgPath: string, dirName: string): Promise<SpaceFolder | undefined> {\n const name = parsePrefixedName(dirName, SPACE_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const spacePath = join(orgPath, dirName);\n const appDirs = await safeReaddir(spacePath);\n const apps: AppFolder[] = [];\n for (const appDir of appDirs) {\n apps.push(await scanApp(spacePath, appDir));\n }\n return { path: spacePath, name, apps };\n}\n\nasync function scanOrg(regionPath: string, dirName: string): Promise<OrgFolder | undefined> {\n const name = parsePrefixedName(dirName, ORG_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const orgPath = join(regionPath, dirName);\n const spaceDirs = await safeReaddir(orgPath);\n const spaces: SpaceFolder[] = [];\n for (const spaceDir of spaceDirs) {\n const space = await scanSpace(orgPath, spaceDir);\n if (space) {\n spaces.push(space);\n }\n }\n return { path: orgPath, name, spaces };\n}\n\nasync function scanRegion(root: string, dirName: string): Promise<RegionFolder | undefined> {\n const key = parsePrefixedName(dirName, REGION_FOLDER_PREFIX);\n if (key === undefined) {\n return undefined;\n }\n const regionPath = join(root, dirName);\n const orgDirs = await safeReaddir(regionPath);\n const orgs: OrgFolder[] = [];\n for (const orgDir of orgDirs) {\n const org = await scanOrg(regionPath, orgDir);\n if (org) {\n orgs.push(org);\n }\n }\n return { path: regionPath, key, orgs };\n}\n\nexport async function scanCollection(root: string): Promise<BrunoCollection> {\n const regionDirs = await safeReaddir(root);\n const regions: RegionFolder[] = [];\n for (const dir of regionDirs) {\n const region = await scanRegion(root, dir);\n if (region) {\n regions.push(region);\n }\n }\n return { root, regions };\n}\n\nexport interface ShorthandRef {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly environment?: string;\n readonly filePath?: string;\n}\n\nexport function parseShorthandPath(shorthand: string): ShorthandRef | undefined {\n const cleaned = shorthand.replace(/^[./]+/, \"\").replace(/\\\\/g, \"/\");\n const segs = cleaned.split(\"/\").filter((s) => s.length > 0);\n if (segs.length < 4) {\n return undefined;\n }\n const [region, org, space, app, ...rest] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n if (rest.length === 0) {\n return { region, org, space, app };\n }\n const filePath = rest.join(\"/\");\n const last = rest[rest.length - 1] ?? \"\";\n const environment = last.endsWith(\".bru\") ? last.replace(/\\.bru$/, \"\") : undefined;\n return environment\n ? { region, org, space, app, environment, filePath }\n : { region, org, space, app, filePath };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const SAPTOOLS_DIR_NAME = \".saptools\";\nexport const BRUNO_CONTEXT_FILENAME = \"bruno-context.json\";\n\nexport const REGION_FOLDER_PREFIX = \"region__\";\nexport const ORG_FOLDER_PREFIX = \"org__\";\nexport const SPACE_FOLDER_PREFIX = \"space__\";\nexport const ENVIRONMENTS_DIR = \"environments\";\n\nexport function saptoolsDir(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nexport function brunoContextPath(): string {\n return join(saptoolsDir(), BRUNO_CONTEXT_FILENAME);\n}\n\nexport function regionFolderName(key: string): string {\n return `${REGION_FOLDER_PREFIX}${key}`;\n}\n\nexport function orgFolderName(name: string): string {\n return `${ORG_FOLDER_PREFIX}${name}`;\n}\n\nexport function spaceFolderName(name: string): string {\n return `${SPACE_FOLDER_PREFIX}${name}`;\n}\n\nexport function parsePrefixedName(\n dirName: string,\n prefix: string,\n): string | undefined {\n if (!dirName.startsWith(prefix)) {\n return undefined;\n }\n return dirName.slice(prefix.length);\n}\n","import { mkdir, readdir, writeFile } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport type { OrgNode, RegionKey, RegionNode, SpaceNode } from \"@saptools/cf-sync\";\n\nimport type { CfInfoDeps } from \"../cf/info.js\";\nimport { defaultCfInfoDeps, listRegionsWithContent } from \"../cf/info.js\";\nimport { writeCfMetaToFile } from \"../cf/meta.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\nimport type { CfAppRef } from \"../types.js\";\n\nexport interface EnvironmentSelection {\n readonly common: readonly string[];\n readonly existing: readonly string[];\n}\n\nexport interface SetupAppPrompts {\n readonly selectRegion: (choices: readonly { value: RegionKey; name: string }[]) => Promise<RegionKey>;\n readonly selectOrg: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectSpace: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectApp: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly confirmCreate: (path: string) => Promise<boolean>;\n readonly selectEnvironments: (opts: EnvironmentSelection) => Promise<readonly string[]>;\n}\n\nexport interface SetupAppOptions {\n readonly root: string;\n readonly prompts: SetupAppPrompts;\n readonly deps?: CfInfoDeps;\n readonly log?: (msg: string) => void;\n}\n\nexport interface SetupAppResult {\n readonly ref: CfAppRef;\n readonly appPath: string;\n readonly environments: readonly string[];\n readonly created: boolean;\n}\n\nexport const COMMON_ENVIRONMENTS = [\"local\", \"dev\", \"staging\", \"prod\"] as const;\nconst BRUNO_COLLECTION_CONFIG_FILENAME = \"bruno.json\";\n\nexport const ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nexport function assertValidEnvName(name: string): void {\n if (!ENV_NAME_PATTERN.test(name)) {\n throw new Error(\n `Invalid environment name '${name}': only letters, digits, dot, underscore, and dash are allowed.`,\n );\n }\n}\n\nfunction emptyEnvContent(envName: string, ref: CfAppRef): string {\n const lines = [\n \"vars {\",\n ` __cf_region: ${ref.region}`,\n ` __cf_org: ${ref.org}`,\n ` __cf_space: ${ref.space}`,\n ` __cf_app: ${ref.app}`,\n ` environment: ${envName}`,\n \" baseUrl: \",\n \"}\",\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nfunction normalizeCollectionName(root: string): string {\n const candidate = basename(root).replace(/^\\.+/, \"\").trim();\n return candidate.length > 0 ? candidate : \"bruno-collection\";\n}\n\nfunction defaultBrunoConfig(root: string): string {\n return `${JSON.stringify(\n {\n version: \"1\",\n name: normalizeCollectionName(root),\n type: \"collection\",\n ignore: [\"node_modules\", \".git\"],\n },\n null,\n 2,\n )}\\n`;\n}\n\nasync function ensureCollectionConfig(root: string): Promise<void> {\n const filePath = join(root, BRUNO_COLLECTION_CONFIG_FILENAME);\n try {\n await writeFile(filePath, defaultBrunoConfig(root), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n }\n}\n\nasync function ensureEnvFile(appPath: string, envName: string, ref: CfAppRef): Promise<string> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n await mkdir(envDir, { recursive: true });\n const filePath = join(envDir, `${envName}.bru`);\n try {\n await writeFile(filePath, emptyEnvContent(envName, ref), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n await writeCfMetaToFile(filePath, ref);\n }\n return filePath;\n}\n\nfunction pickRegion(regions: readonly { key: RegionKey; label: string; orgCount: number }[]): readonly {\n readonly value: RegionKey;\n readonly name: string;\n}[] {\n return regions.map((r) => ({ value: r.key, name: `${r.key} — ${r.label} (${r.orgCount.toString()} org${r.orgCount === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickOrg(region: RegionNode): readonly { value: string; name: string }[] {\n return region.orgs.map((o) => ({ value: o.name, name: `${o.name} (${o.spaces.length.toString()} space${o.spaces.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickSpace(org: OrgNode): readonly { value: string; name: string }[] {\n return org.spaces.map((s) => ({ value: s.name, name: `${s.name} (${s.apps.length.toString()} app${s.apps.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickApp(space: SpaceNode): readonly { value: string; name: string }[] {\n return space.apps.map((a) => ({ value: a.name, name: a.name }));\n}\n\nasync function selectRegion(\n prompts: SetupAppPrompts,\n deps: CfInfoDeps,\n): Promise<{ readonly regionKey: RegionKey; readonly region: RegionNode }> {\n const regions = await listRegionsWithContent(deps);\n if (regions.length === 0) {\n throw new Error(\"No CF regions with orgs are cached. Run `cf-sync sync` first.\");\n }\n\n const regionKey = await prompts.selectRegion(pickRegion(regions));\n const regionView = await deps.readRegionView(regionKey);\n if (!regionView) {\n throw new Error(`Region ${regionKey} is not cached. Run \\`cf-sync region ${regionKey}\\` or \\`cf-sync sync\\` first.`);\n }\n const region = regionView.region;\n\n if (region.orgs.length === 0) {\n throw new Error(`Region ${regionKey} has no accessible orgs.`);\n }\n\n return { regionKey, region };\n}\n\nasync function selectOrg(\n prompts: SetupAppPrompts,\n region: RegionNode,\n regionKey: RegionKey,\n): Promise<{ readonly orgName: string; readonly org: OrgNode }> {\n const orgName = await prompts.selectOrg(pickOrg(region));\n const org = region.orgs.find((o) => o.name === orgName);\n if (!org) {\n throw new Error(`Org ${orgName} not found in region ${regionKey}`);\n }\n if (org.spaces.length === 0) {\n throw new Error(`Org ${orgName} has no spaces.`);\n }\n\n return { orgName, org };\n}\n\nasync function selectSpace(\n prompts: SetupAppPrompts,\n org: OrgNode,\n orgName: string,\n): Promise<{ readonly spaceName: string; readonly space: SpaceNode }> {\n const spaceName = await prompts.selectSpace(pickSpace(org));\n const space = org.spaces.find((s) => s.name === spaceName);\n if (!space) {\n throw new Error(`Space ${spaceName} not found in org ${orgName}`);\n }\n if (space.apps.length === 0) {\n throw new Error(`Space ${spaceName} has no apps.`);\n }\n\n return { spaceName, space };\n}\n\nasync function selectCfAppRef(\n prompts: SetupAppPrompts,\n deps: CfInfoDeps,\n): Promise<CfAppRef> {\n const { regionKey, region } = await selectRegion(prompts, deps);\n const { orgName, org } = await selectOrg(prompts, region, regionKey);\n const { spaceName, space } = await selectSpace(prompts, org, orgName);\n const appName = await prompts.selectApp(pickApp(space));\n return { region: regionKey, org: orgName, space: spaceName, app: appName };\n}\n\nfunction appPathFor(root: string, ref: CfAppRef): string {\n return join(\n root,\n regionFolderName(ref.region),\n orgFolderName(ref.org),\n spaceFolderName(ref.space),\n ref.app,\n );\n}\n\nfunction normalizeEnvironmentNames(selected: readonly string[]): readonly string[] {\n const merged: string[] = [];\n for (const name of selected) {\n const trimmed = name.trim();\n if (trimmed.length === 0 || merged.includes(trimmed)) {\n continue;\n }\n assertValidEnvName(trimmed);\n merged.push(trimmed);\n }\n if (merged.length === 0) {\n throw new Error(\"At least one environment is required.\");\n }\n return merged;\n}\n\nasync function selectEnvironmentNames(\n appPath: string,\n prompts: SetupAppPrompts,\n): Promise<readonly string[]> {\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await prompts.selectEnvironments({ common, existing: existingEnvs });\n return normalizeEnvironmentNames(selected);\n}\n\nasync function createEnvironmentFiles(\n appPath: string,\n envNames: readonly string[],\n ref: CfAppRef,\n log: (msg: string) => void,\n): Promise<readonly string[]> {\n const created: string[] = [];\n for (const envName of envNames) {\n const path = await ensureEnvFile(appPath, envName, ref);\n created.push(path);\n log(`• ${path}`);\n }\n return created;\n}\n\nexport async function setupApp(options: SetupAppOptions): Promise<SetupAppResult> {\n const deps = options.deps ?? defaultCfInfoDeps;\n const log = options.log ?? ((): void => undefined);\n const ref = await selectCfAppRef(options.prompts, deps);\n const appPath = appPathFor(options.root, ref);\n\n const confirmed = await options.prompts.confirmCreate(appPath);\n if (!confirmed) {\n return { ref, appPath, environments: [], created: false };\n }\n\n await mkdir(appPath, { recursive: true });\n await ensureCollectionConfig(appPath);\n\n const envNames = await selectEnvironmentNames(appPath, options.prompts);\n const created = await createEnvironmentFiles(appPath, envNames, ref, log);\n return { ref, appPath, environments: created, created: true };\n}\n\nasync function listExistingEnvs(appPath: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(join(appPath, ENVIRONMENTS_DIR), { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".bru\"))\n .map((e) => e.name.replace(/\\.bru$/, \"\"));\n } catch {\n return [];\n }\n}\n","import type {\n CfStructure,\n OrgNode,\n RegionKey,\n RegionNode,\n RegionsView,\n RegionView,\n SpaceNode,\n StructureView,\n} from \"@saptools/cf-sync\";\nimport {\n getRegionView as getRegionViewApi,\n readRegionsView,\n readRegionView,\n readStructureView,\n REGION_KEYS,\n} from \"@saptools/cf-sync\";\n\nexport interface CfInfoDeps {\n readonly readStructureView: () => Promise<StructureView | undefined>;\n readonly readRegionsView: () => Promise<RegionsView>;\n readonly readRegionView: (key: RegionKey) => Promise<RegionView | undefined>;\n readonly getRegionView: (opts: {\n readonly regionKey: RegionKey;\n readonly email?: string;\n readonly password?: string;\n readonly refreshIfMissing?: boolean;\n }) => Promise<RegionView | undefined>;\n}\n\nexport const defaultCfInfoDeps: CfInfoDeps = {\n readStructureView,\n readRegionsView,\n readRegionView,\n getRegionView: getRegionViewApi,\n};\n\nexport function isValidRegionKey(value: string): value is RegionKey {\n return (REGION_KEYS as readonly string[]).includes(value);\n}\n\nexport interface StructureSnapshot {\n readonly source: \"runtime\" | \"stable\" | \"empty\";\n readonly structure: CfStructure | undefined;\n readonly stale: boolean;\n readonly message: string | undefined;\n}\n\nexport async function getStructureSnapshot(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<StructureSnapshot> {\n const view = await deps.readStructureView();\n if (!view) {\n return {\n source: \"empty\",\n structure: undefined,\n stale: true,\n message: \"No CF structure cached. Run `cf-sync sync` first.\",\n };\n }\n\n const stale = view.source === \"runtime\" && view.metadata?.status === \"running\";\n return {\n source: view.source,\n structure: view.structure,\n stale,\n message: stale ? \"A CF sync is still running — showing partial data.\" : undefined,\n };\n}\n\nexport interface RegionSuggestion {\n readonly key: RegionKey;\n readonly label: string;\n readonly orgCount: number;\n}\n\nexport async function listRegionsWithContent(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<readonly RegionSuggestion[]> {\n const snapshot = await getStructureSnapshot(deps);\n if (!snapshot.structure) {\n return [];\n }\n return snapshot.structure.regions\n .filter((r) => r.accessible && r.orgs.length > 0)\n .map((r) => ({ key: r.key, label: r.label, orgCount: r.orgs.length }));\n}\n\nexport async function getRegion(\n key: RegionKey,\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<RegionNode | undefined> {\n const view = await deps.readRegionView(key);\n return view?.region;\n}\n\nexport function findOrg(region: RegionNode, orgName: string): OrgNode | undefined {\n return region.orgs.find((o) => o.name === orgName);\n}\n\nexport function findSpace(org: OrgNode, spaceName: string): SpaceNode | undefined {\n return org.spaces.find((s) => s.name === spaceName);\n}\n\nexport function findApp(space: SpaceNode, appName: string): { readonly name: string } | undefined {\n return space.apps.find((a) => a.name === appName);\n}\n\nexport interface ResolvedRef {\n readonly region: RegionNode;\n readonly org: OrgNode;\n readonly space: SpaceNode;\n readonly app: { readonly name: string };\n}\n\nexport async function resolveRef(\n ref: {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n },\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<ResolvedRef | undefined> {\n const region = await getRegion(ref.region, deps);\n if (!region) {\n return undefined;\n }\n const org = findOrg(region, ref.org);\n if (!org) {\n return undefined;\n }\n const space = findSpace(org, ref.space);\n if (!space) {\n return undefined;\n }\n const app = findApp(space, ref.app);\n if (!app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"../collection/paths.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport async function readContext(): Promise<BrunoContext | undefined> {\n try {\n const raw = await readFile(brunoContextPath(), \"utf8\");\n return JSON.parse(raw) as BrunoContext;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport async function writeContext(ctx: Omit<BrunoContext, \"updatedAt\">): Promise<BrunoContext> {\n const updated: BrunoContext = { ...ctx, updatedAt: new Date().toISOString() };\n const path = brunoContextPath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n return updated;\n}\n","import type { CfInfoDeps } from \"../cf/info.js\";\nimport { isValidRegionKey, resolveRef } from \"../cf/info.js\";\nimport { writeContext } from \"../state/context.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport function parseContextShorthand(shorthand: string): {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n} | undefined {\n const segs = shorthand.split(\"/\").filter((s) => s.length > 0);\n if (segs.length !== 4) {\n return undefined;\n }\n const [region, org, space, app] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport interface UseOptions {\n readonly shorthand: string;\n readonly deps?: CfInfoDeps;\n readonly verify?: boolean;\n}\n\nexport async function useContext(options: UseOptions): Promise<BrunoContext> {\n const parsed = parseContextShorthand(options.shorthand);\n if (!parsed) {\n throw new Error(\n `Invalid context shorthand: ${options.shorthand}. Expected <region>/<org>/<space>/<app>.`,\n );\n }\n\n if (!isValidRegionKey(parsed.region)) {\n throw new Error(`Unknown region key: ${parsed.region}`);\n }\n\n if (options.verify !== false) {\n const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);\n if (!resolved) {\n throw new Error(\n `Could not verify ${options.shorthand} against the cached CF structure. Run \\`cf-sync sync\\` first.`,\n );\n }\n }\n\n return await writeContext(parsed);\n}\n","import { search } from \"@inquirer/prompts\";\n\nexport interface AppChoice {\n readonly value: string;\n readonly name: string;\n}\n\ninterface SearchResultChoice extends AppChoice {\n readonly disabled?: boolean | string;\n}\n\ninterface AppSearchPromptConfig {\n readonly message: string;\n readonly pageSize: number;\n readonly source: (\n term: string | undefined,\n opt: { signal: AbortSignal },\n ) => Promise<readonly SearchResultChoice[]>;\n readonly validate: (value: string) => boolean | string | Promise<boolean | string>;\n}\n\ninterface AppSearchPromptDeps {\n readonly searchPrompt?: (config: AppSearchPromptConfig) => Promise<string>;\n}\n\nconst DEFAULT_PAGE_SIZE = 12;\nconst NO_MATCHING_APP = \"__saptools_no_matching_app__\";\n\nfunction normalizeTerm(term: string | undefined): string {\n return term?.trim().toLowerCase() ?? \"\";\n}\n\nfunction scoreChoice(choice: AppChoice, normalizedTerm: string): number {\n const name = choice.name.toLowerCase();\n const value = choice.value.toLowerCase();\n\n if (name === normalizedTerm || value === normalizedTerm) {\n return 0;\n }\n if (name.startsWith(normalizedTerm) || value.startsWith(normalizedTerm)) {\n return 1;\n }\n if (name.includes(normalizedTerm) || value.includes(normalizedTerm)) {\n return 2;\n }\n return Number.POSITIVE_INFINITY;\n}\n\nfunction noMatchChoice(term: string | undefined): SearchResultChoice {\n const label = term?.trim() ?? \"\";\n return {\n value: NO_MATCHING_APP,\n name: `No apps match \"${label}\"`,\n disabled: \"Type a different search term\",\n };\n}\n\nfunction buildAppSearchChoices(\n choices: readonly AppChoice[],\n term: string | undefined,\n): readonly SearchResultChoice[] {\n const normalizedTerm = normalizeTerm(term);\n if (normalizedTerm.length === 0) {\n return [...choices];\n }\n\n const rankedMatches = choices\n .map((choice, index) => ({ choice, index, score: scoreChoice(choice, normalizedTerm) }))\n .filter((item) => Number.isFinite(item.score))\n .sort((left, right) => left.score - right.score || left.index - right.index)\n .map((item) => item.choice);\n\n if (rankedMatches.length > 0) {\n return rankedMatches;\n }\n\n return [noMatchChoice(term)];\n}\n\nexport async function promptForAppSelection(\n choices: readonly AppChoice[],\n deps: AppSearchPromptDeps = {},\n): Promise<string> {\n const searchPrompt = deps.searchPrompt ?? search;\n return await searchPrompt({\n message: \"Select app\",\n pageSize: DEFAULT_PAGE_SIZE,\n source: (term) => Promise.resolve(buildAppSearchChoices(choices, term)),\n validate: (value) => (value === NO_MATCHING_APP ? \"Select a real app.\" : true),\n });\n}\n\nexport const appSearchPromptTestHelpers = {\n buildAppSearchChoices,\n};\n","import { Separator, checkbox, input } from \"@inquirer/prompts\";\n\nimport type { EnvironmentSelection } from \"../commands/setup-app.js\";\nimport { assertValidEnvName } from \"../commands/setup-app.js\";\n\nconst ADD_CUSTOM_ENVIRONMENT = \"__saptools_add_custom_environment__\";\n\ninterface EnvironmentChoice {\n readonly value: string;\n readonly name: string;\n readonly checked?: boolean;\n readonly description?: string;\n}\n\ninterface CheckboxChoiceState {\n readonly value: string;\n}\n\ninterface EnvironmentPromptDeps {\n readonly checkboxPrompt?: (config: {\n message: string;\n choices: readonly (Separator | EnvironmentChoice)[];\n validate: (choices: readonly CheckboxChoiceState[]) => boolean | string;\n }) => Promise<string[]>;\n readonly inputPrompt?: (config: {\n message: string;\n default: string;\n validate: (value: string) => boolean | string;\n }) => Promise<string>;\n}\n\nfunction uniqueNames(names: readonly string[]): string[] {\n const merged: string[] = [];\n for (const name of names) {\n if (!merged.includes(name)) {\n merged.push(name);\n }\n }\n return merged;\n}\n\nfunction validateEnvironmentSelection(choices: readonly CheckboxChoiceState[]): boolean | string {\n const selected = choices.map((choice) => choice.value);\n const hasEnvironment = selected.some((value) => value !== ADD_CUSTOM_ENVIRONMENT);\n if (hasEnvironment || selected.includes(ADD_CUSTOM_ENVIRONMENT)) {\n return true;\n }\n return 'Select at least one environment, or choose \"Add custom environment\".';\n}\n\nfunction buildEnvironmentChoices(\n names: readonly string[],\n selected: ReadonlySet<string>,\n): readonly (Separator | EnvironmentChoice)[] {\n return [\n ...names.map((name) => ({\n value: name,\n name,\n checked: selected.has(name),\n })),\n new Separator(),\n {\n value: ADD_CUSTOM_ENVIRONMENT,\n name: \"Add custom environment\",\n description: \"Create another environment name and return to this menu\",\n },\n ];\n}\n\nfunction validateCustomEnvironmentName(value: string): boolean | string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n return true;\n }\n\n try {\n assertValidEnvName(trimmed);\n return true;\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n}\n\nexport async function promptForEnvironments(\n opts: EnvironmentSelection,\n deps: EnvironmentPromptDeps = {},\n): Promise<readonly string[]> {\n const checkboxPrompt = deps.checkboxPrompt ?? checkbox;\n const inputPrompt = deps.inputPrompt ?? input;\n const selected = new Set<string>(opts.existing);\n const customNames: string[] = [];\n\n for (;;) {\n const names = uniqueNames([...opts.common, ...opts.existing, ...customNames]);\n const answers = await checkboxPrompt({\n message: \"Environments to create (space to toggle, enter to continue)\",\n choices: buildEnvironmentChoices(names, selected),\n validate: validateEnvironmentSelection,\n });\n\n selected.clear();\n for (const name of answers) {\n if (name !== ADD_CUSTOM_ENVIRONMENT) {\n selected.add(name);\n }\n }\n\n if (!answers.includes(ADD_CUSTOM_ENVIRONMENT)) {\n return [...selected];\n }\n\n const custom = (await inputPrompt({\n message: \"Custom environment name (leave empty to go back)\",\n default: \"\",\n validate: validateCustomEnvironmentName,\n })).trim();\n\n if (custom.length === 0) {\n continue;\n }\n\n if (!customNames.includes(custom) && !names.includes(custom)) {\n customNames.push(custom);\n }\n selected.add(custom);\n }\n}\n\nexport const environmentPromptTestHelpers = {\n buildEnvironmentChoices,\n validateEnvironmentSelection,\n validateCustomEnvironmentName,\n};\n"],"mappings":"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","names":["process","readFile","writeFile","join","sep","readFile","join","readFile","join","require","join","readFile","writeFile","readdir","writeFile","join","join","writeFile","readdir","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","process"]}
|
package/dist/index.js
CHANGED
|
@@ -740,14 +740,12 @@ function pickSpace(org) {
|
|
|
740
740
|
function pickApp(space) {
|
|
741
741
|
return space.apps.map((a) => ({ value: a.name, name: a.name }));
|
|
742
742
|
}
|
|
743
|
-
async function
|
|
744
|
-
const deps = options.deps ?? defaultCfInfoDeps;
|
|
745
|
-
const log = options.log ?? (() => void 0);
|
|
743
|
+
async function selectRegion(prompts, deps) {
|
|
746
744
|
const regions = await listRegionsWithContent(deps);
|
|
747
745
|
if (regions.length === 0) {
|
|
748
746
|
throw new Error("No CF regions with orgs are cached. Run `cf-sync sync` first.");
|
|
749
747
|
}
|
|
750
|
-
const regionKey = await
|
|
748
|
+
const regionKey = await prompts.selectRegion(pickRegion(regions));
|
|
751
749
|
const regionView = await deps.readRegionView(regionKey);
|
|
752
750
|
if (!regionView) {
|
|
753
751
|
throw new Error(`Region ${regionKey} is not cached. Run \`cf-sync region ${regionKey}\` or \`cf-sync sync\` first.`);
|
|
@@ -756,7 +754,10 @@ async function setupApp(options) {
|
|
|
756
754
|
if (region.orgs.length === 0) {
|
|
757
755
|
throw new Error(`Region ${regionKey} has no accessible orgs.`);
|
|
758
756
|
}
|
|
759
|
-
|
|
757
|
+
return { regionKey, region };
|
|
758
|
+
}
|
|
759
|
+
async function selectOrg(prompts, region, regionKey) {
|
|
760
|
+
const orgName = await prompts.selectOrg(pickOrg(region));
|
|
760
761
|
const org = region.orgs.find((o) => o.name === orgName);
|
|
761
762
|
if (!org) {
|
|
762
763
|
throw new Error(`Org ${orgName} not found in region ${regionKey}`);
|
|
@@ -764,7 +765,10 @@ async function setupApp(options) {
|
|
|
764
765
|
if (org.spaces.length === 0) {
|
|
765
766
|
throw new Error(`Org ${orgName} has no spaces.`);
|
|
766
767
|
}
|
|
767
|
-
|
|
768
|
+
return { orgName, org };
|
|
769
|
+
}
|
|
770
|
+
async function selectSpace(prompts, org, orgName) {
|
|
771
|
+
const spaceName = await prompts.selectSpace(pickSpace(org));
|
|
768
772
|
const space = org.spaces.find((s) => s.name === spaceName);
|
|
769
773
|
if (!space) {
|
|
770
774
|
throw new Error(`Space ${spaceName} not found in org ${orgName}`);
|
|
@@ -772,24 +776,25 @@ async function setupApp(options) {
|
|
|
772
776
|
if (space.apps.length === 0) {
|
|
773
777
|
throw new Error(`Space ${spaceName} has no apps.`);
|
|
774
778
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
779
|
+
return { spaceName, space };
|
|
780
|
+
}
|
|
781
|
+
async function selectCfAppRef(prompts, deps) {
|
|
782
|
+
const { regionKey, region } = await selectRegion(prompts, deps);
|
|
783
|
+
const { orgName, org } = await selectOrg(prompts, region, regionKey);
|
|
784
|
+
const { spaceName, space } = await selectSpace(prompts, org, orgName);
|
|
785
|
+
const appName = await prompts.selectApp(pickApp(space));
|
|
786
|
+
return { region: regionKey, org: orgName, space: spaceName, app: appName };
|
|
787
|
+
}
|
|
788
|
+
function appPathFor(root, ref) {
|
|
789
|
+
return join4(
|
|
790
|
+
root,
|
|
791
|
+
regionFolderName(ref.region),
|
|
792
|
+
orgFolderName(ref.org),
|
|
793
|
+
spaceFolderName(ref.space),
|
|
794
|
+
ref.app
|
|
783
795
|
);
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
return { ref, appPath, environments: [], created: false };
|
|
787
|
-
}
|
|
788
|
-
await mkdir(appPath, { recursive: true });
|
|
789
|
-
await ensureCollectionConfig(appPath);
|
|
790
|
-
const existingEnvs = await listExistingEnvs(appPath);
|
|
791
|
-
const common = [...COMMON_ENVIRONMENTS];
|
|
792
|
-
const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });
|
|
796
|
+
}
|
|
797
|
+
function normalizeEnvironmentNames(selected) {
|
|
793
798
|
const merged = [];
|
|
794
799
|
for (const name of selected) {
|
|
795
800
|
const trimmed = name.trim();
|
|
@@ -802,12 +807,36 @@ async function setupApp(options) {
|
|
|
802
807
|
if (merged.length === 0) {
|
|
803
808
|
throw new Error("At least one environment is required.");
|
|
804
809
|
}
|
|
810
|
+
return merged;
|
|
811
|
+
}
|
|
812
|
+
async function selectEnvironmentNames(appPath, prompts) {
|
|
813
|
+
const existingEnvs = await listExistingEnvs(appPath);
|
|
814
|
+
const common = [...COMMON_ENVIRONMENTS];
|
|
815
|
+
const selected = await prompts.selectEnvironments({ common, existing: existingEnvs });
|
|
816
|
+
return normalizeEnvironmentNames(selected);
|
|
817
|
+
}
|
|
818
|
+
async function createEnvironmentFiles(appPath, envNames, ref, log) {
|
|
805
819
|
const created = [];
|
|
806
|
-
for (const envName of
|
|
820
|
+
for (const envName of envNames) {
|
|
807
821
|
const path = await ensureEnvFile(appPath, envName, ref);
|
|
808
822
|
created.push(path);
|
|
809
823
|
log(`\u2022 ${path}`);
|
|
810
824
|
}
|
|
825
|
+
return created;
|
|
826
|
+
}
|
|
827
|
+
async function setupApp(options) {
|
|
828
|
+
const deps = options.deps ?? defaultCfInfoDeps;
|
|
829
|
+
const log = options.log ?? (() => void 0);
|
|
830
|
+
const ref = await selectCfAppRef(options.prompts, deps);
|
|
831
|
+
const appPath = appPathFor(options.root, ref);
|
|
832
|
+
const confirmed = await options.prompts.confirmCreate(appPath);
|
|
833
|
+
if (!confirmed) {
|
|
834
|
+
return { ref, appPath, environments: [], created: false };
|
|
835
|
+
}
|
|
836
|
+
await mkdir(appPath, { recursive: true });
|
|
837
|
+
await ensureCollectionConfig(appPath);
|
|
838
|
+
const envNames = await selectEnvironmentNames(appPath, options.prompts);
|
|
839
|
+
const created = await createEnvironmentFiles(appPath, envNames, ref, log);
|
|
811
840
|
return { ref, appPath, environments: created, created: true };
|
|
812
841
|
}
|
|
813
842
|
async function listExistingEnvs(appPath) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/bruno/parser.ts","../src/bruno/writer.ts","../src/cf/info.ts","../src/cf/meta.ts","../src/collection/folder-scan.ts","../src/collection/paths.ts","../src/commands/run.ts","../src/commands/setup-app.ts","../src/state/context.ts","../src/commands/use.ts"],"sourcesContent":["import type { RegionKey } from \"@saptools/cf-sync\";\n\nexport interface CfAppRef {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport interface BruVarsBlock {\n readonly entries: ReadonlyMap<string, string>;\n}\n\nexport interface BruEnvFile {\n readonly path: string;\n readonly name: string;\n readonly raw: string;\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport interface AppFolder {\n readonly path: string;\n readonly name: string;\n readonly environments: readonly BruEnvFile[];\n}\n\nexport interface SpaceFolder {\n readonly path: string;\n readonly name: string;\n readonly apps: readonly AppFolder[];\n}\n\nexport interface OrgFolder {\n readonly path: string;\n readonly name: string;\n readonly spaces: readonly SpaceFolder[];\n}\n\nexport interface RegionFolder {\n readonly path: string;\n readonly key: string;\n readonly orgs: readonly OrgFolder[];\n}\n\nexport interface BrunoCollection {\n readonly root: string;\n readonly regions: readonly RegionFolder[];\n}\n\nexport interface BrunoContext {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly updatedAt: string;\n}\n\nexport interface CfRoute {\n readonly url: string;\n}\n\nexport const CF_META_KEYS = [\"__cf_region\", \"__cf_org\", \"__cf_space\", \"__cf_app\"] as const;\nexport type CfMetaKey = (typeof CF_META_KEYS)[number];\n","import type { BruVarsBlock } from \"../types.js\";\n\ninterface BlockRange {\n readonly header: string;\n readonly start: number;\n readonly end: number;\n readonly bodyStart: number;\n readonly bodyEnd: number;\n readonly open: \"{\" | \"[\";\n readonly close: \"}\" | \"]\";\n}\n\nconst HEADER_REGEX = /(^|\\n)[^\\S\\n]*([a-zA-Z][a-zA-Z0-9:_-]*)[^\\S\\n]*([{[])/g;\n\nfunction findMatchingClose(raw: string, open: \"{\" | \"[\", openIdx: number): number {\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 1;\n let i = openIdx + 1;\n while (i < raw.length) {\n const ch = raw[i];\n if (ch === open) {\n depth++;\n } else if (ch === close) {\n depth--;\n if (depth === 0) {\n return i;\n }\n }\n i++;\n }\n return -1;\n}\n\nexport function listBlocks(raw: string): readonly BlockRange[] {\n const blocks: BlockRange[] = [];\n HEADER_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = HEADER_REGEX.exec(raw)) !== null) {\n const leadingNewline = match[1] ?? \"\";\n const header = match[2];\n const open = match[3];\n if (header === undefined || (open !== \"{\" && open !== \"[\")) {\n continue;\n }\n const headerStart = match.index + leadingNewline.length;\n const openIdx = match.index + match[0].length - 1;\n const closeIdx = findMatchingClose(raw, open, openIdx);\n if (closeIdx === -1) {\n continue;\n }\n blocks.push({\n header,\n start: headerStart,\n end: closeIdx + 1,\n bodyStart: openIdx + 1,\n bodyEnd: closeIdx,\n open,\n close: open === \"{\" ? \"}\" : \"]\",\n });\n }\n return blocks;\n}\n\nexport function parseKeyValueBody(body: string): Map<string, string> {\n const entries = new Map<string, string>();\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n const colon = line.indexOf(\":\");\n if (colon === -1) {\n continue;\n }\n const key = line.slice(0, colon).trim();\n const value = line.slice(colon + 1).trim();\n if (key.length > 0) {\n entries.set(key, value);\n }\n }\n return entries;\n}\n\nexport function parseListBody(body: string): string[] {\n const items: string[] = [];\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n items.push(line);\n }\n return items;\n}\n\nexport interface ParsedBruEnv {\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport function parseBruEnvFile(raw: string): ParsedBruEnv {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n const entries = varsBlock\n ? parseKeyValueBody(raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd))\n : new Map<string, string>();\n const secrets = secretsBlock\n ? parseListBody(raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd))\n : [];\n\n return { vars: { entries }, secrets };\n}\n","import { listBlocks, parseKeyValueBody } from \"./parser.js\";\n\nexport interface UpsertResult {\n readonly content: string;\n readonly changed: boolean;\n}\n\nfunction formatVarsBlock(entries: ReadonlyMap<string, string>): string {\n const lines: string[] = [];\n for (const [key, value] of entries) {\n lines.push(` ${key}: ${value}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function upsertVars(\n raw: string,\n updates: ReadonlyMap<string, string>,\n): UpsertResult {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n\n if (!varsBlock) {\n const newBlock = `vars {\\n${formatVarsBlock(updates)}\\n}\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: updates.size > 0 };\n }\n\n const body = raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd);\n const existing = parseKeyValueBody(body);\n let changed = false;\n for (const [k, v] of updates) {\n if (existing.get(k) !== v) {\n existing.set(k, v);\n changed = true;\n }\n }\n\n if (!changed) {\n return { content: raw, changed: false };\n }\n\n const rebuilt = `\\n${formatVarsBlock(existing)}\\n`;\n const before = raw.slice(0, varsBlock.bodyStart);\n const after = raw.slice(varsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n\nexport function ensureSecretEntry(raw: string, secretName: string): UpsertResult {\n const blocks = listBlocks(raw);\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n if (!secretsBlock) {\n const newBlock = `vars:secret [\\n ${secretName}\\n]\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: true };\n }\n\n const body = raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd);\n const items = body\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\"//\"));\n if (items.includes(secretName)) {\n return { content: raw, changed: false };\n }\n items.push(secretName);\n const rebuilt = `\\n ${items.join(\"\\n \")}\\n`;\n const before = raw.slice(0, secretsBlock.bodyStart);\n const after = raw.slice(secretsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n","import type {\n CfStructure,\n OrgNode,\n RegionKey,\n RegionNode,\n RegionsView,\n RegionView,\n SpaceNode,\n StructureView,\n} from \"@saptools/cf-sync\";\nimport {\n getRegionView as getRegionViewApi,\n readRegionsView,\n readRegionView,\n readStructureView,\n REGION_KEYS,\n} from \"@saptools/cf-sync\";\n\nexport interface CfInfoDeps {\n readonly readStructureView: () => Promise<StructureView | undefined>;\n readonly readRegionsView: () => Promise<RegionsView>;\n readonly readRegionView: (key: RegionKey) => Promise<RegionView | undefined>;\n readonly getRegionView: (opts: {\n readonly regionKey: RegionKey;\n readonly email?: string;\n readonly password?: string;\n readonly refreshIfMissing?: boolean;\n }) => Promise<RegionView | undefined>;\n}\n\nexport const defaultCfInfoDeps: CfInfoDeps = {\n readStructureView,\n readRegionsView,\n readRegionView,\n getRegionView: getRegionViewApi,\n};\n\nexport function isValidRegionKey(value: string): value is RegionKey {\n return (REGION_KEYS as readonly string[]).includes(value);\n}\n\nexport interface StructureSnapshot {\n readonly source: \"runtime\" | \"stable\" | \"empty\";\n readonly structure: CfStructure | undefined;\n readonly stale: boolean;\n readonly message: string | undefined;\n}\n\nexport async function getStructureSnapshot(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<StructureSnapshot> {\n const view = await deps.readStructureView();\n if (!view) {\n return {\n source: \"empty\",\n structure: undefined,\n stale: true,\n message: \"No CF structure cached. Run `cf-sync sync` first.\",\n };\n }\n\n const stale = view.source === \"runtime\" && view.metadata?.status === \"running\";\n return {\n source: view.source,\n structure: view.structure,\n stale,\n message: stale ? \"A CF sync is still running — showing partial data.\" : undefined,\n };\n}\n\nexport interface RegionSuggestion {\n readonly key: RegionKey;\n readonly label: string;\n readonly orgCount: number;\n}\n\nexport async function listRegionsWithContent(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<readonly RegionSuggestion[]> {\n const snapshot = await getStructureSnapshot(deps);\n if (!snapshot.structure) {\n return [];\n }\n return snapshot.structure.regions\n .filter((r) => r.accessible && r.orgs.length > 0)\n .map((r) => ({ key: r.key, label: r.label, orgCount: r.orgs.length }));\n}\n\nexport async function getRegion(\n key: RegionKey,\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<RegionNode | undefined> {\n const view = await deps.readRegionView(key);\n return view?.region;\n}\n\nexport function findOrg(region: RegionNode, orgName: string): OrgNode | undefined {\n return region.orgs.find((o) => o.name === orgName);\n}\n\nexport function findSpace(org: OrgNode, spaceName: string): SpaceNode | undefined {\n return org.spaces.find((s) => s.name === spaceName);\n}\n\nexport function findApp(space: SpaceNode, appName: string): { readonly name: string } | undefined {\n return space.apps.find((a) => a.name === appName);\n}\n\nexport interface ResolvedRef {\n readonly region: RegionNode;\n readonly org: OrgNode;\n readonly space: SpaceNode;\n readonly app: { readonly name: string };\n}\n\nexport async function resolveRef(\n ref: {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n },\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<ResolvedRef | undefined> {\n const region = await getRegion(ref.region, deps);\n if (!region) {\n return undefined;\n }\n const org = findOrg(region, ref.org);\n if (!org) {\n return undefined;\n }\n const space = findSpace(org, ref.space);\n if (!space) {\n return undefined;\n }\n const app = findApp(space, ref.app);\n if (!app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { CF_META_KEYS } from \"../types.js\";\nimport type { CfAppRef, CfMetaKey } from \"../types.js\";\n\nexport interface CfMeta {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport function readCfMetaFromVars(vars: ReadonlyMap<string, string>): CfMeta | undefined {\n const region = vars.get(\"__cf_region\");\n const org = vars.get(\"__cf_org\");\n const space = vars.get(\"__cf_space\");\n const app = vars.get(\"__cf_app\");\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport function buildCfMetaUpdates(ref: CfAppRef, baseUrl?: string): Map<string, string> {\n const updates = new Map<string, string>();\n const pairs: readonly [CfMetaKey, string][] = [\n [\"__cf_region\", ref.region],\n [\"__cf_org\", ref.org],\n [\"__cf_space\", ref.space],\n [\"__cf_app\", ref.app],\n ];\n for (const [k, v] of pairs) {\n updates.set(k, v);\n }\n if (baseUrl !== undefined) {\n updates.set(\"baseUrl\", baseUrl);\n }\n return updates;\n}\n\nexport function hasCfMeta(vars: ReadonlyMap<string, string>): boolean {\n return CF_META_KEYS.every((k) => {\n const v = vars.get(k);\n return v !== undefined && v.length > 0;\n });\n}\n\nexport async function readCfMetaFromFile(path: string): Promise<CfMeta | undefined> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return readCfMetaFromVars(parsed.vars.entries);\n}\n\nexport async function writeCfMetaToFile(\n path: string,\n ref: CfAppRef,\n baseUrl?: string,\n): Promise<boolean> {\n const raw = await readFile(path, \"utf8\");\n const updates = buildCfMetaUpdates(ref, baseUrl);\n const { content, changed } = upsertVars(raw, updates);\n if (changed) {\n await writeFile(path, content, \"utf8\");\n }\n return changed;\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"../types.js\";\n\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\n\nasync function safeReaddir(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function listFiles(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isFile()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function loadEnvFile(path: string, name: string): Promise<BruEnvFile> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return {\n path,\n name: name.replace(/\\.bru$/, \"\"),\n raw,\n vars: parsed.vars,\n secrets: parsed.secrets,\n };\n}\n\nasync function scanAppEnvironments(appPath: string): Promise<readonly BruEnvFile[]> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n const files = await listFiles(envDir);\n const bruFiles = files.filter((f) => f.endsWith(\".bru\"));\n const loaded: BruEnvFile[] = [];\n for (const file of bruFiles) {\n loaded.push(await loadEnvFile(join(envDir, file), file));\n }\n return loaded;\n}\n\nasync function scanApp(spacePath: string, name: string): Promise<AppFolder> {\n const appPath = join(spacePath, name);\n const environments = await scanAppEnvironments(appPath);\n return { path: appPath, name, environments };\n}\n\nasync function scanSpace(orgPath: string, dirName: string): Promise<SpaceFolder | undefined> {\n const name = parsePrefixedName(dirName, SPACE_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const spacePath = join(orgPath, dirName);\n const appDirs = await safeReaddir(spacePath);\n const apps: AppFolder[] = [];\n for (const appDir of appDirs) {\n apps.push(await scanApp(spacePath, appDir));\n }\n return { path: spacePath, name, apps };\n}\n\nasync function scanOrg(regionPath: string, dirName: string): Promise<OrgFolder | undefined> {\n const name = parsePrefixedName(dirName, ORG_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const orgPath = join(regionPath, dirName);\n const spaceDirs = await safeReaddir(orgPath);\n const spaces: SpaceFolder[] = [];\n for (const spaceDir of spaceDirs) {\n const space = await scanSpace(orgPath, spaceDir);\n if (space) {\n spaces.push(space);\n }\n }\n return { path: orgPath, name, spaces };\n}\n\nasync function scanRegion(root: string, dirName: string): Promise<RegionFolder | undefined> {\n const key = parsePrefixedName(dirName, REGION_FOLDER_PREFIX);\n if (key === undefined) {\n return undefined;\n }\n const regionPath = join(root, dirName);\n const orgDirs = await safeReaddir(regionPath);\n const orgs: OrgFolder[] = [];\n for (const orgDir of orgDirs) {\n const org = await scanOrg(regionPath, orgDir);\n if (org) {\n orgs.push(org);\n }\n }\n return { path: regionPath, key, orgs };\n}\n\nexport async function scanCollection(root: string): Promise<BrunoCollection> {\n const regionDirs = await safeReaddir(root);\n const regions: RegionFolder[] = [];\n for (const dir of regionDirs) {\n const region = await scanRegion(root, dir);\n if (region) {\n regions.push(region);\n }\n }\n return { root, regions };\n}\n\nexport interface ShorthandRef {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly environment?: string;\n readonly filePath?: string;\n}\n\nexport function parseShorthandPath(shorthand: string): ShorthandRef | undefined {\n const cleaned = shorthand.replace(/^[./]+/, \"\").replace(/\\\\/g, \"/\");\n const segs = cleaned.split(\"/\").filter((s) => s.length > 0);\n if (segs.length < 4) {\n return undefined;\n }\n const [region, org, space, app, ...rest] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n if (rest.length === 0) {\n return { region, org, space, app };\n }\n const filePath = rest.join(\"/\");\n const last = rest[rest.length - 1] ?? \"\";\n const environment = last.endsWith(\".bru\") ? last.replace(/\\.bru$/, \"\") : undefined;\n return environment\n ? { region, org, space, app, environment, filePath }\n : { region, org, space, app, filePath };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const SAPTOOLS_DIR_NAME = \".saptools\";\nexport const BRUNO_CONTEXT_FILENAME = \"bruno-context.json\";\n\nexport const REGION_FOLDER_PREFIX = \"region__\";\nexport const ORG_FOLDER_PREFIX = \"org__\";\nexport const SPACE_FOLDER_PREFIX = \"space__\";\nexport const ENVIRONMENTS_DIR = \"environments\";\n\nexport function saptoolsDir(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nexport function brunoContextPath(): string {\n return join(saptoolsDir(), BRUNO_CONTEXT_FILENAME);\n}\n\nexport function regionFolderName(key: string): string {\n return `${REGION_FOLDER_PREFIX}${key}`;\n}\n\nexport function orgFolderName(name: string): string {\n return `${ORG_FOLDER_PREFIX}${name}`;\n}\n\nexport function spaceFolderName(name: string): string {\n return `${SPACE_FOLDER_PREFIX}${name}`;\n}\n\nexport function parsePrefixedName(\n dirName: string,\n prefix: string,\n): string | undefined {\n if (!dirName.startsWith(prefix)) {\n return undefined;\n }\n return dirName.slice(prefix.length);\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\n\nimport type { AppRef } from \"@saptools/cf-xsuaa\";\nimport { getTokenCached as getTokenCachedApi } from \"@saptools/cf-xsuaa\";\n\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { readCfMetaFromFile } from \"../cf/meta.js\";\nimport type { ShorthandRef } from \"../collection/folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"../collection/folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\n\nexport type GetTokenCachedFn = (ref: AppRef) => Promise<string>;\n\nexport interface RunSpawnResult {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type SpawnBruFn = (\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n) => Promise<RunSpawnResult>;\n\nexport interface RunOptions {\n readonly root: string;\n readonly target: string;\n readonly environment?: string;\n readonly extraArgs?: readonly string[];\n readonly getTokenCached?: GetTokenCachedFn;\n readonly spawnBru?: SpawnBruFn;\n readonly log?: (msg: string) => void;\n}\n\nexport interface RunPlan {\n readonly filePath: string;\n readonly environment: string;\n readonly envFile: string;\n readonly meta: { readonly region: string; readonly org: string; readonly space: string; readonly app: string };\n readonly token: string;\n readonly bruArgs: readonly string[];\n readonly cwd: string;\n}\n\nexport interface RunResult extends RunPlan {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nconst require = createRequire(import.meta.url);\n\nexport interface BruRuntime {\n readonly command: string;\n readonly argsPrefix: readonly string[];\n}\n\nexport interface ResolveBruRuntimeDeps {\n readonly findOnPath?: (command: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;\n readonly readTextFile?: (path: string) => Promise<string>;\n readonly resolvePackageJsonPath?: () => string;\n}\n\nfunction pathEntries(env: NodeJS.ProcessEnv): readonly string[] {\n const value = env[\"PATH\"] ?? process.env[\"PATH\"] ?? \"\";\n return value.split(delimiter).filter((entry) => entry.length > 0);\n}\n\nfunction pathCandidates(command: string, env: NodeJS.ProcessEnv): readonly string[] {\n if (process.platform !== \"win32\" || command.includes(\".\")) {\n return [command];\n }\n const pathExt =\n env[\"PATHEXT\"]?.split(\";\").filter((entry) => entry.length > 0) ?? [\".COM\", \".EXE\", \".BAT\", \".CMD\"];\n return [command, ...pathExt.map((ext) => `${command}${ext}`)];\n}\n\nasync function findCommandOnPath(command: string, env: NodeJS.ProcessEnv): Promise<string | undefined> {\n const candidates = pathCandidates(command, env);\n for (const entry of pathEntries(env)) {\n for (const candidate of candidates) {\n const fullPath = join(entry, candidate);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction bruBinRelativePath(value: unknown): string | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const bin = value[\"bin\"];\n if (typeof bin === \"string\") {\n return bin;\n }\n if (!isRecord(bin)) {\n return undefined;\n }\n const bru = bin[\"bru\"];\n return typeof bru === \"string\" ? bru : undefined;\n}\n\nfunction defaultResolvePackageJsonPath(): string {\n return require.resolve(\"@usebruno/cli/package.json\");\n}\n\nasync function defaultReadTextFile(path: string): Promise<string> {\n return await readFile(path, \"utf8\");\n}\n\nasync function resolveBundledBruBinPath(\n deps: ResolveBruRuntimeDeps,\n): Promise<string | undefined> {\n try {\n const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();\n const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);\n const binPath = bruBinRelativePath(JSON.parse(raw) as unknown);\n if (!binPath) {\n return undefined;\n }\n return resolve(dirname(packageJsonPath), binPath);\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveBruRuntime(\n env: NodeJS.ProcessEnv = process.env,\n deps: ResolveBruRuntimeDeps = {},\n): Promise<BruRuntime> {\n const onPath = await (deps.findOnPath ?? findCommandOnPath)(\"bru\", env);\n if (onPath) {\n return { command: onPath, argsPrefix: [] };\n }\n const bundledBin = await resolveBundledBruBinPath(deps);\n if (bundledBin) {\n return { command: process.execPath, argsPrefix: [bundledBin] };\n }\n throw new Error(\n \"Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH.\",\n );\n}\n\nasync function defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n const runtime = await resolveBruRuntime(env);\n return await new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: \"pipe\" });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n process.stderr.write(chunk);\n });\n child.on(\"error\", rejectPromise);\n child.on(\"close\", (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\n });\n });\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveTarget(\n root: string,\n target: string,\n): Promise<{ readonly filePath: string; readonly shorthand: ShorthandRef | undefined }> {\n const direct = isAbsolute(target) ? target : resolve(process.cwd(), target);\n if (await exists(direct)) {\n return { filePath: direct, shorthand: undefined };\n }\n\n const shorthand = parseShorthandPath(target);\n if (!shorthand) {\n throw new Error(`Target not found: ${target}`);\n }\n\n const { region, org, space, app, filePath } = shorthand;\n const appDir = join(\n root,\n regionFolderName(region),\n orgFolderName(org),\n spaceFolderName(space),\n app,\n );\n\n if (!filePath) {\n return { filePath: appDir, shorthand };\n }\n\n const candidate = join(appDir, filePath);\n if (await exists(candidate)) {\n return { filePath: candidate, shorthand };\n }\n\n const withExt = candidate.endsWith(\".bru\") ? candidate : `${candidate}.bru`;\n if (await exists(withExt)) {\n return { filePath: withExt, shorthand };\n }\n\n throw new Error(`File not found: ${candidate}`);\n}\n\nasync function chooseEnvironmentFile(\n appDir: string,\n environment: string | undefined,\n): Promise<{ readonly envFile: string; readonly environment: string }> {\n if (environment) {\n const envFile = join(appDir, ENVIRONMENTS_DIR, `${environment}.bru`);\n if (!(await exists(envFile))) {\n throw new Error(`Environment file not found: ${envFile}`);\n }\n return { envFile, environment };\n }\n\n const collection = await scanCollection(resolve(appDir, \"..\", \"..\", \"..\", \"..\"));\n for (const region of collection.regions) {\n for (const org of region.orgs) {\n for (const space of org.spaces) {\n for (const app of space.apps) {\n if (app.path === appDir && app.environments.length > 0) {\n const first = app.environments[0];\n if (first) {\n return { envFile: first.path, environment: first.name };\n }\n }\n }\n }\n }\n }\n throw new Error(`No environment files found under ${appDir}/${ENVIRONMENTS_DIR}`);\n}\n\nfunction findAppDirFromFile(filePath: string, root: string): string {\n const rel = relative(root, filePath).split(sep);\n if (rel.length < 4) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n const [regionDir, orgDir, spaceDir, appDir] = rel;\n if (!regionDir || !orgDir || !spaceDir || !appDir) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n return join(root, regionDir, orgDir, spaceDir, appDir);\n}\n\nasync function persistAccessToken(envFile: string, token: string): Promise<void> {\n const raw = await readFile(envFile, \"utf8\");\n const { content, changed } = upsertVars(raw, new Map([[\"accessToken\", token]]));\n if (changed) {\n await writeFile(envFile, content, \"utf8\");\n }\n}\n\nexport async function buildRunPlan(options: RunOptions): Promise<RunPlan> {\n const { filePath } = await resolveTarget(options.root, options.target);\n const stats = await stat(filePath);\n\n let appDir: string;\n let requestFile: string | undefined;\n\n if (stats.isDirectory()) {\n appDir = filePath;\n requestFile = undefined;\n } else {\n appDir = findAppDirFromFile(filePath, options.root);\n requestFile = filePath;\n }\n\n const { envFile, environment } = await chooseEnvironmentFile(appDir, options.environment);\n\n const meta = await readCfMetaFromFile(envFile);\n if (!meta) {\n throw new Error(\n `Missing __cf_region/__cf_org/__cf_space/__cf_app in ${envFile}. Run \\`saptools-bruno setup-app\\` first.`,\n );\n }\n\n const getToken = options.getTokenCached ?? getTokenCachedApi;\n const token = await getToken(meta);\n await persistAccessToken(envFile, token);\n\n const bruArgs: string[] = [\"run\"];\n if (requestFile) {\n bruArgs.push(relative(appDir, requestFile) || \".\");\n }\n bruArgs.push(\"--env\", environment, \"--env-var\", `accessToken=${token}`);\n if (options.extraArgs) {\n bruArgs.push(...options.extraArgs);\n }\n\n return {\n filePath,\n environment,\n envFile,\n meta,\n token,\n bruArgs,\n cwd: appDir,\n };\n}\n\nexport async function runBruno(options: RunOptions): Promise<RunResult> {\n const plan = await buildRunPlan(options);\n const spawnFn = options.spawnBru ?? defaultSpawnBru;\n const env: NodeJS.ProcessEnv = { ...process.env, SAPTOOLS_ACCESS_TOKEN: plan.token };\n options.log?.(`▶ bru ${plan.bruArgs.join(\" \")} (cwd=${plan.cwd})`);\n const result = await spawnFn(plan.bruArgs, env, plan.cwd);\n return { ...plan, ...result };\n}\n","import { mkdir, readdir, writeFile } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport type { OrgNode, RegionKey, RegionNode, SpaceNode } from \"@saptools/cf-sync\";\n\nimport type { CfInfoDeps } from \"../cf/info.js\";\nimport { defaultCfInfoDeps, listRegionsWithContent } from \"../cf/info.js\";\nimport { writeCfMetaToFile } from \"../cf/meta.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\nimport type { CfAppRef } from \"../types.js\";\n\nexport interface EnvironmentSelection {\n readonly common: readonly string[];\n readonly existing: readonly string[];\n}\n\nexport interface SetupAppPrompts {\n readonly selectRegion: (choices: readonly { value: RegionKey; name: string }[]) => Promise<RegionKey>;\n readonly selectOrg: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectSpace: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectApp: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly confirmCreate: (path: string) => Promise<boolean>;\n readonly selectEnvironments: (opts: EnvironmentSelection) => Promise<readonly string[]>;\n}\n\nexport interface SetupAppOptions {\n readonly root: string;\n readonly prompts: SetupAppPrompts;\n readonly deps?: CfInfoDeps;\n readonly log?: (msg: string) => void;\n}\n\nexport interface SetupAppResult {\n readonly ref: CfAppRef;\n readonly appPath: string;\n readonly environments: readonly string[];\n readonly created: boolean;\n}\n\nexport const COMMON_ENVIRONMENTS = [\"local\", \"dev\", \"staging\", \"prod\"] as const;\nconst BRUNO_COLLECTION_CONFIG_FILENAME = \"bruno.json\";\n\nexport const ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nexport function assertValidEnvName(name: string): void {\n if (!ENV_NAME_PATTERN.test(name)) {\n throw new Error(\n `Invalid environment name '${name}': only letters, digits, dot, underscore, and dash are allowed.`,\n );\n }\n}\n\nfunction emptyEnvContent(envName: string, ref: CfAppRef): string {\n const lines = [\n \"vars {\",\n ` __cf_region: ${ref.region}`,\n ` __cf_org: ${ref.org}`,\n ` __cf_space: ${ref.space}`,\n ` __cf_app: ${ref.app}`,\n ` environment: ${envName}`,\n \" baseUrl: \",\n \"}\",\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nfunction normalizeCollectionName(root: string): string {\n const candidate = basename(root).replace(/^\\.+/, \"\").trim();\n return candidate.length > 0 ? candidate : \"bruno-collection\";\n}\n\nfunction defaultBrunoConfig(root: string): string {\n return `${JSON.stringify(\n {\n version: \"1\",\n name: normalizeCollectionName(root),\n type: \"collection\",\n ignore: [\"node_modules\", \".git\"],\n },\n null,\n 2,\n )}\\n`;\n}\n\nasync function ensureCollectionConfig(root: string): Promise<void> {\n const filePath = join(root, BRUNO_COLLECTION_CONFIG_FILENAME);\n try {\n await writeFile(filePath, defaultBrunoConfig(root), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n }\n}\n\nasync function ensureEnvFile(appPath: string, envName: string, ref: CfAppRef): Promise<string> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n await mkdir(envDir, { recursive: true });\n const filePath = join(envDir, `${envName}.bru`);\n try {\n await writeFile(filePath, emptyEnvContent(envName, ref), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n await writeCfMetaToFile(filePath, ref);\n }\n return filePath;\n}\n\nfunction pickRegion(regions: readonly { key: RegionKey; label: string; orgCount: number }[]): readonly {\n readonly value: RegionKey;\n readonly name: string;\n}[] {\n return regions.map((r) => ({ value: r.key, name: `${r.key} — ${r.label} (${r.orgCount.toString()} org${r.orgCount === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickOrg(region: RegionNode): readonly { value: string; name: string }[] {\n return region.orgs.map((o) => ({ value: o.name, name: `${o.name} (${o.spaces.length.toString()} space${o.spaces.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickSpace(org: OrgNode): readonly { value: string; name: string }[] {\n return org.spaces.map((s) => ({ value: s.name, name: `${s.name} (${s.apps.length.toString()} app${s.apps.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickApp(space: SpaceNode): readonly { value: string; name: string }[] {\n return space.apps.map((a) => ({ value: a.name, name: a.name }));\n}\n\nexport async function setupApp(options: SetupAppOptions): Promise<SetupAppResult> {\n const deps = options.deps ?? defaultCfInfoDeps;\n const log = options.log ?? ((): void => undefined);\n\n const regions = await listRegionsWithContent(deps);\n if (regions.length === 0) {\n throw new Error(\"No CF regions with orgs are cached. Run `cf-sync sync` first.\");\n }\n\n const regionKey = await options.prompts.selectRegion(pickRegion(regions));\n const regionView = await deps.readRegionView(regionKey);\n if (!regionView) {\n throw new Error(`Region ${regionKey} is not cached. Run \\`cf-sync region ${regionKey}\\` or \\`cf-sync sync\\` first.`);\n }\n const region = regionView.region;\n\n if (region.orgs.length === 0) {\n throw new Error(`Region ${regionKey} has no accessible orgs.`);\n }\n\n const orgName = await options.prompts.selectOrg(pickOrg(region));\n const org = region.orgs.find((o) => o.name === orgName);\n if (!org) {\n throw new Error(`Org ${orgName} not found in region ${regionKey}`);\n }\n if (org.spaces.length === 0) {\n throw new Error(`Org ${orgName} has no spaces.`);\n }\n\n const spaceName = await options.prompts.selectSpace(pickSpace(org));\n const space = org.spaces.find((s) => s.name === spaceName);\n if (!space) {\n throw new Error(`Space ${spaceName} not found in org ${orgName}`);\n }\n if (space.apps.length === 0) {\n throw new Error(`Space ${spaceName} has no apps.`);\n }\n\n const appName = await options.prompts.selectApp(pickApp(space));\n const ref: CfAppRef = { region: regionKey, org: orgName, space: spaceName, app: appName };\n\n const appPath = join(\n options.root,\n regionFolderName(regionKey),\n orgFolderName(orgName),\n spaceFolderName(spaceName),\n appName,\n );\n\n const confirmed = await options.prompts.confirmCreate(appPath);\n if (!confirmed) {\n return { ref, appPath, environments: [], created: false };\n }\n\n await mkdir(appPath, { recursive: true });\n await ensureCollectionConfig(appPath);\n\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const merged: string[] = [];\n for (const name of selected) {\n const trimmed = name.trim();\n if (trimmed.length === 0 || merged.includes(trimmed)) {\n continue;\n }\n assertValidEnvName(trimmed);\n merged.push(trimmed);\n }\n if (merged.length === 0) {\n throw new Error(\"At least one environment is required.\");\n }\n\n const created: string[] = [];\n for (const envName of merged) {\n const path = await ensureEnvFile(appPath, envName, ref);\n created.push(path);\n log(`• ${path}`);\n }\n\n return { ref, appPath, environments: created, created: true };\n}\n\nasync function listExistingEnvs(appPath: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(join(appPath, ENVIRONMENTS_DIR), { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".bru\"))\n .map((e) => e.name.replace(/\\.bru$/, \"\"));\n } catch {\n return [];\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"../collection/paths.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport async function readContext(): Promise<BrunoContext | undefined> {\n try {\n const raw = await readFile(brunoContextPath(), \"utf8\");\n return JSON.parse(raw) as BrunoContext;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport async function writeContext(ctx: Omit<BrunoContext, \"updatedAt\">): Promise<BrunoContext> {\n const updated: BrunoContext = { ...ctx, updatedAt: new Date().toISOString() };\n const path = brunoContextPath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n return updated;\n}\n","import type { CfInfoDeps } from \"../cf/info.js\";\nimport { isValidRegionKey, resolveRef } from \"../cf/info.js\";\nimport { writeContext } from \"../state/context.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport function parseContextShorthand(shorthand: string): {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n} | undefined {\n const segs = shorthand.split(\"/\").filter((s) => s.length > 0);\n if (segs.length !== 4) {\n return undefined;\n }\n const [region, org, space, app] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport interface UseOptions {\n readonly shorthand: string;\n readonly deps?: CfInfoDeps;\n readonly verify?: boolean;\n}\n\nexport async function useContext(options: UseOptions): Promise<BrunoContext> {\n const parsed = parseContextShorthand(options.shorthand);\n if (!parsed) {\n throw new Error(\n `Invalid context shorthand: ${options.shorthand}. Expected <region>/<org>/<space>/<app>.`,\n );\n }\n\n if (!isValidRegionKey(parsed.region)) {\n throw new Error(`Unknown region key: ${parsed.region}`);\n }\n\n if (options.verify !== false) {\n const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);\n if (!resolved) {\n throw new Error(\n `Could not verify ${options.shorthand} against the cached CF structure. Run \\`cf-sync sync\\` first.`,\n );\n }\n }\n\n return await writeContext(parsed);\n}\n"],"mappings":"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","names":["sep","readFile","join","readFile","join","readFile","writeFile","join","require","join","readFile","writeFile","readdir","writeFile","join","join","writeFile","readdir","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/bruno/parser.ts","../src/bruno/writer.ts","../src/cf/info.ts","../src/cf/meta.ts","../src/collection/folder-scan.ts","../src/collection/paths.ts","../src/commands/run.ts","../src/commands/setup-app.ts","../src/state/context.ts","../src/commands/use.ts"],"sourcesContent":["import type { RegionKey } from \"@saptools/cf-sync\";\n\nexport interface CfAppRef {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport interface BruVarsBlock {\n readonly entries: ReadonlyMap<string, string>;\n}\n\nexport interface BruEnvFile {\n readonly path: string;\n readonly name: string;\n readonly raw: string;\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport interface AppFolder {\n readonly path: string;\n readonly name: string;\n readonly environments: readonly BruEnvFile[];\n}\n\nexport interface SpaceFolder {\n readonly path: string;\n readonly name: string;\n readonly apps: readonly AppFolder[];\n}\n\nexport interface OrgFolder {\n readonly path: string;\n readonly name: string;\n readonly spaces: readonly SpaceFolder[];\n}\n\nexport interface RegionFolder {\n readonly path: string;\n readonly key: string;\n readonly orgs: readonly OrgFolder[];\n}\n\nexport interface BrunoCollection {\n readonly root: string;\n readonly regions: readonly RegionFolder[];\n}\n\nexport interface BrunoContext {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly updatedAt: string;\n}\n\nexport interface CfRoute {\n readonly url: string;\n}\n\nexport const CF_META_KEYS = [\"__cf_region\", \"__cf_org\", \"__cf_space\", \"__cf_app\"] as const;\nexport type CfMetaKey = (typeof CF_META_KEYS)[number];\n","import type { BruVarsBlock } from \"../types.js\";\n\ninterface BlockRange {\n readonly header: string;\n readonly start: number;\n readonly end: number;\n readonly bodyStart: number;\n readonly bodyEnd: number;\n readonly open: \"{\" | \"[\";\n readonly close: \"}\" | \"]\";\n}\n\nconst HEADER_REGEX = /(^|\\n)[^\\S\\n]*([a-zA-Z][a-zA-Z0-9:_-]*)[^\\S\\n]*([{[])/g;\n\nfunction findMatchingClose(raw: string, open: \"{\" | \"[\", openIdx: number): number {\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 1;\n let i = openIdx + 1;\n while (i < raw.length) {\n const ch = raw[i];\n if (ch === open) {\n depth++;\n } else if (ch === close) {\n depth--;\n if (depth === 0) {\n return i;\n }\n }\n i++;\n }\n return -1;\n}\n\nexport function listBlocks(raw: string): readonly BlockRange[] {\n const blocks: BlockRange[] = [];\n HEADER_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = HEADER_REGEX.exec(raw)) !== null) {\n const leadingNewline = match[1] ?? \"\";\n const header = match[2];\n const open = match[3];\n if (header === undefined || (open !== \"{\" && open !== \"[\")) {\n continue;\n }\n const headerStart = match.index + leadingNewline.length;\n const openIdx = match.index + match[0].length - 1;\n const closeIdx = findMatchingClose(raw, open, openIdx);\n if (closeIdx === -1) {\n continue;\n }\n blocks.push({\n header,\n start: headerStart,\n end: closeIdx + 1,\n bodyStart: openIdx + 1,\n bodyEnd: closeIdx,\n open,\n close: open === \"{\" ? \"}\" : \"]\",\n });\n }\n return blocks;\n}\n\nexport function parseKeyValueBody(body: string): Map<string, string> {\n const entries = new Map<string, string>();\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n const colon = line.indexOf(\":\");\n if (colon === -1) {\n continue;\n }\n const key = line.slice(0, colon).trim();\n const value = line.slice(colon + 1).trim();\n if (key.length > 0) {\n entries.set(key, value);\n }\n }\n return entries;\n}\n\nexport function parseListBody(body: string): string[] {\n const items: string[] = [];\n for (const lineRaw of body.split(\"\\n\")) {\n const line = lineRaw.trim();\n if (line.length === 0 || line.startsWith(\"//\")) {\n continue;\n }\n items.push(line);\n }\n return items;\n}\n\nexport interface ParsedBruEnv {\n readonly vars: BruVarsBlock;\n readonly secrets: readonly string[];\n}\n\nexport function parseBruEnvFile(raw: string): ParsedBruEnv {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n const entries = varsBlock\n ? parseKeyValueBody(raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd))\n : new Map<string, string>();\n const secrets = secretsBlock\n ? parseListBody(raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd))\n : [];\n\n return { vars: { entries }, secrets };\n}\n","import { listBlocks, parseKeyValueBody } from \"./parser.js\";\n\nexport interface UpsertResult {\n readonly content: string;\n readonly changed: boolean;\n}\n\nfunction formatVarsBlock(entries: ReadonlyMap<string, string>): string {\n const lines: string[] = [];\n for (const [key, value] of entries) {\n lines.push(` ${key}: ${value}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function upsertVars(\n raw: string,\n updates: ReadonlyMap<string, string>,\n): UpsertResult {\n const blocks = listBlocks(raw);\n const varsBlock = blocks.find((b) => b.header === \"vars\" && b.open === \"{\");\n\n if (!varsBlock) {\n const newBlock = `vars {\\n${formatVarsBlock(updates)}\\n}\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: updates.size > 0 };\n }\n\n const body = raw.slice(varsBlock.bodyStart, varsBlock.bodyEnd);\n const existing = parseKeyValueBody(body);\n let changed = false;\n for (const [k, v] of updates) {\n if (existing.get(k) !== v) {\n existing.set(k, v);\n changed = true;\n }\n }\n\n if (!changed) {\n return { content: raw, changed: false };\n }\n\n const rebuilt = `\\n${formatVarsBlock(existing)}\\n`;\n const before = raw.slice(0, varsBlock.bodyStart);\n const after = raw.slice(varsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n\nexport function ensureSecretEntry(raw: string, secretName: string): UpsertResult {\n const blocks = listBlocks(raw);\n const secretsBlock = blocks.find((b) => b.header === \"vars:secret\" && b.open === \"[\");\n\n if (!secretsBlock) {\n const newBlock = `vars:secret [\\n ${secretName}\\n]\\n`;\n const sep = raw.length > 0 && !raw.endsWith(\"\\n\") ? \"\\n\\n\" : raw.length > 0 ? \"\\n\" : \"\";\n return { content: `${raw}${sep}${newBlock}`, changed: true };\n }\n\n const body = raw.slice(secretsBlock.bodyStart, secretsBlock.bodyEnd);\n const items = body\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\"//\"));\n if (items.includes(secretName)) {\n return { content: raw, changed: false };\n }\n items.push(secretName);\n const rebuilt = `\\n ${items.join(\"\\n \")}\\n`;\n const before = raw.slice(0, secretsBlock.bodyStart);\n const after = raw.slice(secretsBlock.bodyEnd);\n return { content: `${before}${rebuilt}${after}`, changed: true };\n}\n","import type {\n CfStructure,\n OrgNode,\n RegionKey,\n RegionNode,\n RegionsView,\n RegionView,\n SpaceNode,\n StructureView,\n} from \"@saptools/cf-sync\";\nimport {\n getRegionView as getRegionViewApi,\n readRegionsView,\n readRegionView,\n readStructureView,\n REGION_KEYS,\n} from \"@saptools/cf-sync\";\n\nexport interface CfInfoDeps {\n readonly readStructureView: () => Promise<StructureView | undefined>;\n readonly readRegionsView: () => Promise<RegionsView>;\n readonly readRegionView: (key: RegionKey) => Promise<RegionView | undefined>;\n readonly getRegionView: (opts: {\n readonly regionKey: RegionKey;\n readonly email?: string;\n readonly password?: string;\n readonly refreshIfMissing?: boolean;\n }) => Promise<RegionView | undefined>;\n}\n\nexport const defaultCfInfoDeps: CfInfoDeps = {\n readStructureView,\n readRegionsView,\n readRegionView,\n getRegionView: getRegionViewApi,\n};\n\nexport function isValidRegionKey(value: string): value is RegionKey {\n return (REGION_KEYS as readonly string[]).includes(value);\n}\n\nexport interface StructureSnapshot {\n readonly source: \"runtime\" | \"stable\" | \"empty\";\n readonly structure: CfStructure | undefined;\n readonly stale: boolean;\n readonly message: string | undefined;\n}\n\nexport async function getStructureSnapshot(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<StructureSnapshot> {\n const view = await deps.readStructureView();\n if (!view) {\n return {\n source: \"empty\",\n structure: undefined,\n stale: true,\n message: \"No CF structure cached. Run `cf-sync sync` first.\",\n };\n }\n\n const stale = view.source === \"runtime\" && view.metadata?.status === \"running\";\n return {\n source: view.source,\n structure: view.structure,\n stale,\n message: stale ? \"A CF sync is still running — showing partial data.\" : undefined,\n };\n}\n\nexport interface RegionSuggestion {\n readonly key: RegionKey;\n readonly label: string;\n readonly orgCount: number;\n}\n\nexport async function listRegionsWithContent(\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<readonly RegionSuggestion[]> {\n const snapshot = await getStructureSnapshot(deps);\n if (!snapshot.structure) {\n return [];\n }\n return snapshot.structure.regions\n .filter((r) => r.accessible && r.orgs.length > 0)\n .map((r) => ({ key: r.key, label: r.label, orgCount: r.orgs.length }));\n}\n\nexport async function getRegion(\n key: RegionKey,\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<RegionNode | undefined> {\n const view = await deps.readRegionView(key);\n return view?.region;\n}\n\nexport function findOrg(region: RegionNode, orgName: string): OrgNode | undefined {\n return region.orgs.find((o) => o.name === orgName);\n}\n\nexport function findSpace(org: OrgNode, spaceName: string): SpaceNode | undefined {\n return org.spaces.find((s) => s.name === spaceName);\n}\n\nexport function findApp(space: SpaceNode, appName: string): { readonly name: string } | undefined {\n return space.apps.find((a) => a.name === appName);\n}\n\nexport interface ResolvedRef {\n readonly region: RegionNode;\n readonly org: OrgNode;\n readonly space: SpaceNode;\n readonly app: { readonly name: string };\n}\n\nexport async function resolveRef(\n ref: {\n readonly region: RegionKey;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n },\n deps: CfInfoDeps = defaultCfInfoDeps,\n): Promise<ResolvedRef | undefined> {\n const region = await getRegion(ref.region, deps);\n if (!region) {\n return undefined;\n }\n const org = findOrg(region, ref.org);\n if (!org) {\n return undefined;\n }\n const space = findSpace(org, ref.space);\n if (!space) {\n return undefined;\n }\n const app = findApp(space, ref.app);\n if (!app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { CF_META_KEYS } from \"../types.js\";\nimport type { CfAppRef, CfMetaKey } from \"../types.js\";\n\nexport interface CfMeta {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n}\n\nexport function readCfMetaFromVars(vars: ReadonlyMap<string, string>): CfMeta | undefined {\n const region = vars.get(\"__cf_region\");\n const org = vars.get(\"__cf_org\");\n const space = vars.get(\"__cf_space\");\n const app = vars.get(\"__cf_app\");\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport function buildCfMetaUpdates(ref: CfAppRef, baseUrl?: string): Map<string, string> {\n const updates = new Map<string, string>();\n const pairs: readonly [CfMetaKey, string][] = [\n [\"__cf_region\", ref.region],\n [\"__cf_org\", ref.org],\n [\"__cf_space\", ref.space],\n [\"__cf_app\", ref.app],\n ];\n for (const [k, v] of pairs) {\n updates.set(k, v);\n }\n if (baseUrl !== undefined) {\n updates.set(\"baseUrl\", baseUrl);\n }\n return updates;\n}\n\nexport function hasCfMeta(vars: ReadonlyMap<string, string>): boolean {\n return CF_META_KEYS.every((k) => {\n const v = vars.get(k);\n return v !== undefined && v.length > 0;\n });\n}\n\nexport async function readCfMetaFromFile(path: string): Promise<CfMeta | undefined> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return readCfMetaFromVars(parsed.vars.entries);\n}\n\nexport async function writeCfMetaToFile(\n path: string,\n ref: CfAppRef,\n baseUrl?: string,\n): Promise<boolean> {\n const raw = await readFile(path, \"utf8\");\n const updates = buildCfMetaUpdates(ref, baseUrl);\n const { content, changed } = upsertVars(raw, updates);\n if (changed) {\n await writeFile(path, content, \"utf8\");\n }\n return changed;\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"../bruno/parser.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"../types.js\";\n\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\n\nasync function safeReaddir(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function listFiles(path: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries.filter((e) => e.isFile()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function loadEnvFile(path: string, name: string): Promise<BruEnvFile> {\n const raw = await readFile(path, \"utf8\");\n const parsed = parseBruEnvFile(raw);\n return {\n path,\n name: name.replace(/\\.bru$/, \"\"),\n raw,\n vars: parsed.vars,\n secrets: parsed.secrets,\n };\n}\n\nasync function scanAppEnvironments(appPath: string): Promise<readonly BruEnvFile[]> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n const files = await listFiles(envDir);\n const bruFiles = files.filter((f) => f.endsWith(\".bru\"));\n const loaded: BruEnvFile[] = [];\n for (const file of bruFiles) {\n loaded.push(await loadEnvFile(join(envDir, file), file));\n }\n return loaded;\n}\n\nasync function scanApp(spacePath: string, name: string): Promise<AppFolder> {\n const appPath = join(spacePath, name);\n const environments = await scanAppEnvironments(appPath);\n return { path: appPath, name, environments };\n}\n\nasync function scanSpace(orgPath: string, dirName: string): Promise<SpaceFolder | undefined> {\n const name = parsePrefixedName(dirName, SPACE_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const spacePath = join(orgPath, dirName);\n const appDirs = await safeReaddir(spacePath);\n const apps: AppFolder[] = [];\n for (const appDir of appDirs) {\n apps.push(await scanApp(spacePath, appDir));\n }\n return { path: spacePath, name, apps };\n}\n\nasync function scanOrg(regionPath: string, dirName: string): Promise<OrgFolder | undefined> {\n const name = parsePrefixedName(dirName, ORG_FOLDER_PREFIX);\n if (name === undefined) {\n return undefined;\n }\n const orgPath = join(regionPath, dirName);\n const spaceDirs = await safeReaddir(orgPath);\n const spaces: SpaceFolder[] = [];\n for (const spaceDir of spaceDirs) {\n const space = await scanSpace(orgPath, spaceDir);\n if (space) {\n spaces.push(space);\n }\n }\n return { path: orgPath, name, spaces };\n}\n\nasync function scanRegion(root: string, dirName: string): Promise<RegionFolder | undefined> {\n const key = parsePrefixedName(dirName, REGION_FOLDER_PREFIX);\n if (key === undefined) {\n return undefined;\n }\n const regionPath = join(root, dirName);\n const orgDirs = await safeReaddir(regionPath);\n const orgs: OrgFolder[] = [];\n for (const orgDir of orgDirs) {\n const org = await scanOrg(regionPath, orgDir);\n if (org) {\n orgs.push(org);\n }\n }\n return { path: regionPath, key, orgs };\n}\n\nexport async function scanCollection(root: string): Promise<BrunoCollection> {\n const regionDirs = await safeReaddir(root);\n const regions: RegionFolder[] = [];\n for (const dir of regionDirs) {\n const region = await scanRegion(root, dir);\n if (region) {\n regions.push(region);\n }\n }\n return { root, regions };\n}\n\nexport interface ShorthandRef {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n readonly environment?: string;\n readonly filePath?: string;\n}\n\nexport function parseShorthandPath(shorthand: string): ShorthandRef | undefined {\n const cleaned = shorthand.replace(/^[./]+/, \"\").replace(/\\\\/g, \"/\");\n const segs = cleaned.split(\"/\").filter((s) => s.length > 0);\n if (segs.length < 4) {\n return undefined;\n }\n const [region, org, space, app, ...rest] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n if (rest.length === 0) {\n return { region, org, space, app };\n }\n const filePath = rest.join(\"/\");\n const last = rest[rest.length - 1] ?? \"\";\n const environment = last.endsWith(\".bru\") ? last.replace(/\\.bru$/, \"\") : undefined;\n return environment\n ? { region, org, space, app, environment, filePath }\n : { region, org, space, app, filePath };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const SAPTOOLS_DIR_NAME = \".saptools\";\nexport const BRUNO_CONTEXT_FILENAME = \"bruno-context.json\";\n\nexport const REGION_FOLDER_PREFIX = \"region__\";\nexport const ORG_FOLDER_PREFIX = \"org__\";\nexport const SPACE_FOLDER_PREFIX = \"space__\";\nexport const ENVIRONMENTS_DIR = \"environments\";\n\nexport function saptoolsDir(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nexport function brunoContextPath(): string {\n return join(saptoolsDir(), BRUNO_CONTEXT_FILENAME);\n}\n\nexport function regionFolderName(key: string): string {\n return `${REGION_FOLDER_PREFIX}${key}`;\n}\n\nexport function orgFolderName(name: string): string {\n return `${ORG_FOLDER_PREFIX}${name}`;\n}\n\nexport function spaceFolderName(name: string): string {\n return `${SPACE_FOLDER_PREFIX}${name}`;\n}\n\nexport function parsePrefixedName(\n dirName: string,\n prefix: string,\n): string | undefined {\n if (!dirName.startsWith(prefix)) {\n return undefined;\n }\n return dirName.slice(prefix.length);\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\n\nimport type { AppRef } from \"@saptools/cf-xsuaa\";\nimport { getTokenCached as getTokenCachedApi } from \"@saptools/cf-xsuaa\";\n\nimport { upsertVars } from \"../bruno/writer.js\";\nimport { readCfMetaFromFile } from \"../cf/meta.js\";\nimport type { ShorthandRef } from \"../collection/folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"../collection/folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\n\nexport type GetTokenCachedFn = (ref: AppRef) => Promise<string>;\n\nexport interface RunSpawnResult {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type SpawnBruFn = (\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n) => Promise<RunSpawnResult>;\n\nexport interface RunOptions {\n readonly root: string;\n readonly target: string;\n readonly environment?: string;\n readonly extraArgs?: readonly string[];\n readonly getTokenCached?: GetTokenCachedFn;\n readonly spawnBru?: SpawnBruFn;\n readonly log?: (msg: string) => void;\n}\n\nexport interface RunPlan {\n readonly filePath: string;\n readonly environment: string;\n readonly envFile: string;\n readonly meta: { readonly region: string; readonly org: string; readonly space: string; readonly app: string };\n readonly token: string;\n readonly bruArgs: readonly string[];\n readonly cwd: string;\n}\n\nexport interface RunResult extends RunPlan {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nconst require = createRequire(import.meta.url);\n\nexport interface BruRuntime {\n readonly command: string;\n readonly argsPrefix: readonly string[];\n}\n\nexport interface ResolveBruRuntimeDeps {\n readonly findOnPath?: (command: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;\n readonly readTextFile?: (path: string) => Promise<string>;\n readonly resolvePackageJsonPath?: () => string;\n}\n\nfunction pathEntries(env: NodeJS.ProcessEnv): readonly string[] {\n const value = env[\"PATH\"] ?? process.env[\"PATH\"] ?? \"\";\n return value.split(delimiter).filter((entry) => entry.length > 0);\n}\n\nfunction pathCandidates(command: string, env: NodeJS.ProcessEnv): readonly string[] {\n if (process.platform !== \"win32\" || command.includes(\".\")) {\n return [command];\n }\n const pathExt =\n env[\"PATHEXT\"]?.split(\";\").filter((entry) => entry.length > 0) ?? [\".COM\", \".EXE\", \".BAT\", \".CMD\"];\n return [command, ...pathExt.map((ext) => `${command}${ext}`)];\n}\n\nasync function findCommandOnPath(command: string, env: NodeJS.ProcessEnv): Promise<string | undefined> {\n const candidates = pathCandidates(command, env);\n for (const entry of pathEntries(env)) {\n for (const candidate of candidates) {\n const fullPath = join(entry, candidate);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction bruBinRelativePath(value: unknown): string | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const bin = value[\"bin\"];\n if (typeof bin === \"string\") {\n return bin;\n }\n if (!isRecord(bin)) {\n return undefined;\n }\n const bru = bin[\"bru\"];\n return typeof bru === \"string\" ? bru : undefined;\n}\n\nfunction defaultResolvePackageJsonPath(): string {\n return require.resolve(\"@usebruno/cli/package.json\");\n}\n\nasync function defaultReadTextFile(path: string): Promise<string> {\n return await readFile(path, \"utf8\");\n}\n\nasync function resolveBundledBruBinPath(\n deps: ResolveBruRuntimeDeps,\n): Promise<string | undefined> {\n try {\n const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();\n const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);\n const binPath = bruBinRelativePath(JSON.parse(raw) as unknown);\n if (!binPath) {\n return undefined;\n }\n return resolve(dirname(packageJsonPath), binPath);\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveBruRuntime(\n env: NodeJS.ProcessEnv = process.env,\n deps: ResolveBruRuntimeDeps = {},\n): Promise<BruRuntime> {\n const onPath = await (deps.findOnPath ?? findCommandOnPath)(\"bru\", env);\n if (onPath) {\n return { command: onPath, argsPrefix: [] };\n }\n const bundledBin = await resolveBundledBruBinPath(deps);\n if (bundledBin) {\n return { command: process.execPath, argsPrefix: [bundledBin] };\n }\n throw new Error(\n \"Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH.\",\n );\n}\n\nasync function defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n const runtime = await resolveBruRuntime(env);\n return await new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: \"pipe\" });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n process.stdout.write(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n process.stderr.write(chunk);\n });\n child.on(\"error\", rejectPromise);\n child.on(\"close\", (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\n });\n });\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveTarget(\n root: string,\n target: string,\n): Promise<{ readonly filePath: string; readonly shorthand: ShorthandRef | undefined }> {\n const direct = isAbsolute(target) ? target : resolve(process.cwd(), target);\n if (await exists(direct)) {\n return { filePath: direct, shorthand: undefined };\n }\n\n const shorthand = parseShorthandPath(target);\n if (!shorthand) {\n throw new Error(`Target not found: ${target}`);\n }\n\n const { region, org, space, app, filePath } = shorthand;\n const appDir = join(\n root,\n regionFolderName(region),\n orgFolderName(org),\n spaceFolderName(space),\n app,\n );\n\n if (!filePath) {\n return { filePath: appDir, shorthand };\n }\n\n const candidate = join(appDir, filePath);\n if (await exists(candidate)) {\n return { filePath: candidate, shorthand };\n }\n\n const withExt = candidate.endsWith(\".bru\") ? candidate : `${candidate}.bru`;\n if (await exists(withExt)) {\n return { filePath: withExt, shorthand };\n }\n\n throw new Error(`File not found: ${candidate}`);\n}\n\nasync function chooseEnvironmentFile(\n appDir: string,\n environment: string | undefined,\n): Promise<{ readonly envFile: string; readonly environment: string }> {\n if (environment) {\n const envFile = join(appDir, ENVIRONMENTS_DIR, `${environment}.bru`);\n if (!(await exists(envFile))) {\n throw new Error(`Environment file not found: ${envFile}`);\n }\n return { envFile, environment };\n }\n\n const collection = await scanCollection(resolve(appDir, \"..\", \"..\", \"..\", \"..\"));\n for (const region of collection.regions) {\n for (const org of region.orgs) {\n for (const space of org.spaces) {\n for (const app of space.apps) {\n if (app.path === appDir && app.environments.length > 0) {\n const first = app.environments[0];\n if (first) {\n return { envFile: first.path, environment: first.name };\n }\n }\n }\n }\n }\n }\n throw new Error(`No environment files found under ${appDir}/${ENVIRONMENTS_DIR}`);\n}\n\nfunction findAppDirFromFile(filePath: string, root: string): string {\n const rel = relative(root, filePath).split(sep);\n if (rel.length < 4) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n const [regionDir, orgDir, spaceDir, appDir] = rel;\n if (!regionDir || !orgDir || !spaceDir || !appDir) {\n throw new Error(`File is not inside a CF-structured bruno collection: ${filePath}`);\n }\n return join(root, regionDir, orgDir, spaceDir, appDir);\n}\n\nasync function persistAccessToken(envFile: string, token: string): Promise<void> {\n const raw = await readFile(envFile, \"utf8\");\n const { content, changed } = upsertVars(raw, new Map([[\"accessToken\", token]]));\n if (changed) {\n await writeFile(envFile, content, \"utf8\");\n }\n}\n\nexport async function buildRunPlan(options: RunOptions): Promise<RunPlan> {\n const { filePath } = await resolveTarget(options.root, options.target);\n const stats = await stat(filePath);\n\n let appDir: string;\n let requestFile: string | undefined;\n\n if (stats.isDirectory()) {\n appDir = filePath;\n requestFile = undefined;\n } else {\n appDir = findAppDirFromFile(filePath, options.root);\n requestFile = filePath;\n }\n\n const { envFile, environment } = await chooseEnvironmentFile(appDir, options.environment);\n\n const meta = await readCfMetaFromFile(envFile);\n if (!meta) {\n throw new Error(\n `Missing __cf_region/__cf_org/__cf_space/__cf_app in ${envFile}. Run \\`saptools-bruno setup-app\\` first.`,\n );\n }\n\n const getToken = options.getTokenCached ?? getTokenCachedApi;\n const token = await getToken(meta);\n await persistAccessToken(envFile, token);\n\n const bruArgs: string[] = [\"run\"];\n if (requestFile) {\n bruArgs.push(relative(appDir, requestFile) || \".\");\n }\n bruArgs.push(\"--env\", environment, \"--env-var\", `accessToken=${token}`);\n if (options.extraArgs) {\n bruArgs.push(...options.extraArgs);\n }\n\n return {\n filePath,\n environment,\n envFile,\n meta,\n token,\n bruArgs,\n cwd: appDir,\n };\n}\n\nexport async function runBruno(options: RunOptions): Promise<RunResult> {\n const plan = await buildRunPlan(options);\n const spawnFn = options.spawnBru ?? defaultSpawnBru;\n const env: NodeJS.ProcessEnv = { ...process.env, SAPTOOLS_ACCESS_TOKEN: plan.token };\n options.log?.(`▶ bru ${plan.bruArgs.join(\" \")} (cwd=${plan.cwd})`);\n const result = await spawnFn(plan.bruArgs, env, plan.cwd);\n return { ...plan, ...result };\n}\n","import { mkdir, readdir, writeFile } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport type { OrgNode, RegionKey, RegionNode, SpaceNode } from \"@saptools/cf-sync\";\n\nimport type { CfInfoDeps } from \"../cf/info.js\";\nimport { defaultCfInfoDeps, listRegionsWithContent } from \"../cf/info.js\";\nimport { writeCfMetaToFile } from \"../cf/meta.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"../collection/paths.js\";\nimport type { CfAppRef } from \"../types.js\";\n\nexport interface EnvironmentSelection {\n readonly common: readonly string[];\n readonly existing: readonly string[];\n}\n\nexport interface SetupAppPrompts {\n readonly selectRegion: (choices: readonly { value: RegionKey; name: string }[]) => Promise<RegionKey>;\n readonly selectOrg: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectSpace: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly selectApp: (choices: readonly { value: string; name: string }[]) => Promise<string>;\n readonly confirmCreate: (path: string) => Promise<boolean>;\n readonly selectEnvironments: (opts: EnvironmentSelection) => Promise<readonly string[]>;\n}\n\nexport interface SetupAppOptions {\n readonly root: string;\n readonly prompts: SetupAppPrompts;\n readonly deps?: CfInfoDeps;\n readonly log?: (msg: string) => void;\n}\n\nexport interface SetupAppResult {\n readonly ref: CfAppRef;\n readonly appPath: string;\n readonly environments: readonly string[];\n readonly created: boolean;\n}\n\nexport const COMMON_ENVIRONMENTS = [\"local\", \"dev\", \"staging\", \"prod\"] as const;\nconst BRUNO_COLLECTION_CONFIG_FILENAME = \"bruno.json\";\n\nexport const ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nexport function assertValidEnvName(name: string): void {\n if (!ENV_NAME_PATTERN.test(name)) {\n throw new Error(\n `Invalid environment name '${name}': only letters, digits, dot, underscore, and dash are allowed.`,\n );\n }\n}\n\nfunction emptyEnvContent(envName: string, ref: CfAppRef): string {\n const lines = [\n \"vars {\",\n ` __cf_region: ${ref.region}`,\n ` __cf_org: ${ref.org}`,\n ` __cf_space: ${ref.space}`,\n ` __cf_app: ${ref.app}`,\n ` environment: ${envName}`,\n \" baseUrl: \",\n \"}\",\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nfunction normalizeCollectionName(root: string): string {\n const candidate = basename(root).replace(/^\\.+/, \"\").trim();\n return candidate.length > 0 ? candidate : \"bruno-collection\";\n}\n\nfunction defaultBrunoConfig(root: string): string {\n return `${JSON.stringify(\n {\n version: \"1\",\n name: normalizeCollectionName(root),\n type: \"collection\",\n ignore: [\"node_modules\", \".git\"],\n },\n null,\n 2,\n )}\\n`;\n}\n\nasync function ensureCollectionConfig(root: string): Promise<void> {\n const filePath = join(root, BRUNO_COLLECTION_CONFIG_FILENAME);\n try {\n await writeFile(filePath, defaultBrunoConfig(root), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n }\n}\n\nasync function ensureEnvFile(appPath: string, envName: string, ref: CfAppRef): Promise<string> {\n const envDir = join(appPath, ENVIRONMENTS_DIR);\n await mkdir(envDir, { recursive: true });\n const filePath = join(envDir, `${envName}.bru`);\n try {\n await writeFile(filePath, emptyEnvContent(envName, ref), { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n await writeCfMetaToFile(filePath, ref);\n }\n return filePath;\n}\n\nfunction pickRegion(regions: readonly { key: RegionKey; label: string; orgCount: number }[]): readonly {\n readonly value: RegionKey;\n readonly name: string;\n}[] {\n return regions.map((r) => ({ value: r.key, name: `${r.key} — ${r.label} (${r.orgCount.toString()} org${r.orgCount === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickOrg(region: RegionNode): readonly { value: string; name: string }[] {\n return region.orgs.map((o) => ({ value: o.name, name: `${o.name} (${o.spaces.length.toString()} space${o.spaces.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickSpace(org: OrgNode): readonly { value: string; name: string }[] {\n return org.spaces.map((s) => ({ value: s.name, name: `${s.name} (${s.apps.length.toString()} app${s.apps.length === 1 ? \"\" : \"s\"})` }));\n}\n\nfunction pickApp(space: SpaceNode): readonly { value: string; name: string }[] {\n return space.apps.map((a) => ({ value: a.name, name: a.name }));\n}\n\nasync function selectRegion(\n prompts: SetupAppPrompts,\n deps: CfInfoDeps,\n): Promise<{ readonly regionKey: RegionKey; readonly region: RegionNode }> {\n const regions = await listRegionsWithContent(deps);\n if (regions.length === 0) {\n throw new Error(\"No CF regions with orgs are cached. Run `cf-sync sync` first.\");\n }\n\n const regionKey = await prompts.selectRegion(pickRegion(regions));\n const regionView = await deps.readRegionView(regionKey);\n if (!regionView) {\n throw new Error(`Region ${regionKey} is not cached. Run \\`cf-sync region ${regionKey}\\` or \\`cf-sync sync\\` first.`);\n }\n const region = regionView.region;\n\n if (region.orgs.length === 0) {\n throw new Error(`Region ${regionKey} has no accessible orgs.`);\n }\n\n return { regionKey, region };\n}\n\nasync function selectOrg(\n prompts: SetupAppPrompts,\n region: RegionNode,\n regionKey: RegionKey,\n): Promise<{ readonly orgName: string; readonly org: OrgNode }> {\n const orgName = await prompts.selectOrg(pickOrg(region));\n const org = region.orgs.find((o) => o.name === orgName);\n if (!org) {\n throw new Error(`Org ${orgName} not found in region ${regionKey}`);\n }\n if (org.spaces.length === 0) {\n throw new Error(`Org ${orgName} has no spaces.`);\n }\n\n return { orgName, org };\n}\n\nasync function selectSpace(\n prompts: SetupAppPrompts,\n org: OrgNode,\n orgName: string,\n): Promise<{ readonly spaceName: string; readonly space: SpaceNode }> {\n const spaceName = await prompts.selectSpace(pickSpace(org));\n const space = org.spaces.find((s) => s.name === spaceName);\n if (!space) {\n throw new Error(`Space ${spaceName} not found in org ${orgName}`);\n }\n if (space.apps.length === 0) {\n throw new Error(`Space ${spaceName} has no apps.`);\n }\n\n return { spaceName, space };\n}\n\nasync function selectCfAppRef(\n prompts: SetupAppPrompts,\n deps: CfInfoDeps,\n): Promise<CfAppRef> {\n const { regionKey, region } = await selectRegion(prompts, deps);\n const { orgName, org } = await selectOrg(prompts, region, regionKey);\n const { spaceName, space } = await selectSpace(prompts, org, orgName);\n const appName = await prompts.selectApp(pickApp(space));\n return { region: regionKey, org: orgName, space: spaceName, app: appName };\n}\n\nfunction appPathFor(root: string, ref: CfAppRef): string {\n return join(\n root,\n regionFolderName(ref.region),\n orgFolderName(ref.org),\n spaceFolderName(ref.space),\n ref.app,\n );\n}\n\nfunction normalizeEnvironmentNames(selected: readonly string[]): readonly string[] {\n const merged: string[] = [];\n for (const name of selected) {\n const trimmed = name.trim();\n if (trimmed.length === 0 || merged.includes(trimmed)) {\n continue;\n }\n assertValidEnvName(trimmed);\n merged.push(trimmed);\n }\n if (merged.length === 0) {\n throw new Error(\"At least one environment is required.\");\n }\n return merged;\n}\n\nasync function selectEnvironmentNames(\n appPath: string,\n prompts: SetupAppPrompts,\n): Promise<readonly string[]> {\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await prompts.selectEnvironments({ common, existing: existingEnvs });\n return normalizeEnvironmentNames(selected);\n}\n\nasync function createEnvironmentFiles(\n appPath: string,\n envNames: readonly string[],\n ref: CfAppRef,\n log: (msg: string) => void,\n): Promise<readonly string[]> {\n const created: string[] = [];\n for (const envName of envNames) {\n const path = await ensureEnvFile(appPath, envName, ref);\n created.push(path);\n log(`• ${path}`);\n }\n return created;\n}\n\nexport async function setupApp(options: SetupAppOptions): Promise<SetupAppResult> {\n const deps = options.deps ?? defaultCfInfoDeps;\n const log = options.log ?? ((): void => undefined);\n const ref = await selectCfAppRef(options.prompts, deps);\n const appPath = appPathFor(options.root, ref);\n\n const confirmed = await options.prompts.confirmCreate(appPath);\n if (!confirmed) {\n return { ref, appPath, environments: [], created: false };\n }\n\n await mkdir(appPath, { recursive: true });\n await ensureCollectionConfig(appPath);\n\n const envNames = await selectEnvironmentNames(appPath, options.prompts);\n const created = await createEnvironmentFiles(appPath, envNames, ref, log);\n return { ref, appPath, environments: created, created: true };\n}\n\nasync function listExistingEnvs(appPath: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(join(appPath, ENVIRONMENTS_DIR), { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".bru\"))\n .map((e) => e.name.replace(/\\.bru$/, \"\"));\n } catch {\n return [];\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"../collection/paths.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport async function readContext(): Promise<BrunoContext | undefined> {\n try {\n const raw = await readFile(brunoContextPath(), \"utf8\");\n return JSON.parse(raw) as BrunoContext;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport async function writeContext(ctx: Omit<BrunoContext, \"updatedAt\">): Promise<BrunoContext> {\n const updated: BrunoContext = { ...ctx, updatedAt: new Date().toISOString() };\n const path = brunoContextPath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n return updated;\n}\n","import type { CfInfoDeps } from \"../cf/info.js\";\nimport { isValidRegionKey, resolveRef } from \"../cf/info.js\";\nimport { writeContext } from \"../state/context.js\";\nimport type { BrunoContext } from \"../types.js\";\n\nexport function parseContextShorthand(shorthand: string): {\n readonly region: string;\n readonly org: string;\n readonly space: string;\n readonly app: string;\n} | undefined {\n const segs = shorthand.split(\"/\").filter((s) => s.length > 0);\n if (segs.length !== 4) {\n return undefined;\n }\n const [region, org, space, app] = segs;\n if (!region || !org || !space || !app) {\n return undefined;\n }\n return { region, org, space, app };\n}\n\nexport interface UseOptions {\n readonly shorthand: string;\n readonly deps?: CfInfoDeps;\n readonly verify?: boolean;\n}\n\nexport async function useContext(options: UseOptions): Promise<BrunoContext> {\n const parsed = parseContextShorthand(options.shorthand);\n if (!parsed) {\n throw new Error(\n `Invalid context shorthand: ${options.shorthand}. Expected <region>/<org>/<space>/<app>.`,\n );\n }\n\n if (!isValidRegionKey(parsed.region)) {\n throw new Error(`Unknown region key: ${parsed.region}`);\n }\n\n if (options.verify !== false) {\n const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);\n if (!resolved) {\n throw new Error(\n `Could not verify ${options.shorthand} against the cached CF structure. Run \\`cf-sync sync\\` first.`,\n );\n }\n }\n\n return await writeContext(parsed);\n}\n"],"mappings":"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","names":["sep","readFile","join","readFile","join","readFile","writeFile","join","require","join","readFile","writeFile","readdir","writeFile","join","join","writeFile","readdir","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile"]}
|