@devdogsuga/devtools 0.1.26 → 0.1.28

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.
Files changed (271) hide show
  1. package/README.md +72 -11
  2. package/bin/devtools.mjs +4 -4
  3. package/dist/cli-CZKkNHK5.js +6619 -0
  4. package/dist/failure-log-BBPGejQv.js +256 -0
  5. package/dist/launch.js +267 -281
  6. package/dist/local-env-D8HC2JK_.js +351 -0
  7. package/dist/local-env-DrBCXqD8.js +2 -0
  8. package/dist/menu-CQBsQRgH.js +1684 -0
  9. package/dist/peer-redirect-hooks.js +15 -0
  10. package/dist/peers-RBplwovA.js +229 -0
  11. package/dist/root-C2OmZDwD.js +94 -0
  12. package/dist/stack-Bx-55oi_.js +2 -0
  13. package/dist/stack-BynCgRVS.js +181 -0
  14. package/dist/supabase-project-0knM0mqd.js +426 -0
  15. package/dist/telemetry-C4foD8MD.js +249 -0
  16. package/dist/telemetry.js +2 -148
  17. package/package.json +10 -29
  18. package/bin/devtools-ci-bare.mjs +0 -48
  19. package/bin/devtools-ci.mjs +0 -31
  20. package/dist/args.d.ts +0 -26
  21. package/dist/args.js +0 -78
  22. package/dist/bws/bw.d.ts +0 -18
  23. package/dist/bws/bw.js +0 -70
  24. package/dist/bws/client.d.ts +0 -43
  25. package/dist/bws/client.js +0 -363
  26. package/dist/bws/environments.d.ts +0 -96
  27. package/dist/bws/environments.js +0 -111
  28. package/dist/bws/pace.d.ts +0 -25
  29. package/dist/bws/pace.js +0 -43
  30. package/dist/bws/retry.d.ts +0 -12
  31. package/dist/bws/retry.js +0 -39
  32. package/dist/bws/store.d.ts +0 -1
  33. package/dist/bws/store.js +0 -32
  34. package/dist/bws/token.d.ts +0 -31
  35. package/dist/bws/token.js +0 -88
  36. package/dist/bws/vault.d.ts +0 -29
  37. package/dist/bws/vault.js +0 -200
  38. package/dist/catalog.d.ts +0 -57
  39. package/dist/catalog.js +0 -57
  40. package/dist/cf/build.d.ts +0 -13
  41. package/dist/cf/build.js +0 -65
  42. package/dist/cf/commands.d.ts +0 -1
  43. package/dist/cf/commands.js +0 -172
  44. package/dist/cf/local-env.d.ts +0 -58
  45. package/dist/cf/local-env.js +0 -177
  46. package/dist/ci.d.ts +0 -1
  47. package/dist/ci.js +0 -328
  48. package/dist/cli.d.ts +0 -11
  49. package/dist/cli.js +0 -1094
  50. package/dist/commands.d.ts +0 -261
  51. package/dist/commands.js +0 -1318
  52. package/dist/completions.d.ts +0 -4
  53. package/dist/completions.js +0 -110
  54. package/dist/cron/commands.d.ts +0 -47
  55. package/dist/cron/commands.js +0 -372
  56. package/dist/cron/discovery.d.ts +0 -55
  57. package/dist/cron/discovery.js +0 -85
  58. package/dist/cron/schema.d.ts +0 -45
  59. package/dist/cron/schema.js +0 -35
  60. package/dist/db/config-push.d.ts +0 -8
  61. package/dist/db/config-push.js +0 -11
  62. package/dist/db/connection.d.ts +0 -79
  63. package/dist/db/connection.js +0 -114
  64. package/dist/db/exec.d.ts +0 -1
  65. package/dist/db/exec.js +0 -11
  66. package/dist/db/generate-types.d.ts +0 -1
  67. package/dist/db/generate-types.js +0 -4
  68. package/dist/db/generated-env.d.ts +0 -69
  69. package/dist/db/generated-env.js +0 -113
  70. package/dist/db/introspect.d.ts +0 -1
  71. package/dist/db/introspect.js +0 -122
  72. package/dist/db/local-env.d.ts +0 -65
  73. package/dist/db/local-env.js +0 -23
  74. package/dist/db/new-migration.d.ts +0 -8
  75. package/dist/db/new-migration.js +0 -69
  76. package/dist/db/pooler.d.ts +0 -23
  77. package/dist/db/pooler.js +0 -55
  78. package/dist/db/run.d.ts +0 -68
  79. package/dist/db/run.js +0 -156
  80. package/dist/db/seed-buckets.d.ts +0 -2
  81. package/dist/db/seed-buckets.js +0 -4
  82. package/dist/db/seed-production.d.ts +0 -8
  83. package/dist/db/seed-production.js +0 -79
  84. package/dist/db/seed-roles.d.ts +0 -7
  85. package/dist/db/seed-roles.js +0 -33
  86. package/dist/db/session-refresh.d.ts +0 -43
  87. package/dist/db/session-refresh.js +0 -40
  88. package/dist/deploy/migrations.d.ts +0 -20
  89. package/dist/deploy/migrations.js +0 -68
  90. package/dist/deploy/orphans.d.ts +0 -20
  91. package/dist/deploy/orphans.js +0 -177
  92. package/dist/deploy/preflight.d.ts +0 -53
  93. package/dist/deploy/preflight.js +0 -189
  94. package/dist/deploy/report.d.ts +0 -26
  95. package/dist/deploy/report.js +0 -70
  96. package/dist/deploy/require-planner.d.ts +0 -2
  97. package/dist/deploy/require-planner.js +0 -60
  98. package/dist/deploy/require-token.d.ts +0 -15
  99. package/dist/deploy/require-token.js +0 -78
  100. package/dist/deploy/secrets-file.d.ts +0 -17
  101. package/dist/deploy/secrets-file.js +0 -166
  102. package/dist/deploy/write-env.d.ts +0 -40
  103. package/dist/deploy/write-env.js +0 -395
  104. package/dist/docs/index-pages.d.ts +0 -38
  105. package/dist/docs/index-pages.js +0 -186
  106. package/dist/emails/commands.d.ts +0 -15
  107. package/dist/emails/commands.js +0 -130
  108. package/dist/emails/email-types.d.ts +0 -13
  109. package/dist/emails/email-types.js +0 -1
  110. package/dist/emails/fixtures.d.ts +0 -20
  111. package/dist/emails/fixtures.js +0 -20
  112. package/dist/env/audit.d.ts +0 -206
  113. package/dist/env/audit.js +0 -436
  114. package/dist/env/cloudflare.d.ts +0 -21
  115. package/dist/env/cloudflare.js +0 -61
  116. package/dist/env/commands.d.ts +0 -99
  117. package/dist/env/commands.js +0 -613
  118. package/dist/env/discovery.d.ts +0 -15
  119. package/dist/env/discovery.js +0 -239
  120. package/dist/env/document.d.ts +0 -119
  121. package/dist/env/document.js +0 -323
  122. package/dist/env/example.d.ts +0 -68
  123. package/dist/env/example.js +0 -605
  124. package/dist/env/selection.d.ts +0 -105
  125. package/dist/env/selection.js +0 -228
  126. package/dist/env-entry.d.ts +0 -49
  127. package/dist/env-entry.js +0 -204
  128. package/dist/environment-doctor.d.ts +0 -45
  129. package/dist/environment-doctor.js +0 -429
  130. package/dist/environment.d.ts +0 -92
  131. package/dist/environment.js +0 -185
  132. package/dist/fingerprint.d.ts +0 -10
  133. package/dist/fingerprint.js +0 -18
  134. package/dist/gen/campus-map.d.ts +0 -1
  135. package/dist/gen/campus-map.js +0 -473
  136. package/dist/gen/commands.d.ts +0 -1
  137. package/dist/gen/commands.js +0 -25
  138. package/dist/gen/hypno.d.ts +0 -1
  139. package/dist/gen/hypno.js +0 -134
  140. package/dist/gh/client.d.ts +0 -80
  141. package/dist/gh/client.js +0 -259
  142. package/dist/gh/environments.d.ts +0 -83
  143. package/dist/gh/environments.js +0 -178
  144. package/dist/gh/rulesets/actors.d.ts +0 -14
  145. package/dist/gh/rulesets/actors.js +0 -69
  146. package/dist/gh/rulesets/api.d.ts +0 -15
  147. package/dist/gh/rulesets/api.js +0 -104
  148. package/dist/gh/rulesets/commands.d.ts +0 -3
  149. package/dist/gh/rulesets/commands.js +0 -203
  150. package/dist/gh/rulesets/desired.d.ts +0 -112
  151. package/dist/gh/rulesets/desired.js +0 -271
  152. package/dist/gh/rulesets/diff.d.ts +0 -65
  153. package/dist/gh/rulesets/diff.js +0 -170
  154. package/dist/gh/rulesets/types.d.ts +0 -76
  155. package/dist/gh/rulesets/types.js +0 -13
  156. package/dist/gh/settings/api.d.ts +0 -40
  157. package/dist/gh/settings/api.js +0 -180
  158. package/dist/gh/settings/commands.d.ts +0 -1
  159. package/dist/gh/settings/commands.js +0 -254
  160. package/dist/gh/settings/desired.d.ts +0 -53
  161. package/dist/gh/settings/desired.js +0 -43
  162. package/dist/gh/settings/diff.d.ts +0 -57
  163. package/dist/gh/settings/diff.js +0 -161
  164. package/dist/gh/settings/types.d.ts +0 -92
  165. package/dist/gh/settings/types.js +0 -11
  166. package/dist/gh/settings/workflows.d.ts +0 -41
  167. package/dist/gh/settings/workflows.js +0 -128
  168. package/dist/grantRoot.d.ts +0 -42
  169. package/dist/grantRoot.js +0 -89
  170. package/dist/help.d.ts +0 -18
  171. package/dist/help.js +0 -169
  172. package/dist/images/commands.d.ts +0 -32
  173. package/dist/images/commands.js +0 -231
  174. package/dist/images/events.d.ts +0 -47
  175. package/dist/images/events.js +0 -116
  176. package/dist/images/graphics.d.ts +0 -70
  177. package/dist/images/graphics.js +0 -234
  178. package/dist/images/open-graph-types.d.ts +0 -75
  179. package/dist/images/open-graph-types.js +0 -1
  180. package/dist/images/prompts.d.ts +0 -34
  181. package/dist/images/prompts.js +0 -100
  182. package/dist/images/render.d.ts +0 -21
  183. package/dist/images/render.js +0 -61
  184. package/dist/images/select.d.ts +0 -64
  185. package/dist/images/select.js +0 -96
  186. package/dist/instance.d.ts +0 -69
  187. package/dist/instance.js +0 -102
  188. package/dist/invocation.d.ts +0 -49
  189. package/dist/invocation.js +0 -78
  190. package/dist/launch-ci.d.ts +0 -1
  191. package/dist/launch-ci.js +0 -90
  192. package/dist/launch.d.ts +0 -18
  193. package/dist/menu.d.ts +0 -43
  194. package/dist/menu.js +0 -300
  195. package/dist/moderation.d.ts +0 -70
  196. package/dist/moderation.js +0 -128
  197. package/dist/oauth/browser.d.ts +0 -1
  198. package/dist/oauth/browser.js +0 -13
  199. package/dist/oauth/config.d.ts +0 -24
  200. package/dist/oauth/config.js +0 -24
  201. package/dist/oauth/connect-url.d.ts +0 -17
  202. package/dist/oauth/connect-url.js +0 -23
  203. package/dist/oauth/db.d.ts +0 -37
  204. package/dist/oauth/db.js +0 -108
  205. package/dist/oauth/device.d.ts +0 -93
  206. package/dist/oauth/device.js +0 -198
  207. package/dist/oauth/discovery.d.ts +0 -28
  208. package/dist/oauth/discovery.js +0 -54
  209. package/dist/oauth/env-file.d.ts +0 -6
  210. package/dist/oauth/env-file.js +0 -35
  211. package/dist/oauth/exchange.d.ts +0 -43
  212. package/dist/oauth/exchange.js +0 -93
  213. package/dist/oauth/label.d.ts +0 -1
  214. package/dist/oauth/label.js +0 -25
  215. package/dist/oauth/loopback.d.ts +0 -52
  216. package/dist/oauth/loopback.js +0 -168
  217. package/dist/oauth/pkce.d.ts +0 -6
  218. package/dist/oauth/pkce.js +0 -34
  219. package/dist/oauth/target.d.ts +0 -54
  220. package/dist/oauth/target.js +0 -102
  221. package/dist/oauth/transport.d.ts +0 -41
  222. package/dist/oauth/transport.js +0 -32
  223. package/dist/oauth/wizard.d.ts +0 -40
  224. package/dist/oauth/wizard.js +0 -578
  225. package/dist/persona.d.ts +0 -18
  226. package/dist/persona.js +0 -221
  227. package/dist/pick.d.ts +0 -6
  228. package/dist/pick.js +0 -64
  229. package/dist/pipes.d.ts +0 -1
  230. package/dist/pipes.js +0 -25
  231. package/dist/planner/checks.d.ts +0 -26
  232. package/dist/planner/checks.js +0 -104
  233. package/dist/planner/commands.d.ts +0 -10
  234. package/dist/planner/commands.js +0 -367
  235. package/dist/planner/db.d.ts +0 -15
  236. package/dist/planner/db.js +0 -33
  237. package/dist/planner/role.d.ts +0 -33
  238. package/dist/planner/role.js +0 -68
  239. package/dist/repo/peer-redirect-hooks.d.ts +0 -16
  240. package/dist/repo/peer-redirect-hooks.js +0 -10
  241. package/dist/repo/peer-redirect.d.ts +0 -4
  242. package/dist/repo/peer-redirect.js +0 -26
  243. package/dist/repo/peers.d.ts +0 -39
  244. package/dist/repo/peers.js +0 -139
  245. package/dist/repo/resolve.d.ts +0 -41
  246. package/dist/repo/resolve.js +0 -152
  247. package/dist/repo/root.d.ts +0 -23
  248. package/dist/repo/root.js +0 -91
  249. package/dist/repo/source.d.ts +0 -14
  250. package/dist/repo/source.js +0 -54
  251. package/dist/repo/supabase-project.d.ts +0 -60
  252. package/dist/repo/supabase-project.js +0 -124
  253. package/dist/repo/tsx-loader.d.ts +0 -6
  254. package/dist/repo/tsx-loader.js +0 -41
  255. package/dist/run/pick.d.ts +0 -90
  256. package/dist/run/pick.js +0 -664
  257. package/dist/setup.d.ts +0 -1
  258. package/dist/setup.js +0 -280
  259. package/dist/stack.d.ts +0 -48
  260. package/dist/stack.js +0 -403
  261. package/dist/telemetry.d.ts +0 -59
  262. package/dist/tier.d.ts +0 -40
  263. package/dist/tier.js +0 -96
  264. package/dist/ui.d.ts +0 -40
  265. package/dist/ui.js +0 -71
  266. package/dist/version.d.ts +0 -7
  267. package/dist/version.js +0 -17
  268. package/dist/workers.d.ts +0 -5
  269. package/dist/workers.js +0 -33
  270. package/dist/workflows/commands.d.ts +0 -54
  271. package/dist/workflows/commands.js +0 -763
