@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.
- package/README.md +18 -0
- package/dist/{cli-CeCAuSJd.js → cli-B_AiECh4.js} +190 -90
- package/dist/{failure-log-B5GG_8T1.js → failure-log-DOt6E3hS.js} +1 -1
- package/dist/launch.js +8 -8
- package/dist/{local-env-hH4encfD.js → local-env-BuHU5Ckd.js} +84 -23
- package/dist/local-env-MqH18s-N.js +2 -0
- package/dist/{menu-Craj11Sn.js → menu-DYQ-Dd-O.js} +15 -11
- package/dist/{peers-RBplwovA.js → peers-DvUH5VxX.js} +128 -3
- package/dist/{root-C2OmZDwD.js → root-CjPWNkBu.js} +12 -7
- package/dist/{stack-7PuRcaI2.js → stack-C_50FafG.js} +5 -5
- package/dist/stack-o1Kml3V0.js +2 -0
- package/dist/{supabase-project-Bw8sBFcE.js → supabase-project-C93xRFkN.js} +22 -14
- package/dist/{telemetry-Do13RFhc.js → telemetry-C07-ioHm.js} +139 -3
- package/dist/telemetry.js +1 -1
- package/env.ts +1 -1
- package/package.json +6 -5
- package/dist/local-env-CR3McKHZ.js +0 -2
- package/dist/stack-B5UHASY2.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as ownPackageDir
|
|
2
|
-
import { a as repoPeerUrl, n as loadEnv, t as getEnvSync } from "./peers-
|
|
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
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
function
|
|
29
|
-
register("./peer-redirect-hooks.js", import.meta.url, { data:
|
|
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
|
-
*
|
|
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)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
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
|
|
221
|
-
for (const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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(
|
|
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. */
|
|
@@ -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-
|
|
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-
|
|
3
|
-
import { r as findRepoRoot } from "./root-
|
|
4
|
-
import { n as loadEnv, r as loadEnvLoad } from "./peers-
|
|
5
|
-
import { c as reportDevtoolsError, f as isNonInteractive } from "./telemetry-
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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-
|
|
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"
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
-
/**
|
|
47
|
-
|
|
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
|
-
|
|
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,
|
|
2
|
-
import { r as
|
|
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(
|
|
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
|
-
|
|
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
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { a as cliName, r as noteRan } from "./failure-log-
|
|
2
|
-
import { r as findRepoRoot } from "./root-
|
|
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
|
|
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`.
|
|
197
|
-
* findRepoRoot()
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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 };
|