@saptools/bruno 0.2.13 โ†’ 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,8 +46,8 @@ You just ran Bruno against a production-grade XSUAA-protected service **without
46
46
  - ๐Ÿ“ฆ **Bundled Bruno CLI fallback** โ€” if `bru` is already on your `PATH`, `saptools-bruno` uses it. If not, it falls back to the bundled [`@usebruno/cli`](https://www.npmjs.com/package/@usebruno/cli).
47
47
  - ๐ŸŽฏ **Default context** โ€” `saptools-bruno use <shorthand>` pins a target so subsequent `run` calls need zero arguments. Feels like `cf target` for Bruno.
48
48
  - ๐Ÿงฉ **CLI & typed API** โ€” every command has a zero-config Node.js equivalent. Full TypeScript definitions shipped. Bring your own prompts for headless/CI use.
49
- - ๐Ÿงช **Fully tested** โ€” 90 unit tests + 8 offline e2e tests (stub `bru` binary + fixture CF snapshot). No network required in CI.
50
- - ๐Ÿชถ **Small + boring** โ€” three runtime deps, no background daemons, no plugin system, no magic.
49
+ - ๐Ÿงช **Fully tested** โ€” unit tests plus offline e2e coverage (stub `bru` binary + fixture CF snapshot). No network required in CI.
50
+ - ๐Ÿชถ **Small + boring** โ€” a small runtime surface, no background daemons, no plugin system, no magic.
51
51
 
52
52
  ---
53
53
 
@@ -95,8 +95,8 @@ saptools-bruno run --env dev
95
95
  ## ๐Ÿ“ฆ Install
96
96
 
97
97
  ```bash
98
- # Global CLI
99
- npm install -g @saptools/bruno
98
+ # Global CLIs
99
+ npm install -g @saptools/cf-sync @saptools/bruno
100
100
 
101
101
  # Or as a project dependency
102
102
  npm install @saptools/bruno
@@ -107,7 +107,7 @@ npm install @saptools/bruno
107
107
  > [!NOTE]
108
108
  > Requires **Node.js โ‰ฅ 20** and a cached CF landscape from [`@saptools/cf-sync`](https://www.npmjs.com/package/@saptools/cf-sync). `@saptools/bruno` now bundles [`@usebruno/cli`](https://www.npmjs.com/package/@usebruno/cli) automatically, but still prefers an existing `bru` on `PATH` if you already have one installed.
109
109
  >
110
- > `npm` does install `@saptools/cf-sync` as a dependency of `@saptools/bruno`, but when you install `@saptools/bruno` globally the transitive `cf-sync` bin is not linked into your global `PATH`. Use `saptools-bruno sync` as the default entry point.
110
+ > `npm` does install `@saptools/cf-sync` as a dependency of `@saptools/bruno`, but a global install of `@saptools/bruno` does **not** expose the transitive `cf-sync` binary on your `PATH`. For global CLI usage, install `@saptools/cf-sync` explicitly. For project-local usage, invoke the local bin through your package manager, for example `npx --no-install cf-sync sync` or `pnpm exec cf-sync sync`.
111
111
 
112
112
  ---
113
113
 
@@ -115,7 +115,7 @@ npm install @saptools/bruno
115
115
 
116
116
  ```bash
117
117
  # 1. Sync your CF landscape once
118
- saptools-bruno sync
118
+ cf-sync sync
119
119
 
120
120
  # 2. Scaffold an app folder with seeded __cf_* metadata
121
121
  saptools-bruno setup-app
@@ -160,24 +160,6 @@ Your `.bru` requests reference `{{accessToken}}` like any other Bruno variable
160
160
 
161
161
  ## ๐Ÿงฐ CLI
162
162
 
163
- ### โ˜๏ธ `saptools-bruno sync`
164
-
165
- Cache the Cloud Foundry landscape that `setup-app` and `use` verify against.
166
-
167
- ```bash
168
- saptools-bruno sync
169
- saptools-bruno sync --only ap10,eu10
170
- saptools-bruno sync --verbose
171
- ```
172
-
173
- | Flag | Description |
174
- | --- | --- |
175
- | `--only <keys>` | Comma-separated list of region keys to sync (default: all) |
176
- | `--verbose` | Print progress lines to stdout |
177
- | `--no-interactive` | Disable the spinner (useful in CI) |
178
-
179
- Requires `SAP_EMAIL` and `SAP_PASSWORD` in the environment, just like the standalone `@saptools/cf-sync` package.
180
-
181
163
  ### ๐Ÿ—๏ธ `saptools-bruno setup-app`
182
164
 
183
165
  Interactively scaffold a Bruno app folder inside the current Bruno collection directory. Walks you through **region โ†’ org โ†’ space โ†’ app**, with the **app step using a searchable picker** for large spaces, then lets you **pick which environments to create** and add custom names without leaving the environment picker.
@@ -190,6 +172,9 @@ saptools-bruno --collection ./collections setup-app
190
172
  > [!TIP]
191
173
  > `--collection` only applies to the current command. If you omit it, `saptools-bruno` falls back to `$SAPTOOLS_BRUNO_COLLECTION`, then to your current working directory.
192
174
 
175
+ > [!IMPORTANT]
176
+ > `setup-app` reads the cached CF landscape prepared by `cf-sync`. If the cache is missing or stale, run `cf-sync sync` first.
177
+
193
178
  **What you get**
194
179
 
195
180
  - An app-level `bruno.json` inside `region__<key>/org__<org>/space__<space>/<app>/`
@@ -487,12 +472,14 @@ The e2e suite uses a stub `bru` binary and fixture CF snapshots, so it runs full
487
472
 
488
473
  ---
489
474
 
490
- <div align="center">
475
+ ## ๐Ÿ‘จโ€๐Ÿ’ป Author
491
476
 
492
- **Made with โค๏ธ for SAP BTP developers who'd rather script their API tests than click them.**
477
+ **dongtran** โœจ
493
478
 
494
- If this saved you an afternoon, consider โญ starring the [repo](https://github.com/dongitran/saptools) โ€” it's the main thing that tells me to keep shipping.
479
+ ## ๐Ÿ“„ License
495
480
 
496
- **License** ยท [MIT](./LICENSE)
481
+ MIT
497
482
 
498
- </div>
483
+ ---
484
+
485
+ Made with โค๏ธ to make your work life easier!
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import process3 from "process";
4
+ import process2 from "process";
5
5
  import { confirm, select } from "@inquirer/prompts";
6
6
  import { Command, Option } from "commander";
7
7
 
@@ -142,7 +142,7 @@ async function getStructureSnapshot(deps = defaultCfInfoDeps) {
142
142
  source: "empty",
143
143
  structure: void 0,
144
144
  stale: true,
145
- message: "No CF structure cached. Run `saptools-bruno sync` first."
145
+ message: "No CF structure cached. Run `cf-sync sync` first."
146
146
  };
147
147
  }
148
148
  const stale = view.source === "runtime" && view.metadata?.status === "running";
@@ -448,16 +448,12 @@ async function setupApp(options) {
448
448
  const log = options.log ?? (() => void 0);
449
449
  const regions = await listRegionsWithContent(deps);
450
450
  if (regions.length === 0) {
451
- throw new Error(
452
- "No CF regions with orgs are cached. Run `saptools-bruno sync` first, or pass SAP_EMAIL/SAP_PASSWORD to refresh."
453
- );
451
+ throw new Error("No CF regions with orgs are cached. Run `cf-sync sync` first.");
454
452
  }
455
453
  const regionKey = await options.prompts.selectRegion(pickRegion(regions));
456
454
  const regionView = await deps.readRegionView(regionKey);
457
455
  if (!regionView) {
458
- throw new Error(
459
- `Region ${regionKey} is not cached. Run \`saptools-bruno sync\` first, or use \`cf-sync region ${regionKey}\` if you have the standalone tool installed.`
460
- );
456
+ throw new Error(`Region ${regionKey} is not cached. Run \`cf-sync region ${regionKey}\` or \`cf-sync sync\` first.`);
461
457
  }
462
458
  const region = regionView.region;
463
459
  if (region.orgs.length === 0) {
@@ -959,55 +955,6 @@ async function runBruno(options) {
959
955
  return { ...plan, ...result };
960
956
  }
961
957
 
962
- // src/sync-command.ts
963
- import process2 from "process";
964
- import { REGION_KEYS as REGION_KEYS2, cfStructurePath, runSync } from "@saptools/cf-sync";
965
- function requireEnv(name, env) {
966
- const value = env[name];
967
- if (!value) {
968
- throw new Error(`Missing required environment variable: ${name}`);
969
- }
970
- return value;
971
- }
972
- function parseOnlyRegions(raw) {
973
- const requested = raw.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
974
- if (requested.length === 0) {
975
- throw new Error("--only must list at least one region key");
976
- }
977
- const allowed = new Set(REGION_KEYS2);
978
- const invalid = requested.filter((value) => !allowed.has(value));
979
- if (invalid.length > 0) {
980
- throw new Error(`Unknown region key(s): ${invalid.join(", ")}. Allowed: ${REGION_KEYS2.join(", ")}`);
981
- }
982
- return requested;
983
- }
984
- function resolveInteractive(options, env, stdoutIsTTY) {
985
- return options.interactive !== false && stdoutIsTTY && env["CI"] !== "true";
986
- }
987
- function writeSummary(result, writeStdout) {
988
- writeStdout(
989
- `\u2714 Structure written to ${cfStructurePath()}
990
- Accessible regions: ${result.accessibleRegions.length.toString()}
991
- Inaccessible regions: ${result.inaccessibleRegions.length.toString()}
992
- `
993
- );
994
- }
995
- function defaultWriteStdout(message) {
996
- process2.stdout.write(message);
997
- }
998
- async function runSyncCommand(options, deps = {}) {
999
- const env = deps.env ?? process2.env;
1000
- const onlyRegions = options.only ? parseOnlyRegions(options.only) : void 0;
1001
- const result = await (deps.runSync ?? runSync)({
1002
- email: requireEnv("SAP_EMAIL", env),
1003
- password: requireEnv("SAP_PASSWORD", env),
1004
- verbose: options.verbose ?? false,
1005
- interactive: resolveInteractive(options, env, deps.stdoutIsTTY ?? process2.stdout.isTTY),
1006
- ...onlyRegions ? { onlyRegions } : {}
1007
- });
1008
- writeSummary(result, deps.writeStdout ?? defaultWriteStdout);
1009
- }
1010
-
1011
958
  // src/use.ts
1012
959
  function parseContextShorthand(shorthand) {
1013
960
  const segs = shorthand.split("/").filter((s) => s.length > 0);
@@ -1034,7 +981,7 @@ async function useContext(options) {
1034
981
  const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);
1035
982
  if (!resolved) {
1036
983
  throw new Error(
1037
- `Could not verify ${options.shorthand} against the cached CF structure. Run \`saptools-bruno sync\` first.`
984
+ `Could not verify ${options.shorthand} against the cached CF structure. Run \`cf-sync sync\` first.`
1038
985
  );
1039
986
  }
1040
987
  }
@@ -1049,13 +996,13 @@ function resolveCollectionDir(explicitCollection, explicitRoot) {
1049
996
  if (explicitRoot) {
1050
997
  return explicitRoot;
1051
998
  }
1052
- if (process3.env["SAPTOOLS_BRUNO_COLLECTION"]) {
1053
- return process3.env["SAPTOOLS_BRUNO_COLLECTION"];
999
+ if (process2.env["SAPTOOLS_BRUNO_COLLECTION"]) {
1000
+ return process2.env["SAPTOOLS_BRUNO_COLLECTION"];
1054
1001
  }
1055
- if (process3.env["SAPTOOLS_BRUNO_ROOT"]) {
1056
- return process3.env["SAPTOOLS_BRUNO_ROOT"];
1002
+ if (process2.env["SAPTOOLS_BRUNO_ROOT"]) {
1003
+ return process2.env["SAPTOOLS_BRUNO_ROOT"];
1057
1004
  }
1058
- return process3.cwd();
1005
+ return process2.cwd();
1059
1006
  }
1060
1007
  async function main(argv) {
1061
1008
  const program = new Command();
@@ -1076,20 +1023,17 @@ async function main(argv) {
1076
1023
  selectEnvironments: async (opts) => await promptForEnvironments(opts)
1077
1024
  },
1078
1025
  log: (msg) => {
1079
- process3.stdout.write(`${msg}
1026
+ process2.stdout.write(`${msg}
1080
1027
  `);
1081
1028
  }
1082
1029
  });
1083
1030
  if (!result.created) {
1084
- process3.stdout.write("Aborted.\n");
1031
+ process2.stdout.write("Aborted.\n");
1085
1032
  return;
1086
1033
  }
1087
- process3.stdout.write(`\u2714 App folder ready at ${result.appPath}
1034
+ process2.stdout.write(`\u2714 App folder ready at ${result.appPath}
1088
1035
  `);
1089
1036
  });
1090
- program.command("sync").description("Cache the Cloud Foundry landscape required by setup-app and use").option("--verbose", "Print progress lines to stdout", false).option("--no-interactive", "Disable spinner (auto-detected in CI)").option("--only <keys>", "Comma-separated list of region keys to sync (default: all)").action(async (opts) => {
1091
- await runSyncCommand(opts);
1092
- });
1093
1037
  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(
1094
1038
  async (target, opts) => {
1095
1039
  const collectionDir = resolveCollectionDir(
@@ -1111,11 +1055,11 @@ async function main(argv) {
1111
1055
  target: effectiveTarget,
1112
1056
  ...opts.env ? { environment: opts.env } : {},
1113
1057
  log: (msg) => {
1114
- process3.stdout.write(`${msg}
1058
+ process2.stdout.write(`${msg}
1115
1059
  `);
1116
1060
  }
1117
1061
  });
1118
- process3.exit(result.code);
1062
+ process2.exit(result.code);
1119
1063
  }
1120
1064
  );
1121
1065
  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) => {
@@ -1123,18 +1067,18 @@ async function main(argv) {
1123
1067
  shorthand,
1124
1068
  verify: opts.verify !== false
1125
1069
  });
1126
- process3.stdout.write(`\u2714 Default context set to ${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}
1070
+ process2.stdout.write(`\u2714 Default context set to ${ctx.region}/${ctx.org}/${ctx.space}/${ctx.app}
1127
1071
  `);
1128
1072
  });
1129
1073
  await program.parseAsync([...argv]);
1130
1074
  }
1131
1075
  try {
1132
- await main(process3.argv);
1076
+ await main(process2.argv);
1133
1077
  } catch (err) {
1134
1078
  const msg = err instanceof Error ? err.message : String(err);
1135
- process3.stderr.write(`Error: ${msg}
1079
+ process2.stderr.write(`Error: ${msg}
1136
1080
  `);
1137
- process3.exit(1);
1081
+ process2.exit(1);
1138
1082
  }
1139
1083
  export {
1140
1084
  main
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/app-search-prompt.ts","../src/context.ts","../src/paths.ts","../src/environment-prompt.ts","../src/setup-app.ts","../src/cf-info.ts","../src/cf-meta.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/run.ts","../src/folder-scan.ts","../src/sync-command.ts","../src/use.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { confirm, select } from \"@inquirer/prompts\";\nimport { Command, Option } from \"commander\";\n\nimport { promptForAppSelection } from \"./app-search-prompt.js\";\nimport { readContext } from \"./context.js\";\nimport { promptForEnvironments } from \"./environment-prompt.js\";\nimport { runBruno } from \"./run.js\";\nimport { setupApp } from \"./setup-app.js\";\nimport { runSyncCommand } from \"./sync-command.js\";\nimport { useContext } from \"./use.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(\"sync\")\n .description(\"Cache the Cloud Foundry landscape required by setup-app and use\")\n .option(\"--verbose\", \"Print progress lines to stdout\", false)\n .option(\"--no-interactive\", \"Disable spinner (auto-detected in CI)\")\n .option(\"--only <keys>\", \"Comma-separated list of region keys to sync (default: all)\")\n .action(async (opts: { verbose?: boolean; interactive?: boolean; only?: string }): Promise<void> => {\n await runSyncCommand(opts);\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 { 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 { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"./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 { 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 { Separator, checkbox, input } from \"@inquirer/prompts\";\n\nimport type { EnvironmentSelection } from \"./setup-app.js\";\nimport { assertValidEnvName } from \"./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","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 \"./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(\n \"No CF regions with orgs are cached. Run `saptools-bruno sync` first, or pass SAP_EMAIL/SAP_PASSWORD to refresh.\",\n );\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(\n `Region ${regionKey} is not cached. Run \\`saptools-bruno sync\\` first, or use \\`cf-sync region ${regionKey}\\` if you have the standalone tool installed.`,\n );\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 `saptools-bruno 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 \"./bru-parser.js\";\nimport { upsertVars } from \"./bru-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 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 \"./bru-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 { 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 \"./bru-writer.js\";\nimport { readCfMetaFromFile } from \"./cf-meta.js\";\nimport type { ShorthandRef } from \"./folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"./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 { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"./bru-parser.js\";\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"./types.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 process from \"node:process\";\n\nimport { REGION_KEYS, cfStructurePath, runSync } from \"@saptools/cf-sync\";\nimport type { RegionKey, SyncOptions, SyncResult } from \"@saptools/cf-sync\";\n\nexport interface SyncCommandOptions {\n readonly verbose?: boolean;\n readonly interactive?: boolean;\n readonly only?: string;\n}\n\ntype RunSyncFn = (options: SyncOptions) => Promise<SyncResult>;\n\nexport interface SyncCommandDeps {\n readonly env?: NodeJS.ProcessEnv;\n readonly stdoutIsTTY?: boolean;\n readonly runSync?: RunSyncFn;\n readonly writeStdout?: (message: string) => void;\n}\n\nfunction requireEnv(name: string, env: NodeJS.ProcessEnv): string {\n const value = env[name];\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function parseOnlyRegions(raw: string): readonly RegionKey[] {\n const requested = raw\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n\n if (requested.length === 0) {\n throw new Error(\"--only must list at least one region key\");\n }\n\n const allowed = new Set<string>(REGION_KEYS);\n const invalid = requested.filter((value) => !allowed.has(value));\n if (invalid.length > 0) {\n throw new Error(`Unknown region key(s): ${invalid.join(\", \")}. Allowed: ${REGION_KEYS.join(\", \")}`);\n }\n\n return requested as readonly RegionKey[];\n}\n\nfunction resolveInteractive(options: SyncCommandOptions, env: NodeJS.ProcessEnv, stdoutIsTTY: boolean): boolean {\n return options.interactive !== false && stdoutIsTTY && env[\"CI\"] !== \"true\";\n}\n\nfunction writeSummary(result: SyncResult, writeStdout: (message: string) => void): void {\n writeStdout(\n `โœ” Structure written to ${cfStructurePath()}\\n` +\n ` Accessible regions: ${result.accessibleRegions.length.toString()}\\n` +\n ` Inaccessible regions: ${result.inaccessibleRegions.length.toString()}\\n`,\n );\n}\n\nfunction defaultWriteStdout(message: string): void {\n process.stdout.write(message);\n}\n\nexport async function runSyncCommand(\n options: SyncCommandOptions,\n deps: SyncCommandDeps = {},\n): Promise<void> {\n const env = deps.env ?? process.env;\n const onlyRegions = options.only ? parseOnlyRegions(options.only) : undefined;\n const result = await (deps.runSync ?? runSync)({\n email: requireEnv(\"SAP_EMAIL\", env),\n password: requireEnv(\"SAP_PASSWORD\", env),\n verbose: options.verbose ?? false,\n interactive: resolveInteractive(options, env, deps.stdoutIsTTY ?? process.stdout.isTTY),\n ...(onlyRegions ? { onlyRegions } : {}),\n });\n\n writeSummary(result, deps.writeStdout ?? defaultWriteStdout);\n}\n","import type { CfInfoDeps } from \"./cf-info.js\";\nimport { isValidRegionKey, resolveRef } from \"./cf-info.js\";\nimport { writeContext } from \"./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 \\`saptools-bruno sync\\` first.`,\n );\n }\n }\n\n return await writeContext(parsed);\n}\n"],"mappings":"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","names":["process","mkdir","writeFile","join","readFile","writeFile","sep","readFile","writeFile","join","writeFile","mkdir","readFile","writeFile","dirname","join","readdir","readFile","join","readdir","readFile","join","require","join","readFile","dirname","writeFile","process","REGION_KEYS","process"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/app-search-prompt.ts","../src/context.ts","../src/paths.ts","../src/environment-prompt.ts","../src/setup-app.ts","../src/cf-info.ts","../src/cf-meta.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/run.ts","../src/folder-scan.ts","../src/use.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { confirm, select } from \"@inquirer/prompts\";\nimport { Command, Option } from \"commander\";\n\nimport { promptForAppSelection } from \"./app-search-prompt.js\";\nimport { readContext } from \"./context.js\";\nimport { promptForEnvironments } from \"./environment-prompt.js\";\nimport { runBruno } from \"./run.js\";\nimport { setupApp } from \"./setup-app.js\";\nimport { useContext } from \"./use.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 { 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 { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"./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 { 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 { Separator, checkbox, input } from \"@inquirer/prompts\";\n\nimport type { EnvironmentSelection } from \"./setup-app.js\";\nimport { assertValidEnvName } from \"./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","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 \"./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 { readFile, writeFile } from \"node:fs/promises\";\n\nimport { parseBruEnvFile } from \"./bru-parser.js\";\nimport { upsertVars } from \"./bru-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 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 \"./bru-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 { 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 \"./bru-writer.js\";\nimport { readCfMetaFromFile } from \"./cf-meta.js\";\nimport type { ShorthandRef } from \"./folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"./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 { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseBruEnvFile } from \"./bru-parser.js\";\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"./types.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 type { CfInfoDeps } from \"./cf-info.js\";\nimport { isValidRegionKey, resolveRef } from \"./cf-info.js\";\nimport { writeContext } from \"./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":["process","mkdir","writeFile","join","readFile","writeFile","sep","readFile","writeFile","join","writeFile","mkdir","readFile","writeFile","dirname","join","readdir","readFile","join","readdir","readFile","join","require","join","readFile","dirname","writeFile","process"]}
package/dist/index.js CHANGED
@@ -209,7 +209,7 @@ async function getStructureSnapshot(deps = defaultCfInfoDeps) {
209
209
  source: "empty",
210
210
  structure: void 0,
211
211
  stale: true,
212
- message: "No CF structure cached. Run `saptools-bruno sync` first."
212
+ message: "No CF structure cached. Run `cf-sync sync` first."
213
213
  };
214
214
  }
215
215
  const stale = view.source === "runtime" && view.metadata?.status === "running";
@@ -537,16 +537,12 @@ async function setupApp(options) {
537
537
  const log = options.log ?? (() => void 0);
538
538
  const regions = await listRegionsWithContent(deps);
539
539
  if (regions.length === 0) {
540
- throw new Error(
541
- "No CF regions with orgs are cached. Run `saptools-bruno sync` first, or pass SAP_EMAIL/SAP_PASSWORD to refresh."
542
- );
540
+ throw new Error("No CF regions with orgs are cached. Run `cf-sync sync` first.");
543
541
  }
544
542
  const regionKey = await options.prompts.selectRegion(pickRegion(regions));
545
543
  const regionView = await deps.readRegionView(regionKey);
546
544
  if (!regionView) {
547
- throw new Error(
548
- `Region ${regionKey} is not cached. Run \`saptools-bruno sync\` first, or use \`cf-sync region ${regionKey}\` if you have the standalone tool installed.`
549
- );
545
+ throw new Error(`Region ${regionKey} is not cached. Run \`cf-sync region ${regionKey}\` or \`cf-sync sync\` first.`);
550
546
  }
551
547
  const region = regionView.region;
552
548
  if (region.orgs.length === 0) {
@@ -870,7 +866,7 @@ async function useContext(options) {
870
866
  const resolved = await resolveRef({ ...parsed, region: parsed.region }, options.deps);
871
867
  if (!resolved) {
872
868
  throw new Error(
873
- `Could not verify ${options.shorthand} against the cached CF structure. Run \`saptools-bruno sync\` first.`
869
+ `Could not verify ${options.shorthand} against the cached CF structure. Run \`cf-sync sync\` first.`
874
870
  );
875
871
  }
876
872
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/paths.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/cf-info.ts","../src/cf-meta.ts","../src/folder-scan.ts","../src/context.ts","../src/setup-app.ts","../src/run.ts","../src/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 { 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 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 \"./bru-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 `saptools-bruno 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 \"./bru-parser.js\";\nimport { upsertVars } from \"./bru-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 \"./bru-parser.js\";\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"./types.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 { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"./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 { 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 \"./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(\n \"No CF regions with orgs are cached. Run `saptools-bruno sync` first, or pass SAP_EMAIL/SAP_PASSWORD to refresh.\",\n );\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(\n `Region ${regionKey} is not cached. Run \\`saptools-bruno sync\\` first, or use \\`cf-sync region ${regionKey}\\` if you have the standalone tool installed.`,\n );\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 { 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 \"./bru-writer.js\";\nimport { readCfMetaFromFile } from \"./cf-meta.js\";\nimport type { ShorthandRef } from \"./folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"./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 { CfInfoDeps } from \"./cf-info.js\";\nimport { isValidRegionKey, resolveRef } from \"./cf-info.js\";\nimport { writeContext } from \"./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 \\`saptools-bruno 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","readFile","writeFile","mkdir","readdir","writeFile","join","join","writeFile","mkdir","readdir","readFile","writeFile","dirname","join","require","join","readFile","dirname","writeFile"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/paths.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/cf-info.ts","../src/cf-meta.ts","../src/folder-scan.ts","../src/context.ts","../src/setup-app.ts","../src/run.ts","../src/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 { 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 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 \"./bru-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 \"./bru-parser.js\";\nimport { upsertVars } from \"./bru-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 \"./bru-parser.js\";\nimport {\n ENVIRONMENTS_DIR,\n ORG_FOLDER_PREFIX,\n parsePrefixedName,\n REGION_FOLDER_PREFIX,\n SPACE_FOLDER_PREFIX,\n} from \"./paths.js\";\nimport type {\n AppFolder,\n BrunoCollection,\n BruEnvFile,\n OrgFolder,\n RegionFolder,\n SpaceFolder,\n} from \"./types.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 { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { brunoContextPath } from \"./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 { 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 \"./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 { 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 \"./bru-writer.js\";\nimport { readCfMetaFromFile } from \"./cf-meta.js\";\nimport type { ShorthandRef } from \"./folder-scan.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport {\n ENVIRONMENTS_DIR,\n orgFolderName,\n regionFolderName,\n spaceFolderName,\n} from \"./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 { CfInfoDeps } from \"./cf-info.js\";\nimport { isValidRegionKey, resolveRef } from \"./cf-info.js\";\nimport { writeContext } from \"./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","readFile","writeFile","mkdir","readdir","writeFile","join","join","writeFile","mkdir","readdir","readFile","writeFile","dirname","join","require","join","readFile","dirname","writeFile"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saptools/bruno",
3
- "version": "0.2.13",
3
+ "version": "0.3.1",
4
4
  "description": "Smart runner for Bruno โ€” CF-aware env metadata, automatic token injection, and shorthand paths",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -26,7 +26,6 @@
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsup",
29
- "postinstall": "node --input-type=module -e \"import('./dist/postinstall.js').then((m) => { if (m.shouldPrintInstallHint()) m.printInstallHint(); }).catch(() => {})\"",
30
29
  "typecheck": "tsc --noEmit",
31
30
  "lint": "eslint src tests --ignore-pattern tests/e2e/fixtures/fake-bru.mjs",
32
31
  "test:unit": "vitest run --coverage",
@@ -52,7 +51,7 @@
52
51
  },
53
52
  "dependencies": {
54
53
  "@inquirer/prompts": "^8.3.2",
55
- "@saptools/cf-sync": "^0.3.5",
54
+ "@saptools/cf-sync": "^0.4.1",
56
55
  "@saptools/cf-xsuaa": "^0.1.6",
57
56
  "@usebruno/cli": "^3.2.2",
58
57
  "commander": "^13.0.0"
@@ -1,5 +0,0 @@
1
- declare function buildInstallHint(): string;
2
- declare function shouldPrintInstallHint(env?: NodeJS.ProcessEnv): boolean;
3
- declare function printInstallHint(writeStdout?: (message: string) => void): void;
4
-
5
- export { buildInstallHint, printInstallHint, shouldPrintInstallHint };
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/postinstall.ts
4
- import process from "process";
5
- import { fileURLToPath } from "url";
6
- function buildInstallHint() {
7
- return "[saptools-bruno] Next step: run `saptools-bruno sync` to cache your CF landscape.\n[saptools-bruno] If this was a project install, run it via your package manager, for example `npx saptools-bruno sync`.\n";
8
- }
9
- function shouldPrintInstallHint(env = process.env) {
10
- return env["CI"] !== "true" && env["npm_config_loglevel"] !== "silent";
11
- }
12
- function isDirectExecution(metaUrl, argv1) {
13
- if (!argv1) {
14
- return false;
15
- }
16
- return fileURLToPath(metaUrl) === argv1;
17
- }
18
- function printInstallHint(writeStdout = (message) => {
19
- process.stdout.write(message);
20
- }) {
21
- writeStdout(buildInstallHint());
22
- }
23
- if (isDirectExecution(import.meta.url, process.argv[1]) && shouldPrintInstallHint()) {
24
- printInstallHint();
25
- }
26
- export {
27
- buildInstallHint,
28
- printInstallHint,
29
- shouldPrintInstallHint
30
- };
31
- //# sourceMappingURL=postinstall.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["import process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function buildInstallHint(): string {\n return (\n \"[saptools-bruno] Next step: run `saptools-bruno sync` to cache your CF landscape.\\n\" +\n \"[saptools-bruno] If this was a project install, run it via your package manager, for example `npx saptools-bruno sync`.\\n\"\n );\n}\n\nexport function shouldPrintInstallHint(env: NodeJS.ProcessEnv = process.env): boolean {\n return env[\"CI\"] !== \"true\" && env[\"npm_config_loglevel\"] !== \"silent\";\n}\n\nfunction isDirectExecution(metaUrl: string, argv1: string | undefined): boolean {\n if (!argv1) {\n return false;\n }\n\n return fileURLToPath(metaUrl) === argv1;\n}\n\nexport function printInstallHint(writeStdout: (message: string) => void = (message) => {\n process.stdout.write(message);\n}): void {\n writeStdout(buildInstallHint());\n}\n\nif (isDirectExecution(import.meta.url, process.argv[1]) && shouldPrintInstallHint()) {\n printInstallHint();\n}\n"],"mappings":";;;AAAA,OAAO,aAAa;AACpB,SAAS,qBAAqB;AAEvB,SAAS,mBAA2B;AACzC,SACE;AAGJ;AAEO,SAAS,uBAAuB,MAAyB,QAAQ,KAAc;AACpF,SAAO,IAAI,IAAI,MAAM,UAAU,IAAI,qBAAqB,MAAM;AAChE;AAEA,SAAS,kBAAkB,SAAiB,OAAoC;AAC9E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,OAAO,MAAM;AACpC;AAEO,SAAS,iBAAiB,cAAyC,CAAC,YAAY;AACrF,UAAQ,OAAO,MAAM,OAAO;AAC9B,GAAS;AACP,cAAY,iBAAiB,CAAC;AAChC;AAEA,IAAI,kBAAkB,YAAY,KAAK,QAAQ,KAAK,CAAC,CAAC,KAAK,uBAAuB,GAAG;AACnF,mBAAiB;AACnB;","names":[]}