@@ -0,0 +1,15 @@
1
+ //#region ../cli-core/src/repo/peer-redirect-hooks.ts
2
+ let redirects = [];
3
+ const initialize = (data) => {
4
+ redirects = data;
5
+ };
6
+ const resolve = (specifier, context, nextResolve) => {
7
+ const redirect = redirects.find((r) => r.specifier === specifier && r.parentURL === context.parentURL);
8
+ if (redirect) return {
9
+ url: redirect.url,
10
+ shortCircuit: true
11
+ };
12
+ return nextResolve(specifier, context);
13
+ };
14
+ //#endregion
15
+ export { initialize, resolve };
@@ -0,0 +1,229 @@
1
+ import { r as findRepoRoot, t as RepoNotFoundError } from "./root-C2OmZDwD.js";
2
+ import { createRequire } from "node:module";
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ //#region ../cli-core/src/repo/resolve.ts
7
+ /**
8
+ * Resolves an `@devdogsuga/*` package FROM the target repo, not from
9
+ * devtools' own (dlx-isolated) `node_modules`.
10
+ *
11
+ * Ported from the `devtools-dlx` prototype
12
+ * (`/home/sloan/scratchpad/devdogs/prototypes/devtools-dlx/FINDINGS.md`,
13
+ * experiments 2 and 4 — read that file for the two gotchas this module
14
+ * exists to avoid). The short version:
15
+ *
16
+ * - `require.resolve(\`${specifier}/package.json\`)` throws
17
+ * `ERR_PACKAGE_PATH_NOT_EXPORTED` on packages (like `@devdogsuga/env`,
18
+ * `@devdogsuga/open-graph`) whose `exports` map does not list
19
+ * `"./package.json"`, even though the file is on disk.
20
+ * - A resolved path cannot be assumed to contain a literal
21
+ * `node_modules/<specifier>` segment — pnpm workspace-linked packages
22
+ * resolve to their REALPATH (e.g. `packages/open-graph/dist/index.js`),
23
+ * which has no such segment at all.
24
+ * - `require.resolve` ignores whatever `conditions` a caller has set on
25
+ * `tsx`'s `register()` — condition-based resolution (the
26
+ * `devdogs-source` condition) has to be done by hand, reading the
27
+ * target package's own `exports["."]` map.
28
+ *
29
+ * Both problems are solved the same way: walk up from the resolved file's
30
+ * directory to the nearest `package.json` whose own `"name"` field matches
31
+ * the specifier. That works for a real installed dependency AND a
32
+ * workspace symlink, uniformly.
33
+ */
34
+ /**
35
+ * The installable package name a (possibly subpath) specifier belongs to:
36
+ * `@devdogsuga/env/load` → `@devdogsuga/env`, `foo/bar` → `foo`. A repo's
37
+ * package.json declares the PACKAGE as a dependency, never a subpath, so
38
+ * `findDependent` has to search on this rather than the literal specifier a
39
+ * caller wants to import.
40
+ */
41
+ function packageNameOf(specifier) {
42
+ const parts = specifier.split("/");
43
+ return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
44
+ }
45
+ /**
46
+ * Scans `apps/*` and `packages/*` under `repoRoot` for the first
47
+ * `package.json` whose `dependencies`/`devDependencies`/`peerDependencies`
48
+ * names `specifier`'s package (see `packageNameOf`). Returns its path
49
+ * relative to `repoRoot`, or `null` if nothing in the repo depends on it.
50
+ *
51
+ * Re-scans the filesystem on every call — fine for a short-lived CLI
52
+ * invocation calling this a handful of times; see FINDINGS item 5 if this
53
+ * is ever called in a hot loop.
54
+ */
55
+ function findDependent(repoRoot, specifier) {
56
+ const packageName = packageNameOf(specifier);
57
+ for (const group of ["apps", "packages"]) {
58
+ const groupDir = join(repoRoot, group);
59
+ let entries;
60
+ try {
61
+ entries = readdirSync(groupDir);
62
+ } catch {
63
+ continue;
64
+ }
65
+ for (const entry of entries) {
66
+ const pkgJsonPath = join(groupDir, entry, "package.json");
67
+ if (!existsSync(pkgJsonPath)) continue;
68
+ let pkg;
69
+ try {
70
+ pkg = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
71
+ } catch {
72
+ continue;
73
+ }
74
+ if (packageName in {
75
+ ...pkg.dependencies,
76
+ ...pkg.devDependencies,
77
+ ...pkg.peerDependencies
78
+ }) return join(group, entry, "package.json");
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ /** Walks up from `startDir` to the nearest `package.json` whose `"name"` matches `specifier`. */
84
+ function findOwningPackageJson(startDir, specifier) {
85
+ const packageName = packageNameOf(specifier);
86
+ let dir = startDir;
87
+ for (;;) {
88
+ const candidate = join(dir, "package.json");
89
+ if (existsSync(candidate)) try {
90
+ if (JSON.parse(readFileSync(candidate, "utf8")).name === packageName) return candidate;
91
+ } catch {}
92
+ const parent = dirname(dir);
93
+ if (parent === dir) throw new Error(`resolveFromRepo: could not find ${specifier}'s own package.json by walking up from ${startDir}`);
94
+ dir = parent;
95
+ }
96
+ }
97
+ /**
98
+ * Resolves `specifier` as `resolutionBase` (a workspace-relative
99
+ * `package.json` path known to depend on it, from `findDependent()`) would
100
+ * see it.
101
+ *
102
+ * `opts.condition`, when given, is NOT passed through to Node's resolver —
103
+ * `require.resolve` ignores tsx's `register({ conditions })` entirely (see
104
+ * this module's header). Instead the target package's own
105
+ * `exports["."]` map is read directly and `exports["."][condition]` is
106
+ * picked, falling back to `.default`.
107
+ */
108
+ function resolveFromRepo(repoRoot, resolutionBase, specifier, opts) {
109
+ const baseFile = join(repoRoot, resolutionBase);
110
+ const require = createRequire(baseFile);
111
+ let resolvedPath;
112
+ if (opts?.condition) {
113
+ const defaultEntry = require.resolve(specifier);
114
+ const pkgJsonPath = findOwningPackageJson(dirname(defaultEntry), specifier);
115
+ const rootExport = JSON.parse(readFileSync(pkgJsonPath, "utf8")).exports?.["."];
116
+ const conditioned = rootExport && typeof rootExport === "object" ? rootExport[opts.condition] ?? rootExport.default : void 0;
117
+ if (typeof conditioned !== "string") throw new Error(`resolveFromRepo: ${specifier} has no "${opts.condition}" (or "default") export in its exports["."] map`);
118
+ resolvedPath = join(dirname(pkgJsonPath), conditioned);
119
+ } else resolvedPath = require.resolve(specifier);
120
+ const pkgJsonPath = findOwningPackageJson(dirname(resolvedPath), specifier);
121
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
122
+ return {
123
+ resolvedPath,
124
+ version: pkg.version ?? "0.0.0",
125
+ pkgJsonPath
126
+ };
127
+ }
128
+ //#endregion
129
+ //#region ../cli-core/src/repo/peers.ts
130
+ /**
131
+ * Loads devtools' optional-peer `@devdogsuga/*` libraries — the ones
132
+ * published to npm and consumed by the TARGET repo, which devtools reads at
133
+ * runtime rather than bundling its own copy of (see this package's
134
+ * `package.json`: `peerDependencies` + `peerDependenciesMeta.optional`, and
135
+ * `FINDINGS.md` experiment 2).
136
+ *
137
+ * Every export here is memoized per module (one dynamic `import()` per
138
+ * process, not per call) — this is what makes the module-identity guarantee
139
+ * in FINDINGS experiment 3 hold: every devtools call site that needs
140
+ * `@devdogsuga/env`'s registry gets the exact same module instance the
141
+ * repo's own manifests populated via `declare()`/`define()`, because both
142
+ * resolve to the identical absolute file path and Node's ESM cache is keyed
143
+ * by resolved URL.
144
+ */
145
+ const moduleCache = /* @__PURE__ */ new Map();
146
+ /** The file URL each peer resolved to through the target repo, set only on
147
+ * that path (not on either plain bare-specifier fallback). See
148
+ * `repoPeerUrl()`. */
149
+ const resolvedUrls = /* @__PURE__ */ new Map();
150
+ /**
151
+ * Dynamically imports `specifier` as the repo would resolve it, memoized so
152
+ * repeated calls in one process return the SAME module instance (required
153
+ * for the env-registry identity guarantee above).
154
+ *
155
+ * Falls back to a plain bare-specifier `import()` when devtools is not
156
+ * running inside a DevDogsUGA checkout at all (`findRepoRoot()` throws
157
+ * `RepoNotFoundError`). That is not a production affordance — under real
158
+ * `pnpm dlx` use, `specifier` is an optional peer devtools' own package
159
+ * never installs, so the fallback import fails with the ordinary
160
+ * `MODULE_NOT_FOUND` either way. It exists so devtools' OWN test suite
161
+ * (which has no target repo to discover, but does have every one of these
162
+ * peers as a real Backstage workspace package) exercises this code against
163
+ * the genuine package rather than needing every test to mock this module.
164
+ */
165
+ function loadPeer(specifier) {
166
+ const cached = moduleCache.get(specifier);
167
+ if (cached) return cached;
168
+ const promise = (async () => {
169
+ if (process.env.DEVTOOLS_TEST_REPO_ROOT) return import(specifier);
170
+ let repoRoot;
171
+ try {
172
+ repoRoot = findRepoRoot();
173
+ } catch (err) {
174
+ if (err instanceof RepoNotFoundError) return import(specifier);
175
+ throw err;
176
+ }
177
+ const resolutionBase = findDependent(repoRoot, specifier);
178
+ if (!resolutionBase) throw new Error(`Nothing in this repo depends on ${specifier} — expected an app or package under apps/* or packages/* to declare it (dependencies/devDependencies/peerDependencies).`);
179
+ const { resolvedPath } = resolveFromRepo(repoRoot, resolutionBase, specifier);
180
+ const url = pathToFileURL(resolvedPath).href;
181
+ resolvedUrls.set(specifier, url);
182
+ return import(url);
183
+ })();
184
+ moduleCache.set(specifier, promise);
185
+ return promise;
186
+ }
187
+ /**
188
+ * The file URL `specifier` was loaded from through the target repo, or
189
+ * undefined if it has not been loaded yet or came from a plain bare-specifier
190
+ * `import()` (the test-suite and not-in-a-repo fallbacks above).
191
+ *
192
+ * For code devtools imports that itself names a peer by bare specifier --
193
+ * today only devtools' own `env.ts` manifest. From an installed copy that
194
+ * specifier cannot resolve at all (an optional peer is never installed next
195
+ * to devtools under `pnpm dlx`), and even where it can, the only copy that
196
+ * keeps module identity is this one. `repo/peer-redirect.ts` uses it to
197
+ * point the import here.
198
+ */
199
+ function repoPeerUrl(specifier) {
200
+ return resolvedUrls.get(specifier);
201
+ }
202
+ let resolvedEnvModule;
203
+ function loadEnv() {
204
+ return loadPeer("@devdogsuga/env").then((mod) => {
205
+ resolvedEnvModule = mod;
206
+ return mod;
207
+ });
208
+ }
209
+ /**
210
+ * The synchronous companion to `loadEnv()`, for the handful of call sites
211
+ * (`gh/environments.ts`'s `GITHUB_ENVIRONMENT_SPECS` getters) that cannot
212
+ * become async without changing their own callers' contract — they read a
213
+ * plain array off a getter, not a Promise. Safe ONLY after `loadEnv()` has
214
+ * resolved at least once; every caller of these getters already requires
215
+ * `env/discovery.ts`'s `loadRegistry()` (which calls `loadEnv()` itself) to
216
+ * have run first, via `assertRegistryLoaded()`'s own guard.
217
+ */
218
+ function getEnvSync() {
219
+ if (!resolvedEnvModule) throw new Error("getEnvSync() called before loadEnv() ever resolved — call loadRegistry() (env/discovery.ts) first.");
220
+ return resolvedEnvModule;
221
+ }
222
+ function loadEnvLoad() {
223
+ return loadPeer("@devdogsuga/env/load");
224
+ }
225
+ function loadEnvSession() {
226
+ return loadPeer("@devdogsuga/env/session");
227
+ }
228
+ //#endregion
229
+ export { repoPeerUrl as a, loadEnvSession as i, loadEnv as n, loadEnvLoad as r, getEnvSync as t };
@@ -0,0 +1,94 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ //#region ../cli-core/src/version.ts
5
+ let cachedOwnDir;
6
+ /** The published package's own root: the nearest directory above this
7
+ * module's file that holds a `package.json`. A bundled CLI runs from a flat
8
+ * `dist/`, so that is the CLI's root (`dist/launch.js` -> up one); the core
9
+ * is inlined into it, so its own source location never matters at run time.
10
+ * Memoized since it never changes within a process. */
11
+ function ownPackageDir() {
12
+ if (cachedOwnDir !== void 0) return cachedOwnDir;
13
+ let dir = dirname(fileURLToPath(import.meta.url));
14
+ while (!existsSync(join(dir, "package.json")) && dirname(dir) !== dir) dir = dirname(dir);
15
+ cachedOwnDir = dir;
16
+ return dir;
17
+ }
18
+ /** Reads this build's own `package.json` version — used by `telemetry.ts`
19
+ * (release tagging) and the CLI's `version` command. */
20
+ function ownVersion() {
21
+ const pkg = JSON.parse(readFileSync(join(ownPackageDir(), "package.json"), "utf8"));
22
+ return typeof pkg.version === "string" ? pkg.version : "0.0.0";
23
+ }
24
+ //#endregion
25
+ //#region ../cli-core/src/repo/root.ts
26
+ /**
27
+ * Where devtools finds the DevDogsUGA checkout it is running against.
28
+ *
29
+ * devtools used to live inside `packages/devtools` of that repo, so its own
30
+ * `import.meta.url` WAS a path into the repo (`PROJECT_ROOT` /
31
+ * `REPO_ROOT` walked up a fixed number of `..` segments from this file).
32
+ * Published as its own package and run through `pnpm dlx`, that assumption
33
+ * breaks: this file's `import.meta.url` points into a dlx cache directory
34
+ * or an isolated `node_modules` tree that has nothing to do with the repo
35
+ * the contributor is standing in.
36
+ *
37
+ * So repo discovery walks up from `process.cwd()` instead, looking for the
38
+ * marker validated in the `devtools-dlx` prototype
39
+ * (`/home/sloan/scratchpad/devdogs/prototypes/devtools-dlx/FINDINGS.md`,
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".
45
+ */
46
+ /** The `package.json` name every real DevDogsUGA checkout carries at its root. */
47
+ const REPO_MARKER_NAME = "devdogs-monorepo";
48
+ var RepoNotFoundError = class extends Error {
49
+ constructor() {
50
+ super("run this from inside a DevDogsUGA clone");
51
+ this.name = "RepoNotFoundError";
52
+ }
53
+ };
54
+ function looksLikeRepoRoot(dir) {
55
+ if (!existsSync(join(dir, "pnpm-workspace.yaml"))) return false;
56
+ try {
57
+ return JSON.parse(readFileSync(join(dir, "package.json"), "utf8")).name === REPO_MARKER_NAME;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ /**
63
+ * Walks up from `startDir` (default `process.cwd()`) looking for the repo
64
+ * marker. Returns `null` rather than throwing — `findRepoRoot()` below is
65
+ * the throwing convenience most callers want; this is exported for callers
66
+ * (like `setup`) that need to know without failing.
67
+ */
68
+ function discoverRepoRoot(startDir = process.cwd()) {
69
+ let dir = startDir;
70
+ for (;;) {
71
+ if (looksLikeRepoRoot(dir)) return dir;
72
+ const parent = dirname(dir);
73
+ if (parent === dir) return null;
74
+ dir = parent;
75
+ }
76
+ }
77
+ let cachedRoot;
78
+ /**
79
+ * The memoized, throwing repo-root lookup. Lazy on purpose: importing this
80
+ * module must never fail just because nothing has called it yet (`setup`
81
+ * and `completions` in `launch.ts` never need a repo at all, and must stay
82
+ * that way — see that file's header comment on why).
83
+ *
84
+ * Resolved once per process: `process.cwd()` does not change mid-invocation
85
+ * for this CLI, and re-walking the filesystem on every call would be pure
86
+ * waste.
87
+ */
88
+ function findRepoRoot() {
89
+ if (cachedRoot === void 0) cachedRoot = process.env.DEVTOOLS_TEST_REPO_ROOT ?? discoverRepoRoot();
90
+ if (cachedRoot === null) throw new RepoNotFoundError();
91
+ return cachedRoot;
92
+ }
93
+ //#endregion
94
+ export { ownVersion as a, ownPackageDir as i, discoverRepoRoot as n, findRepoRoot as r, RepoNotFoundError as t };
@@ -0,0 +1,2 @@
1
+ import { t as runStackCommand } from "./stack-BynCgRVS.js";
2
+ export { runStackCommand };
@@ -0,0 +1,181 @@
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-0knM0mqd.js";
2
+ import { r as findRepoRoot } from "./root-C2OmZDwD.js";
3
+ import { i as loadEnvSession, r as loadEnvLoad } from "./peers-RBplwovA.js";
4
+ import { writeFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ //#region src/db/session-refresh.ts
7
+ /**
8
+ * Re-enters development — refreshing `process.env` from `.env.generated`'s
9
+ * latest state — when (and only when) this process is already running under
10
+ * development. Returns the one-line note callers report on success, or an
11
+ * empty array when the guard held and nothing needed refreshing.
12
+ */
13
+ async function refreshSessionEnv(opts = {}) {
14
+ const deployEnv = opts.deployEnv ?? process.env.DEPLOY_ENV;
15
+ if (deployEnv !== void 0 && deployEnv !== "" && deployEnv !== "development") return [];
16
+ const envLoad = await loadEnvLoad();
17
+ const enter = opts.enterEnvironment ?? (await loadEnvSession()).enterEnvironment;
18
+ try {
19
+ await enter("development", { override: true });
20
+ } catch (err) {
21
+ if (!(err instanceof envLoad.LocalStackOfflineError)) throw err;
22
+ const devDb = process.env[envLoad.DEV_DB_ENV];
23
+ delete process.env[envLoad.DEV_DB_ENV];
24
+ try {
25
+ await enter("development", { override: true });
26
+ } finally {
27
+ if (devDb !== void 0) process.env[envLoad.DEV_DB_ENV] = devDb;
28
+ }
29
+ }
30
+ return [`refreshed ${envLoad.GENERATED_FILE}`];
31
+ }
32
+ //#endregion
33
+ //#region src/db/stack.ts
34
+ /**
35
+ * The local Supabase stack's lifecycle: `start`, `stop` and the `restart`
36
+ * preset.
37
+ *
38
+ * `start` writes `.env.generated` and seeds the storage buckets, which is what
39
+ * the deprecated `db start` alias on DevDogsUGA's main relies on until the
40
+ * cutover; `with-env` takes the file over after it. `stop` leaves the file
41
+ * alone: `with-env` already ignores it while the stack is down.
42
+ */
43
+ /**
44
+ * A running Docker container whose name says it belongs to a DIFFERENT
45
+ * Supabase project than this checkout's own `config.toml` — the signature
46
+ * of a foreign stack holding the shared ports (see
47
+ * `repo/supabase-project.ts`'s header). `undefined` when nothing points
48
+ * that way, including when Docker or `config.toml` could not be read at
49
+ * all: with no signal either way, `startLocalStack`'s own failure and the
50
+ * Supabase CLI's own output are still the reader's best explanation.
51
+ */
52
+ function foreignStackHint() {
53
+ const names = listContainerNames(STACK_API_PORT);
54
+ if (names === null) return void 0;
55
+ const foreign = foreignStackProjectId(names, readProjectId(findRepoRoot()));
56
+ return foreign === null ? void 0 : foreignStackMessage(foreign);
57
+ }
58
+ /**
59
+ * `wroteEnvFile` is split out from `code` on purpose: `.env.generated` is
60
+ * written to disk BEFORE `seedBuckets` runs, so a nonzero `code` from
61
+ * `seedBuckets` alone does not mean the file on disk is unchanged — the
62
+ * fresh connection block is already there, a later `db start` retry or the
63
+ * probe table would already see it, and this process's OWN entered
64
+ * environment is now the stale one. `afterLocalStackChange` below refreshes
65
+ * whenever the file changed, independently of whether the command as a whole
66
+ * succeeded, and still reports the failing code so the caller does not
67
+ * mistake a seed failure for success.
68
+ *
69
+ * `hint` is set when `supabase start` itself fails (before anything here
70
+ * could have written `.env.generated`) AND a foreign project's stack is
71
+ * holding the ports — the same signal `db/generated-env.ts` surfaces for a
72
+ * failed `supabase status -o env`, named here too so `db start` explains
73
+ * itself instead of leaving only the bare Supabase CLI error.
74
+ */
75
+ async function startLocalStack() {
76
+ const code = await supabase("start");
77
+ if (isDryRun()) {
78
+ process.stderr.write("Would write .env.generated from the running stack\n");
79
+ return {
80
+ code: 0,
81
+ wroteEnvFile: false
82
+ };
83
+ }
84
+ if (code !== 0) {
85
+ const hint = foreignStackHint();
86
+ return hint === void 0 ? {
87
+ code,
88
+ wroteEnvFile: false
89
+ } : {
90
+ code,
91
+ wroteEnvFile: false,
92
+ hint
93
+ };
94
+ }
95
+ let env;
96
+ try {
97
+ env = await supabaseCapture("status", "-o", "env");
98
+ } catch {
99
+ return {
100
+ code: 1,
101
+ wroteEnvFile: false
102
+ };
103
+ }
104
+ await writeFile(join(findRepoRoot(), ".env.generated"), env);
105
+ return {
106
+ code: await seedBuckets({ kind: "local" }),
107
+ wroteEnvFile: true
108
+ };
109
+ }
110
+ async function stopLocalStack() {
111
+ return supabase("stop");
112
+ }
113
+ /**
114
+ * BUG 2's fix, applied at every point `start`/`stop`/`restart` can change
115
+ * `.env.generated`: on success, refresh this process's entered environment
116
+ * (see `db/session-refresh.ts`) so the rest of the session — including a
117
+ * `db introspect` run right after this one — sees the stack's CURRENT
118
+ * connection, not whatever `process.env` held at launch. A failed stack
119
+ * command USUALLY changed nothing on disk, so by default there is nothing to
120
+ * refresh.
121
+ *
122
+ * `wroteEnvFile` is the one exception: `startLocalStack` writes
123
+ * `.env.generated` BEFORE the buckets-seed step that can still fail
124
+ * afterwards, so a nonzero `code` from THAT failure does not mean the file on
125
+ * disk is unchanged — see `startLocalStack`'s own doc. Passing `true` here
126
+ * refreshes regardless of `code`, while the failing code itself still reaches
127
+ * the caller untouched, so `db start` is still reported as failed even though
128
+ * the session's environment was brought current.
129
+ */
130
+ async function afterLocalStackChange(code, wroteEnvFile = false) {
131
+ if (isDryRun() || code !== 0 && !wroteEnvFile) return [];
132
+ return refreshSessionEnv();
133
+ }
134
+ /**
135
+ * Stop, then start again.
136
+ *
137
+ * Two steps rather than one, because `supabase restart` does not exist. The
138
+ * CLI's own answer to a changed `config.toml` is a stop/start pair. Doing it
139
+ * here turns that into one menu entry, rather than two commands the contributor
140
+ * has to know to run in that order.
141
+ *
142
+ * A failed stop short-circuits. Starting a stack that never went down would
143
+ * report success and leave the config change unapplied, which is the one
144
+ * outcome worse than a visible failure.
145
+ */
146
+ async function restartLocal() {
147
+ const stopCode = await stopLocalStack();
148
+ if (stopCode !== 0) return {
149
+ code: stopCode,
150
+ lines: ["Stopping failed, so nothing was restarted. Scroll up for the output from the Supabase CLI."]
151
+ };
152
+ const { code, wroteEnvFile, hint } = await startLocalStack();
153
+ const lines = await afterLocalStackChange(code, wroteEnvFile);
154
+ return {
155
+ code,
156
+ lines: hint === void 0 ? lines : [hint, ...lines]
157
+ };
158
+ }
159
+ /**
160
+ * Runs a stack lifecycle command, returning its exit code and anything to
161
+ * report. The lifecycle commands act on this machine's containers and so need
162
+ * no resolvable database (that is what `start` is FOR).
163
+ */
164
+ async function runStackCommand(command) {
165
+ if (command === "restart") return restartLocal();
166
+ if (command === "stop") {
167
+ const code = await stopLocalStack();
168
+ return {
169
+ code,
170
+ lines: await afterLocalStackChange(code)
171
+ };
172
+ }
173
+ const { code, wroteEnvFile, hint } = await startLocalStack();
174
+ const lines = await afterLocalStackChange(code, wroteEnvFile);
175
+ return {
176
+ code,
177
+ lines: hint === void 0 ? lines : [hint, ...lines]
178
+ };
179
+ }
180
+ //#endregion
181
+ export { runStackCommand as t };