@pithy-sh/cli 0.1.0
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/LICENSE +21 -0
- package/package.json +72 -0
- package/scripts/templateManifest.ts +49 -0
- package/scripts/tsconfig.json +26 -0
- package/scripts/vendorTemplate.ts +84 -0
- package/scripts/verifyPack.ts +88 -0
- package/src/audit/cliAudit.ts +406 -0
- package/src/bin.ts +111 -0
- package/src/capabilities/add.ts +288 -0
- package/src/capabilities/addBootstrap.ts +275 -0
- package/src/capabilities/catalog.ts +175 -0
- package/src/capabilities/compose.ts +39 -0
- package/src/capabilities/configConstants.ts +74 -0
- package/src/capabilities/configImports.ts +397 -0
- package/src/capabilities/eject.ts +331 -0
- package/src/capabilities/emailProvisioner.ts +346 -0
- package/src/capabilities/entitlementGap.ts +70 -0
- package/src/capabilities/entryExports.ts +162 -0
- package/src/capabilities/flow.ts +550 -0
- package/src/capabilities/hostRegistry.ts +368 -0
- package/src/capabilities/loadFailure.ts +208 -0
- package/src/capabilities/manifests.ts +238 -0
- package/src/capabilities/mediaProvisioner.ts +471 -0
- package/src/capabilities/mintSecrets.ts +306 -0
- package/src/capabilities/paymentsProvisioner.ts +207 -0
- package/src/capabilities/prerequisites.ts +168 -0
- package/src/capabilities/r2Bucket.ts +113 -0
- package/src/capabilities/reconcile.ts +1483 -0
- package/src/capabilities/remove.ts +597 -0
- package/src/capabilities/requiredOptions.ts +92 -0
- package/src/capabilities/rotateSecrets.ts +305 -0
- package/src/capabilities/secrets.ts +178 -0
- package/src/capabilities/secretsDispatcher.ts +29 -0
- package/src/capabilities/secretsProvisioner.ts +389 -0
- package/src/capabilities/storageProvisioner.ts +414 -0
- package/src/capabilities/supportProvisioner.ts +515 -0
- package/src/capabilities/testersLoader.ts +52 -0
- package/src/capabilities/testersProvisioner.ts +236 -0
- package/src/capabilities/turnstileProvisioner.ts +347 -0
- package/src/capabilities/vectorProvisioner.ts +260 -0
- package/src/ci/fileModes.ts +223 -0
- package/src/ci/sourceFiles.ts +200 -0
- package/src/ci/workflowDrivers.ts +524 -0
- package/src/cloudflare/accountAnswer.ts +110 -0
- package/src/cloudflare/config.ts +685 -0
- package/src/cloudflare/storeId.ts +129 -0
- package/src/commands/add.ts +372 -0
- package/src/commands/alias.ts +205 -0
- package/src/commands/dashboard.ts +651 -0
- package/src/commands/deploy.ts +150 -0
- package/src/commands/dev.ts +37 -0
- package/src/commands/doctor.ts +2059 -0
- package/src/commands/email.ts +425 -0
- package/src/commands/env.ts +155 -0
- package/src/commands/feature.ts +359 -0
- package/src/commands/init.ts +538 -0
- package/src/commands/media.ts +303 -0
- package/src/commands/migrate.ts +129 -0
- package/src/commands/payments.ts +336 -0
- package/src/commands/provision.ts +368 -0
- package/src/commands/remove.ts +151 -0
- package/src/commands/secrets.ts +652 -0
- package/src/commands/seed.ts +229 -0
- package/src/commands/storage.ts +309 -0
- package/src/commands/support.ts +331 -0
- package/src/commands/testers.ts +1020 -0
- package/src/commands/token.ts +364 -0
- package/src/commands/turnstile.ts +271 -0
- package/src/commands/ui.ts +222 -0
- package/src/commands/upgrade.ts +517 -0
- package/src/commands/vector.ts +390 -0
- package/src/commands/worker.ts +295 -0
- package/src/dashboard/api.ts +323 -0
- package/src/dashboard/connect.ts +758 -0
- package/src/dashboard/contract.ts +289 -0
- package/src/dashboard/grant.ts +124 -0
- package/src/dashboard/registry.ts +519 -0
- package/src/dashboard/resolveTarget.ts +119 -0
- package/src/dev/delivery.ts +174 -0
- package/src/dev/devLogin.ts +155 -0
- package/src/dev/devLoginTargets.ts +91 -0
- package/src/dev/env.ts +206 -0
- package/src/dev/hostWorkers.ts +290 -0
- package/src/dev/keys.ts +111 -0
- package/src/dev/logging.ts +87 -0
- package/src/dev/openUrl.ts +75 -0
- package/src/dev/orchestrator.ts +1014 -0
- package/src/dev/ports.ts +220 -0
- package/src/dev/readyWatch.ts +142 -0
- package/src/dev/state.ts +90 -0
- package/src/devSecrets/bootstrapVars.ts +265 -0
- package/src/devSecrets/devVars.ts +240 -0
- package/src/devSecrets/edit.ts +256 -0
- package/src/devSecrets/file.ts +277 -0
- package/src/devSecrets/generate.ts +428 -0
- package/src/devSecrets/location.ts +80 -0
- package/src/devSecrets/mode.ts +71 -0
- package/src/devSecrets/records.ts +30 -0
- package/src/devSecrets/report.ts +99 -0
- package/src/devSecrets/seed.ts +344 -0
- package/src/devSecrets/store.ts +262 -0
- package/src/devSecrets/targets.ts +204 -0
- package/src/dispatch.ts +147 -0
- package/src/docs/catalog.ts +246 -0
- package/src/docs/writeCatalog.ts +45 -0
- package/src/doctor/cloudflare.ts +287 -0
- package/src/doctor/devPreferences.ts +155 -0
- package/src/doctor/devSecrets.ts +464 -0
- package/src/doctor/devVars.ts +414 -0
- package/src/doctor/devVarsLocal.ts +138 -0
- package/src/doctor/environments.ts +155 -0
- package/src/doctor/health.ts +354 -0
- package/src/doctor/localDelivery.ts +91 -0
- package/src/doctor/portsRegistry.ts +252 -0
- package/src/doctor/projectName.ts +584 -0
- package/src/doctor/secretBindings.ts +166 -0
- package/src/doctor/settings.ts +274 -0
- package/src/doctor/settingsSources.ts +202 -0
- package/src/doctor/workerName.ts +174 -0
- package/src/doctor/wranglerVars.ts +33 -0
- package/src/feature/bindings.ts +93 -0
- package/src/feature/create.ts +179 -0
- package/src/feature/destroy.ts +160 -0
- package/src/feature/devConfig.ts +201 -0
- package/src/feature/identity.ts +100 -0
- package/src/feature/manifest.ts +132 -0
- package/src/feature/ports.ts +615 -0
- package/src/feature/provision.ts +362 -0
- package/src/feature/sync.ts +148 -0
- package/src/feature/worktree.ts +282 -0
- package/src/help/groups.ts +47 -0
- package/src/help/rootUsage.ts +135 -0
- package/src/main.ts +73 -0
- package/src/migrations/ledger.ts +129 -0
- package/src/migrations/registry.ts +47 -0
- package/src/migrations/run.ts +1066 -0
- package/src/notifier/check.ts +129 -0
- package/src/notifier/installer.ts +48 -0
- package/src/notifier/notify.ts +152 -0
- package/src/notifier/state.ts +248 -0
- package/src/notifier/version.ts +59 -0
- package/src/platform/editor.ts +333 -0
- package/src/platform/rc.ts +118 -0
- package/src/platform/shell.ts +83 -0
- package/src/project/appBindings.ts +184 -0
- package/src/project/appWorkflows.ts +266 -0
- package/src/project/applyDomains.ts +166 -0
- package/src/project/askDomains.ts +220 -0
- package/src/project/atomic.ts +466 -0
- package/src/project/bindingEntries.ts +425 -0
- package/src/project/config.ts +701 -0
- package/src/project/dashboard.ts +118 -0
- package/src/project/deploy.ts +364 -0
- package/src/project/devVars.ts +113 -0
- package/src/project/domainPrompt.ts +191 -0
- package/src/project/domains.ts +386 -0
- package/src/project/envInventory.ts +356 -0
- package/src/project/environment.ts +125 -0
- package/src/project/extensions.ts +69 -0
- package/src/project/jsonc.ts +289 -0
- package/src/project/packageManager.ts +238 -0
- package/src/project/readOptionalFile.ts +342 -0
- package/src/project/rollback.ts +145 -0
- package/src/project/scaffold.ts +1088 -0
- package/src/project/templateFiles.ts +53 -0
- package/src/project/verifyDeploy.ts +230 -0
- package/src/project/versionMetadata.ts +77 -0
- package/src/project/workerAddress.ts +176 -0
- package/src/project/workerCommand.ts +564 -0
- package/src/project/workerIdentity.ts +50 -0
- package/src/project/workerManifest.ts +135 -0
- package/src/project/workerScaffold.ts +289 -0
- package/src/project/workerScope.ts +394 -0
- package/src/project/workers.ts +86 -0
- package/src/project/workflows.ts +281 -0
- package/src/project/wrangler.ts +168 -0
- package/src/provision/confirm.ts +86 -0
- package/src/provision/environment.ts +407 -0
- package/src/provision/featureConfig.ts +98 -0
- package/src/provision/mode.ts +62 -0
- package/src/provision/pendingSecrets.ts +96 -0
- package/src/provision/resources.ts +126 -0
- package/src/provision/secretBindings.ts +149 -0
- package/src/provision/store.ts +33 -0
- package/src/provision/unprovisioned.ts +114 -0
- package/src/provision/wranglerEnv.ts +220 -0
- package/src/rootFlags.ts +48 -0
- package/src/seed/drivers.ts +423 -0
- package/src/seed/media.ts +187 -0
- package/src/seed/plan.ts +137 -0
- package/src/seed/prepare.ts +224 -0
- package/src/seed/registry.ts +25 -0
- package/src/seed/run.ts +793 -0
- package/src/seed/safety.ts +206 -0
- package/src/terminal/logger.ts +42 -0
- package/src/terminal/output.ts +64 -0
- package/src/terminal/style.ts +132 -0
- package/src/test-utils/doctorHarness.ts +190 -0
- package/src/test-utils/migrateHarness.ts +126 -0
- package/src/test-utils/seedHarness.ts +173 -0
- package/src/test-utils/tempRepo.ts +45 -0
- package/src/tokens/config.ts +16 -0
- package/src/tokens/engine.ts +345 -0
- package/src/tokens/mintedTokens.ts +233 -0
- package/src/tokens/sinks.ts +84 -0
- package/src/ui/flow.ts +451 -0
- package/src/ui/react.ts +112 -0
- package/src/ui/routeAllowlist.ts +208 -0
- package/src/ui/scaffold.ts +113 -0
- package/src/ui/screenStyles.ts +127 -0
- package/src/ui/stubs.ts +135 -0
- package/src/ui/templates.ts +52 -0
- package/src/ui/wire.ts +311 -0
- package/src/ui/workerUi.ts +172 -0
- package/templates/starter/.dev.secrets.example.jsonc +43 -0
- package/templates/starter/.dev.vars.example +30 -0
- package/templates/starter/apps/api/package.json +22 -0
- package/templates/starter/apps/api/pithy.config.ts +65 -0
- package/templates/starter/apps/api/pithy.worker.jsonc +11 -0
- package/templates/starter/apps/api/src/bindings.workers.test.ts +18 -0
- package/templates/starter/apps/api/src/cloudflare-test.d.ts +11 -0
- package/templates/starter/apps/api/src/index.ts +8 -0
- package/templates/starter/apps/api/tsconfig.json +26 -0
- package/templates/starter/apps/api/wrangler.jsonc +68 -0
- package/templates/starter/biome.template.jsonc +75 -0
- package/templates/starter/gitignore +37 -0
- package/templates/starter/package.json +28 -0
- package/templates/starter/pithy.config.ts +67 -0
- package/templates/starter/plugins/no-console.grit +25 -0
- package/templates/starter/plugins/no-process-io.grit +25 -0
- package/templates/starter/tsconfig.json +14 -0
- package/templates/starter/tsconfig.tools.json +30 -0
- package/templates/starter/vitest.config.ts +124 -0
- package/templates/starter/vitest.workers.config.ts +26 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
import { createProjectCliAudit } from "../audit/cliAudit";
|
|
6
|
+
import { type CloudflareAccountSelection, cloudflareEnv } from "../cloudflare/config";
|
|
7
|
+
import { readProjectLedger } from "../migrations/run";
|
|
8
|
+
import { projectCloudflareAccount } from "../project/config";
|
|
9
|
+
import { deployProject, deployVerificationFailed, pendingWarning, summarizeDeploy } from "../project/deploy";
|
|
10
|
+
import { assertOriginsDeclared } from "../project/domains";
|
|
11
|
+
import { optionalEnvArg, requireEnvironment } from "../project/environment";
|
|
12
|
+
import { assertWorkflowsBound } from "../project/workflows";
|
|
13
|
+
import { assertEnvironmentProvisioned } from "../provision/unprovisioned";
|
|
14
|
+
import { formatDone, formatJsonLine, withErrorReporting } from "../terminal/output";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How many migrations are unapplied for the target env — best-effort, never blocking. Deploy and
|
|
18
|
+
* migrate are orthogonal (deploy never migrates), so a config that can't load or a database it can't
|
|
19
|
+
* reach yields `undefined` (no warning) rather than failing the deploy.
|
|
20
|
+
*
|
|
21
|
+
* Deploy ships every Worker, so the count does too — it fans out over `apps/*` exactly as `pithy migrate`
|
|
22
|
+
* would. The warning is about the project's schema being behind, and a table any Worker owns is one this
|
|
23
|
+
* deploy's code may read.
|
|
24
|
+
*
|
|
25
|
+
* **Best-effort is not unattributed.** The count reaches a remote D1 for any `--env`, so it takes the
|
|
26
|
+
* same account the deploy beside it does. Omitting it resolved `<config>/cloudflare.json` while the
|
|
27
|
+
* deploy resolved the project's named account — one command, one run, two tenants, and a number about
|
|
28
|
+
* somebody else's schema printed as though it were this project's (#206, #226).
|
|
29
|
+
*/
|
|
30
|
+
async function pendingFor(
|
|
31
|
+
projectDir: string,
|
|
32
|
+
env: string,
|
|
33
|
+
account: CloudflareAccountSelection | null,
|
|
34
|
+
): Promise<number | undefined> {
|
|
35
|
+
try {
|
|
36
|
+
// Only the pending half here. A drifted ledger is a fault `pithy doctor` names and `pithy migrate`
|
|
37
|
+
// refuses on, and deploy never migrates — it reports how far the schema is behind, which stays a
|
|
38
|
+
// truthful number either way.
|
|
39
|
+
const ledger = await readProjectLedger({ projectDir, env, account });
|
|
40
|
+
// A partial read still warns, and the number it warns with is the one it established (#371). A sum
|
|
41
|
+
// over the databases that answered can only understate how far behind the project is, so it never
|
|
42
|
+
// raises a false alarm — and this line is warn-only. Which database went unread is `pithy doctor`'s
|
|
43
|
+
// sentence to say, in the report whose job is naming faults.
|
|
44
|
+
if (ledger.state === "partial") return ledger.counted.pending;
|
|
45
|
+
return ledger.state === "read" ? ledger.pending : undefined;
|
|
46
|
+
} catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The audit emitter for `pithy deploy`. Shipping code to an environment is exactly the kind of action
|
|
53
|
+
* an audit trail exists for, so every worker deploy — success or failure — is recorded when the project
|
|
54
|
+
* has audit wired. A bare `pithy deploy` (no `--env`) still targets the project's own app database, the
|
|
55
|
+
* same one `dev` reads (see `resolveAuditDatabaseId`), so the fallback lines up with the real target.
|
|
56
|
+
*/
|
|
57
|
+
async function buildAudit(projectDir: string, env: string, account: CloudflareAccountSelection | null) {
|
|
58
|
+
const vars = cloudflareEnv({ account });
|
|
59
|
+
// `audit` composed by any Worker means the project has a trail; deploy spans them all. Here `env` really
|
|
60
|
+
// is the environment acted on, so it is also the recorded origin.
|
|
61
|
+
return createProjectCliAudit({
|
|
62
|
+
projectDir,
|
|
63
|
+
accountId: vars.CLOUDFLARE_ACCOUNT_ID,
|
|
64
|
+
apiToken: vars.CLOUDFLARE_API_TOKEN,
|
|
65
|
+
env,
|
|
66
|
+
actedOn: env,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default defineCommand({
|
|
71
|
+
meta: { name: "deploy", description: "Deploy to Cloudflare Workers" },
|
|
72
|
+
args: {
|
|
73
|
+
env: optionalEnvArg("Target environment (omit for each worker's top-level config)"),
|
|
74
|
+
json: { type: "boolean", default: false, description: "Machine-readable output" },
|
|
75
|
+
},
|
|
76
|
+
run: ({ args }) =>
|
|
77
|
+
withErrorReporting(args.json, async () => {
|
|
78
|
+
// Optional here, and only here: a bare `pithy deploy` ships each worker's top-level stanza, which
|
|
79
|
+
// is not an environment at all. A value that *is* given is held to the same rule as everywhere else.
|
|
80
|
+
const env = args.env === undefined ? undefined : requireEnvironment(args.env);
|
|
81
|
+
const projectDir = process.cwd();
|
|
82
|
+
|
|
83
|
+
// The migration warning only makes sense against a concrete remote target. A bare `pithy deploy`
|
|
84
|
+
// ships each worker's top-level config, whose deployed schema is not the local dev D1 — so skip the
|
|
85
|
+
// check (and its REST round trip) unless an `--env` names the environment being deployed.
|
|
86
|
+
// The account first, before anything resolves a credential. It is read from the project's own
|
|
87
|
+
// config and passed to every step below, rather than left to whatever a later load happens to
|
|
88
|
+
// publish — a deploy that authenticates against the wrong tenant succeeds, and says nothing.
|
|
89
|
+
// Refuse before anything is built or spawned. A binding with no id fails *inside* wrangler, on a
|
|
90
|
+
// field the adopter never wrote, after `init`, `add`, `migrate` and `dev` have all succeeded —
|
|
91
|
+
// and with no hint that provisioning was a step they had missed (#240). Only for a named `--env`:
|
|
92
|
+
// a bare deploy ships the top-level stanza, whose ids `pithy dev` resolves from Miniflare.
|
|
93
|
+
if (env) await assertEnvironmentProvisioned(projectDir, env);
|
|
94
|
+
// And the other half of "is this environment ready to be real": does its config name every origin
|
|
95
|
+
// it will answer on (#253). Refused here for the same reason the binding check is — deploy knows
|
|
96
|
+
// the environment and the config, and this is the last moment before a staging Worker starts
|
|
97
|
+
// emailing real users magic links into production. Beside it rather than inside it because the two
|
|
98
|
+
// are different questions with different fixes; `assertOriginsDeclared` exempts a feature
|
|
99
|
+
// environment itself, which has no declared domain by design.
|
|
100
|
+
if (env) await assertOriginsDeclared(projectDir, env);
|
|
101
|
+
// And the third half of it, on the same evidence and at the same moment: does this environment's
|
|
102
|
+
// stanza bind what its Workers' app capabilities declare (#267)? `reconcileAppWorkflows` writes
|
|
103
|
+
// that table and `pithy worker sync` is its only caller, so an adopter who declared a job and
|
|
104
|
+
// never ran it shipped a Worker with no `workflows` entry and no `triggers.crons` — the binding
|
|
105
|
+
// fails on the first request, and the cron simply never fires and says nothing at all. Beside the
|
|
106
|
+
// origins gate rather than inside it for the same reason that one is beside the binding gate: a
|
|
107
|
+
// different question with a different fix, and a feature environment is exempt from this one too.
|
|
108
|
+
if (env) await assertWorkflowsBound(projectDir, env);
|
|
109
|
+
|
|
110
|
+
const account = await projectCloudflareAccount(projectDir);
|
|
111
|
+
// **The account is settled here, before anything best-effort runs (#236).** `pendingFor` swallows
|
|
112
|
+
// every failure on purpose — a database it cannot reach costs a warning line, not the deploy — and
|
|
113
|
+
// a pin the credentials contradict is not a reachability failure. Swallowed, it becomes
|
|
114
|
+
// `pendingMigrations: null`: an absence that reads as a fact. `cloudflareEnv` refuses it in the one
|
|
115
|
+
// sentence `pithy doctor` already reads out. A *missing* pair still passes, because `wrangler
|
|
116
|
+
// deploy` authenticates on its own OAuth login and always could.
|
|
117
|
+
cloudflareEnv({ account });
|
|
118
|
+
const pending = env ? await pendingFor(projectDir, env, account) : undefined;
|
|
119
|
+
const audit = await buildAudit(projectDir, env ?? "dev", account);
|
|
120
|
+
const deploys = await deployProject({ projectDir, account, env, audit });
|
|
121
|
+
// A deploy that shipped but is not the thing answering at the declared address is a failure too,
|
|
122
|
+
// and it fails the pipeline rather than printing a line nobody reads. Two shapes count: a
|
|
123
|
+
// *consistent* mismatch, and nothing answering at all (#264). A gradual rollout and a Worker that
|
|
124
|
+
// answered without a version are both inconclusive, and failing on either would train everyone to
|
|
125
|
+
// ignore the check.
|
|
126
|
+
const failed = deploys.some((deploy) => !deploy.ok) || deployVerificationFailed(deploys);
|
|
127
|
+
|
|
128
|
+
if (args.json) {
|
|
129
|
+
process.stdout.write(
|
|
130
|
+
`${formatJsonLine({
|
|
131
|
+
command: "deploy",
|
|
132
|
+
env: env ?? null,
|
|
133
|
+
pendingMigrations: pending ?? null,
|
|
134
|
+
workers: deploys,
|
|
135
|
+
})}\n`,
|
|
136
|
+
);
|
|
137
|
+
if (failed) process.exitCode = 1;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const warning = env ? pendingWarning(pending, env) : undefined;
|
|
142
|
+
if (warning) process.stdout.write(`${warning}\n`);
|
|
143
|
+
for (const deploy of deploys) process.stdout.write(`${summarizeDeploy(deploy)}\n`);
|
|
144
|
+
if (failed) {
|
|
145
|
+
process.exitCode = 1; // The per-worker failure lines are the report; exit non-zero for CI.
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
process.stdout.write(`${formatDone()}\n`);
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
import { startDev } from "../dev/orchestrator";
|
|
6
|
+
import { formatJsonLine, withErrorReporting } from "../terminal/output";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `pithy dev` — run every autostart worker locally under one supervisor.
|
|
10
|
+
*
|
|
11
|
+
* Discovers the workers from `apps/`, resolves each one's pinned port from `.dev.config.json` (verifying it
|
|
12
|
+
* is free, never drifting), spawns them as process groups, tees their labeled output to the terminal and
|
|
13
|
+
* `logs/dev.log`, and prints one ready banner. Ctrl-C (SIGINT) or SIGTERM tears the whole session down; any
|
|
14
|
+
* worker exiting brings the rest down with it. The real work lives in `startDev`; this stays thin.
|
|
15
|
+
*/
|
|
16
|
+
export default defineCommand({
|
|
17
|
+
meta: { name: "dev", description: "Run every worker locally under one supervisor" },
|
|
18
|
+
args: {
|
|
19
|
+
json: { type: "boolean", default: false, description: "Machine-readable output" },
|
|
20
|
+
},
|
|
21
|
+
run: ({ args }) =>
|
|
22
|
+
withErrorReporting(args.json, async () => {
|
|
23
|
+
const projectDir = process.cwd();
|
|
24
|
+
const handle = await startDev({ projectDir, json: args.json });
|
|
25
|
+
|
|
26
|
+
if (args.json) {
|
|
27
|
+
const workers = Object.fromEntries(handle.workers.map((w) => [w.name, { port: w.port, origin: w.origin }]));
|
|
28
|
+
process.stdout.write(`${formatJsonLine({ command: "dev", workers })}\n`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
process.once("SIGINT", () => void handle.shutdown("interrupted"));
|
|
32
|
+
process.once("SIGTERM", () => void handle.shutdown("terminated"));
|
|
33
|
+
|
|
34
|
+
await handle.closed;
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}),
|
|
37
|
+
});
|