@devdogsuga/devtools 0.1.41 → 0.1.43

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.
@@ -1,7 +1,7 @@
1
- import { i as ownPackageDir, r as findRepoRoot } from "./root-C2OmZDwD.js";
2
- import { a as repoPeerUrl, n as loadEnv, t as getEnvSync } from "./peers-RBplwovA.js";
1
+ import { i as ownPackageDir } from "./root-CjPWNkBu.js";
2
+ import { a as repoPeerUrl, n as loadEnv, o as resolveRepoPeerUrl, p as resolveLayout, t as getEnvSync } from "./peers-DvUH5VxX.js";
3
3
  import { register } from "node:module";
4
- import { existsSync, readdirSync } from "node:fs";
4
+ import { existsSync, readdirSync, realpathSync } from "node:fs";
5
5
  import { join } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  //#region ../cli-core/src/repo/peer-redirect.ts
@@ -23,10 +23,10 @@ import { pathToFileURL } from "node:url";
23
23
  * manifest also imports `zod`, which has to keep resolving from devtools'
24
24
  * own location, and a copy written anywhere else would lose that.
25
25
  */
26
- /** Registers `redirect`. Hooks cannot be unregistered, so each call adds a
27
- * loader for the rest of the process; call it once per redirect. */
28
- function redirectPeer(redirect) {
29
- register("./peer-redirect-hooks.js", import.meta.url, { data: [redirect] });
26
+ /** `redirectPeer` for several at once: the hooks keep one table per
27
+ * registration, so everything that needs redirecting goes in one call. */
28
+ function redirectPeers(redirects) {
29
+ register("./peer-redirect-hooks.js", import.meta.url, { data: redirects });
30
30
  }
31
31
  //#endregion
32
32
  //#region ../cli-core/src/repo/tsx-loader.ts
@@ -85,7 +85,11 @@ async function importRepoTs(absolutePath) {
85
85
  * filename (`tsconfig.json`, `wrangler.jsonc`, `supadart.yaml`), and a pointer
86
86
  * would be the only one of its kind.
87
87
  *
88
- * One special case: `supabase/env.ts` sits at the repo root, OUTSIDE the
88
+ * From a Backstage checkout the scan covers BOTH repos (`repo/layout.ts`):
89
+ * Backstage's `apps/*` and `packages/*`, then DevDogsUGA's through
90
+ * `devdogsuga/`, de-duplicated by directory name with Backstage first.
91
+ *
92
+ * One special case: `supabase/env.ts` sits at DevDogsUGA's root, OUTSIDE the
89
93
  * workspace globs. Its variables belong to `config.toml` and the Supabase
90
94
  * CLI, not to any package, so it lives next to the config that reads them.
91
95
  *
@@ -157,12 +161,17 @@ function assertRegistryLoaded() {
157
161
  }
158
162
  async function importManifests() {
159
163
  await loadEnv();
164
+ const redirects = [];
160
165
  const envUrl = repoPeerUrl("@devdogsuga/env");
161
- if (envUrl) redirectPeer({
162
- parentURL: pathToFileURL(ownManifestPath()).href,
163
- specifier: "@devdogsuga/env",
164
- url: envUrl
165
- });
166
+ if (envUrl) {
167
+ redirects.push({
168
+ parentURL: pathToFileURL(ownManifestPath()).href,
169
+ specifier: "@devdogsuga/env",
170
+ url: envUrl
171
+ });
172
+ redirects.push(...siblingRedirects(envUrl));
173
+ }
174
+ if (redirects.length > 0) redirectPeers(redirects);
166
175
  const previous = process.env.SKIP_ENV_VALIDATION;
167
176
  process.env.SKIP_ENV_VALIDATION = "1";
168
177
  try {
@@ -177,6 +186,36 @@ async function importManifests() {
177
186
  }
178
187
  }
179
188
  /**
189
+ * From a Backstage checkout, the manifests under `devdogsuga/` import
190
+ * `@devdogsuga/env` through THAT checkout's `node_modules` (or not at all, when
191
+ * it has none): a second copy of the package, and so a second registry that
192
+ * every `declare()` there would populate instead of the one this process
193
+ * reads. Point their imports at the copy `loadEnv()` resolved. Resolved
194
+ * through `realpath`, because the loader sees the module's real location, not
195
+ * the `devdogsuga` symlink.
196
+ */
197
+ function siblingRedirects(envUrl) {
198
+ const layout = resolveLayout();
199
+ if (layout.kind !== "backstage" || !layout.hasDevdogsuga) return [];
200
+ const nextjs = resolveRepoPeerUrl("@devdogsuga/env/nextjs");
201
+ const redirects = [];
202
+ for (const path of manifestPaths()) {
203
+ if (!path.startsWith(layout.devdogsugaRoot)) continue;
204
+ const parentURL = pathToFileURL(realpathSync(path)).href;
205
+ redirects.push({
206
+ parentURL,
207
+ specifier: "@devdogsuga/env",
208
+ url: envUrl
209
+ });
210
+ if (nextjs) redirects.push({
211
+ parentURL,
212
+ specifier: "@devdogsuga/env/nextjs",
213
+ url: nextjs
214
+ });
215
+ }
216
+ return redirects;
217
+ }
218
+ /**
180
219
  * Every manifest file, in a stable order.
181
220
  *
182
221
  * The workspace members are enumerated by scanning `apps/*` and `packages/*`
@@ -192,7 +231,8 @@ function manifestPaths() {
192
231
  const manifest = manifestIn(dir);
193
232
  if (manifest) paths.push(manifest);
194
233
  }
195
- const supabase = manifestIn(join(findRepoRoot(), "supabase"));
234
+ const layout = resolveLayout();
235
+ const supabase = layout.hasDevdogsuga ? manifestIn(join(layout.devdogsugaRoot, "supabase")) : null;
196
236
  if (supabase) paths.push(supabase);
197
237
  paths.push(ownManifestPath());
198
238
  return paths;
@@ -213,20 +253,41 @@ function manifestPaths() {
213
253
  function ownManifestPath() {
214
254
  return join(ownPackageDir(), "env.ts");
215
255
  }
256
+ /**
257
+ * The CLIs' own packages: each loads its own operator manifest through
258
+ * `ownManifestPath()`, so scanning them from a Backstage checkout would
259
+ * declare the same keys twice.
260
+ */
261
+ const CLI_PACKAGES = /* @__PURE__ */ new Set(["devtools", "backstage"]);
262
+ /**
263
+ * `apps/*` and `packages/*` of every repo in the layout (the repo you are in
264
+ * first, so it wins a name clash: before the cutover both repos carry
265
+ * `apps/platform` and `packages/email`), then DevDogsUGA's `docs`.
266
+ */
216
267
  function workspaceDirs() {
268
+ const layout = resolveLayout();
269
+ const roots = [layout.root];
270
+ if (layout.kind === "backstage" && layout.hasDevdogsuga) roots.push(layout.devdogsugaRoot);
217
271
  const dirs = [];
218
- const repoRoot = findRepoRoot();
219
272
  for (const parent of ["apps", "packages"]) {
220
- const names = [];
221
- for (const entry of readdirSync(join(repoRoot, parent), { withFileTypes: true })) {
222
- if (!entry.isDirectory()) continue;
223
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
224
- names.push(entry.name);
273
+ const found = /* @__PURE__ */ new Map();
274
+ for (const root of roots) {
275
+ let entries;
276
+ try {
277
+ entries = readdirSync(join(root, parent), { withFileTypes: true });
278
+ } catch {
279
+ continue;
280
+ }
281
+ for (const entry of entries) {
282
+ if (!entry.isDirectory()) continue;
283
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
284
+ if (layout.kind === "backstage" && parent === "packages" && CLI_PACKAGES.has(entry.name)) continue;
285
+ if (!found.has(entry.name)) found.set(entry.name, join(root, parent, entry.name));
286
+ }
225
287
  }
226
- names.sort();
227
- for (const name of names) dirs.push(join(repoRoot, parent, name));
288
+ for (const name of [...found.keys()].sort()) dirs.push(found.get(name));
228
289
  }
229
- dirs.push(join(repoRoot, "docs"));
290
+ if (layout.hasDevdogsuga) dirs.push(join(layout.devdogsugaRoot, "docs"));
230
291
  return dirs;
231
292
  }
232
293
  /** `src/env.ts`, then `env.ts`; both present in one package is a hard error. */
@@ -0,0 +1,2 @@
1
+ import { t as scopedProcessEnv } from "./local-env-BuHU5Ckd.js";
2
+ export { scopedProcessEnv };
@@ -1,8 +1,8 @@
1
- import { c as YES, d as positionals, i as suppressFailureLog, l as createCatalog, o as JSON_FLAG, s as SCOPES } from "./failure-log-B5GG_8T1.js";
2
- import { a as listContainerNames, i as foreignStackProjectId, n as containerPrefix, o as readProjectId, p as supabaseCapture, r as foreignStackMessage, t as STACK_API_PORT } from "./supabase-project-Bw8sBFcE.js";
3
- import { r as findRepoRoot } from "./root-C2OmZDwD.js";
4
- import { n as loadEnv, r as loadEnvLoad } from "./peers-RBplwovA.js";
5
- import { c as reportDevtoolsError, f as isNonInteractive } from "./telemetry-Do13RFhc.js";
1
+ import { c as YES, d as positionals, i as suppressFailureLog, l as createCatalog, o as JSON_FLAG, s as SCOPES } from "./failure-log-DOt6E3hS.js";
2
+ import { a as listContainerNames, i as foreignStackProjectId, n as containerPrefix, o as readProjectId, p as supabaseCapture, r as foreignStackMessage, t as STACK_API_PORT } from "./supabase-project-C93xRFkN.js";
3
+ import { r as findRepoRoot } from "./root-CjPWNkBu.js";
4
+ import { c as devdogsugaRootOrNull, n as loadEnv, p as resolveLayout, r as loadEnvLoad } from "./peers-DvUH5VxX.js";
5
+ import { c as reportDevtoolsError, f as isNonInteractive } from "./telemetry-C07-ioHm.js";
6
6
  import { cancel, confirm, isCancel, log, note, select, text } from "@clack/prompts";
7
7
  import { existsSync } from "node:fs";
8
8
  import { writeFile } from "node:fs/promises";
@@ -826,7 +826,7 @@ async function ensureGeneratedEnvFile(tier, devDatabase, deps) {
826
826
  if (!await deps.probeLocalStack()) return { outcome: "skipped" };
827
827
  try {
828
828
  const env = await deps.captureStatus();
829
- await deps.write(join(deps.repoRoot, GENERATED_FILE), env);
829
+ for (const dir of [deps.repoRoot, ...deps.mirrorRoots ?? []]) await deps.write(join(dir, GENERATED_FILE), env);
830
830
  return {
831
831
  outcome: "wrote",
832
832
  line: "devtools: wrote .env.generated from the running local stack"
@@ -851,15 +851,18 @@ async function ensureGeneratedEnvFile(tier, devDatabase, deps) {
851
851
  * different copies of the same optional peer in play.
852
852
  */
853
853
  function realEnsureGeneratedEnvDeps(probeLocalStack) {
854
- const repoRoot = findRepoRoot();
854
+ const layout = resolveLayout();
855
+ const repoRoot = layout.root;
856
+ const supabaseRoot = devdogsugaRootOrNull(layout);
855
857
  return {
856
858
  probeLocalStack,
857
- exists: (file) => existsSync(join(repoRoot, file)),
859
+ exists: (file) => [repoRoot, ...layout.envMirrors].every((dir) => existsSync(join(dir, file))),
858
860
  captureStatus: () => supabaseCapture("status", "-o", "env"),
859
861
  write: (path, contents) => writeFile(path, contents),
860
862
  listContainerNames: () => listContainerNames(STACK_API_PORT),
861
- projectId: () => readProjectId(repoRoot),
862
- repoRoot
863
+ projectId: () => supabaseRoot === null ? null : readProjectId(supabaseRoot),
864
+ repoRoot,
865
+ mirrorRoots: layout.envMirrors
863
866
  };
864
867
  }
865
868
  //#endregion
@@ -1276,7 +1279,8 @@ function probeEnvironment(execute = run) {
1276
1279
  stack: "unknown",
1277
1280
  envFile
1278
1281
  };
1279
- const prefix = containerPrefix(readProjectId(findRepoRoot()));
1282
+ const supabaseRoot = devdogsugaRootOrNull(resolveLayout());
1283
+ const prefix = containerPrefix(supabaseRoot === null ? null : readProjectId(supabaseRoot));
1280
1284
  return {
1281
1285
  docker,
1282
1286
  stack: names.split("\n").some((name) => name.trim().startsWith(prefix)) ? "yes" : "no",
@@ -1,8 +1,114 @@
1
- import { r as findRepoRoot, t as RepoNotFoundError } from "./root-C2OmZDwD.js";
1
+ import { r as findRepoRoot, t as RepoNotFoundError } from "./root-CjPWNkBu.js";
2
2
  import { createRequire } from "node:module";
3
- import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
+ /** The directory (relative to a Backstage root) holding the DevDogsUGA checkout. */
7
+ const DEVDOGSUGA_LINK = "devdogsuga";
8
+ var DevdogsugaMissingError = class extends Error {
9
+ constructor(path) {
10
+ super(`The DevDogsUGA checkout is missing at ${path}. Run \`pnpm devdogsuga\` (links the sibling clone, or \$DEVDOGSUGA_DIR) or \`pnpm install\` in the Backstage root first.`);
11
+ this.name = "DevdogsugaMissingError";
12
+ }
13
+ };
14
+ /** The kind of repo `dir` is the root of, by its `package.json` name; null if neither. */
15
+ function repoKindOf(dir) {
16
+ try {
17
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
18
+ if (pkg.name === "devdogs-monorepo") return "devdogsuga";
19
+ if (pkg.name === "backstage") return "backstage";
20
+ } catch {}
21
+ return null;
22
+ }
23
+ function isDir(path) {
24
+ try {
25
+ return statSync(path).isDirectory();
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ /**
31
+ * The layout of the repo rooted at `root`. Pure: nothing is memoized, so tests
32
+ * can build fixtures freely. An unrecognised package name is treated as
33
+ * DevDogsUGA (the contract fixtures and every pre-Backstage caller).
34
+ */
35
+ function layoutAt(root) {
36
+ const kind = repoKindOf(root) === "backstage" ? "backstage" : "devdogsuga";
37
+ const sibling = join(root, DEVDOGSUGA_LINK);
38
+ const hasDevdogsuga = kind === "devdogsuga" || isDir(sibling);
39
+ const devdogsugaRoot = kind === "devdogsuga" ? root : sibling;
40
+ const appsDirs = [join(root, "apps")];
41
+ if (kind === "backstage" && hasDevdogsuga) appsDirs.push(join(devdogsugaRoot, "apps"));
42
+ return {
43
+ kind,
44
+ root,
45
+ get devdogsugaRoot() {
46
+ if (!hasDevdogsuga) throw new DevdogsugaMissingError(sibling);
47
+ return devdogsugaRoot;
48
+ },
49
+ ...kind === "backstage" ? { backstageRoot: root } : {},
50
+ hasDevdogsuga,
51
+ appsDirs: appsDirs.filter(isDir),
52
+ envMirrors: kind === "backstage" && hasDevdogsuga ? [devdogsugaRoot] : []
53
+ };
54
+ }
55
+ /** `layout.devdogsugaRoot`, or null instead of a throw when the checkout is missing. */
56
+ function devdogsugaRootOrNull(layout) {
57
+ return layout.hasDevdogsuga ? layout.devdogsugaRoot : null;
58
+ }
59
+ let cached;
60
+ let cachedFor;
61
+ /** The layout of the repo the process is in (`findRepoRoot()`), memoized per root. */
62
+ function resolveLayout() {
63
+ const root = findRepoRoot();
64
+ if (cached === void 0 || cachedFor !== root) {
65
+ cached = layoutAt(root);
66
+ cachedFor = root;
67
+ }
68
+ return cached;
69
+ }
70
+ /** Every directory under `appsDirs` (one app each), de-duplicated by name, sorted by name. */
71
+ function listApps(layout = resolveLayout()) {
72
+ const seen = /* @__PURE__ */ new Map();
73
+ for (const parent of layout.appsDirs) for (const entry of readdirSync(parent, { withFileTypes: true })) {
74
+ if (!entry.isDirectory()) continue;
75
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
76
+ if (!seen.has(entry.name)) seen.set(entry.name, {
77
+ name: entry.name,
78
+ dir: join(parent, entry.name)
79
+ });
80
+ }
81
+ return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
82
+ }
83
+ /** The directory of the app called `name`, or undefined when no repo has it. */
84
+ function findApp(name, layout = resolveLayout()) {
85
+ return listApps(layout).find((app) => app.name === name)?.dir;
86
+ }
87
+ /**
88
+ * Resolves a workspace-relative path such as `workers.json`'s
89
+ * `apps/schedule-builder` to a directory: the repo you are in first, then
90
+ * DevDogsUGA's. When neither has it the first candidate is returned, so
91
+ * callers get an ordinary ENOENT naming the path rather than a second error.
92
+ */
93
+ function resolveAppPath(relative, layout = resolveLayout()) {
94
+ const first = join(layout.root, relative);
95
+ if (existsSync(first)) return first;
96
+ if (layout.kind === "backstage" && layout.hasDevdogsuga) {
97
+ const second = join(layout.devdogsugaRoot, relative);
98
+ if (existsSync(second)) return second;
99
+ }
100
+ return first;
101
+ }
102
+ /**
103
+ * The pnpm workspace root holding the app called `name`: where
104
+ * `pnpm --filter <name>` has to run. DevDogsUGA's root for its apps seen from a
105
+ * Backstage checkout, `layout.root` otherwise.
106
+ */
107
+ function appWorkspaceRoot(name, layout = resolveLayout()) {
108
+ const dir = findApp(name, layout);
109
+ return dir === void 0 ? layout.root : dirname(dirname(dir));
110
+ }
111
+ //#endregion
6
112
  //#region ../cli-core/src/repo/resolve.ts
7
113
  /**
8
114
  * Resolves an `@devdogsuga/*` package FROM the target repo, not from
@@ -199,6 +305,25 @@ function loadPeer(specifier) {
199
305
  function repoPeerUrl(specifier) {
200
306
  return resolvedUrls.get(specifier);
201
307
  }
308
+ /**
309
+ * Like `repoPeerUrl`, but for any specifier a package of the repo you are in
310
+ * can resolve, subpaths included (`@devdogsuga/env/nextjs`), without having
311
+ * loaded it. Undefined outside a real repo or when nothing depends on it.
312
+ */
313
+ function resolveRepoPeerUrl(specifier) {
314
+ const known = resolvedUrls.get(specifier);
315
+ if (known) return known;
316
+ if (process.env.DEVTOOLS_TEST_REPO_ROOT) return void 0;
317
+ try {
318
+ const repoRoot = findRepoRoot();
319
+ const base = findDependent(repoRoot, specifier);
320
+ if (!base) return void 0;
321
+ const { resolvedPath } = resolveFromRepo(repoRoot, base, specifier);
322
+ return pathToFileURL(resolvedPath).href;
323
+ } catch {
324
+ return;
325
+ }
326
+ }
202
327
  let resolvedEnvModule;
203
328
  function loadEnv() {
204
329
  return loadPeer("@devdogsuga/env").then((mod) => {
@@ -226,4 +351,4 @@ function loadEnvSession() {
226
351
  return loadPeer("@devdogsuga/env/session");
227
352
  }
228
353
  //#endregion
229
- export { repoPeerUrl as a, loadEnvSession as i, loadEnv as n, loadEnvLoad as r, getEnvSync as t };
354
+ export { repoPeerUrl as a, devdogsugaRootOrNull as c, listApps as d, resolveAppPath as f, loadEnvSession as i, findApp as l, loadEnv as n, resolveRepoPeerUrl as o, resolveLayout as p, loadEnvLoad as r, appWorkspaceRoot as s, getEnvSync as t, layoutAt as u };
@@ -38,13 +38,17 @@ function ownVersion() {
38
38
  * marker validated in the `devtools-dlx` prototype
39
39
  * (`/home/sloan/scratchpad/devdogs/prototypes/devtools-dlx/FINDINGS.md`,
40
40
  * experiment 1): a directory containing `pnpm-workspace.yaml` AND whose
41
- * `package.json` has `"name": "devdogs-monorepo"`. The name check is not
42
- * redundant — a bare `pnpm-workspace.yaml` also matches a Backstage
43
- * checkout (a separate pnpm workspace), which devtools should refuse
44
- * rather than silently "find".
41
+ * `package.json` has `"name": "devdogs-monorepo"` (DevDogsUGA) or
42
+ * `"backstage"` (Backstage, which the CLIs also run from; `layout.ts` says
43
+ * what differs). The name check is not redundant — a bare
44
+ * `pnpm-workspace.yaml` matches any pnpm workspace, which devtools should
45
+ * refuse rather than silently "find".
45
46
  */
46
- /** The `package.json` name every real DevDogsUGA checkout carries at its root. */
47
- const REPO_MARKER_NAME = "devdogs-monorepo";
47
+ /**
48
+ * The `package.json` names a repo root may carry: DevDogsUGA's, and Backstage's
49
+ * (the CLIs run from both; see `layout.ts`).
50
+ */
51
+ const REPO_MARKER_NAMES = ["devdogs-monorepo", "backstage"];
48
52
  var RepoNotFoundError = class extends Error {
49
53
  constructor() {
50
54
  super("run this from inside a DevDogsUGA clone");
@@ -54,7 +58,8 @@ var RepoNotFoundError = class extends Error {
54
58
  function looksLikeRepoRoot(dir) {
55
59
  if (!existsSync(join(dir, "pnpm-workspace.yaml"))) return false;
56
60
  try {
57
- return JSON.parse(readFileSync(join(dir, "package.json"), "utf8")).name === REPO_MARKER_NAME;
61
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
62
+ return REPO_MARKER_NAMES.includes(pkg.name);
58
63
  } catch {
59
64
  return false;
60
65
  }
@@ -1,6 +1,5 @@
1
- import { a as listContainerNames, d as seedBuckets, f as supabase, i as foreignStackProjectId, o as readProjectId, p as supabaseCapture, r as foreignStackMessage, t as STACK_API_PORT, v as isDryRun } from "./supabase-project-Bw8sBFcE.js";
2
- import { r as findRepoRoot } from "./root-C2OmZDwD.js";
3
- import { i as loadEnvSession, r as loadEnvLoad } from "./peers-RBplwovA.js";
1
+ import { a as listContainerNames, d as seedBuckets, f as supabase, i as foreignStackProjectId, o as readProjectId, p as supabaseCapture, r as foreignStackMessage, t as STACK_API_PORT, y as isDryRun } from "./supabase-project-C93xRFkN.js";
2
+ import { i as loadEnvSession, p as resolveLayout, r as loadEnvLoad } from "./peers-DvUH5VxX.js";
4
3
  import { writeFile } from "node:fs/promises";
5
4
  import { join } from "node:path";
6
5
  //#region src/db/session-refresh.ts
@@ -52,7 +51,7 @@ async function refreshSessionEnv(opts = {}) {
52
51
  function foreignStackHint() {
53
52
  const names = listContainerNames(STACK_API_PORT);
54
53
  if (names === null) return void 0;
55
- const foreign = foreignStackProjectId(names, readProjectId(findRepoRoot()));
54
+ const foreign = foreignStackProjectId(names, readProjectId(resolveLayout().devdogsugaRoot));
56
55
  return foreign === null ? void 0 : foreignStackMessage(foreign);
57
56
  }
58
57
  /**
@@ -101,7 +100,8 @@ async function startLocalStack() {
101
100
  wroteEnvFile: false
102
101
  };
103
102
  }
104
- await writeFile(join(findRepoRoot(), ".env.generated"), env);
103
+ const layout = resolveLayout();
104
+ for (const dir of [layout.root, ...layout.envMirrors]) await writeFile(join(dir, ".env.generated"), env);
105
105
  return {
106
106
  code: await seedBuckets({ kind: "local" }),
107
107
  wroteEnvFile: true
@@ -0,0 +1,2 @@
1
+ import { t as runStackCommand } from "./stack-C_50FafG.js";
2
+ export { runStackCommand };
@@ -1,5 +1,6 @@
1
- import { a as cliName, r as noteRan } from "./failure-log-B5GG_8T1.js";
2
- import { r as findRepoRoot } from "./root-C2OmZDwD.js";
1
+ import { a as cliName, r as noteRan } from "./failure-log-DOt6E3hS.js";
2
+ import { r as findRepoRoot } from "./root-CjPWNkBu.js";
3
+ import { p as resolveLayout } from "./peers-DvUH5VxX.js";
3
4
  import { readFileSync } from "node:fs";
4
5
  import { join } from "node:path";
5
6
  import { execFile, execFileSync, spawn } from "node:child_process";
@@ -190,20 +191,27 @@ function reportRan(command, args, result) {
190
191
  //#endregion
191
192
  //#region ../cli-core/src/db/run.ts
192
193
  /**
193
- * Shared helpers for running supabase CLI and pnpm commands from the repo root.
194
+ * Shared helpers for running supabase CLI and pnpm commands.
194
195
  *
195
196
  * The supabase CLI is a workspace devDependency (not a global install), so
196
- * every invocation goes through `pnpm exec supabase`. The cwd is always
197
- * findRepoRoot(), where `supabase/config.toml` lives.
197
+ * every invocation goes through `pnpm exec supabase`. Plain pnpm commands run
198
+ * in `findRepoRoot()`; the supabase ones run in DevDogsUGA's root
199
+ * (`supabaseRoot()`), where `supabase/config.toml` lives and where the CLI is
200
+ * installed. From a Backstage checkout that is `<root>/devdogsuga`, so it needs
201
+ * its own `pnpm install` there before any of these work.
198
202
  */
199
203
  const runFile = promisify(execFile);
204
+ /** Where `supabase/` lives, and so the cwd of every supabase CLI call. */
205
+ function supabaseRoot() {
206
+ return resolveLayout().devdogsugaRoot;
207
+ }
200
208
  /** Spawn a pnpm command with inherited stdio; resolves to the exit code. Pass
201
209
  * `env` to run the child against a loaded tier rather than process.env. The
202
210
  * child runs in its own process group, so stopping this process stops
203
211
  * whatever it started (see `process-group.ts`). */
204
- async function run(args, env) {
212
+ async function run(args, env, cwd = findRepoRoot()) {
205
213
  const result = await runInGroup("pnpm", args, {
206
- cwd: findRepoRoot(),
214
+ cwd,
207
215
  ...env ? { env } : {}
208
216
  });
209
217
  if (reporting) reportRan("pnpm", args, result);
@@ -221,7 +229,7 @@ function reportRuns(enabled) {
221
229
  }
222
230
  /** Spawn a pnpm command while echoing and retaining stderr for diagnostics.
223
231
  * Pass `env` to run the child against a loaded tier rather than process.env. */
224
- function runWithStderr(args, env) {
232
+ function runWithStderr(args, env, cwd = findRepoRoot()) {
225
233
  return new Promise((resolve) => {
226
234
  const child = spawn("pnpm", args, {
227
235
  stdio: [
@@ -229,7 +237,7 @@ function runWithStderr(args, env) {
229
237
  "inherit",
230
238
  "pipe"
231
239
  ],
232
- cwd: findRepoRoot(),
240
+ cwd,
233
241
  ...env ? { env } : {}
234
242
  });
235
243
  let stderr = "";
@@ -254,9 +262,9 @@ function runWithStderr(args, env) {
254
262
  });
255
263
  }
256
264
  /** Spawn a pnpm command, capture stdout, throw on non-zero exit. */
257
- async function capture(args) {
265
+ async function capture(args, cwd = findRepoRoot()) {
258
266
  const { stdout } = await runFile("pnpm", args, {
259
- cwd: findRepoRoot(),
267
+ cwd,
260
268
  encoding: "utf8"
261
269
  });
262
270
  return stdout;
@@ -266,13 +274,13 @@ const supabase = (...args) => run([
266
274
  "exec",
267
275
  "supabase",
268
276
  ...args
269
- ]);
277
+ ], void 0, supabaseRoot());
270
278
  /** `pnpm exec supabase …` with captured stdout. */
271
279
  const supabaseCapture = (...args) => capture([
272
280
  "exec",
273
281
  "supabase",
274
282
  ...args
275
- ]);
283
+ ], supabaseRoot());
276
284
  /**
277
285
  * `supabase db push` over `dbUrl`, inherited stdio, resolving to the exit code.
278
286
  *
@@ -425,4 +433,4 @@ function foreignStackMessage(foreignProjectId) {
425
433
  return `The stack on port ${STACK_API_PORT} belongs to project "${foreignProjectId}", not this checkout's. Stop it with \`supabase stop --project-id ${foreignProjectId}\` then \`pnpm devtools supabase start\`.`;
426
434
  }
427
435
  //#endregion
428
- export { dryRunKind as _, listContainerNames as a, setDryRun as b, reportRuns as c, seedBuckets as d, supabase as f, runInGroup as g, reportRan as h, foreignStackProjectId as i, run as l, formatCommand as m, containerPrefix as n, readProjectId as o, supabaseCapture as p, foreignStackMessage as r, dbPush as s, STACK_API_PORT as t, runWithStderr as u, isDryRun as v, wouldRunLine as x, resolveDryRun as y };
436
+ export { wouldRunLine as S, runInGroup as _, listContainerNames as a, resolveDryRun as b, reportRuns as c, seedBuckets as d, supabase as f, reportRan as g, formatCommand as h, foreignStackProjectId as i, run as l, supabaseRoot as m, containerPrefix as n, readProjectId as o, supabaseCapture as p, foreignStackMessage as r, dbPush as s, STACK_API_PORT as t, runWithStderr as u, dryRunKind as v, setDryRun as x, isDryRun as y };