@saptools/bruno 0.2.0 โ†’ 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,6 @@ Scaffold a CF-aware collection. Resolve requests by `region/org/space/app` short
10
10
  [![downloads](https://img.shields.io/npm/dm/@saptools/bruno.svg?style=flat&color=success&logo=npm)](https://www.npmjs.com/package/@saptools/bruno)
11
11
  [![license](https://img.shields.io/npm/l/@saptools/bruno.svg?style=flat&color=blue)](./LICENSE)
12
12
  [![node](https://img.shields.io/node/v/@saptools/bruno.svg?style=flat&color=339933&logo=node.js&logoColor=white)](https://nodejs.org)
13
- [![install size](https://packagephobia.com/badge?p=@saptools/bruno)](https://packagephobia.com/result?p=@saptools/bruno)
14
13
  [![types](https://img.shields.io/npm/types/@saptools/bruno.svg?style=flat&color=3178C6&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
15
14
  [![build](https://img.shields.io/github/actions/workflow/status/dongitran/saptools/bruno.yml?style=flat&logo=github&label=CI)](https://github.com/dongitran/saptools/actions/workflows/bruno.yml)
16
15
 
@@ -44,6 +43,7 @@ You just ran Bruno against a production-grade XSUAA-protected service **without
44
43
  - ๐Ÿ—๏ธ **Interactive `setup-app`** โ€” pick a region โ†’ org โ†’ space โ†’ app from your cached CF landscape, then **choose exactly the environments you want** (or type a custom name like `qa-eu`). Every env file is seeded with `__cf_*` metadata so the runner knows where to fetch a token.
45
44
  - ๐Ÿงญ **Shorthand paths** โ€” `region/org/space/app[/folder/file.bru]` expands to the right filesystem path. No more `cd`-ing through nested folders.
46
45
  - ๐Ÿ” **Automatic XSUAA tokens** โ€” every `run` fetches (or reuses) a cached token via [`@saptools/cf-xsuaa`](https://www.npmjs.com/package/@saptools/cf-xsuaa) and injects it as `accessToken` for `bru`.
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
49
  - ๐Ÿงช **Fully tested** โ€” 74 unit tests + 4 offline e2e tests (stub `bru` binary + fixture CF snapshot). No network required in CI.
@@ -105,7 +105,7 @@ npm install @saptools/bruno
105
105
  ```
106
106
 
107
107
  > [!NOTE]
108
- > Requires **Node.js โ‰ฅ 20**, the official **[`bru` CLI](https://www.npmjs.com/package/@usebruno/cli)** on `PATH`, and a cached CF landscape from [`@saptools/cf-sync`](https://www.npmjs.com/package/@saptools/cf-sync).
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
110
  ---
111
111
 
package/dist/cli.js CHANGED
@@ -63,8 +63,9 @@ async function writeContext(ctx) {
63
63
 
64
64
  // src/run.ts
65
65
  import { spawn } from "child_process";
66
- import { stat } from "fs/promises";
67
- import { isAbsolute, join as join3, relative, resolve, sep } from "path";
66
+ import { readFile as readFile4, stat } from "fs/promises";
67
+ import { createRequire } from "module";
68
+ import { delimiter, dirname as dirname2, isAbsolute, join as join3, relative, resolve, sep } from "path";
68
69
  import { getTokenCached as getTokenCachedApi } from "@saptools/cf-xsuaa";
69
70
 
70
71
  // src/cf-meta.ts
@@ -360,9 +361,83 @@ function parseShorthandPath(shorthand) {
360
361
  }
361
362
 
362
363
  // src/run.ts
363
- function defaultSpawnBru(args, env, cwd) {
364
- return new Promise((resolvePromise, rejectPromise) => {
365
- const child = spawn("bru", [...args], { cwd, env, stdio: "pipe" });
364
+ var require2 = createRequire(import.meta.url);
365
+ function pathEntries(env) {
366
+ const value = env["PATH"] ?? process.env["PATH"] ?? "";
367
+ return value.split(delimiter).filter((entry) => entry.length > 0);
368
+ }
369
+ function pathCandidates(command, env) {
370
+ if (process.platform !== "win32" || command.includes(".")) {
371
+ return [command];
372
+ }
373
+ const pathExt = env["PATHEXT"]?.split(";").filter((entry) => entry.length > 0) ?? [".COM", ".EXE", ".BAT", ".CMD"];
374
+ return [command, ...pathExt.map((ext) => `${command}${ext}`)];
375
+ }
376
+ async function findCommandOnPath(command, env) {
377
+ const candidates = pathCandidates(command, env);
378
+ for (const entry of pathEntries(env)) {
379
+ for (const candidate of candidates) {
380
+ const fullPath = join3(entry, candidate);
381
+ if (await exists(fullPath)) {
382
+ return fullPath;
383
+ }
384
+ }
385
+ }
386
+ return void 0;
387
+ }
388
+ function isRecord(value) {
389
+ return typeof value === "object" && value !== null;
390
+ }
391
+ function bruBinRelativePath(value) {
392
+ if (!isRecord(value)) {
393
+ return void 0;
394
+ }
395
+ const bin = value["bin"];
396
+ if (typeof bin === "string") {
397
+ return bin;
398
+ }
399
+ if (!isRecord(bin)) {
400
+ return void 0;
401
+ }
402
+ const bru = bin["bru"];
403
+ return typeof bru === "string" ? bru : void 0;
404
+ }
405
+ function defaultResolvePackageJsonPath() {
406
+ return require2.resolve("@usebruno/cli/package.json");
407
+ }
408
+ async function defaultReadTextFile(path) {
409
+ return await readFile4(path, "utf8");
410
+ }
411
+ async function resolveBundledBruBinPath(deps) {
412
+ try {
413
+ const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();
414
+ const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);
415
+ const binPath = bruBinRelativePath(JSON.parse(raw));
416
+ if (!binPath) {
417
+ return void 0;
418
+ }
419
+ return resolve(dirname2(packageJsonPath), binPath);
420
+ } catch {
421
+ return void 0;
422
+ }
423
+ }
424
+ async function resolveBruRuntime(env = process.env, deps = {}) {
425
+ const onPath = await (deps.findOnPath ?? findCommandOnPath)("bru", env);
426
+ if (onPath) {
427
+ return { command: onPath, argsPrefix: [] };
428
+ }
429
+ const bundledBin = await resolveBundledBruBinPath(deps);
430
+ if (bundledBin) {
431
+ return { command: process.execPath, argsPrefix: [bundledBin] };
432
+ }
433
+ throw new Error(
434
+ "Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH."
435
+ );
436
+ }
437
+ async function defaultSpawnBru(args, env, cwd) {
438
+ const runtime = await resolveBruRuntime(env);
439
+ return await new Promise((resolvePromise, rejectPromise) => {
440
+ const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: "pipe" });
366
441
  let stdout = "";
367
442
  let stderr = "";
368
443
  child.stdout.on("data", (chunk) => {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/context.ts","../src/paths.ts","../src/run.ts","../src/cf-meta.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/folder-scan.ts","../src/setup-app.ts","../src/cf-info.ts","../src/use.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { checkbox, confirm, input, select } from \"@inquirer/prompts\";\nimport { Command } from \"commander\";\n\nimport { readContext } from \"./context.js\";\nimport { runBruno } from \"./run.js\";\nimport { setupApp } from \"./setup-app.js\";\nimport { useContext } from \"./use.js\";\n\nfunction resolveRoot(explicit: string | undefined): string {\n if (explicit) {\n return explicit;\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 .option(\"--root <dir>\", \"Root directory of the bruno collection (default: cwd)\");\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 root = resolveRoot(program.opts<{ root?: string }>().root);\n const result = await setupApp({\n root,\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 select({ message: \"Select app\", choices: [...choices] }),\n confirmCreate: async (path) => await confirm({ message: `Create ${path}?`, default: true }),\n selectEnvironments: async ({ common, existing }) => {\n const seen = new Set<string>();\n const all = [...common, ...existing].filter((name) => {\n if (seen.has(name)) {\n return false;\n }\n seen.add(name);\n return true;\n });\n return await checkbox({\n message: \"Environments to create (space to toggle, enter to confirm)\",\n choices: all.map((name) => ({\n name,\n value: name,\n checked: existing.includes(name),\n })),\n });\n },\n inputCustomEnvName: async () => {\n const raw = await input({\n message: \"Custom environment name (leave empty to skip)\",\n default: \"\",\n validate: (v) => {\n const t = v.trim();\n if (t.length === 0) {\n return true;\n }\n return /^[A-Za-z0-9._-]+$/.test(t)\n ? true\n : \"Only letters, digits, dot, underscore, and dash are allowed.\";\n },\n });\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : null;\n },\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 root = resolveRoot(program.opts<{ root?: string }>().root);\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,\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 { 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 { spawn } from \"node:child_process\";\nimport { stat } from \"node:fs/promises\";\nimport { 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 { readCfMetaFromFile } from \"./cf-meta.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport type { ShorthandRef } 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\nfunction defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(\"bru\", [...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\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\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 { 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*([a-zA-Z][a-zA-Z0-9:_-]*)\\s*([{[])/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 { 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, readdir, writeFile } from \"node:fs/promises\";\nimport { 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 readonly inputCustomEnvName: () => Promise<string | null>;\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;\n\nconst ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nfunction 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\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 `cf-sync 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(`Region ${regionKey} is not cached. Run \\`cf-sync sync\\` or \\`cf-sync region ${regionKey}\\`.`);\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\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const custom = await options.prompts.inputCustomEnvName();\n const merged: string[] = [];\n for (const name of [...selected, ...(custom ? [custom] : [])]) {\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 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","join","readFile","writeFile","sep","readFile","writeFile","readFile","join","readFile","join","join","mkdir","readdir","writeFile","join","join","mkdir","writeFile","readdir","process"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/context.ts","../src/paths.ts","../src/run.ts","../src/cf-meta.ts","../src/bru-parser.ts","../src/bru-writer.ts","../src/folder-scan.ts","../src/setup-app.ts","../src/cf-info.ts","../src/use.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { checkbox, confirm, input, select } from \"@inquirer/prompts\";\nimport { Command } from \"commander\";\n\nimport { readContext } from \"./context.js\";\nimport { runBruno } from \"./run.js\";\nimport { setupApp } from \"./setup-app.js\";\nimport { useContext } from \"./use.js\";\n\nfunction resolveRoot(explicit: string | undefined): string {\n if (explicit) {\n return explicit;\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 .option(\"--root <dir>\", \"Root directory of the bruno collection (default: cwd)\");\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 root = resolveRoot(program.opts<{ root?: string }>().root);\n const result = await setupApp({\n root,\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 select({ message: \"Select app\", choices: [...choices] }),\n confirmCreate: async (path) => await confirm({ message: `Create ${path}?`, default: true }),\n selectEnvironments: async ({ common, existing }) => {\n const seen = new Set<string>();\n const all = [...common, ...existing].filter((name) => {\n if (seen.has(name)) {\n return false;\n }\n seen.add(name);\n return true;\n });\n return await checkbox({\n message: \"Environments to create (space to toggle, enter to confirm)\",\n choices: all.map((name) => ({\n name,\n value: name,\n checked: existing.includes(name),\n })),\n });\n },\n inputCustomEnvName: async () => {\n const raw = await input({\n message: \"Custom environment name (leave empty to skip)\",\n default: \"\",\n validate: (v) => {\n const t = v.trim();\n if (t.length === 0) {\n return true;\n }\n return /^[A-Za-z0-9._-]+$/.test(t)\n ? true\n : \"Only letters, digits, dot, underscore, and dash are allowed.\";\n },\n });\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : null;\n },\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 root = resolveRoot(program.opts<{ root?: string }>().root);\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,\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 { 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 { spawn } from \"node:child_process\";\nimport { readFile, stat } 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 { 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\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\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 { 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*([a-zA-Z][a-zA-Z0-9:_-]*)\\s*([{[])/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 { 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, readdir, writeFile } from \"node:fs/promises\";\nimport { 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 readonly inputCustomEnvName: () => Promise<string | null>;\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;\n\nconst ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nfunction 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\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 `cf-sync 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(`Region ${regionKey} is not cached. Run \\`cf-sync sync\\` or \\`cf-sync region ${regionKey}\\`.`);\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\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const custom = await options.prompts.inputCustomEnvName();\n const merged: string[] = [];\n for (const name of [...selected, ...(custom ? [custom] : [])]) {\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 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","readFile","dirname","join","readFile","writeFile","sep","readFile","writeFile","readFile","join","readFile","join","require","join","readFile","dirname","mkdir","readdir","writeFile","join","join","mkdir","writeFile","readdir","process"]}
package/dist/index.d.ts CHANGED
@@ -240,6 +240,16 @@ interface RunResult extends RunPlan {
240
240
  readonly stdout: string;
241
241
  readonly stderr: string;
242
242
  }
243
+ interface BruRuntime {
244
+ readonly command: string;
245
+ readonly argsPrefix: readonly string[];
246
+ }
247
+ interface ResolveBruRuntimeDeps {
248
+ readonly findOnPath?: (command: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;
249
+ readonly readTextFile?: (path: string) => Promise<string>;
250
+ readonly resolvePackageJsonPath?: () => string;
251
+ }
252
+ declare function resolveBruRuntime(env?: NodeJS.ProcessEnv, deps?: ResolveBruRuntimeDeps): Promise<BruRuntime>;
243
253
  declare function buildRunPlan(options: RunOptions): Promise<RunPlan>;
244
254
  declare function runBruno(options: RunOptions): Promise<RunResult>;
245
255
 
@@ -256,4 +266,4 @@ interface UseOptions {
256
266
  }
257
267
  declare function useContext(options: UseOptions): Promise<BrunoContext>;
258
268
 
259
- export { type AppFolder, BRUNO_CONTEXT_FILENAME, type BruEnvFile, type BruVarsBlock, type BrunoCollection, type BrunoContext, CF_META_KEYS, COMMON_ENVIRONMENTS, type CfAppRef, type CfInfoDeps, type CfMeta, type CfMetaKey, type CfRoute, ENVIRONMENTS_DIR, type EnvironmentSelection, type GetTokenCachedFn, ORG_FOLDER_PREFIX, type OrgFolder, type ParsedBruEnv, REGION_FOLDER_PREFIX, type RegionFolder, type RegionSuggestion, type ResolvedRef, type RunOptions, type RunPlan, type RunResult, type RunSpawnResult, SAPTOOLS_DIR_NAME, SPACE_FOLDER_PREFIX, type SetupAppOptions, type SetupAppPrompts, type SetupAppResult, type ShorthandRef, type SpaceFolder, type SpawnBruFn, type StructureSnapshot, type UpsertResult, type UseOptions, brunoContextPath, buildCfMetaUpdates, buildRunPlan, defaultCfInfoDeps, ensureSecretEntry, findApp, findOrg, findSpace, getRegion, getStructureSnapshot, hasCfMeta, isValidRegionKey, listBlocks, listRegionsWithContent, orgFolderName, parseBruEnvFile, parseContextShorthand, parseKeyValueBody, parseListBody, parsePrefixedName, parseShorthandPath, readCfMetaFromFile, readCfMetaFromVars, readContext, regionFolderName, resolveRef, runBruno, saptoolsDir, scanCollection, setupApp, spaceFolderName, upsertVars, useContext, writeCfMetaToFile, writeContext };
269
+ export { type AppFolder, BRUNO_CONTEXT_FILENAME, type BruEnvFile, type BruRuntime, type BruVarsBlock, type BrunoCollection, type BrunoContext, CF_META_KEYS, COMMON_ENVIRONMENTS, type CfAppRef, type CfInfoDeps, type CfMeta, type CfMetaKey, type CfRoute, ENVIRONMENTS_DIR, type EnvironmentSelection, type GetTokenCachedFn, ORG_FOLDER_PREFIX, type OrgFolder, type ParsedBruEnv, REGION_FOLDER_PREFIX, type RegionFolder, type RegionSuggestion, type ResolveBruRuntimeDeps, type ResolvedRef, type RunOptions, type RunPlan, type RunResult, type RunSpawnResult, SAPTOOLS_DIR_NAME, SPACE_FOLDER_PREFIX, type SetupAppOptions, type SetupAppPrompts, type SetupAppResult, type ShorthandRef, type SpaceFolder, type SpawnBruFn, type StructureSnapshot, type UpsertResult, type UseOptions, brunoContextPath, buildCfMetaUpdates, buildRunPlan, defaultCfInfoDeps, ensureSecretEntry, findApp, findOrg, findSpace, getRegion, getStructureSnapshot, hasCfMeta, isValidRegionKey, listBlocks, listRegionsWithContent, orgFolderName, parseBruEnvFile, parseContextShorthand, parseKeyValueBody, parseListBody, parsePrefixedName, parseShorthandPath, readCfMetaFromFile, readCfMetaFromVars, readContext, regionFolderName, resolveBruRuntime, resolveRef, runBruno, saptoolsDir, scanCollection, setupApp, spaceFolderName, upsertVars, useContext, writeCfMetaToFile, writeContext };
package/dist/index.js CHANGED
@@ -587,12 +587,87 @@ async function listExistingEnvs(appPath) {
587
587
 
588
588
  // src/run.ts
589
589
  import { spawn } from "child_process";
590
- import { stat } from "fs/promises";
591
- import { isAbsolute, join as join4, relative, resolve, sep } from "path";
590
+ import { readFile as readFile4, stat } from "fs/promises";
591
+ import { createRequire } from "module";
592
+ import { delimiter, dirname as dirname2, isAbsolute, join as join4, relative, resolve, sep } from "path";
592
593
  import { getTokenCached as getTokenCachedApi } from "@saptools/cf-xsuaa";
593
- function defaultSpawnBru(args, env, cwd) {
594
- return new Promise((resolvePromise, rejectPromise) => {
595
- const child = spawn("bru", [...args], { cwd, env, stdio: "pipe" });
594
+ var require2 = createRequire(import.meta.url);
595
+ function pathEntries(env) {
596
+ const value = env["PATH"] ?? process.env["PATH"] ?? "";
597
+ return value.split(delimiter).filter((entry) => entry.length > 0);
598
+ }
599
+ function pathCandidates(command, env) {
600
+ if (process.platform !== "win32" || command.includes(".")) {
601
+ return [command];
602
+ }
603
+ const pathExt = env["PATHEXT"]?.split(";").filter((entry) => entry.length > 0) ?? [".COM", ".EXE", ".BAT", ".CMD"];
604
+ return [command, ...pathExt.map((ext) => `${command}${ext}`)];
605
+ }
606
+ async function findCommandOnPath(command, env) {
607
+ const candidates = pathCandidates(command, env);
608
+ for (const entry of pathEntries(env)) {
609
+ for (const candidate of candidates) {
610
+ const fullPath = join4(entry, candidate);
611
+ if (await exists(fullPath)) {
612
+ return fullPath;
613
+ }
614
+ }
615
+ }
616
+ return void 0;
617
+ }
618
+ function isRecord(value) {
619
+ return typeof value === "object" && value !== null;
620
+ }
621
+ function bruBinRelativePath(value) {
622
+ if (!isRecord(value)) {
623
+ return void 0;
624
+ }
625
+ const bin = value["bin"];
626
+ if (typeof bin === "string") {
627
+ return bin;
628
+ }
629
+ if (!isRecord(bin)) {
630
+ return void 0;
631
+ }
632
+ const bru = bin["bru"];
633
+ return typeof bru === "string" ? bru : void 0;
634
+ }
635
+ function defaultResolvePackageJsonPath() {
636
+ return require2.resolve("@usebruno/cli/package.json");
637
+ }
638
+ async function defaultReadTextFile(path) {
639
+ return await readFile4(path, "utf8");
640
+ }
641
+ async function resolveBundledBruBinPath(deps) {
642
+ try {
643
+ const packageJsonPath = (deps.resolvePackageJsonPath ?? defaultResolvePackageJsonPath)();
644
+ const raw = await (deps.readTextFile ?? defaultReadTextFile)(packageJsonPath);
645
+ const binPath = bruBinRelativePath(JSON.parse(raw));
646
+ if (!binPath) {
647
+ return void 0;
648
+ }
649
+ return resolve(dirname2(packageJsonPath), binPath);
650
+ } catch {
651
+ return void 0;
652
+ }
653
+ }
654
+ async function resolveBruRuntime(env = process.env, deps = {}) {
655
+ const onPath = await (deps.findOnPath ?? findCommandOnPath)("bru", env);
656
+ if (onPath) {
657
+ return { command: onPath, argsPrefix: [] };
658
+ }
659
+ const bundledBin = await resolveBundledBruBinPath(deps);
660
+ if (bundledBin) {
661
+ return { command: process.execPath, argsPrefix: [bundledBin] };
662
+ }
663
+ throw new Error(
664
+ "Unable to find Bruno CLI. Install @usebruno/cli or ensure `bru` is available on PATH."
665
+ );
666
+ }
667
+ async function defaultSpawnBru(args, env, cwd) {
668
+ const runtime = await resolveBruRuntime(env);
669
+ return await new Promise((resolvePromise, rejectPromise) => {
670
+ const child = spawn(runtime.command, [...runtime.argsPrefix, ...args], { cwd, env, stdio: "pipe" });
596
671
  let stdout = "";
597
672
  let stderr = "";
598
673
  child.stdout.on("data", (chunk) => {
@@ -797,6 +872,7 @@ export {
797
872
  readCfMetaFromVars,
798
873
  readContext,
799
874
  regionFolderName,
875
+ resolveBruRuntime,
800
876
  resolveRef,
801
877
  runBruno,
802
878
  saptoolsDir,
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*([a-zA-Z][a-zA-Z0-9:_-]*)\\s*([{[])/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 { 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 readonly inputCustomEnvName: () => Promise<string | null>;\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;\n\nconst ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nfunction 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\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 `cf-sync 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(`Region ${regionKey} is not cached. Run \\`cf-sync sync\\` or \\`cf-sync region ${regionKey}\\`.`);\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\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const custom = await options.prompts.inputCustomEnvName();\n const merged: string[] = [];\n for (const name of [...selected, ...(custom ? [custom] : [])]) {\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 { stat } from \"node:fs/promises\";\nimport { 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 { readCfMetaFromFile } from \"./cf-meta.js\";\nimport { parseShorthandPath, scanCollection } from \"./folder-scan.js\";\nimport type { ShorthandRef } 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\nfunction defaultSpawnBru(\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n cwd: string,\n): Promise<RunSpawnResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(\"bru\", [...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\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\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":";;;AA8DO,IAAM,eAAe,CAAC,eAAe,YAAY,cAAc,UAAU;;;AC9DhF,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,IAAM,oBAAoB;AAC1B,IAAM,yBAAyB;AAE/B,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAEzB,SAAS,cAAsB;AACpC,SAAO,KAAK,QAAQ,GAAG,iBAAiB;AAC1C;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,YAAY,GAAG,sBAAsB;AACnD;AAEO,SAAS,iBAAiB,KAAqB;AACpD,SAAO,GAAG,oBAAoB,GAAG,GAAG;AACtC;AAEO,SAAS,cAAc,MAAsB;AAClD,SAAO,GAAG,iBAAiB,GAAG,IAAI;AACpC;AAEO,SAAS,gBAAgB,MAAsB;AACpD,SAAO,GAAG,mBAAmB,GAAG,IAAI;AACtC;AAEO,SAAS,kBACd,SACA,QACoB;AACpB,MAAI,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,MAAM,OAAO,MAAM;AACpC;;;AC3BA,IAAM,eAAe;AAErB,SAAS,kBAAkB,KAAa,MAAiB,SAAyB;AAChF,QAAM,QAAQ,SAAS,MAAM,MAAM;AACnC,MAAI,QAAQ;AACZ,MAAI,IAAI,UAAU;AAClB,SAAO,IAAI,IAAI,QAAQ;AACrB,UAAM,KAAK,IAAI,CAAC;AAChB,QAAI,OAAO,MAAM;AACf;AAAA,IACF,WAAW,OAAO,OAAO;AACvB;AACA,UAAI,UAAU,GAAG;AACf,eAAO;AAAA,MACT;AAAA,IACF;AACA;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,WAAW,KAAoC;AAC7D,QAAM,SAAuB,CAAC;AAC9B,eAAa,YAAY;AACzB,MAAI;AACJ,UAAQ,QAAQ,aAAa,KAAK,GAAG,OAAO,MAAM;AAChD,UAAM,iBAAiB,MAAM,CAAC,KAAK;AACnC,UAAM,SAAS,MAAM,CAAC;AACtB,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,WAAW,UAAc,SAAS,OAAO,SAAS,KAAM;AAC1D;AAAA,IACF;AACA,UAAM,cAAc,MAAM,QAAQ,eAAe;AACjD,UAAM,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS;AAChD,UAAM,WAAW,kBAAkB,KAAK,MAAM,OAAO;AACrD,QAAI,aAAa,IAAI;AACnB;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,OAAO;AAAA,MACP,KAAK,WAAW;AAAA,MAChB,WAAW,UAAU;AAAA,MACrB,SAAS;AAAA,MACT;AAAA,MACA,OAAO,SAAS,MAAM,MAAM;AAAA,IAC9B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,MAAmC;AACnE,QAAM,UAAU,oBAAI,IAAoB;AACxC,aAAW,WAAW,KAAK,MAAM,IAAI,GAAG;AACtC,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,WAAW,KAAK,KAAK,WAAW,IAAI,GAAG;AAC9C;AAAA,IACF;AACA,UAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,QAAI,UAAU,IAAI;AAChB;AAAA,IACF;AACA,UAAM,MAAM,KAAK,MAAM,GAAG,KAAK,EAAE,KAAK;AACtC,UAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,EAAE,KAAK;AACzC,QAAI,IAAI,SAAS,GAAG;AAClB,cAAQ,IAAI,KAAK,KAAK;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,MAAwB;AACpD,QAAM,QAAkB,CAAC;AACzB,aAAW,WAAW,KAAK,MAAM,IAAI,GAAG;AACtC,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,WAAW,KAAK,KAAK,WAAW,IAAI,GAAG;AAC9C;AAAA,IACF;AACA,UAAM,KAAK,IAAI;AAAA,EACjB;AACA,SAAO;AACT;AAOO,SAAS,gBAAgB,KAA2B;AACzD,QAAM,SAAS,WAAW,GAAG;AAC7B,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE,SAAS,GAAG;AAC1E,QAAM,eAAe,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,iBAAiB,EAAE,SAAS,GAAG;AAEpF,QAAM,UAAU,YACZ,kBAAkB,IAAI,MAAM,UAAU,WAAW,UAAU,OAAO,CAAC,IACnE,oBAAI,IAAoB;AAC5B,QAAM,UAAU,eACZ,cAAc,IAAI,MAAM,aAAa,WAAW,aAAa,OAAO,CAAC,IACrE,CAAC;AAEL,SAAO,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ;AACtC;;;AC1GA,SAAS,gBAAgB,SAA8C;AACrE,QAAM,QAAkB,CAAC;AACzB,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,UAAM,KAAK,KAAK,GAAG,KAAK,KAAK,EAAE;AAAA,EACjC;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,WACd,KACA,SACc;AACd,QAAM,SAAS,WAAW,GAAG;AAC7B,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE,SAAS,GAAG;AAE1E,MAAI,CAAC,WAAW;AACd,UAAM,WAAW;AAAA,EAAW,gBAAgB,OAAO,CAAC;AAAA;AAAA;AACpD,UAAMA,OAAM,IAAI,SAAS,KAAK,CAAC,IAAI,SAAS,IAAI,IAAI,SAAS,IAAI,SAAS,IAAI,OAAO;AACrF,WAAO,EAAE,SAAS,GAAG,GAAG,GAAGA,IAAG,GAAG,QAAQ,IAAI,SAAS,QAAQ,OAAO,EAAE;AAAA,EACzE;AAEA,QAAM,OAAO,IAAI,MAAM,UAAU,WAAW,UAAU,OAAO;AAC7D,QAAM,WAAW,kBAAkB,IAAI;AACvC,MAAI,UAAU;AACd,aAAW,CAAC,GAAG,CAAC,KAAK,SAAS;AAC5B,QAAI,SAAS,IAAI,CAAC,MAAM,GAAG;AACzB,eAAS,IAAI,GAAG,CAAC;AACjB,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,SAAS,KAAK,SAAS,MAAM;AAAA,EACxC;AAEA,QAAM,UAAU;AAAA,EAAK,gBAAgB,QAAQ,CAAC;AAAA;AAC9C,QAAM,SAAS,IAAI,MAAM,GAAG,UAAU,SAAS;AAC/C,QAAM,QAAQ,IAAI,MAAM,UAAU,OAAO;AACzC,SAAO,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,IAAI,SAAS,KAAK;AACjE;AAEO,SAAS,kBAAkB,KAAa,YAAkC;AAC/E,QAAM,SAAS,WAAW,GAAG;AAC7B,QAAM,eAAe,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,iBAAiB,EAAE,SAAS,GAAG;AAEpF,MAAI,CAAC,cAAc;AACjB,UAAM,WAAW;AAAA,IAAoB,UAAU;AAAA;AAAA;AAC/C,UAAMA,OAAM,IAAI,SAAS,KAAK,CAAC,IAAI,SAAS,IAAI,IAAI,SAAS,IAAI,SAAS,IAAI,OAAO;AACrF,WAAO,EAAE,SAAS,GAAG,GAAG,GAAGA,IAAG,GAAG,QAAQ,IAAI,SAAS,KAAK;AAAA,EAC7D;AAEA,QAAM,OAAO,IAAI,MAAM,aAAa,WAAW,aAAa,OAAO;AACnE,QAAM,QAAQ,KACX,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,EAAE,WAAW,IAAI,CAAC;AACpD,MAAI,MAAM,SAAS,UAAU,GAAG;AAC9B,WAAO,EAAE,SAAS,KAAK,SAAS,MAAM;AAAA,EACxC;AACA,QAAM,KAAK,UAAU;AACrB,QAAM,UAAU;AAAA,IAAO,MAAM,KAAK,MAAM,CAAC;AAAA;AACzC,QAAM,SAAS,IAAI,MAAM,GAAG,aAAa,SAAS;AAClD,QAAM,QAAQ,IAAI,MAAM,aAAa,OAAO;AAC5C,SAAO,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,IAAI,SAAS,KAAK;AACjE;;;AC7DA;AAAA,EACE,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAcA,IAAM,oBAAgC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB;AAEO,SAAS,iBAAiB,OAAmC;AAClE,SAAQ,YAAkC,SAAS,KAAK;AAC1D;AASA,eAAsB,qBACpB,OAAmB,mBACS;AAC5B,QAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,QAAQ,KAAK,WAAW,aAAa,KAAK,UAAU,WAAW;AACrE,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,SAAS,QAAQ,4DAAuD;AAAA,EAC1E;AACF;AAQA,eAAsB,uBACpB,OAAmB,mBACmB;AACtC,QAAM,WAAW,MAAM,qBAAqB,IAAI;AAChD,MAAI,CAAC,SAAS,WAAW;AACvB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,SAAS,UAAU,QACvB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,SAAS,CAAC,EAC/C,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,OAAO,UAAU,EAAE,KAAK,OAAO,EAAE;AACzE;AAEA,eAAsB,UACpB,KACA,OAAmB,mBACc;AACjC,QAAM,OAAO,MAAM,KAAK,eAAe,GAAG;AAC1C,SAAO,MAAM;AACf;AAEO,SAAS,QAAQ,QAAoB,SAAsC;AAChF,SAAO,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO;AACnD;AAEO,SAAS,UAAU,KAAc,WAA0C;AAChF,SAAO,IAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS;AACpD;AAEO,SAAS,QAAQ,OAAkB,SAAwD;AAChG,SAAO,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO;AAClD;AASA,eAAsB,WACpB,KAMA,OAAmB,mBACe;AAClC,QAAM,SAAS,MAAM,UAAU,IAAI,QAAQ,IAAI;AAC/C,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,QAAM,MAAM,QAAQ,QAAQ,IAAI,GAAG;AACnC,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,UAAU,KAAK,IAAI,KAAK;AACtC,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,MAAM,QAAQ,OAAO,IAAI,GAAG;AAClC,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,SAAO,EAAE,QAAQ,KAAK,OAAO,IAAI;AACnC;;;AC7IA,SAAS,UAAU,iBAAiB;AAc7B,SAAS,mBAAmB,MAAuD;AACxF,QAAM,SAAS,KAAK,IAAI,aAAa;AACrC,QAAM,MAAM,KAAK,IAAI,UAAU;AAC/B,QAAM,QAAQ,KAAK,IAAI,YAAY;AACnC,QAAM,MAAM,KAAK,IAAI,UAAU;AAC/B,MAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK;AACrC,WAAO;AAAA,EACT;AACA,SAAO,EAAE,QAAQ,KAAK,OAAO,IAAI;AACnC;AAEO,SAAS,mBAAmB,KAAe,SAAuC;AACvF,QAAM,UAAU,oBAAI,IAAoB;AACxC,QAAM,QAAwC;AAAA,IAC5C,CAAC,eAAe,IAAI,MAAM;AAAA,IAC1B,CAAC,YAAY,IAAI,GAAG;AAAA,IACpB,CAAC,cAAc,IAAI,KAAK;AAAA,IACxB,CAAC,YAAY,IAAI,GAAG;AAAA,EACtB;AACA,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO;AAC1B,YAAQ,IAAI,GAAG,CAAC;AAAA,EAClB;AACA,MAAI,YAAY,QAAW;AACzB,YAAQ,IAAI,WAAW,OAAO;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,UAAU,MAA4C;AACpE,SAAO,aAAa,MAAM,CAAC,MAAM;AAC/B,UAAM,IAAI,KAAK,IAAI,CAAC;AACpB,WAAO,MAAM,UAAa,EAAE,SAAS;AAAA,EACvC,CAAC;AACH;AAEA,eAAsB,mBAAmB,MAA2C;AAClF,QAAM,MAAM,MAAM,SAAS,MAAM,MAAM;AACvC,QAAM,SAAS,gBAAgB,GAAG;AAClC,SAAO,mBAAmB,OAAO,KAAK,OAAO;AAC/C;AAEA,eAAsB,kBACpB,MACA,KACA,SACkB;AAClB,QAAM,MAAM,MAAM,SAAS,MAAM,MAAM;AACvC,QAAM,UAAU,mBAAmB,KAAK,OAAO;AAC/C,QAAM,EAAE,SAAS,QAAQ,IAAI,WAAW,KAAK,OAAO;AACpD,MAAI,SAAS;AACX,UAAM,UAAU,MAAM,SAAS,MAAM;AAAA,EACvC;AACA,SAAO;AACT;;;ACnEA,SAAS,SAAS,YAAAC,iBAAgB;AAClC,SAAS,QAAAC,aAAY;AAmBrB,eAAe,YAAY,MAA0C;AACnE,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,UAAU,MAA0C;AACjE,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,YAAY,MAAc,MAAmC;AAC1E,QAAM,MAAM,MAAMC,UAAS,MAAM,MAAM;AACvC,QAAM,SAAS,gBAAgB,GAAG;AAClC,SAAO;AAAA,IACL;AAAA,IACA,MAAM,KAAK,QAAQ,UAAU,EAAE;AAAA,IAC/B;AAAA,IACA,MAAM,OAAO;AAAA,IACb,SAAS,OAAO;AAAA,EAClB;AACF;AAEA,eAAe,oBAAoB,SAAiD;AAClF,QAAM,SAASC,MAAK,SAAS,gBAAgB;AAC7C,QAAM,QAAQ,MAAM,UAAU,MAAM;AACpC,QAAM,WAAW,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC;AACvD,QAAM,SAAuB,CAAC;AAC9B,aAAW,QAAQ,UAAU;AAC3B,WAAO,KAAK,MAAM,YAAYA,MAAK,QAAQ,IAAI,GAAG,IAAI,CAAC;AAAA,EACzD;AACA,SAAO;AACT;AAEA,eAAe,QAAQ,WAAmB,MAAkC;AAC1E,QAAM,UAAUA,MAAK,WAAW,IAAI;AACpC,QAAM,eAAe,MAAM,oBAAoB,OAAO;AACtD,SAAO,EAAE,MAAM,SAAS,MAAM,aAAa;AAC7C;AAEA,eAAe,UAAU,SAAiB,SAAmD;AAC3F,QAAM,OAAO,kBAAkB,SAAS,mBAAmB;AAC3D,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,EACT;AACA,QAAM,YAAYA,MAAK,SAAS,OAAO;AACvC,QAAM,UAAU,MAAM,YAAY,SAAS;AAC3C,QAAM,OAAoB,CAAC;AAC3B,aAAW,UAAU,SAAS;AAC5B,SAAK,KAAK,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,EAC5C;AACA,SAAO,EAAE,MAAM,WAAW,MAAM,KAAK;AACvC;AAEA,eAAe,QAAQ,YAAoB,SAAiD;AAC1F,QAAM,OAAO,kBAAkB,SAAS,iBAAiB;AACzD,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,EACT;AACA,QAAM,UAAUA,MAAK,YAAY,OAAO;AACxC,QAAM,YAAY,MAAM,YAAY,OAAO;AAC3C,QAAM,SAAwB,CAAC;AAC/B,aAAW,YAAY,WAAW;AAChC,UAAM,QAAQ,MAAM,UAAU,SAAS,QAAQ;AAC/C,QAAI,OAAO;AACT,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AACA,SAAO,EAAE,MAAM,SAAS,MAAM,OAAO;AACvC;AAEA,eAAe,WAAW,MAAc,SAAoD;AAC1F,QAAM,MAAM,kBAAkB,SAAS,oBAAoB;AAC3D,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AACA,QAAM,aAAaA,MAAK,MAAM,OAAO;AACrC,QAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,QAAM,OAAoB,CAAC;AAC3B,aAAW,UAAU,SAAS;AAC5B,UAAM,MAAM,MAAM,QAAQ,YAAY,MAAM;AAC5C,QAAI,KAAK;AACP,WAAK,KAAK,GAAG;AAAA,IACf;AAAA,EACF;AACA,SAAO,EAAE,MAAM,YAAY,KAAK,KAAK;AACvC;AAEA,eAAsB,eAAe,MAAwC;AAC3E,QAAM,aAAa,MAAM,YAAY,IAAI;AACzC,QAAM,UAA0B,CAAC;AACjC,aAAW,OAAO,YAAY;AAC5B,UAAM,SAAS,MAAM,WAAW,MAAM,GAAG;AACzC,QAAI,QAAQ;AACV,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AACA,SAAO,EAAE,MAAM,QAAQ;AACzB;AAWO,SAAS,mBAAmB,WAA6C;AAC9E,QAAM,UAAU,UAAU,QAAQ,UAAU,EAAE,EAAE,QAAQ,OAAO,GAAG;AAClE,QAAM,OAAO,QAAQ,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC1D,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO;AAAA,EACT;AACA,QAAM,CAAC,QAAQ,KAAK,OAAO,KAAK,GAAG,IAAI,IAAI;AAC3C,MAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK;AACrC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,EAAE,QAAQ,KAAK,OAAO,IAAI;AAAA,EACnC;AACA,QAAM,WAAW,KAAK,KAAK,GAAG;AAC9B,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC,KAAK;AACtC,QAAM,cAAc,KAAK,SAAS,MAAM,IAAI,KAAK,QAAQ,UAAU,EAAE,IAAI;AACzE,SAAO,cACH,EAAE,QAAQ,KAAK,OAAO,KAAK,aAAa,SAAS,IACjD,EAAE,QAAQ,KAAK,OAAO,KAAK,SAAS;AAC1C;;;AC3JA,SAAS,OAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,eAAe;AAKxB,eAAsB,cAAiD;AACrE,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,iBAAiB,GAAG,MAAM;AACrD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,aAAa,KAA6D;AAC9F,QAAM,UAAwB,EAAE,GAAG,KAAK,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAC5E,QAAM,OAAO,iBAAiB;AAC9B,QAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAMC,WAAU,MAAM,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AACrE,SAAO;AACT;;;ACxBA,SAAS,SAAAC,QAAO,WAAAC,UAAS,aAAAC,kBAAiB;AAC1C,SAAS,QAAAC,aAAY;AA4Cd,IAAM,sBAAsB,CAAC,SAAS,OAAO,WAAW,MAAM;AAErE,IAAM,mBAAmB;AAEzB,SAAS,mBAAmB,MAAoB;AAC9C,MAAI,CAAC,iBAAiB,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI;AAAA,MACR,6BAA6B,IAAI;AAAA,IACnC;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,SAAiB,KAAuB;AAC/D,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,kBAAkB,IAAI,MAAM;AAAA,IAC5B,eAAe,IAAI,GAAG;AAAA,IACtB,iBAAiB,IAAI,KAAK;AAAA,IAC1B,eAAe,IAAI,GAAG;AAAA,IACtB,kBAAkB,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAe,cAAc,SAAiB,SAAiB,KAAgC;AAC7F,QAAM,SAASC,MAAK,SAAS,gBAAgB;AAC7C,QAAMC,OAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACvC,QAAM,WAAWD,MAAK,QAAQ,GAAG,OAAO,MAAM;AAC9C,MAAI;AACF,UAAME,WAAU,UAAU,gBAAgB,SAAS,GAAG,GAAG,EAAE,UAAU,QAAQ,MAAM,KAAK,CAAC;AAAA,EAC3F,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,YAAM;AAAA,IACR;AACA,UAAM,kBAAkB,UAAU,GAAG;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,SAGhB;AACF,SAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,WAAM,EAAE,KAAK,KAAK,EAAE,SAAS,SAAS,CAAC,OAAO,EAAE,aAAa,IAAI,KAAK,GAAG,IAAI,EAAE;AAC1I;AAEA,SAAS,QAAQ,QAAgE;AAC/E,SAAO,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,OAAO,OAAO,SAAS,CAAC,SAAS,EAAE,OAAO,WAAW,IAAI,KAAK,GAAG,IAAI,EAAE;AAC/I;AAEA,SAAS,UAAU,KAA0D;AAC3E,SAAO,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,KAAK,OAAO,SAAS,CAAC,OAAO,EAAE,KAAK,WAAW,IAAI,KAAK,GAAG,IAAI,EAAE;AACxI;AAEA,SAAS,QAAQ,OAA8D;AAC7E,SAAO,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAChE;AAEA,eAAsB,SAAS,SAAmD;AAChF,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,QAAQ,QAAQ,MAAY;AAExC,QAAM,UAAU,MAAM,uBAAuB,IAAI;AACjD,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,QAAQ,QAAQ,aAAa,WAAW,OAAO,CAAC;AACxE,QAAM,aAAa,MAAM,KAAK,eAAe,SAAS;AACtD,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,UAAU,SAAS,4DAA4D,SAAS,KAAK;AAAA,EAC/G;AACA,QAAM,SAAS,WAAW;AAE1B,MAAI,OAAO,KAAK,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,UAAU,SAAS,0BAA0B;AAAA,EAC/D;AAEA,QAAM,UAAU,MAAM,QAAQ,QAAQ,UAAU,QAAQ,MAAM,CAAC;AAC/D,QAAM,MAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO;AACtD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,OAAO,OAAO,wBAAwB,SAAS,EAAE;AAAA,EACnE;AACA,MAAI,IAAI,OAAO,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,OAAO,OAAO,iBAAiB;AAAA,EACjD;AAEA,QAAM,YAAY,MAAM,QAAQ,QAAQ,YAAY,UAAU,GAAG,CAAC;AAClE,QAAM,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS;AACzD,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,SAAS,SAAS,qBAAqB,OAAO,EAAE;AAAA,EAClE;AACA,MAAI,MAAM,KAAK,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,SAAS,SAAS,eAAe;AAAA,EACnD;AAEA,QAAM,UAAU,MAAM,QAAQ,QAAQ,UAAU,QAAQ,KAAK,CAAC;AAC9D,QAAM,MAAgB,EAAE,QAAQ,WAAW,KAAK,SAAS,OAAO,WAAW,KAAK,QAAQ;AAExF,QAAM,UAAUF;AAAA,IACd,QAAQ;AAAA,IACR,iBAAiB,SAAS;AAAA,IAC1B,cAAc,OAAO;AAAA,IACrB,gBAAgB,SAAS;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,QAAQ,QAAQ,cAAc,OAAO;AAC7D,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,KAAK,SAAS,cAAc,CAAC,GAAG,SAAS,MAAM;AAAA,EAC1D;AAEA,QAAMC,OAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAExC,QAAM,eAAe,MAAM,iBAAiB,OAAO;AACnD,QAAM,SAAS,CAAC,GAAG,mBAAmB;AACtC,QAAM,WAAW,MAAM,QAAQ,QAAQ,mBAAmB,EAAE,QAAQ,UAAU,aAAa,CAAC;AAC5F,QAAM,SAAS,MAAM,QAAQ,QAAQ,mBAAmB;AACxD,QAAM,SAAmB,CAAC;AAC1B,aAAW,QAAQ,CAAC,GAAG,UAAU,GAAI,SAAS,CAAC,MAAM,IAAI,CAAC,CAAE,GAAG;AAC7D,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,KAAK,OAAO,SAAS,OAAO,GAAG;AACpD;AAAA,IACF;AACA,uBAAmB,OAAO;AAC1B,WAAO,KAAK,OAAO;AAAA,EACrB;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,QAAM,UAAoB,CAAC;AAC3B,aAAW,WAAW,QAAQ;AAC5B,UAAM,OAAO,MAAM,cAAc,SAAS,SAAS,GAAG;AACtD,YAAQ,KAAK,IAAI;AACjB,QAAI,UAAK,IAAI,EAAE;AAAA,EACjB;AAEA,SAAO,EAAE,KAAK,SAAS,cAAc,SAAS,SAAS,KAAK;AAC9D;AAEA,eAAe,iBAAiB,SAA6C;AAC3E,MAAI;AACF,UAAM,UAAU,MAAME,SAAQH,MAAK,SAAS,gBAAgB,GAAG,EAAE,eAAe,KAAK,CAAC;AACtF,WAAO,QACJ,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,KAAK,SAAS,MAAM,CAAC,EACnD,IAAI,CAAC,MAAM,EAAE,KAAK,QAAQ,UAAU,EAAE,CAAC;AAAA,EAC5C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;;;ACxMA,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,YAAY,QAAAI,OAAM,UAAU,SAAS,WAAW;AAGzD,SAAS,kBAAkB,yBAAyB;AAoDpD,SAAS,gBACP,MACA,KACA,KACyB;AACzB,SAAO,IAAI,QAAQ,CAAC,gBAAgB,kBAAkB;AACpD,UAAM,QAAQ,MAAM,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,KAAK,KAAK,OAAO,OAAO,CAAC;AACjE,QAAI,SAAS;AACb,QAAI,SAAS;AACb,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACzC,gBAAU,MAAM,SAAS,MAAM;AAC/B,cAAQ,OAAO,MAAM,KAAK;AAAA,IAC5B,CAAC;AACD,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACzC,gBAAU,MAAM,SAAS,MAAM;AAC/B,cAAQ,OAAO,MAAM,KAAK;AAAA,IAC5B,CAAC;AACD,UAAM,GAAG,SAAS,aAAa;AAC/B,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,qBAAe,EAAE,MAAM,QAAQ,GAAG,QAAQ,OAAO,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,OAAO,MAAgC;AACpD,MAAI;AACF,UAAM,KAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,cACb,MACA,QACsF;AACtF,QAAM,SAAS,WAAW,MAAM,IAAI,SAAS,QAAQ,QAAQ,IAAI,GAAG,MAAM;AAC1E,MAAI,MAAM,OAAO,MAAM,GAAG;AACxB,WAAO,EAAE,UAAU,QAAQ,WAAW,OAAU;AAAA,EAClD;AAEA,QAAM,YAAY,mBAAmB,MAAM;AAC3C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,qBAAqB,MAAM,EAAE;AAAA,EAC/C;AAEA,QAAM,EAAE,QAAQ,KAAK,OAAO,KAAK,SAAS,IAAI;AAC9C,QAAM,SAASC;AAAA,IACb;AAAA,IACA,iBAAiB,MAAM;AAAA,IACvB,cAAc,GAAG;AAAA,IACjB,gBAAgB,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,MAAI,CAAC,UAAU;AACb,WAAO,EAAE,UAAU,QAAQ,UAAU;AAAA,EACvC;AAEA,QAAM,YAAYA,MAAK,QAAQ,QAAQ;AACvC,MAAI,MAAM,OAAO,SAAS,GAAG;AAC3B,WAAO,EAAE,UAAU,WAAW,UAAU;AAAA,EAC1C;AAEA,QAAM,UAAU,UAAU,SAAS,MAAM,IAAI,YAAY,GAAG,SAAS;AACrE,MAAI,MAAM,OAAO,OAAO,GAAG;AACzB,WAAO,EAAE,UAAU,SAAS,UAAU;AAAA,EACxC;AAEA,QAAM,IAAI,MAAM,mBAAmB,SAAS,EAAE;AAChD;AAEA,eAAe,sBACb,QACA,aACqE;AACrE,MAAI,aAAa;AACf,UAAM,UAAUA,MAAK,QAAQ,kBAAkB,GAAG,WAAW,MAAM;AACnE,QAAI,CAAE,MAAM,OAAO,OAAO,GAAI;AAC5B,YAAM,IAAI,MAAM,+BAA+B,OAAO,EAAE;AAAA,IAC1D;AACA,WAAO,EAAE,SAAS,YAAY;AAAA,EAChC;AAEA,QAAM,aAAa,MAAM,eAAe,QAAQ,QAAQ,MAAM,MAAM,MAAM,IAAI,CAAC;AAC/E,aAAW,UAAU,WAAW,SAAS;AACvC,eAAW,OAAO,OAAO,MAAM;AAC7B,iBAAW,SAAS,IAAI,QAAQ;AAC9B,mBAAW,OAAO,MAAM,MAAM;AAC5B,cAAI,IAAI,SAAS,UAAU,IAAI,aAAa,SAAS,GAAG;AACtD,kBAAM,QAAQ,IAAI,aAAa,CAAC;AAChC,gBAAI,OAAO;AACT,qBAAO,EAAE,SAAS,MAAM,MAAM,aAAa,MAAM,KAAK;AAAA,YACxD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,oCAAoC,MAAM,IAAI,gBAAgB,EAAE;AAClF;AAEA,SAAS,mBAAmB,UAAkB,MAAsB;AAClE,QAAM,MAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,GAAG;AAC9C,MAAI,IAAI,SAAS,GAAG;AAClB,UAAM,IAAI,MAAM,wDAAwD,QAAQ,EAAE;AAAA,EACpF;AACA,QAAM,CAAC,WAAW,QAAQ,UAAU,MAAM,IAAI;AAC9C,MAAI,CAAC,aAAa,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ;AACjD,UAAM,IAAI,MAAM,wDAAwD,QAAQ,EAAE;AAAA,EACpF;AACA,SAAOA,MAAK,MAAM,WAAW,QAAQ,UAAU,MAAM;AACvD;AAEA,eAAsB,aAAa,SAAuC;AACxE,QAAM,EAAE,SAAS,IAAI,MAAM,cAAc,QAAQ,MAAM,QAAQ,MAAM;AACrE,QAAM,QAAQ,MAAM,KAAK,QAAQ;AAEjC,MAAI;AACJ,MAAI;AAEJ,MAAI,MAAM,YAAY,GAAG;AACvB,aAAS;AACT,kBAAc;AAAA,EAChB,OAAO;AACL,aAAS,mBAAmB,UAAU,QAAQ,IAAI;AAClD,kBAAc;AAAA,EAChB;AAEA,QAAM,EAAE,SAAS,YAAY,IAAI,MAAM,sBAAsB,QAAQ,QAAQ,WAAW;AAExF,QAAM,OAAO,MAAM,mBAAmB,OAAO;AAC7C,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR,uDAAuD,OAAO;AAAA,IAChE;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ,kBAAkB;AAC3C,QAAM,QAAQ,MAAM,SAAS,IAAI;AAEjC,QAAM,UAAoB,CAAC,KAAK;AAChC,MAAI,aAAa;AACf,YAAQ,KAAK,SAAS,QAAQ,WAAW,KAAK,GAAG;AAAA,EACnD;AACA,UAAQ,KAAK,SAAS,aAAa,aAAa,eAAe,KAAK,EAAE;AACtE,MAAI,QAAQ,WAAW;AACrB,YAAQ,KAAK,GAAG,QAAQ,SAAS;AAAA,EACnC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACP;AACF;AAEA,eAAsB,SAAS,SAAyC;AACtE,QAAM,OAAO,MAAM,aAAa,OAAO;AACvC,QAAM,UAAU,QAAQ,YAAY;AACpC,QAAM,MAAyB,EAAE,GAAG,QAAQ,KAAK,uBAAuB,KAAK,MAAM;AACnF,UAAQ,MAAM,cAAS,KAAK,QAAQ,KAAK,GAAG,CAAC,UAAU,KAAK,GAAG,GAAG;AAClE,QAAM,SAAS,MAAM,QAAQ,KAAK,SAAS,KAAK,KAAK,GAAG;AACxD,SAAO,EAAE,GAAG,MAAM,GAAG,OAAO;AAC9B;;;AC7NO,SAAS,sBAAsB,WAKxB;AACZ,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC5D,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO;AAAA,EACT;AACA,QAAM,CAAC,QAAQ,KAAK,OAAO,GAAG,IAAI;AAClC,MAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK;AACrC,WAAO;AAAA,EACT;AACA,SAAO,EAAE,QAAQ,KAAK,OAAO,IAAI;AACnC;AAQA,eAAsB,WAAW,SAA4C;AAC3E,QAAM,SAAS,sBAAsB,QAAQ,SAAS;AACtD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,8BAA8B,QAAQ,SAAS;AAAA,IACjD;AAAA,EACF;AAEA,MAAI,CAAC,iBAAiB,OAAO,MAAM,GAAG;AACpC,UAAM,IAAI,MAAM,uBAAuB,OAAO,MAAM,EAAE;AAAA,EACxD;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,UAAM,WAAW,MAAM,WAAW,EAAE,GAAG,QAAQ,QAAQ,OAAO,OAAO,GAAG,QAAQ,IAAI;AACpF,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,oBAAoB,QAAQ,SAAS;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,aAAa,MAAM;AAClC;","names":["sep","readFile","join","readFile","join","readFile","writeFile","readFile","writeFile","mkdir","readdir","writeFile","join","join","mkdir","writeFile","readdir","join","join"]}
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*([a-zA-Z][a-zA-Z0-9:_-]*)\\s*([{[])/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 { 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 readonly inputCustomEnvName: () => Promise<string | null>;\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;\n\nconst ENV_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nfunction 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\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 `cf-sync 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(`Region ${regionKey} is not cached. Run \\`cf-sync sync\\` or \\`cf-sync region ${regionKey}\\`.`);\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\n const existingEnvs = await listExistingEnvs(appPath);\n const common = [...COMMON_ENVIRONMENTS];\n const selected = await options.prompts.selectEnvironments({ common, existing: existingEnvs });\n const custom = await options.prompts.inputCustomEnvName();\n const merged: string[] = [];\n for (const name of [...selected, ...(custom ? [custom] : [])]) {\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 } 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 { 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\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\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","mkdir","writeFile","readdir","readFile","dirname","join","require","join","readFile","dirname"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saptools/bruno",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Smart runner for Bruno โ€” CF-aware env metadata, automatic token injection, and shorthand paths",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -53,6 +53,7 @@
53
53
  "@inquirer/prompts": "^8.3.2",
54
54
  "@saptools/cf-sync": "workspace:*",
55
55
  "@saptools/cf-xsuaa": "workspace:*",
56
+ "@usebruno/cli": "^3.2.2",
56
57
  "commander": "^13.0.0"
57
58
  },
58
59
  "devDependencies": {