@devdogsuga/devtools 0.1.25 → 0.1.27

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,426 @@
1
+ import { a as cliName, r as noteRan } from "./failure-log-BBPGejQv.js";
2
+ import { r as findRepoRoot } from "./root-C2OmZDwD.js";
3
+ import { readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { execFile, execFileSync, spawn } from "node:child_process";
6
+ import { promisify } from "node:util";
7
+ //#region ../cli-core/src/dry-run.ts
8
+ const DRY_RUN_FLAG = "--dry-run";
9
+ /** Commands that forward everything after their name to another tool. */
10
+ const FORWARDING = /* @__PURE__ */ new Set([
11
+ "supabase",
12
+ "wrangler",
13
+ "drizzle-kit",
14
+ "psql",
15
+ "bw",
16
+ "run"
17
+ ]);
18
+ let active = false;
19
+ function setDryRun(on) {
20
+ active = on;
21
+ }
22
+ function isDryRun() {
23
+ return active;
24
+ }
25
+ /**
26
+ * Decides whether `argv` asks for a dry run and returns the argv to dispatch.
27
+ *
28
+ * For a forwarding command a leading `--dry-run` is consumed (the tool never
29
+ * sees it) and a later one is the tool's. For any other command the argv is
30
+ * returned as it came, because several commands read `--dry-run` themselves.
31
+ */
32
+ function resolveDryRun(argv) {
33
+ const firstPositional = argv.findIndex((arg) => !arg.startsWith("-"));
34
+ const lead = firstPositional === -1 ? argv.length : firstPositional;
35
+ const command = argv[firstPositional];
36
+ if (command !== void 0 && FORWARDING.has(command)) {
37
+ const rest = argv.filter((arg, i) => i >= lead || arg !== "--dry-run");
38
+ return {
39
+ dryRun: rest.length !== argv.length,
40
+ rest
41
+ };
42
+ }
43
+ return {
44
+ dryRun: argv.includes(DRY_RUN_FLAG),
45
+ rest: [...argv]
46
+ };
47
+ }
48
+ /**
49
+ * How a command treats `--dry-run`, from the nearest node on its path that
50
+ * says. `undefined` means it did not say, and the dispatcher stops it.
51
+ */
52
+ function dryRunKind(catalog, path) {
53
+ for (let end = path.length; end > 0; end -= 1) {
54
+ const kind = catalog.findCommand(path.slice(0, end))?.dryRun;
55
+ if (kind !== void 0) return kind;
56
+ }
57
+ }
58
+ /** The command line a stopped command would have run. */
59
+ function wouldRunLine(argv) {
60
+ return `Would run: ${cliName()} ${argv.join(" ")}`;
61
+ }
62
+ //#endregion
63
+ //#region ../cli-core/src/process-group.ts
64
+ /**
65
+ * Running a child tool so that stopping it stops everything it started.
66
+ *
67
+ * `pnpm run dev` forks a shell that forks vinext that forks workerd. Killing
68
+ * only the pnpm process (what a plain `child.kill()` does, and what a closed
69
+ * terminal tab or a `kill` from another window delivers) orphans the rest,
70
+ * and the orphan keeps its port. So the child gets its own process group, and
71
+ * every stop signal this process receives is sent to the whole group.
72
+ *
73
+ * Ctrl-C needs the same care in reverse: a child in its own group is not in
74
+ * the terminal's foreground group, so the terminal no longer delivers ^C to
75
+ * it. The signal handlers below forward it.
76
+ *
77
+ * The group is only swept after the direct child exits when that exit was a
78
+ * signal we forwarded; a child that exits on its own is left to have cleaned
79
+ * up after itself, so a tool that deliberately leaves a daemon running keeps it.
80
+ */
81
+ const FORWARDED = [
82
+ "SIGINT",
83
+ "SIGTERM",
84
+ "SIGHUP"
85
+ ];
86
+ const SIGNAL_NUMBERS = {
87
+ SIGHUP: 1,
88
+ SIGINT: 2,
89
+ SIGTERM: 15,
90
+ SIGKILL: 9
91
+ };
92
+ /** How long a group gets to leave after SIGTERM before SIGKILL. */
93
+ const GRACE_MS = 5e3;
94
+ /** Sends `signal` to every process in `pid`'s group. False if it is already gone. */
95
+ function signalGroup(pid, signal) {
96
+ try {
97
+ process.kill(process.platform === "win32" ? pid : -pid, signal);
98
+ return true;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+ function runInGroup(command, args, opts = {}) {
104
+ if (isDryRun()) {
105
+ process.stderr.write(`Would run: ${formatCommand(command, args)}\n`);
106
+ return Promise.resolve({
107
+ code: 0,
108
+ signal: null
109
+ });
110
+ }
111
+ return new Promise((resolve) => {
112
+ const child = spawn(command, [...args], {
113
+ stdio: opts.stdio ?? "inherit",
114
+ cwd: opts.cwd,
115
+ env: opts.env,
116
+ detached: process.platform !== "win32"
117
+ });
118
+ const pid = child.pid;
119
+ let forwarded = null;
120
+ let escalation;
121
+ const forward = (signal) => {
122
+ if (pid === void 0) return;
123
+ forwarded ??= signal;
124
+ signalGroup(pid, signal);
125
+ escalation ??= setTimeout(() => signalGroup(pid, "SIGKILL"), GRACE_MS);
126
+ escalation.unref();
127
+ };
128
+ if (opts.abort?.aborted) forward("SIGTERM");
129
+ else opts.abort?.addEventListener("abort", () => forward("SIGTERM"), { once: true });
130
+ const handlers = FORWARDED.map((signal) => {
131
+ const handler = () => forward(signal);
132
+ process.on(signal, handler);
133
+ return [signal, handler];
134
+ });
135
+ const onExit = () => {
136
+ if (pid !== void 0) signalGroup(pid, "SIGKILL");
137
+ };
138
+ process.on("exit", onExit);
139
+ const finish = (result) => {
140
+ noteRan(`${formatCommand(command, args)} (exit ${result.code})`);
141
+ for (const [signal, handler] of handlers) process.off(signal, handler);
142
+ process.off("exit", onExit);
143
+ if (escalation) clearTimeout(escalation);
144
+ if (forwarded !== null && pid !== void 0) signalGroup(pid, "SIGKILL");
145
+ resolve(result);
146
+ };
147
+ child.on("error", (error) => {
148
+ process.stderr.write(`${error.message}\n`);
149
+ finish({
150
+ code: 1,
151
+ signal: null
152
+ });
153
+ });
154
+ child.on("exit", (code, signal) => {
155
+ const bySignal = signal ? 128 + (SIGNAL_NUMBERS[signal] ?? 0) : 1;
156
+ finish({
157
+ code: code ?? bySignal,
158
+ signal
159
+ });
160
+ });
161
+ });
162
+ }
163
+ const URL_CREDENTIALS = /\/\/[^/@\s]*@/;
164
+ /**
165
+ * The command as a person would type it, for printing. A database URL carries
166
+ * its password, so the value after `--db-url` (and any URL with credentials)
167
+ * is replaced rather than echoed.
168
+ */
169
+ function formatCommand(command, args) {
170
+ const shown = [];
171
+ for (let i = 0; i < args.length; i += 1) {
172
+ const arg = args[i];
173
+ if (arg === "--db-url" && i + 1 < args.length) {
174
+ shown.push(arg, "<DB_URL>");
175
+ i += 1;
176
+ } else if (arg.startsWith("--db-url=")) shown.push("--db-url=<DB_URL>");
177
+ else shown.push(arg.replace(URL_CREDENTIALS, "//***@"));
178
+ }
179
+ return [command, ...shown].map((part) => /^[\w@%+=:,./<>*-]+$/.test(part) ? part : JSON.stringify(part)).join(" ");
180
+ }
181
+ /**
182
+ * Prints the exact command that ran, AFTER it ran so the tool's own output
183
+ * cannot bury it. On stderr, so a tool whose stdout is a pipe stays clean.
184
+ */
185
+ function reportRan(command, args, result) {
186
+ if (isDryRun()) return;
187
+ const status = result.code === 0 ? "" : ` (exit ${result.code})`;
188
+ process.stderr.write(`Ran: ${formatCommand(command, args)}${status}\n`);
189
+ }
190
+ //#endregion
191
+ //#region ../cli-core/src/db/run.ts
192
+ /**
193
+ * Shared helpers for running supabase CLI and pnpm commands from the repo root.
194
+ *
195
+ * 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.
198
+ */
199
+ const runFile = promisify(execFile);
200
+ /** Spawn a pnpm command with inherited stdio; resolves to the exit code. Pass
201
+ * `env` to run the child against a loaded tier rather than process.env. The
202
+ * child runs in its own process group, so stopping this process stops
203
+ * whatever it started (see `process-group.ts`). */
204
+ async function run(args, env) {
205
+ const result = await runInGroup("pnpm", args, {
206
+ cwd: findRepoRoot(),
207
+ ...env ? { env } : {}
208
+ });
209
+ if (reporting) reportRan("pnpm", args, result);
210
+ return result.code;
211
+ }
212
+ let reporting = false;
213
+ /**
214
+ * Makes every `run()` after this print the exact command it ran (on stderr,
215
+ * after it finishes). Off by default, so a deploy log or a piped command is
216
+ * not changed under its caller; the presets turn it on because showing the
217
+ * tool calls behind a button is their whole point.
218
+ */
219
+ function reportRuns(enabled) {
220
+ reporting = enabled;
221
+ }
222
+ /** Spawn a pnpm command while echoing and retaining stderr for diagnostics.
223
+ * Pass `env` to run the child against a loaded tier rather than process.env. */
224
+ function runWithStderr(args, env) {
225
+ return new Promise((resolve) => {
226
+ const child = spawn("pnpm", args, {
227
+ stdio: [
228
+ "inherit",
229
+ "inherit",
230
+ "pipe"
231
+ ],
232
+ cwd: findRepoRoot(),
233
+ ...env ? { env } : {}
234
+ });
235
+ let stderr = "";
236
+ child.stderr.setEncoding("utf8");
237
+ child.stderr.on("data", (chunk) => {
238
+ stderr += chunk;
239
+ process.stderr.write(chunk);
240
+ });
241
+ child.on("error", (error) => {
242
+ const message = `${error.message}\n`;
243
+ stderr += message;
244
+ process.stderr.write(message);
245
+ resolve({
246
+ code: 1,
247
+ stderr
248
+ });
249
+ });
250
+ child.on("exit", (code) => resolve({
251
+ code: code ?? 1,
252
+ stderr
253
+ }));
254
+ });
255
+ }
256
+ /** Spawn a pnpm command, capture stdout, throw on non-zero exit. */
257
+ async function capture(args) {
258
+ const { stdout } = await runFile("pnpm", args, {
259
+ cwd: findRepoRoot(),
260
+ encoding: "utf8"
261
+ });
262
+ return stdout;
263
+ }
264
+ /** `pnpm exec supabase …` with inherited stdio. */
265
+ const supabase = (...args) => run([
266
+ "exec",
267
+ "supabase",
268
+ ...args
269
+ ]);
270
+ /** `pnpm exec supabase …` with captured stdout. */
271
+ const supabaseCapture = (...args) => capture([
272
+ "exec",
273
+ "supabase",
274
+ ...args
275
+ ]);
276
+ /**
277
+ * `supabase db push` over `dbUrl`, inherited stdio, resolving to the exit code.
278
+ *
279
+ * The one spelling of the migration push, shared by the contributor `db
280
+ * migrate` path (`stack.ts`'s `pushMigrations`) and CI's `deploy migrate`.
281
+ * `--yes` is the unattended apply CI wants; the contributor path omits it so a
282
+ * human still confirms. Neither variant regenerates types — that is
283
+ * `pushMigrations`' own second step, layered on top only where a checkout is
284
+ * meant to be rewritten. A CI apply must NOT write back into the repo, which is
285
+ * exactly why the bare push is factored out here rather than reused whole.
286
+ */
287
+ function dbPush(dbUrl, opts = {}) {
288
+ const args = [
289
+ "db",
290
+ "push",
291
+ "--db-url",
292
+ dbUrl
293
+ ];
294
+ if (opts.yes) args.push("--yes");
295
+ return supabase(...args);
296
+ }
297
+ /** Seed storage buckets on the local stack or a resolved tier's project. */
298
+ async function seedBuckets(conn) {
299
+ if (conn.kind === "local") return supabase("seed", "buckets", "--local", "--yes");
300
+ if (!conn.projectRef) {
301
+ process.stderr.write("devtools db: seed buckets against a hosted project needs PROJECT_REF in the session's env file.\n");
302
+ return 1;
303
+ }
304
+ return supabase("seed", "buckets", "--project-ref", conn.projectRef, "--linked");
305
+ }
306
+ //#endregion
307
+ //#region ../cli-core/src/repo/supabase-project.ts
308
+ /**
309
+ * This repo's Supabase project id — read from `supabase/config.toml` — and
310
+ * the container-name conventions the Supabase CLI derives from it.
311
+ *
312
+ * Shared by `environment.ts`'s adaptive-menu probe (does a stack answer for
313
+ * THIS project?) and the foreign-stack detection in `db/generated-env.ts`
314
+ * and `stack.ts` (does a DIFFERENT project's stack hold the shared ports? —
315
+ * the case where `supabase status -o env` fails not because nothing is
316
+ * running, but because what is running on 127.0.0.1:54321 belongs to
317
+ * another workspace, or to this same repo before/after a `project_id`
318
+ * rename). One project-id reader and one container-name parser, so both
319
+ * questions agree on what "this project" means.
320
+ */
321
+ /**
322
+ * Reads `project_id` out of `<repoRoot>/supabase/config.toml`, or `null`
323
+ * when the file is missing or unparsable.
324
+ *
325
+ * Regex, not a TOML parser: it is one line, the shape has been stable
326
+ * across every CLI version this repo has seen, and a parser on a path some
327
+ * callers pay before their first real subprocess is a cost that stays
328
+ * invisible until it is why the tool feels slow.
329
+ */
330
+ function readProjectId(repoRoot) {
331
+ try {
332
+ const path = join(repoRoot, "supabase", "config.toml");
333
+ return /^\s*project_id\s*=\s*"([^"]+)"/m.exec(readFileSync(path, "utf8"))?.[1] ?? null;
334
+ } catch {
335
+ return null;
336
+ }
337
+ }
338
+ /**
339
+ * The Supabase CLI's container name prefix for a project id, or the bare
340
+ * `supabase_db_` fallback when the id could not be read.
341
+ *
342
+ * Falling back to the bare prefix means a machine whose `config.toml`
343
+ * cannot be read still detects *a* stack, at the cost of over-matching a
344
+ * differently-named project — deliberate, and unchanged from this
345
+ * function's original home in `environment.ts`: over-matching offers
346
+ * `stop`/a foreign-stack hint for a stack that turns out to be this
347
+ * project's own, which is harmless to see and decline, while
348
+ * under-matching hides a real signal entirely.
349
+ */
350
+ function containerPrefix(projectId) {
351
+ return projectId ? `supabase_db_${projectId}` : "supabase_db_";
352
+ }
353
+ /**
354
+ * The local stack's API port, published by its Kong container. Mirrors
355
+ * `@devdogsuga/env/load`'s `LOCAL_STACK_PORT`, which this module cannot import
356
+ * statically (that package is an optional peer, loaded on demand).
357
+ */
358
+ const STACK_API_PORT = 54321;
359
+ function defaultExec(file, args) {
360
+ try {
361
+ return execFileSync(file, args, {
362
+ encoding: "utf8",
363
+ stdio: [
364
+ "ignore",
365
+ "pipe",
366
+ "ignore"
367
+ ],
368
+ timeout: 3e3
369
+ });
370
+ } catch {
371
+ return null;
372
+ }
373
+ }
374
+ /**
375
+ * `docker ps --format '{{.Names}}'`, split into trimmed, non-empty names —
376
+ * or `null` when Docker could not be read at all (no daemon, not
377
+ * installed, timed out). With `publish`, only the containers publishing that
378
+ * host port. `execute` is injectable for tests, mirroring `environment.ts`'s
379
+ * own probes.
380
+ */
381
+ function listContainerNames(publish, execute = defaultExec) {
382
+ const out = execute("docker", [
383
+ "ps",
384
+ ...publish === void 0 ? [] : ["--filter", `publish=${publish}`],
385
+ "--format",
386
+ "{{.Names}}"
387
+ ]);
388
+ if (out === null) return null;
389
+ return out.split("\n").map((name) => name.trim()).filter((name) => name.length > 0);
390
+ }
391
+ /**
392
+ * Finds the `supabase_kong_<id>` container among `names` whose id differs
393
+ * from `projectId` — the signature of a stack started from a DIFFERENT
394
+ * Supabase project (this same repo before/after a rename, or another
395
+ * project entirely) holding the shared ports. Kong is the container that
396
+ * publishes the API port, so callers pass the names `listContainerNames`
397
+ * returns for `STACK_API_PORT`: that names the stack actually on 54321,
398
+ * not just any Supabase stack on the machine.
399
+ *
400
+ * Returns that foreign id, or `null` when every matching container belongs
401
+ * to this project, none match at all, or `projectId` itself could not be
402
+ * read — with no known id of our own, there is nothing to compare against,
403
+ * and guessing would risk telling a contributor their OWN stack is
404
+ * foreign.
405
+ */
406
+ function foreignStackProjectId(names, projectId) {
407
+ if (projectId === null) return null;
408
+ for (const name of names) {
409
+ const match = /^supabase_kong_(.+)$/.exec(name);
410
+ if (!match) continue;
411
+ const id = match[1];
412
+ if (id !== projectId) return id;
413
+ }
414
+ return null;
415
+ }
416
+ /**
417
+ * The actionable message for a detected foreign stack — shared by
418
+ * `db/generated-env.ts` (a failed `supabase status -o env`) and `stack.ts`
419
+ * (a failed `supabase start`), so both name the same fix in the same
420
+ * words.
421
+ */
422
+ function foreignStackMessage(foreignProjectId) {
423
+ 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\`.`;
424
+ }
425
+ //#endregion
426
+ 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 };
@@ -0,0 +1,249 @@
1
+ import { a as cliName, n as noteError } from "./failure-log-BBPGejQv.js";
2
+ import { a as ownVersion, n as discoverRepoRoot } from "./root-C2OmZDwD.js";
3
+ import { readFileSync } from "node:fs";
4
+ import * as Sentry from "@sentry/node";
5
+ import { buildSentryOptions } from "@devdogsuga/telemetry";
6
+ //#region ../cli-core/src/mode.ts
7
+ /**
8
+ * Non-interactive mode: the one definition both published CLIs share.
9
+ *
10
+ * A run is non-interactive when nobody can answer a prompt: no TTY on stdin,
11
+ * or `CI=true`. In that mode there is no wizard and no banner, output is plain
12
+ * lines (errors on stderr), every confirmation needs `--yes`, the tier must be
13
+ * named (`--tier` or `DEPLOY_ENV`), and Sentry reports the environment `ci`.
14
+ * `--no-env` is the companion switch: it skips loading env files, for a job
15
+ * that supplies its own environment.
16
+ */
17
+ /** Skip every confirmation. Also the only way past the hosted-tier gate with no terminal. */
18
+ const YES_FLAG = "--yes";
19
+ /** Do not load env files; the caller's environment is the environment. */
20
+ const NO_ENV_FLAG = "--no-env";
21
+ /** `CI=true` (or `1`), the value every CI runner sets. */
22
+ function isCiEnv(env = process.env) {
23
+ return env.CI === "true" || env.CI === "1";
24
+ }
25
+ /**
26
+ * Whether this run has nobody to ask.
27
+ *
28
+ * Both inputs are injectable for tests; the defaults read the live process.
29
+ */
30
+ function isNonInteractive(env = process.env, isTTY = process.stdin.isTTY === true) {
31
+ return !isTTY || isCiEnv(env);
32
+ }
33
+ /** Whether `--yes` was typed anywhere in `argv`. */
34
+ function hasYes(argv) {
35
+ return argv.includes(YES_FLAG);
36
+ }
37
+ /**
38
+ * Pulls `--no-env` out of `argv`, wherever it sits, leaving everything else in
39
+ * order. Like `--tier`, it is a global flag the launcher strips before any
40
+ * command sees the rest.
41
+ */
42
+ function stripNoEnvFlag(argv) {
43
+ const rest = argv.filter((arg) => arg !== NO_ENV_FLAG);
44
+ return {
45
+ noEnv: rest.length !== argv.length,
46
+ rest
47
+ };
48
+ }
49
+ /**
50
+ * Pulls a global `--tier <t>` out of `argv`, wherever it sits, leaving every
51
+ * other argument untouched and in its original order.
52
+ *
53
+ * A trailing `--tier` with nothing after it removes just the flag; the
54
+ * missing value then reaches tier resolution as `explicit: undefined`, which
55
+ * falls through to `DEPLOY_ENV`/the sole tier/the prompt exactly as if
56
+ * `--tier` had never been typed, rather than this function guessing. A
57
+ * following token that is itself a flag is treated the same way, NOT consumed
58
+ * as the value (the guard every other flag-value reader keeps): without it,
59
+ * `--tier --help` would swallow the flag as a bogus tier and refuse with
60
+ * "unknown tier" instead of reaching the help bypass.
61
+ */
62
+ function stripTierFlag(argv) {
63
+ const rest = [...argv];
64
+ const index = rest.indexOf("--tier");
65
+ if (index === -1) return {
66
+ explicit: void 0,
67
+ rest
68
+ };
69
+ const value = rest[index + 1];
70
+ const missing = value === void 0 || value.startsWith("-");
71
+ rest.splice(index, missing ? 1 : 2);
72
+ return {
73
+ explicit: missing ? void 0 : value,
74
+ rest
75
+ };
76
+ }
77
+ //#endregion
78
+ //#region ../cli-core/src/telemetry.ts
79
+ /**
80
+ * devtools' own Sentry wiring — the CLI is a consumer of
81
+ * `@devdogsuga/telemetry` like `apps/platform`, `apps/schedule-builder`, and
82
+ * `apps/sandbox`, but on `@sentry/node` rather than a framework SDK: a CLI
83
+ * process starts, runs one command, and exits, with none of a server's
84
+ * request lifecycle for a framework integration to hook into.
85
+ *
86
+ * ## Reporting is on by default
87
+ *
88
+ * Every other `*_SENTRY_DSN` in this org is optional-and-empty until
89
+ * configured (see `@devdogsuga/telemetry`'s no-op-without-DSN contract), and
90
+ * so is this one — empty means `buildSentryOptions` returns `undefined` and
91
+ * `Sentry.init` never runs — but the DEFAULT here is reporting ON once a DSN
92
+ * exists, unlike a feature a contributor opts into. `DEVTOOLS_TELEMETRY=0` is
93
+ * the one escape hatch, checked before `Sentry.init` and before every capture
94
+ * call, so it also works as a kill switch after init already ran (a
95
+ * long-lived `pnpm devtools` menu session, for instance).
96
+ *
97
+ * ## Where the DSN comes from
98
+ *
99
+ * Baked in at build time, not read from the consumer's environment: devtools
100
+ * runs on contributors' machines, where no `.env` could be relied on to carry
101
+ * it. `scripts/write-build-info.mjs` writes `dist/build-info.json` from the
102
+ * build's `DEVTOOLS_SENTRY_DSN`, which Backstage's `publish.yaml` sets from
103
+ * the repo's Actions variable of the same name. Every other build bakes ""
104
+ * and reports nothing. `DEVTOOLS_SENTRY_DSN` in the run-time environment still
105
+ * wins, for pointing a local build at a test project.
106
+ */
107
+ /** The DSN baked into this build, or "" if there is none (a source run under
108
+ * tsx, or a build made without `DEVTOOLS_SENTRY_DSN`). */
109
+ function bakedSentryDsn() {
110
+ try {
111
+ const info = JSON.parse(readFileSync(new URL("./build-info.json", import.meta.url), "utf8"));
112
+ return typeof info.sentryDsn === "string" ? info.sentryDsn : "";
113
+ } catch {
114
+ return "";
115
+ }
116
+ }
117
+ /** The run-time `DEVTOOLS_SENTRY_DSN` if set, else the baked one. */
118
+ function resolveDevtoolsDsn(env, baked) {
119
+ return (env.DEVTOOLS_SENTRY_DSN ?? "") || baked;
120
+ }
121
+ let initialized = false;
122
+ /** The id of the last event this process sent to Sentry, if any. */
123
+ let lastEventId;
124
+ /**
125
+ * The Sentry event id of the last error or failure this run reported, or
126
+ * `undefined` when telemetry is off or sent nothing. Printed with the failure
127
+ * log so a maintainer can find the event.
128
+ */
129
+ function lastSentryEventId() {
130
+ return lastEventId;
131
+ }
132
+ /** Records the id only when a client exists: without one nothing was sent. */
133
+ function sent(id) {
134
+ if (Sentry.getClient()) lastEventId = id;
135
+ }
136
+ /**
137
+ * `'ci'` whenever the run is non-interactive (no TTY, or `CI=true`, which the
138
+ * runner sets itself before any workflow-authored env), `'local'` on a
139
+ * contributor's terminal.
140
+ * One of `@devdogsuga/telemetry`'s `ENVIRONMENTS`.
141
+ */
142
+ function devtoolsEnvironment() {
143
+ return isNonInteractive() ? "ci" : "local";
144
+ }
145
+ /**
146
+ * `DEVTOOLS_TELEMETRY=0` (any other value, including unset, leaves reporting
147
+ * on) is the only opt-out. Checked by both `initDevtoolsTelemetry` (skips
148
+ * `Sentry.init` outright) and `captureDevtoolsError` (so setting it mid-run,
149
+ * or between two invocations in the same process, still works).
150
+ */
151
+ function devtoolsTelemetryEnabled() {
152
+ return process.env.DEVTOOLS_TELEMETRY !== "0";
153
+ }
154
+ /**
155
+ * Whether anyone is actually using devtools in this process. Package-registry
156
+ * scanners install every published version within minutes and run it in a
157
+ * throwaway sandbox (random `DESKTOP-xxxxxx` hosts, Firecracker VMs, a fuzzer
158
+ * that turns `process.exit` into a throw). Left unfiltered, each release filed
159
+ * the same two issues from them. They run with no DevDogsUGA checkout and no
160
+ * terminal. A person has at least one of the two (`setup` runs outside a
161
+ * checkout, but in a terminal), and CI always has a checkout.
162
+ */
163
+ function hasRealCaller(inRepo, isTTY) {
164
+ return inRepo || isTTY;
165
+ }
166
+ /**
167
+ * Initializes `@sentry/node` for this CLI process. Safe to call more than
168
+ * once (idempotent) and safe to call with no DSN configured (no-ops via
169
+ * `buildSentryOptions`, see its header).
170
+ *
171
+ * `command` becomes a `command` tag on every event this process reports, so
172
+ * an issue in Sentry names the subcommand it came from (`db reset`,
173
+ * `deploy platform`, …) without anyone opening the job log first.
174
+ */
175
+ function initDevtoolsTelemetry(command) {
176
+ if (initialized) return;
177
+ initialized = true;
178
+ if (!devtoolsTelemetryEnabled()) return;
179
+ if (!hasRealCaller(discoverRepoRoot() !== null, process.stdin.isTTY === true)) return;
180
+ const options = buildSentryOptions({
181
+ service: "devtools",
182
+ environment: devtoolsEnvironment(),
183
+ dsn: resolveDevtoolsDsn(process.env, bakedSentryDsn()),
184
+ release: `${cliName()}@${ownVersion()}`
185
+ });
186
+ if (!options) return;
187
+ Sentry.init(options);
188
+ Sentry.getCurrentScope().setTag("command", command);
189
+ }
190
+ /**
191
+ * Reports an error nothing below the entry points caught — `launch.ts`'s
192
+ * `dispatch`, `launch-ci.ts`, and the bins — then flushes before the process
193
+ * exits. Node's event loop dies with `process.exit`, taking any in-flight
194
+ * request to Sentry's ingest endpoint with it, so the flush must be awaited
195
+ * BEFORE that call — never after.
196
+ *
197
+ * A short timeout: a CLI exiting on error should not hang perceptibly longer
198
+ * because Sentry's ingest is slow or unreachable.
199
+ */
200
+ async function captureDevtoolsError(err) {
201
+ noteError(err);
202
+ if (!devtoolsTelemetryEnabled()) return;
203
+ sent(Sentry.captureException(err));
204
+ await Sentry.flush(2e3);
205
+ }
206
+ /**
207
+ * Reports an error a command caught and explained to the reader itself
208
+ * (`explainError` in `ui.ts`, `backstage deploy`'s catch), then carried on
209
+ * to a normal exit. Not flushed: the SDK's in-flight request keeps the event
210
+ * loop alive until it lands, so a natural exit waits for it on its own. A
211
+ * path that ends in `process.exit` instead must use `captureDevtoolsError`.
212
+ */
213
+ function reportDevtoolsError(err) {
214
+ noteError(err);
215
+ if (!devtoolsTelemetryEnabled()) return;
216
+ sent(Sentry.captureException(err));
217
+ }
218
+ /**
219
+ * Reports a failure that has no error object — a subprocess or deploy step
220
+ * that exited non-zero. Same no-flush contract as `reportDevtoolsError`.
221
+ */
222
+ function reportDevtoolsFailure(message, extra = {}) {
223
+ noteError(new Error(message));
224
+ if (!devtoolsTelemetryEnabled()) return;
225
+ sent(Sentry.captureMessage(message, {
226
+ level: "error",
227
+ extra
228
+ }));
229
+ }
230
+ /**
231
+ * Reports a warning-level message under a FIXED fingerprint, then flushes.
232
+ *
233
+ * For the deprecated aliases: every use groups into one Sentry issue per
234
+ * fingerprint, so the issue's last-seen time says when the alias stopped
235
+ * being used and is safe to remove. Flushed because the callers go on to
236
+ * `process.exit`, which would otherwise drop the request in flight. The
237
+ * timeout is short: the command being run is what the person came for.
238
+ */
239
+ async function captureDevtoolsDeprecation(message, fingerprint, tags) {
240
+ if (!devtoolsTelemetryEnabled()) return;
241
+ Sentry.captureMessage(message, {
242
+ level: "warning",
243
+ fingerprint: [fingerprint],
244
+ tags
245
+ });
246
+ await Sentry.flush(1e3);
247
+ }
248
+ //#endregion
249
+ export { hasRealCaller as a, reportDevtoolsError as c, hasYes as d, isNonInteractive as f, devtoolsTelemetryEnabled as i, reportDevtoolsFailure as l, stripTierFlag as m, captureDevtoolsError as n, initDevtoolsTelemetry as o, stripNoEnvFlag as p, devtoolsEnvironment as r, lastSentryEventId as s, captureDevtoolsDeprecation as t, resolveDevtoolsDsn as u };