@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.
- package/README.md +72 -11
- package/bin/devtools.mjs +4 -4
- package/dist/cli-CZKkNHK5.js +6619 -0
- package/dist/failure-log-BBPGejQv.js +256 -0
- package/dist/launch.js +267 -281
- package/dist/local-env-D8HC2JK_.js +351 -0
- package/dist/local-env-DrBCXqD8.js +2 -0
- package/dist/menu-CQBsQRgH.js +1684 -0
- package/dist/peer-redirect-hooks.js +15 -0
- package/dist/peers-RBplwovA.js +229 -0
- package/dist/root-C2OmZDwD.js +94 -0
- package/dist/stack-Bx-55oi_.js +2 -0
- package/dist/stack-BynCgRVS.js +181 -0
- package/dist/supabase-project-0knM0mqd.js +426 -0
- package/dist/telemetry-C4foD8MD.js +249 -0
- package/dist/telemetry.js +2 -148
- package/package.json +10 -29
- package/bin/devtools-ci-bare.mjs +0 -48
- package/bin/devtools-ci.mjs +0 -31
- package/dist/args.d.ts +0 -26
- package/dist/args.js +0 -78
- package/dist/bws/bw.d.ts +0 -18
- package/dist/bws/bw.js +0 -70
- package/dist/bws/client.d.ts +0 -43
- package/dist/bws/client.js +0 -363
- package/dist/bws/environments.d.ts +0 -96
- package/dist/bws/environments.js +0 -111
- package/dist/bws/pace.d.ts +0 -25
- package/dist/bws/pace.js +0 -43
- package/dist/bws/retry.d.ts +0 -12
- package/dist/bws/retry.js +0 -39
- package/dist/bws/store.d.ts +0 -1
- package/dist/bws/store.js +0 -32
- package/dist/bws/token.d.ts +0 -31
- package/dist/bws/token.js +0 -88
- package/dist/bws/vault.d.ts +0 -29
- package/dist/bws/vault.js +0 -200
- package/dist/catalog.d.ts +0 -57
- package/dist/catalog.js +0 -57
- package/dist/cf/build.d.ts +0 -13
- package/dist/cf/build.js +0 -65
- package/dist/cf/commands.d.ts +0 -1
- package/dist/cf/commands.js +0 -172
- package/dist/cf/local-env.d.ts +0 -58
- package/dist/cf/local-env.js +0 -177
- package/dist/ci.d.ts +0 -1
- package/dist/ci.js +0 -328
- package/dist/cli.d.ts +0 -11
- package/dist/cli.js +0 -1094
- package/dist/commands.d.ts +0 -261
- package/dist/commands.js +0 -1318
- package/dist/completions.d.ts +0 -4
- package/dist/completions.js +0 -110
- package/dist/cron/commands.d.ts +0 -47
- package/dist/cron/commands.js +0 -372
- package/dist/cron/discovery.d.ts +0 -55
- package/dist/cron/discovery.js +0 -85
- package/dist/cron/schema.d.ts +0 -45
- package/dist/cron/schema.js +0 -35
- package/dist/db/config-push.d.ts +0 -8
- package/dist/db/config-push.js +0 -11
- package/dist/db/connection.d.ts +0 -79
- package/dist/db/connection.js +0 -114
- package/dist/db/exec.d.ts +0 -1
- package/dist/db/exec.js +0 -11
- package/dist/db/generate-types.d.ts +0 -1
- package/dist/db/generate-types.js +0 -4
- package/dist/db/generated-env.d.ts +0 -69
- package/dist/db/generated-env.js +0 -113
- package/dist/db/introspect.d.ts +0 -1
- package/dist/db/introspect.js +0 -122
- package/dist/db/local-env.d.ts +0 -65
- package/dist/db/local-env.js +0 -23
- package/dist/db/new-migration.d.ts +0 -8
- package/dist/db/new-migration.js +0 -69
- package/dist/db/pooler.d.ts +0 -23
- package/dist/db/pooler.js +0 -55
- package/dist/db/run.d.ts +0 -68
- package/dist/db/run.js +0 -156
- package/dist/db/seed-buckets.d.ts +0 -2
- package/dist/db/seed-buckets.js +0 -4
- package/dist/db/seed-production.d.ts +0 -8
- package/dist/db/seed-production.js +0 -79
- package/dist/db/seed-roles.d.ts +0 -7
- package/dist/db/seed-roles.js +0 -33
- package/dist/db/session-refresh.d.ts +0 -43
- package/dist/db/session-refresh.js +0 -40
- package/dist/deploy/migrations.d.ts +0 -20
- package/dist/deploy/migrations.js +0 -68
- package/dist/deploy/orphans.d.ts +0 -20
- package/dist/deploy/orphans.js +0 -177
- package/dist/deploy/preflight.d.ts +0 -53
- package/dist/deploy/preflight.js +0 -189
- package/dist/deploy/report.d.ts +0 -26
- package/dist/deploy/report.js +0 -70
- package/dist/deploy/require-planner.d.ts +0 -2
- package/dist/deploy/require-planner.js +0 -60
- package/dist/deploy/require-token.d.ts +0 -15
- package/dist/deploy/require-token.js +0 -78
- package/dist/deploy/secrets-file.d.ts +0 -17
- package/dist/deploy/secrets-file.js +0 -166
- package/dist/deploy/write-env.d.ts +0 -40
- package/dist/deploy/write-env.js +0 -395
- package/dist/docs/index-pages.d.ts +0 -38
- package/dist/docs/index-pages.js +0 -186
- package/dist/emails/commands.d.ts +0 -15
- package/dist/emails/commands.js +0 -130
- package/dist/emails/email-types.d.ts +0 -13
- package/dist/emails/email-types.js +0 -1
- package/dist/emails/fixtures.d.ts +0 -20
- package/dist/emails/fixtures.js +0 -20
- package/dist/env/audit.d.ts +0 -206
- package/dist/env/audit.js +0 -436
- package/dist/env/cloudflare.d.ts +0 -21
- package/dist/env/cloudflare.js +0 -61
- package/dist/env/commands.d.ts +0 -99
- package/dist/env/commands.js +0 -613
- package/dist/env/discovery.d.ts +0 -15
- package/dist/env/discovery.js +0 -239
- package/dist/env/document.d.ts +0 -119
- package/dist/env/document.js +0 -323
- package/dist/env/example.d.ts +0 -68
- package/dist/env/example.js +0 -605
- package/dist/env/selection.d.ts +0 -105
- package/dist/env/selection.js +0 -228
- package/dist/env-entry.d.ts +0 -49
- package/dist/env-entry.js +0 -204
- package/dist/environment-doctor.d.ts +0 -45
- package/dist/environment-doctor.js +0 -429
- package/dist/environment.d.ts +0 -92
- package/dist/environment.js +0 -185
- package/dist/fingerprint.d.ts +0 -10
- package/dist/fingerprint.js +0 -18
- package/dist/gen/campus-map.d.ts +0 -1
- package/dist/gen/campus-map.js +0 -473
- package/dist/gen/commands.d.ts +0 -1
- package/dist/gen/commands.js +0 -25
- package/dist/gen/hypno.d.ts +0 -1
- package/dist/gen/hypno.js +0 -134
- package/dist/gh/client.d.ts +0 -80
- package/dist/gh/client.js +0 -259
- package/dist/gh/environments.d.ts +0 -83
- package/dist/gh/environments.js +0 -178
- package/dist/gh/rulesets/actors.d.ts +0 -14
- package/dist/gh/rulesets/actors.js +0 -69
- package/dist/gh/rulesets/api.d.ts +0 -15
- package/dist/gh/rulesets/api.js +0 -104
- package/dist/gh/rulesets/commands.d.ts +0 -3
- package/dist/gh/rulesets/commands.js +0 -203
- package/dist/gh/rulesets/desired.d.ts +0 -112
- package/dist/gh/rulesets/desired.js +0 -271
- package/dist/gh/rulesets/diff.d.ts +0 -65
- package/dist/gh/rulesets/diff.js +0 -170
- package/dist/gh/rulesets/types.d.ts +0 -76
- package/dist/gh/rulesets/types.js +0 -13
- package/dist/gh/settings/api.d.ts +0 -40
- package/dist/gh/settings/api.js +0 -180
- package/dist/gh/settings/commands.d.ts +0 -1
- package/dist/gh/settings/commands.js +0 -254
- package/dist/gh/settings/desired.d.ts +0 -53
- package/dist/gh/settings/desired.js +0 -43
- package/dist/gh/settings/diff.d.ts +0 -57
- package/dist/gh/settings/diff.js +0 -161
- package/dist/gh/settings/types.d.ts +0 -92
- package/dist/gh/settings/types.js +0 -11
- package/dist/gh/settings/workflows.d.ts +0 -41
- package/dist/gh/settings/workflows.js +0 -128
- package/dist/grantRoot.d.ts +0 -42
- package/dist/grantRoot.js +0 -89
- package/dist/help.d.ts +0 -18
- package/dist/help.js +0 -169
- package/dist/images/commands.d.ts +0 -32
- package/dist/images/commands.js +0 -231
- package/dist/images/events.d.ts +0 -47
- package/dist/images/events.js +0 -116
- package/dist/images/graphics.d.ts +0 -70
- package/dist/images/graphics.js +0 -234
- package/dist/images/open-graph-types.d.ts +0 -75
- package/dist/images/open-graph-types.js +0 -1
- package/dist/images/prompts.d.ts +0 -34
- package/dist/images/prompts.js +0 -100
- package/dist/images/render.d.ts +0 -21
- package/dist/images/render.js +0 -61
- package/dist/images/select.d.ts +0 -64
- package/dist/images/select.js +0 -96
- package/dist/instance.d.ts +0 -69
- package/dist/instance.js +0 -102
- package/dist/invocation.d.ts +0 -49
- package/dist/invocation.js +0 -78
- package/dist/launch-ci.d.ts +0 -1
- package/dist/launch-ci.js +0 -90
- package/dist/launch.d.ts +0 -18
- package/dist/menu.d.ts +0 -43
- package/dist/menu.js +0 -300
- package/dist/moderation.d.ts +0 -70
- package/dist/moderation.js +0 -128
- package/dist/oauth/browser.d.ts +0 -1
- package/dist/oauth/browser.js +0 -13
- package/dist/oauth/config.d.ts +0 -24
- package/dist/oauth/config.js +0 -24
- package/dist/oauth/connect-url.d.ts +0 -17
- package/dist/oauth/connect-url.js +0 -23
- package/dist/oauth/db.d.ts +0 -37
- package/dist/oauth/db.js +0 -108
- package/dist/oauth/device.d.ts +0 -93
- package/dist/oauth/device.js +0 -198
- package/dist/oauth/discovery.d.ts +0 -28
- package/dist/oauth/discovery.js +0 -54
- package/dist/oauth/env-file.d.ts +0 -6
- package/dist/oauth/env-file.js +0 -35
- package/dist/oauth/exchange.d.ts +0 -43
- package/dist/oauth/exchange.js +0 -93
- package/dist/oauth/label.d.ts +0 -1
- package/dist/oauth/label.js +0 -25
- package/dist/oauth/loopback.d.ts +0 -52
- package/dist/oauth/loopback.js +0 -168
- package/dist/oauth/pkce.d.ts +0 -6
- package/dist/oauth/pkce.js +0 -34
- package/dist/oauth/target.d.ts +0 -54
- package/dist/oauth/target.js +0 -102
- package/dist/oauth/transport.d.ts +0 -41
- package/dist/oauth/transport.js +0 -32
- package/dist/oauth/wizard.d.ts +0 -40
- package/dist/oauth/wizard.js +0 -578
- package/dist/persona.d.ts +0 -18
- package/dist/persona.js +0 -221
- package/dist/pick.d.ts +0 -6
- package/dist/pick.js +0 -64
- package/dist/pipes.d.ts +0 -1
- package/dist/pipes.js +0 -25
- package/dist/planner/checks.d.ts +0 -26
- package/dist/planner/checks.js +0 -104
- package/dist/planner/commands.d.ts +0 -10
- package/dist/planner/commands.js +0 -367
- package/dist/planner/db.d.ts +0 -15
- package/dist/planner/db.js +0 -33
- package/dist/planner/role.d.ts +0 -33
- package/dist/planner/role.js +0 -68
- package/dist/repo/peer-redirect-hooks.d.ts +0 -16
- package/dist/repo/peer-redirect-hooks.js +0 -10
- package/dist/repo/peer-redirect.d.ts +0 -4
- package/dist/repo/peer-redirect.js +0 -26
- package/dist/repo/peers.d.ts +0 -39
- package/dist/repo/peers.js +0 -139
- package/dist/repo/resolve.d.ts +0 -41
- package/dist/repo/resolve.js +0 -152
- package/dist/repo/root.d.ts +0 -23
- package/dist/repo/root.js +0 -91
- package/dist/repo/source.d.ts +0 -14
- package/dist/repo/source.js +0 -54
- package/dist/repo/supabase-project.d.ts +0 -60
- package/dist/repo/supabase-project.js +0 -124
- package/dist/repo/tsx-loader.d.ts +0 -6
- package/dist/repo/tsx-loader.js +0 -41
- package/dist/run/pick.d.ts +0 -90
- package/dist/run/pick.js +0 -664
- package/dist/setup.d.ts +0 -1
- package/dist/setup.js +0 -280
- package/dist/stack.d.ts +0 -48
- package/dist/stack.js +0 -403
- package/dist/telemetry.d.ts +0 -59
- package/dist/tier.d.ts +0 -40
- package/dist/tier.js +0 -96
- package/dist/ui.d.ts +0 -40
- package/dist/ui.js +0 -71
- package/dist/version.d.ts +0 -7
- package/dist/version.js +0 -17
- package/dist/workers.d.ts +0 -5
- package/dist/workers.js +0 -33
- package/dist/workflows/commands.d.ts +0 -54
- package/dist/workflows/commands.js +0 -763
package/dist/run/pick.js
DELETED
|
@@ -1,664 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `pnpm devtools run <task>`: which apps a root pnpm task runs against.
|
|
3
|
-
*
|
|
4
|
-
* `pnpm dev` used to start every app in the workspace at once: two Next dev
|
|
5
|
-
* servers on two ports and a Flutter run, when almost nobody is working on
|
|
6
|
-
* more than one. pnpm's own `--filter` has always made scoping possible, so
|
|
7
|
-
* the capability was there. The DEFAULT was wrong, and a default you have to
|
|
8
|
-
* know a flag to escape is one most contributors never escape.
|
|
9
|
-
*
|
|
10
|
-
* So every root package script routes through here. With a TTY and no
|
|
11
|
-
* explicit filter it asks; without either it is a passthrough that costs one
|
|
12
|
-
* or two process spawns (one to build dependencies first, for tasks that need
|
|
13
|
-
* that — see `NEEDS_DEPS_BUILT` below — then one to run the task itself).
|
|
14
|
-
*
|
|
15
|
-
* ## Why this lives in devtools now
|
|
16
|
-
*
|
|
17
|
-
* It began here, moved out to `scripts/pick.mjs` as plain Node, and has come
|
|
18
|
-
* back. The move out rested on two grounds, and re-checking them on 2026-08-27
|
|
19
|
-
* found one of them false:
|
|
20
|
-
*
|
|
21
|
-
* * "CI pays for it." It does not. No workflow invokes the root task
|
|
22
|
-
* aliases: `ci.yaml` and `deploy.yaml` both call `pnpm -r …`/`pnpm --filter
|
|
23
|
-
* …` directly, which never reaches this file. Only a person at a terminal
|
|
24
|
-
* pays it, and there it buys the question this exists to ask. The `CI`
|
|
25
|
-
* guard in `shouldAsk` stays as insurance against a runner that one day
|
|
26
|
-
* does type `pnpm build`.
|
|
27
|
-
* * "It must not need a build." This one holds, and is why the module stays
|
|
28
|
-
* careful. `pnpm build` routes through here, so anything on this path that
|
|
29
|
-
* had to be compiled first would be a cycle. It is safe because devtools
|
|
30
|
-
* runs from source under `--conditions=devdogs-source`, and because the
|
|
31
|
-
* one workspace dependency with no source condition (`@devdogsuga/docs`,
|
|
32
|
-
* which is `dist`-only) is reached through a lazy `await import` in
|
|
33
|
-
* `docs/index-pages.ts` and never loads on this path. ⚠️ A top-level
|
|
34
|
-
* `import` of `@devdogsuga/docs` anywhere in the eager graph would
|
|
35
|
-
* deadlock `pnpm build` on itself.
|
|
36
|
-
*
|
|
37
|
-
* ## Turbo's `^build` ordering, in pnpm terms
|
|
38
|
-
*
|
|
39
|
-
* Turbo's task graph guaranteed that a package's workspace dependencies were
|
|
40
|
-
* built before the task ran against it — `dependsOn: ["^build"]` in the old
|
|
41
|
-
* `turbo.json`, for every task in `NEEDS_DEPS_BUILT` below. pnpm has no single
|
|
42
|
-
* flag that means the same thing, but it has the two pieces that compose into
|
|
43
|
-
* it: `<pkg>^...` selects only the direct and indirect DEPENDENCIES of a
|
|
44
|
-
* package (excluding the package itself), and plain recursive `pnpm -r` runs
|
|
45
|
-
* scripts in dependency order (a package's own dependencies always run before
|
|
46
|
-
* it). So building the deps-of set with `-r --filter '<pkg>^...' run build`
|
|
47
|
-
* and then running the real task against the package itself reproduces
|
|
48
|
-
* turbo's ordering with two spawns instead of turbo's one.
|
|
49
|
-
*
|
|
50
|
-
* `@devdogsuga/email` is the one package that needs its OWN build before its
|
|
51
|
-
* OWN typecheck/test, not just its dependencies' — its build step generates
|
|
52
|
-
* gitignored `src/generated/templates.ts`. That case never runs through this
|
|
53
|
-
* picker (it lists `apps/*`, not `packages/*`; see `appsWith` below), but
|
|
54
|
-
* matters for anyone reasoning about the workspace-wide passthrough path
|
|
55
|
-
* (see `passthroughApps` and `allAppNames`), which builds the union of every
|
|
56
|
-
* app's dependencies — email included, since some app depends on it —
|
|
57
|
-
* before the target task, deliberately stopping short of a bare `pnpm -r run
|
|
58
|
-
* build`: that would also run every APP's own build script, which a
|
|
59
|
-
* typecheck/lint/test/dev run has no business doing (see `passthroughApps`'s
|
|
60
|
-
* doc comment for why that is more than just wasted work).
|
|
61
|
-
*/
|
|
62
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
63
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
64
|
-
import { dirname, join } from "node:path";
|
|
65
|
-
import { cancel, confirm, isCancel, multiselect } from "@clack/prompts";
|
|
66
|
-
import { findRepoRoot } from "../repo/root.js";
|
|
67
|
-
import { loadEnvLoad } from "../repo/peers.js";
|
|
68
|
-
/**
|
|
69
|
-
* Where the last answer per task is kept.
|
|
70
|
-
*
|
|
71
|
-
* Under `node_modules/.cache` rather than a dotfile at the root: it is a
|
|
72
|
-
* convenience, not configuration, and losing it to a reinstall costs one extra
|
|
73
|
-
* keystroke. Putting it there also means no new `.gitignore` entry and no new
|
|
74
|
-
* file in the listing every contributor sees.
|
|
75
|
-
*/
|
|
76
|
-
function memoryPath() {
|
|
77
|
-
return join(findRepoRoot(), "node_modules", ".cache", "devdogs", "tasks.json");
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* pnpm's own ways of naming packages, plus `--scope` for backward
|
|
81
|
-
* compatibility with anyone who still types the turbo-era flag out of habit.
|
|
82
|
-
* Any of them means "already decided" for `shouldAsk`; `--scope`'s value is
|
|
83
|
-
* translated into a `--filter` when a command actually gets built, since pnpm
|
|
84
|
-
* itself has no `--scope` flag.
|
|
85
|
-
*/
|
|
86
|
-
const FILTERS = ["--filter", "-F", "--scope"];
|
|
87
|
-
/**
|
|
88
|
-
* Tasks whose turbo definition depended on `^build` — the packages a target
|
|
89
|
-
* depends on must be built first. Everything else forwarded through `run`
|
|
90
|
-
* (`generate-types`, and any package script not in this list) needs no
|
|
91
|
-
* dependency build: turbo's `generate-types` declared no `dependsOn` at all,
|
|
92
|
-
* and nothing else is routed through the root aliases this picker serves.
|
|
93
|
-
*/
|
|
94
|
-
const NEEDS_DEPS_BUILT = new Set([
|
|
95
|
-
"build",
|
|
96
|
-
"dev",
|
|
97
|
-
"typecheck",
|
|
98
|
-
"lint",
|
|
99
|
-
"lint:fix",
|
|
100
|
-
"test",
|
|
101
|
-
"test:coverage",
|
|
102
|
-
]);
|
|
103
|
-
// ── Passthrough ──────────────────────────────────────────────────────────────
|
|
104
|
-
/**
|
|
105
|
-
* Runs one `pnpm` invocation to completion, reporting its own exit the way
|
|
106
|
-
* `passthroughApps` needs to: a truthy return means "keep going", `never` on
|
|
107
|
-
* anything that ends the process (a signal, or a non-zero status treated as
|
|
108
|
-
* final).
|
|
109
|
-
*
|
|
110
|
-
* `pnpm` resolves from the workspace root's `node_modules/.bin`, which is
|
|
111
|
-
* already on PATH. Signals and exit codes pass straight through, so a Ctrl-C
|
|
112
|
-
* in a dev server behaves exactly as it did before this existed: when the
|
|
113
|
-
* child dies to a signal rather than exiting with a code, this process
|
|
114
|
-
* re-raises that same signal against itself instead of collapsing it to a
|
|
115
|
-
* generic exit code, which is what lets a shell watching this process see a
|
|
116
|
-
* conventional signal death rather than a failure.
|
|
117
|
-
*
|
|
118
|
-
* ⚠️ `cwd` is explicit, and must be. Reached through
|
|
119
|
-
* `pnpm --filter @devdogsuga/devtools run cli`, this process starts in
|
|
120
|
-
* `packages/devtools`, and a `pnpm -r`/`--filter` invoked there would scope
|
|
121
|
-
* itself relative to that one package rather than the workspace root.
|
|
122
|
-
*/
|
|
123
|
-
function runOne(args, extraEnv, { final }) {
|
|
124
|
-
const result = spawnSync("pnpm", args, {
|
|
125
|
-
cwd: findRepoRoot(),
|
|
126
|
-
stdio: "inherit",
|
|
127
|
-
// Guards the one recursion that would matter: a bare, filter-less `pnpm
|
|
128
|
-
// -r` never re-enters the root package's own scripts (pnpm excludes the
|
|
129
|
-
// workspace root from an unfiltered recursive run by default), but an
|
|
130
|
-
// explicit `--filter` naming the root package — or a `!`-exclusion or
|
|
131
|
-
// `[since]` selector, both of which DO match the root even though a bare
|
|
132
|
-
// `-r` does not — would. `DEVDOGS_PICK=0` is the same recursion guard
|
|
133
|
-
// turbo's spawn used: it means "already decided", so a root script that
|
|
134
|
-
// re-entered `pnpm devtools run …` would pass straight through instead of
|
|
135
|
-
// asking again.
|
|
136
|
-
env: { ...process.env, ...extraEnv, DEVDOGS_PICK: "0" },
|
|
137
|
-
});
|
|
138
|
-
if (result.signal) {
|
|
139
|
-
// Restore the default disposition first: any SIGINT/SIGTERM listener
|
|
140
|
-
// this process itself registered (`@clack/prompts` installs one while a
|
|
141
|
-
// prompt is open) would otherwise run instead of the OS just ending the
|
|
142
|
-
// process, which is what re-raising is supposed to produce.
|
|
143
|
-
process.removeAllListeners(result.signal);
|
|
144
|
-
process.kill(process.pid, result.signal);
|
|
145
|
-
// Default disposition means the OS ends this process as part of that
|
|
146
|
-
// call, so nothing below ever runs long enough to matter.
|
|
147
|
-
for (;;) {
|
|
148
|
-
/* unreachable */
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
const status = result.status ?? 1;
|
|
152
|
-
if (status !== 0 || final) {
|
|
153
|
-
process.exit(status);
|
|
154
|
-
}
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Runs a sequence of `pnpm` invocations — typically "build the dependencies",
|
|
159
|
-
* then "run the actual task" — stopping (and exiting non-zero) at the first
|
|
160
|
-
* one that fails, and exiting with the LAST one's status otherwise. This is
|
|
161
|
-
* what stands in for turbo's single-process task graph: turbo built
|
|
162
|
-
* dependencies and ran the target task inside one invocation, so a dependency
|
|
163
|
-
* build failure and a task failure looked identical from the outside (a
|
|
164
|
-
* failed `turbo run`); this reproduces that from the outside by never
|
|
165
|
-
* reaching the second spawn if the first one failed.
|
|
166
|
-
*
|
|
167
|
-
* Never returns: every branch inside `runOne` either exits or re-raises a
|
|
168
|
-
* signal.
|
|
169
|
-
*/
|
|
170
|
-
function passthrough(commands, extraEnv) {
|
|
171
|
-
commands.forEach((args, index) => {
|
|
172
|
-
runOne(args, extraEnv, { final: index === commands.length - 1 });
|
|
173
|
-
});
|
|
174
|
-
// Unreachable: `runOne` above always exits on the final command (`final:
|
|
175
|
-
// true` forces it even on success), and exits early on any earlier
|
|
176
|
-
// failure. This satisfies the `never` return type without a bare `throw`.
|
|
177
|
-
process.exit(1);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Whether to ask at all.
|
|
181
|
-
*
|
|
182
|
-
* Every one of these is a case where a prompt is either impossible or wrong:
|
|
183
|
-
*
|
|
184
|
-
* * `CI`, set by GitHub Actions and every other runner. No workflow reaches
|
|
185
|
-
* this today (see the header), but a workflow that blocked on a
|
|
186
|
-
* multiselect would hang until its timeout with no output saying why, and
|
|
187
|
-
* that failure is bad enough to keep guarding against.
|
|
188
|
-
* * No TTY: a pipe, a `pnpm` invoked by a script, an editor task runner.
|
|
189
|
-
* Nobody is there to answer. Every other picker in this repo checks the
|
|
190
|
-
* same thing.
|
|
191
|
-
* * An explicit filter. The caller has already said which packages, and
|
|
192
|
-
* asking again would be asking them to repeat themselves.
|
|
193
|
-
* * `DEVDOGS_PICK=0`, the escape hatch and the recursion guard above.
|
|
194
|
-
*/
|
|
195
|
-
export function shouldAsk(args) {
|
|
196
|
-
if (process.env.CI)
|
|
197
|
-
return false;
|
|
198
|
-
if (process.env.DEVDOGS_PICK === "0")
|
|
199
|
-
return false;
|
|
200
|
-
if (!process.stdin.isTTY)
|
|
201
|
-
return false;
|
|
202
|
-
return !args.some((arg) => FILTERS.includes(arg) || FILTERS.some((f) => arg.startsWith(`${f}=`)));
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Pulls every `--filter`/`-F`/`--scope` value out of `args`, returning the
|
|
206
|
-
* package patterns named and the remaining args with those flags removed.
|
|
207
|
-
*
|
|
208
|
-
* `--scope` is folded into the same bucket as `--filter` here: pnpm has no
|
|
209
|
-
* `--scope` flag of its own, so a caller who still types the turbo-era name
|
|
210
|
-
* gets it translated into a real `--filter` value rather than passed through
|
|
211
|
-
* to a `pnpm` invocation that would reject it outright.
|
|
212
|
-
*
|
|
213
|
-
* Exported for the same reason `parseTierArg` is: pure, no `process.exit`, so
|
|
214
|
-
* it is unit-testable without going through `passthrough`.
|
|
215
|
-
*/
|
|
216
|
-
export function extractFilters(args) {
|
|
217
|
-
const filters = [];
|
|
218
|
-
const rest = [];
|
|
219
|
-
for (let i = 0; i < args.length; i++) {
|
|
220
|
-
const arg = args[i];
|
|
221
|
-
const eqFlag = FILTERS.find((f) => arg.startsWith(`${f}=`));
|
|
222
|
-
if (eqFlag) {
|
|
223
|
-
filters.push(arg.slice(eqFlag.length + 1));
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
if (FILTERS.includes(arg)) {
|
|
227
|
-
const value = args[i + 1];
|
|
228
|
-
if (value !== undefined) {
|
|
229
|
-
filters.push(value);
|
|
230
|
-
i++;
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
rest.push(arg);
|
|
235
|
-
}
|
|
236
|
-
return { filters, rest };
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Every `apps/*` package name, regardless of whether it defines the task in
|
|
240
|
-
* question — unlike `appsWith`, which is a picker concern (only offer apps
|
|
241
|
-
* that actually have this script). This exists for exactly one thing: naming
|
|
242
|
-
* "every dependency any app has" without hand-listing packages, since apps
|
|
243
|
-
* are the only packages in this workspace nothing else depends on (every
|
|
244
|
-
* `packages/*`/`docs` package is reachable from at least one app's
|
|
245
|
-
* dependency graph, and no app depends on another app).
|
|
246
|
-
*/
|
|
247
|
-
function allAppNames() {
|
|
248
|
-
const dir = join(findRepoRoot(), "apps");
|
|
249
|
-
if (!existsSync(dir))
|
|
250
|
-
return [];
|
|
251
|
-
const names = [];
|
|
252
|
-
for (const entry of readdirSync(dir)) {
|
|
253
|
-
const manifest = join(dir, entry, "package.json");
|
|
254
|
-
if (!existsSync(manifest))
|
|
255
|
-
continue;
|
|
256
|
-
try {
|
|
257
|
-
const pkg = JSON.parse(readFileSync(manifest, "utf8"));
|
|
258
|
-
if (pkg.name)
|
|
259
|
-
names.push(pkg.name);
|
|
260
|
-
}
|
|
261
|
-
catch {
|
|
262
|
-
// Same as `appsWith`: an unparsable manifest is one we cannot use.
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return names;
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* Builds the `pnpm run <task>` invocation(s) for a set of package filters (or
|
|
269
|
-
* none, for the whole workspace) and runs them via `passthrough`.
|
|
270
|
-
*
|
|
271
|
-
* Two spawns for a task in `NEEDS_DEPS_BUILT`: one that builds only the
|
|
272
|
-
* dependencies of the target packages, then one that runs the real task
|
|
273
|
-
* against the target packages themselves. A task outside `NEEDS_DEPS_BUILT`
|
|
274
|
-
* skips straight to the second spawn.
|
|
275
|
-
*
|
|
276
|
-
* The first spawn's filter set matters more than it looks: it must build
|
|
277
|
-
* every dependency the target packages need, and NOTHING ELSE — never an
|
|
278
|
-
* app's own `build` script, since turbo's `^build` never ran one either
|
|
279
|
-
* (typechecking `platform` built platform's DEPENDENCIES, then ran
|
|
280
|
-
* `platform`'s `typecheck` script; it never ran `platform`'s own `build`).
|
|
281
|
-
* Getting this wrong is not just wasted work: an app's `build` script can
|
|
282
|
-
* need things a `typecheck`/`lint`/`test` run has no reason to have (a
|
|
283
|
-
* database, a chosen deploy tier, a Flutter SDK on PATH), so running one
|
|
284
|
-
* unasked can fail outright.
|
|
285
|
-
*
|
|
286
|
-
* * Filtered (`filters` non-empty): `<pkg>^...` per filter — pnpm's
|
|
287
|
-
* deps-of selector, excluding the package itself.
|
|
288
|
-
* * Whole workspace: the union of `<app>^...` over every app in the
|
|
289
|
-
* workspace (`allAppNames()`), NOT a bare `pnpm -r run build`. A bare
|
|
290
|
-
* recursive build would build every package with a `build` script,
|
|
291
|
-
* apps included, for exactly the reason above. Every non-app package in
|
|
292
|
-
* this workspace is reachable from at least one app's dependency graph
|
|
293
|
-
* (verified against every current `apps/*` package, not assumed), so
|
|
294
|
-
* this covers the same ground a bare `-r` would minus the apps
|
|
295
|
-
* themselves.
|
|
296
|
-
*
|
|
297
|
-
* `dev` is the one persistent task and runs with `--parallel`: pnpm's
|
|
298
|
-
* ordinary recursive mode runs one package at a time in dependency order,
|
|
299
|
-
* which is wrong for two dev servers that are each supposed to keep running
|
|
300
|
-
* — `--parallel` "completely disregard[s] concurrency and topological
|
|
301
|
-
* sorting, running a given script immediately in all matching packages with
|
|
302
|
-
* prefixed streaming output" (pnpm's own words for the flag), which is
|
|
303
|
-
* exactly the live, interleaved multi-app output turbo's `dev` gave. Every
|
|
304
|
-
* other task keeps pnpm's default topological/serial recursion, which is a
|
|
305
|
-
* real difference from turbo: turbo ran independent tasks (lint, typecheck,
|
|
306
|
-
* test across several apps) concurrently up to its own concurrency limit,
|
|
307
|
-
* while this runs them one package at a time. Slower on a multi-app
|
|
308
|
-
* selection, never wrong.
|
|
309
|
-
*
|
|
310
|
-
* `build` with no filter (the whole workspace) is the one case that skips
|
|
311
|
-
* the separate dependency spawn even though it is in `NEEDS_DEPS_BUILT`: a
|
|
312
|
-
* bare `pnpm -r run build` already builds every package — apps included, and
|
|
313
|
-
* rightly so, since the task itself IS `build` — in dependency order in one
|
|
314
|
-
* pass, so a preceding dependency-only spawn would just redo part of it. A
|
|
315
|
-
* FILTERED build still needs the pre-step — naming a package by itself,
|
|
316
|
-
* with no `^...`, selects only that package, not what it depends on.
|
|
317
|
-
*/
|
|
318
|
-
function passthroughApps(task, filters, rest, extraEnv) {
|
|
319
|
-
const commands = [];
|
|
320
|
-
const needsDepsPreStep = NEEDS_DEPS_BUILT.has(task) && (task !== "build" || filters.length > 0);
|
|
321
|
-
if (needsDepsPreStep) {
|
|
322
|
-
const depsOfTargets = filters.length > 0 ? filters : allAppNames();
|
|
323
|
-
const depsFilters = depsOfTargets.flatMap((f) => ["--filter", `${f}^...`]);
|
|
324
|
-
commands.push(["-r", "--if-present", ...depsFilters, "run", "build"]);
|
|
325
|
-
}
|
|
326
|
-
const ownFilters = filters.flatMap((f) => ["--filter", f]);
|
|
327
|
-
const parallel = task === "dev" ? ["--parallel"] : [];
|
|
328
|
-
commands.push([
|
|
329
|
-
"-r",
|
|
330
|
-
"--if-present",
|
|
331
|
-
...parallel,
|
|
332
|
-
...ownFilters,
|
|
333
|
-
"run",
|
|
334
|
-
task,
|
|
335
|
-
...rest,
|
|
336
|
-
]);
|
|
337
|
-
passthrough(commands, extraEnv);
|
|
338
|
-
}
|
|
339
|
-
// ── dev on vinext ────────────────────────────────────────────────────────────
|
|
340
|
-
/** A `dev` script that starts `vinext dev` (platform's `with-env vinext dev`). */
|
|
341
|
-
const VINEXT_DEV = /(^|[\s;&|])vinext\s+dev\b/;
|
|
342
|
-
/**
|
|
343
|
-
* Splits a `dev` run between apps whose dev server is `vinext dev` and the
|
|
344
|
-
* rest.
|
|
345
|
-
*
|
|
346
|
-
* A vinext app's server code runs in workerd, which only sees what
|
|
347
|
-
* `@cloudflare/vite-plugin` hands it: the app dir's own `.dev.vars`/`.env`, or
|
|
348
|
-
* with `CLOUDFLARE_INCLUDE_PROCESS_ENV` the whole `process.env`. The repo's
|
|
349
|
-
* `.env` is at the root, so through the app's own `with-env vinext dev` script
|
|
350
|
-
* the Worker gets nothing and env validation fails. So a vinext app skips its
|
|
351
|
-
* script and runs `pnpm --filter <app> exec vinext dev` with the env
|
|
352
|
-
* `scopedProcessEnv` builds, the same way `workflows run` starts one: the
|
|
353
|
-
* flag set, and every other app's variables left out. Its script's own
|
|
354
|
-
* `with-env` would load the whole `.env` back in, so it is not used.
|
|
355
|
-
*
|
|
356
|
-
* Everything else still runs its own `dev` script under one `pnpm --parallel`.
|
|
357
|
-
* `apps` is every app with a `dev` script; `filters` the selection (empty for
|
|
358
|
-
* all of them). Only apps are named here: no other package has a `dev`
|
|
359
|
-
* script.
|
|
360
|
-
*/
|
|
361
|
-
export function planDev(apps, filters, rest) {
|
|
362
|
-
const selected = filters.length > 0
|
|
363
|
-
? apps.filter((app) => filters.includes(app.name))
|
|
364
|
-
: [...apps];
|
|
365
|
-
const vinext = selected
|
|
366
|
-
.filter((app) => VINEXT_DEV.test(app.script))
|
|
367
|
-
.map((app) => app.name);
|
|
368
|
-
const otherFilters = filters.length > 0
|
|
369
|
-
? filters.filter((f) => !vinext.includes(f))
|
|
370
|
-
: apps.map((app) => app.name).filter((name) => !vinext.includes(name));
|
|
371
|
-
const others = otherFilters.length > 0
|
|
372
|
-
? [
|
|
373
|
-
"-r",
|
|
374
|
-
"--if-present",
|
|
375
|
-
"--parallel",
|
|
376
|
-
...otherFilters.flatMap((f) => ["--filter", f]),
|
|
377
|
-
"run",
|
|
378
|
-
"dev",
|
|
379
|
-
...rest,
|
|
380
|
-
]
|
|
381
|
-
: null;
|
|
382
|
-
return { vinext, others };
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* `dev` when at least one selected app runs `vinext dev`: builds every
|
|
386
|
-
* selected app's workspace dependencies, then starts the vinext apps (each
|
|
387
|
-
* with its own scoped env, see `planDev`) and the rest side by side, and
|
|
388
|
-
* exits when the first of them does, stopping the others.
|
|
389
|
-
*
|
|
390
|
-
* The env is the session's: `launch.ts` has already entered the tier into
|
|
391
|
-
* `process.env` (or `--tier` loaded one into `tierEnv`).
|
|
392
|
-
*/
|
|
393
|
-
async function runDev(plan, filters, rest, tierEnv) {
|
|
394
|
-
const depsOfTargets = filters.length > 0 ? filters : allAppNames();
|
|
395
|
-
runOne([
|
|
396
|
-
"-r",
|
|
397
|
-
"--if-present",
|
|
398
|
-
...depsOfTargets.flatMap((f) => ["--filter", `${f}^...`]),
|
|
399
|
-
"run",
|
|
400
|
-
"build",
|
|
401
|
-
], tierEnv, { final: false });
|
|
402
|
-
// Dynamic, like `loadEnvLoad`: the env registry is no business of a plain
|
|
403
|
-
// `pnpm build`.
|
|
404
|
-
const { scopedProcessEnv } = await import("../cf/local-env.js");
|
|
405
|
-
const environment = { ...process.env, ...tierEnv };
|
|
406
|
-
const tier = environment.DEPLOY_ENV ?? "development";
|
|
407
|
-
const children = [
|
|
408
|
-
...(await Promise.all(plan.vinext.map(async (app) => ({
|
|
409
|
-
args: ["--filter", app, "exec", "vinext", "dev", ...rest],
|
|
410
|
-
env: await scopedProcessEnv(app, environment, tier),
|
|
411
|
-
})))),
|
|
412
|
-
...(plan.others ? [{ args: plan.others, env: environment }] : []),
|
|
413
|
-
].map(({ args, env }) => spawn("pnpm", args, {
|
|
414
|
-
cwd: findRepoRoot(),
|
|
415
|
-
stdio: "inherit",
|
|
416
|
-
env: { ...env, DEVDOGS_PICK: "0" },
|
|
417
|
-
}));
|
|
418
|
-
// Ctrl-C reaches every child through the terminal's process group; this
|
|
419
|
-
// process waits for them to finish rather than dying first.
|
|
420
|
-
const ignore = () => undefined;
|
|
421
|
-
process.on("SIGINT", ignore);
|
|
422
|
-
process.on("SIGTERM", ignore);
|
|
423
|
-
const first = await Promise.race(children.map((child) => new Promise((resolve) => {
|
|
424
|
-
child.once("error", () => resolve(1));
|
|
425
|
-
child.once("exit", (code, signal) => resolve(code ?? (signal ? 130 : 1)));
|
|
426
|
-
})));
|
|
427
|
-
for (const child of children) {
|
|
428
|
-
if (child.exitCode === null && child.signalCode === null) {
|
|
429
|
-
child.kill("SIGTERM");
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
process.exit(first);
|
|
433
|
-
}
|
|
434
|
-
/** `passthroughApps`, except that a `dev` selecting a vinext app goes to
|
|
435
|
-
* `runDev`. */
|
|
436
|
-
async function dispatch(task, filters, rest, tierEnv) {
|
|
437
|
-
if (task === "dev") {
|
|
438
|
-
const plan = planDev(appsWith("dev"), filters, rest);
|
|
439
|
-
if (plan.vinext.length > 0)
|
|
440
|
-
return runDev(plan, filters, rest, tierEnv);
|
|
441
|
-
}
|
|
442
|
-
passthroughApps(task, filters, rest, tierEnv);
|
|
443
|
-
}
|
|
444
|
-
// ── Tier ─────────────────────────────────────────────────────────────────────
|
|
445
|
-
/** The tiers a loaded env can select. `preflight` is not a deploy environment
|
|
446
|
-
* (see `@devdogsuga/env`'s target table) and is refused here for the same
|
|
447
|
-
* reason `loadEnvironment` itself would refuse it. */
|
|
448
|
-
const RUN_TIERS = new Set(["development", "staging", "production"]);
|
|
449
|
-
/**
|
|
450
|
-
* Parses and strips `--tier <value>` from pnpm-bound args, mirroring the
|
|
451
|
-
* `--all` strip above.
|
|
452
|
-
*
|
|
453
|
-
* Pure on purpose — no `process.exit` — so this is unit-testable without
|
|
454
|
-
* going through `passthrough`, which every other path in this file ends at
|
|
455
|
-
* and which a test cannot observe return from. `runTask` is the one caller,
|
|
456
|
-
* and it is the one that turns `error` into an exit.
|
|
457
|
-
*/
|
|
458
|
-
export function parseTierArg(args) {
|
|
459
|
-
const idx = args.indexOf("--tier");
|
|
460
|
-
if (idx === -1)
|
|
461
|
-
return { rest: [...args] };
|
|
462
|
-
const value = args[idx + 1];
|
|
463
|
-
if (!value || value.startsWith("-")) {
|
|
464
|
-
return { rest: [...args], error: "devtools run: --tier requires a value." };
|
|
465
|
-
}
|
|
466
|
-
if (!RUN_TIERS.has(value)) {
|
|
467
|
-
return {
|
|
468
|
-
rest: [...args],
|
|
469
|
-
error: `devtools run: unknown tier "${value}". ` +
|
|
470
|
-
"Expected: development, staging, production.",
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
return {
|
|
474
|
-
tier: value,
|
|
475
|
-
rest: [...args.slice(0, idx), ...args.slice(idx + 2)],
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
// ── The apps ─────────────────────────────────────────────────────────────────
|
|
479
|
-
/**
|
|
480
|
-
* The apps that actually define this task, by package name.
|
|
481
|
-
*
|
|
482
|
-
* `apps/*` only. Packages are libraries an app pulls in, and a filtered
|
|
483
|
-
* `pnpm -r --filter '<app>^...' run build` already builds those first (see
|
|
484
|
-
* `passthroughApps` above), so listing all twelve would ask about things the
|
|
485
|
-
* answer does not change. Reading each `package.json` rather than shelling
|
|
486
|
-
* out to a dry-run equivalent, which costs about a second before the first
|
|
487
|
-
* question.
|
|
488
|
-
*/
|
|
489
|
-
function appsWith(task) {
|
|
490
|
-
const dir = join(findRepoRoot(), "apps");
|
|
491
|
-
if (!existsSync(dir))
|
|
492
|
-
return [];
|
|
493
|
-
const found = [];
|
|
494
|
-
for (const entry of readdirSync(dir)) {
|
|
495
|
-
const manifest = join(dir, entry, "package.json");
|
|
496
|
-
if (!existsSync(manifest))
|
|
497
|
-
continue;
|
|
498
|
-
try {
|
|
499
|
-
const pkg = JSON.parse(readFileSync(manifest, "utf8"));
|
|
500
|
-
const script = pkg.scripts?.[task];
|
|
501
|
-
if (pkg.name && script)
|
|
502
|
-
found.push({ name: pkg.name, script });
|
|
503
|
-
}
|
|
504
|
-
catch {
|
|
505
|
-
// A manifest we cannot parse is one we cannot offer. pnpm will report
|
|
506
|
-
// it far better than a picker could.
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
return found;
|
|
510
|
-
}
|
|
511
|
-
// ── Memory ───────────────────────────────────────────────────────────────────
|
|
512
|
-
function remembered(task) {
|
|
513
|
-
try {
|
|
514
|
-
const all = JSON.parse(readFileSync(memoryPath(), "utf8"));
|
|
515
|
-
return all[task] ?? [];
|
|
516
|
-
}
|
|
517
|
-
catch {
|
|
518
|
-
return [];
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
function remember(task, apps) {
|
|
522
|
-
try {
|
|
523
|
-
let all = {};
|
|
524
|
-
try {
|
|
525
|
-
all = JSON.parse(readFileSync(memoryPath(), "utf8"));
|
|
526
|
-
}
|
|
527
|
-
catch {
|
|
528
|
-
// First run, or a file from an older shape. Either way, start clean.
|
|
529
|
-
}
|
|
530
|
-
all[task] = apps;
|
|
531
|
-
mkdirSync(dirname(memoryPath()), { recursive: true });
|
|
532
|
-
writeFileSync(memoryPath(), `${JSON.stringify(all, null, 2)}\n`);
|
|
533
|
-
}
|
|
534
|
-
catch {
|
|
535
|
-
// Remembering is a convenience. Failing to write it must never fail the
|
|
536
|
-
// command the contributor actually asked for.
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
// ── Entry ────────────────────────────────────────────────────────────────────
|
|
540
|
-
/**
|
|
541
|
-
* Runs one root task, asking which apps first where that makes sense.
|
|
542
|
-
*
|
|
543
|
-
* Never returns: every path ends in `passthrough`, which exits with the
|
|
544
|
-
* underlying `pnpm` invocation's own status. That is why `cli.ts` dispatches
|
|
545
|
-
* this before `intro()`. There is no `outro()` to reach, and a banner would
|
|
546
|
-
* land on the stream a dev server is about to take over.
|
|
547
|
-
*/
|
|
548
|
-
export async function runTask(argv) {
|
|
549
|
-
const [task, ...args] = argv;
|
|
550
|
-
if (!task) {
|
|
551
|
-
console.error("usage: pnpm devtools run <task> [pnpm args…]");
|
|
552
|
-
process.exit(1);
|
|
553
|
-
}
|
|
554
|
-
// `--all` is this command's own flag, not pnpm's: it means "no question,
|
|
555
|
-
// every package", which is what the root scripts did before this existed.
|
|
556
|
-
// Removed from the argv so pnpm never sees a flag it does not know.
|
|
557
|
-
const all = args.includes("--all");
|
|
558
|
-
const withoutAll = args.filter((arg) => arg !== "--all");
|
|
559
|
-
const tierArg = parseTierArg(withoutAll);
|
|
560
|
-
if (tierArg.error) {
|
|
561
|
-
console.error(tierArg.error);
|
|
562
|
-
process.exit(1);
|
|
563
|
-
}
|
|
564
|
-
const { tier, rest } = tierArg;
|
|
565
|
-
// No `--yes` here, deliberately: `run` is a bare pnpm passthrough with no
|
|
566
|
-
// confirmation flag of its own to spare, unlike `cron run`/`workflows run`.
|
|
567
|
-
// A non-interactive caller that wants production has no way to say so, and
|
|
568
|
-
// that is the point — the same exposure those two gate behind `--yes` gets
|
|
569
|
-
// gated behind a terminal existing at all.
|
|
570
|
-
if (tier === "production") {
|
|
571
|
-
if (!process.stdin.isTTY) {
|
|
572
|
-
console.error("devtools run: --tier production needs a terminal to confirm — " +
|
|
573
|
-
"nothing ran.");
|
|
574
|
-
process.exit(1);
|
|
575
|
-
}
|
|
576
|
-
const approved = await confirm({
|
|
577
|
-
message: `Run \`${task}\` against production? This loads .env.production's ` +
|
|
578
|
-
"credentials into the child process.",
|
|
579
|
-
initialValue: false,
|
|
580
|
-
});
|
|
581
|
-
if (isCancel(approved) || !approved) {
|
|
582
|
-
cancel("Nothing ran.");
|
|
583
|
-
process.exit(0);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
let tierEnv;
|
|
587
|
-
if (tier) {
|
|
588
|
-
// Dynamic import, not a top-level one: this module is on the `pnpm build`
|
|
589
|
-
// hot path (see the header), and a bare `pnpm build` with no `--tier`
|
|
590
|
-
// must never load `@devdogsuga/env/load` or drag dotenvx into the graph.
|
|
591
|
-
const { loadEnvironment, MissingEnvFileError } = await loadEnvLoad();
|
|
592
|
-
try {
|
|
593
|
-
// override: true because THIS process runs under `with-env`
|
|
594
|
-
// (development), so process.env already holds development's values.
|
|
595
|
-
// Passing the full loaded env — not just DEPLOY_ENV — to the child
|
|
596
|
-
// matters because a grandchild `with-env` (started by the app's own
|
|
597
|
-
// script) resolves variables first-file-wins from ITS OWN process.env:
|
|
598
|
-
// without the full map, that env would still carry devtools' inherited
|
|
599
|
-
// development values, which would beat `.env.<tier>` for anything
|
|
600
|
-
// `.env.<tier>` does not also redeclare.
|
|
601
|
-
const loaded = await loadEnvironment(tier, { override: true });
|
|
602
|
-
tierEnv = { ...loaded.env, DEPLOY_ENV: tier };
|
|
603
|
-
}
|
|
604
|
-
catch (err) {
|
|
605
|
-
if (err instanceof MissingEnvFileError) {
|
|
606
|
-
console.error(`devtools run: ${err.message}`);
|
|
607
|
-
process.exit(1);
|
|
608
|
-
}
|
|
609
|
-
throw err;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
// `shouldAsk` is false whenever `rest` already carries an explicit filter,
|
|
613
|
-
// so extracting filters here (rather than unconditionally) would be
|
|
614
|
-
// redundant with it in every case that matters; `all` is the one case
|
|
615
|
-
// `shouldAsk` cannot see for itself. Either way, `rest` may still carry an
|
|
616
|
-
// explicit `--filter`/`-F`/`--scope` that needs pulling out before it is
|
|
617
|
-
// forwarded — as a trailing arg after `run <task>`, pnpm hands it straight
|
|
618
|
-
// to the underlying script rather than treating it as its own flag.
|
|
619
|
-
if (all || !shouldAsk(rest)) {
|
|
620
|
-
const { filters, rest: cleanRest } = extractFilters(rest);
|
|
621
|
-
return dispatch(task, filters, cleanRest, tierEnv);
|
|
622
|
-
}
|
|
623
|
-
const apps = appsWith(task);
|
|
624
|
-
// Nothing to choose between: one app, or none that define this task (pnpm
|
|
625
|
-
// will say so better than a picker with a single option would).
|
|
626
|
-
if (apps.length < 2)
|
|
627
|
-
return dispatch(task, [], rest, tierEnv);
|
|
628
|
-
const previous = remembered(task);
|
|
629
|
-
const chosen = await multiselect({
|
|
630
|
-
// The `--all` escape is named in the message rather than offered as an
|
|
631
|
-
// option. An "everything" entry used to sit alongside the apps; clack's
|
|
632
|
-
// toggle-all `a` replaces most of what it was for, but not all of it. `a`
|
|
633
|
-
// selects every app in THIS list, which is `apps/*`; `--all` passes no
|
|
634
|
-
// filter at all, which is every package in the workspace.
|
|
635
|
-
//
|
|
636
|
-
// For `build` those nearly coincide, since filtering to an app pulls its
|
|
637
|
-
// dependencies in through the deps-of build step. For `test`, `lint` and
|
|
638
|
-
// `typecheck` they do not: those tasks only run against the apps
|
|
639
|
-
// themselves, not their dependencies, so filtering to the four apps runs
|
|
640
|
-
// four test tasks while an unfiltered run covers every package. Selecting
|
|
641
|
-
// every app and expecting a workspace-wide test run would quietly skip
|
|
642
|
-
// every suite in `packages/*`.
|
|
643
|
-
message: `\`${task}\` — which apps? (a selects all; --all runs every package)`,
|
|
644
|
-
options: apps.map((app) => ({
|
|
645
|
-
value: app.name,
|
|
646
|
-
label: app.name,
|
|
647
|
-
// The actual command, so the choice is made against what runs, not a name.
|
|
648
|
-
hint: app.script.length > 58 ? `${app.script.slice(0, 57)}…` : app.script,
|
|
649
|
-
})),
|
|
650
|
-
// Only what was picked last time, and only names still on offer, which
|
|
651
|
-
// also drops the retired "everything" entry from an older cache rather
|
|
652
|
-
// than preselecting a value nothing would match. Nothing is preselected on
|
|
653
|
-
// a first run, so with `required` the first answer is a real choice rather
|
|
654
|
-
// than an Enter through a default.
|
|
655
|
-
initialValues: previous.filter((name) => apps.some((app) => app.name === name)),
|
|
656
|
-
required: true,
|
|
657
|
-
});
|
|
658
|
-
if (isCancel(chosen)) {
|
|
659
|
-
cancel("Nothing ran.");
|
|
660
|
-
process.exit(0);
|
|
661
|
-
}
|
|
662
|
-
remember(task, chosen);
|
|
663
|
-
return dispatch(task, chosen, rest, tierEnv);
|
|
664
|
-
}
|
package/dist/setup.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function runSetup(): Promise<void>;
|