@hoox-sh/hoox-cli 0.11.2 → 0.11.3
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 +2 -2
- package/bin/hoox.js +14 -0
- package/dist/index.js +218 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
> **Runtime requirement:** Bun ≥ 1.2. The bin shebang and bundle target are Bun-only; `npm install -g` will install the package but the CLI will not run under Node.js.
|
|
8
8
|
|
|
9
|
-
**v0.
|
|
9
|
+
**v0.11.x** — operator security plane (`doctor --security`, `tunnel check`, transport profile Bearer + Access), PYNE edge ops (`hoox pyne`), schema validate/generate, and wrangler **4.x**. **v0.10.x** hardened fail-closed remote TUI / management `/v1/*`. **v0.9.x** shipped hop-level `perf fastpath` observability.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
- **Repair & Recovery** (`hoox repair`): Comprehensive system check, guided rebuild, per-component repair.
|
|
25
25
|
- **Top-level Secrets & Keys**: `hoox secrets` and `hoox keys` for Cloudflare Worker secrets and internal auth keys.
|
|
26
26
|
- **Unified Dashboard** (`hoox dashboard dev | deploy`): Start the dev server or build & deploy the Next.js dashboard.
|
|
27
|
-
- **Interactive menu & TUI**: Running `hoox` with no arguments opens the interactive menu
|
|
27
|
+
- **Interactive menu & TUI**: Running `hoox` with **no arguments**: if `wrangler.jsonc` is missing, auto-runs `onboard` (or `onboard --resume` when `.wizard-state.json` exists); otherwise opens the interactive menu. `hoox tui` launches the full OpenTUI operations center.
|
|
28
28
|
- **Operator security plane** (`hoox doctor`, `hoox tunnel`): Path/TUI hygiene, fail-closed remote transport (Bearer + Access), and private-ingress checks.
|
|
29
29
|
- **Modern-minimal output**: Zinc/indigo palette, completion footer with “next step” suggestions, “did you mean …” for typos, custom help formatter, `--no-color` / `NO_COLOR` / `TERM=dumb`, compact `formatNumber` / `formatBytes`. Shared `format*` helpers available to plugin authors.
|
|
30
30
|
- **Shell Completions**: bash, zsh, and fish completion scripts via `hoox completion <shell>`.
|
package/bin/hoox.js
CHANGED
|
@@ -24,6 +24,20 @@
|
|
|
24
24
|
* when the module is loaded as a side effect from here.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
// Runtime guard before any dynamic import: Node users (wrong shebang, or
|
|
28
|
+
// `node bin/hoox.js`) get a clear message instead of ESM resolution stacks.
|
|
29
|
+
// The same check lives in src/index.ts for direct source entry; this one
|
|
30
|
+
// covers the bin path when Node loads this file without Bun globals.
|
|
31
|
+
if (typeof globalThis.Bun === "undefined") {
|
|
32
|
+
process.stderr.write(
|
|
33
|
+
"Error: the Hoox CLI requires Bun >= 1.2 to run.\n" +
|
|
34
|
+
" Install Bun: curl -fsSL https://bun.sh | bash\n" +
|
|
35
|
+
" Then run: bunx hoox <command>\n" +
|
|
36
|
+
" (npm install -g / node bin/hoox.js will not work.)\n"
|
|
37
|
+
);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
import { existsSync, statSync, readdirSync } from "node:fs";
|
|
28
42
|
import { fileURLToPath } from "node:url";
|
|
29
43
|
import { dirname, resolve, join } from "node:path";
|
package/dist/index.js
CHANGED
|
@@ -25067,7 +25067,7 @@ class ConfigService {
|
|
|
25067
25067
|
const e = result.error;
|
|
25068
25068
|
switch (e.code) {
|
|
25069
25069
|
case "not-found":
|
|
25070
|
-
throw new Error(e.triedFallback ? `Config file not found: ${e.path}. Also tried: ${e.triedFallback}. Run 'hoox
|
|
25070
|
+
throw new Error(e.triedFallback ? `Config file not found: ${e.path}. Also tried: ${e.triedFallback}. Run 'hoox onboard' (or 'hoox init') to create one.` : `Config file not found: ${e.path}. Run 'hoox onboard' (or 'hoox init') to create one.`);
|
|
25071
25071
|
case "invalid-jsonc":
|
|
25072
25072
|
throw new Error(`Invalid JSONC in ${e.path}:
|
|
25073
25073
|
${e.errors.map((m3) => ` - ${m3}`).join(`
|
|
@@ -25891,6 +25891,7 @@ class UpdateService {
|
|
|
25891
25891
|
}
|
|
25892
25892
|
async checkAndPromptUpdate(options) {
|
|
25893
25893
|
const silent = options?.silent === true;
|
|
25894
|
+
const yes = options?.yes === true;
|
|
25894
25895
|
try {
|
|
25895
25896
|
const versionCheck = await this.prereqs.checkWranglerVersion();
|
|
25896
25897
|
if (!versionCheck.outdated) {
|
|
@@ -25900,6 +25901,9 @@ class UpdateService {
|
|
|
25900
25901
|
}
|
|
25901
25902
|
return { updated: false };
|
|
25902
25903
|
}
|
|
25904
|
+
if (silent && !yes) {
|
|
25905
|
+
return { updated: false };
|
|
25906
|
+
}
|
|
25903
25907
|
const current2 = versionCheck.current ?? "unknown";
|
|
25904
25908
|
const minimum = versionCheck.minimum ?? "unknown";
|
|
25905
25909
|
const latest2 = await this.checkLatestVersion();
|
|
@@ -26140,7 +26144,7 @@ var exports_schema_service = {};
|
|
|
26140
26144
|
__export(exports_schema_service, {
|
|
26141
26145
|
SchemaService: () => SchemaService
|
|
26142
26146
|
});
|
|
26143
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
26147
|
+
import { readFileSync as readFileSync5, existsSync as existsSync11 } from "fs";
|
|
26144
26148
|
import { resolve as resolve4 } from "path";
|
|
26145
26149
|
|
|
26146
26150
|
class SchemaService {
|
|
@@ -26174,7 +26178,7 @@ class SchemaService {
|
|
|
26174
26178
|
const workerWranglerPath = resolve4(workersDir, name, "wrangler.jsonc");
|
|
26175
26179
|
const devVarsPath = resolve4(workersDir, name, ".dev.vars");
|
|
26176
26180
|
const errors4 = [];
|
|
26177
|
-
const isHooxProject =
|
|
26181
|
+
const isHooxProject = existsSync11(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync11(resolve4(this.projectRoot, "workers"));
|
|
26178
26182
|
try {
|
|
26179
26183
|
const wranglerContent = readFileSync5(workerWranglerPath, "utf-8");
|
|
26180
26184
|
errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
|
|
@@ -28979,7 +28983,12 @@ function captureHelpEvent(cmd, eventName) {
|
|
|
28979
28983
|
// src/utils/completion.ts
|
|
28980
28984
|
var SUGGEST_NEXT = {
|
|
28981
28985
|
init: { command: "hoox setup", reason: "provision infrastructure" },
|
|
28982
|
-
|
|
28986
|
+
onboard: { command: "hoox check setup", reason: "verify bootstrap" },
|
|
28987
|
+
setup: { command: "hoox check setup", reason: "verify infrastructure" },
|
|
28988
|
+
"check setup": {
|
|
28989
|
+
command: "hoox deploy all",
|
|
28990
|
+
reason: "ship workers to Cloudflare"
|
|
28991
|
+
},
|
|
28983
28992
|
"deploy all": { command: "hoox check health", reason: "verify the deploy" },
|
|
28984
28993
|
"check health": {
|
|
28985
28994
|
command: "hoox monitor trades",
|
|
@@ -29014,6 +29023,7 @@ function getCmdPath(cmd) {
|
|
|
29014
29023
|
// src/commands/init/init-command.ts
|
|
29015
29024
|
init_dist4();
|
|
29016
29025
|
init_src();
|
|
29026
|
+
import * as fs2 from "fs";
|
|
29017
29027
|
|
|
29018
29028
|
// src/services/cloudflare/index.ts
|
|
29019
29029
|
init_cloudflare_service();
|
|
@@ -29080,21 +29090,32 @@ class CLIProvisioner {
|
|
|
29080
29090
|
|
|
29081
29091
|
// src/commands/init/init-command.ts
|
|
29082
29092
|
async function verifyRepoRoot() {
|
|
29083
|
-
const rootConfig = Bun.file("wrangler.jsonc");
|
|
29084
29093
|
const cliPackage = Bun.file("packages/cli/package.json");
|
|
29085
|
-
const
|
|
29086
|
-
|
|
29087
|
-
|
|
29094
|
+
const wranglerExample = Bun.file("wrangler.jsonc.example");
|
|
29095
|
+
const wranglerConfig = Bun.file("wrangler.jsonc");
|
|
29096
|
+
const gitmodules = Bun.file(".gitmodules");
|
|
29097
|
+
const [
|
|
29098
|
+
cliPackageExists,
|
|
29099
|
+
wranglerExampleExists,
|
|
29100
|
+
wranglerConfigExists,
|
|
29101
|
+
gitmodulesExists
|
|
29102
|
+
] = await Promise.all([
|
|
29103
|
+
cliPackage.exists(),
|
|
29104
|
+
wranglerExample.exists(),
|
|
29105
|
+
wranglerConfig.exists(),
|
|
29106
|
+
gitmodules.exists()
|
|
29088
29107
|
]);
|
|
29089
|
-
|
|
29108
|
+
const workersDirExists = fs2.existsSync("workers");
|
|
29109
|
+
const hasRepoSignal = wranglerExampleExists || wranglerConfigExists || workersDirExists || gitmodulesExists;
|
|
29110
|
+
if (cliPackageExists && hasRepoSignal)
|
|
29090
29111
|
return;
|
|
29091
29112
|
const reasons = [];
|
|
29092
|
-
if (!rootConfigExists) {
|
|
29093
|
-
reasons.push("no root `wrangler.jsonc` found in the current directory");
|
|
29094
|
-
}
|
|
29095
29113
|
if (!cliPackageExists) {
|
|
29096
29114
|
reasons.push("no `packages/cli` workspace found (this is not the hoox monorepo)");
|
|
29097
29115
|
}
|
|
29116
|
+
if (cliPackageExists && !hasRepoSignal) {
|
|
29117
|
+
reasons.push("missing Hoox repo markers (expected one of: `wrangler.jsonc.example`, `wrangler.jsonc`, `workers/`, or `.gitmodules`)");
|
|
29118
|
+
}
|
|
29098
29119
|
const cloneHint = " Clone first: git clone --recursive " + "https://github.com/hoox-sh/hoox.git";
|
|
29099
29120
|
throw new CLIError(`Not inside a Hoox repository root.
|
|
29100
29121
|
` + reasons.join(`
|
|
@@ -29267,7 +29288,10 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29267
29288
|
if (error51) {
|
|
29268
29289
|
formatError2(new CLIError(error51, 1 /* ERROR */), globalOpts);
|
|
29269
29290
|
process.exitCode = 1 /* ERROR */;
|
|
29291
|
+
return;
|
|
29270
29292
|
}
|
|
29293
|
+
process.env.CLOUDFLARE_API_TOKEN = token;
|
|
29294
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = account;
|
|
29271
29295
|
if (!globalOpts.quiet) {
|
|
29272
29296
|
formatSuccess("Cloudflare API token validated", globalOpts);
|
|
29273
29297
|
}
|
|
@@ -29305,6 +29329,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29305
29329
|
if (isCancel(resumed)) {
|
|
29306
29330
|
cancel("Setup cancelled.");
|
|
29307
29331
|
process.exitCode = 0;
|
|
29332
|
+
return;
|
|
29308
29333
|
}
|
|
29309
29334
|
if (!resumed) {
|
|
29310
29335
|
engine = null;
|
|
@@ -29324,10 +29349,12 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29324
29349
|
if (isCancel(accepted)) {
|
|
29325
29350
|
cancel("Setup cancelled.");
|
|
29326
29351
|
process.exitCode = 0;
|
|
29352
|
+
return;
|
|
29327
29353
|
}
|
|
29328
29354
|
if (!accepted) {
|
|
29329
29355
|
outro("Setup cancelled. See DISCLAIMER.md for full terms.");
|
|
29330
29356
|
process.exitCode = 0;
|
|
29357
|
+
return;
|
|
29331
29358
|
}
|
|
29332
29359
|
}
|
|
29333
29360
|
engine.execute({ checksPassed: true });
|
|
@@ -29349,6 +29376,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29349
29376
|
if (isCancel(apiToken)) {
|
|
29350
29377
|
cancel("Setup cancelled.");
|
|
29351
29378
|
process.exitCode = 0;
|
|
29379
|
+
return;
|
|
29352
29380
|
}
|
|
29353
29381
|
log.step("Validating Cloudflare API token...");
|
|
29354
29382
|
const tokenError = await validateApiToken(cf, apiToken);
|
|
@@ -29357,6 +29385,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29357
29385
|
log.warn("Please check your token and try again.");
|
|
29358
29386
|
} else {
|
|
29359
29387
|
tokenValid = true;
|
|
29388
|
+
process.env.CLOUDFLARE_API_TOKEN = apiToken;
|
|
29360
29389
|
formatSuccess("Cloudflare API token validated", globalOpts);
|
|
29361
29390
|
}
|
|
29362
29391
|
}
|
|
@@ -29377,6 +29406,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29377
29406
|
if (isCancel(accountResult)) {
|
|
29378
29407
|
cancel("Setup cancelled.");
|
|
29379
29408
|
process.exitCode = 0;
|
|
29409
|
+
return;
|
|
29380
29410
|
}
|
|
29381
29411
|
const secretStoreResult = await text({
|
|
29382
29412
|
message: "Cloudflare Secret Store ID:",
|
|
@@ -29386,6 +29416,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29386
29416
|
if (isCancel(secretStoreResult)) {
|
|
29387
29417
|
cancel("Setup cancelled.");
|
|
29388
29418
|
process.exitCode = 0;
|
|
29419
|
+
return;
|
|
29389
29420
|
}
|
|
29390
29421
|
const prefixResult = await text({
|
|
29391
29422
|
message: "Subdomain prefix:",
|
|
@@ -29400,7 +29431,9 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29400
29431
|
if (isCancel(prefixResult)) {
|
|
29401
29432
|
cancel("Setup cancelled.");
|
|
29402
29433
|
process.exitCode = 0;
|
|
29434
|
+
return;
|
|
29403
29435
|
}
|
|
29436
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = accountResult;
|
|
29404
29437
|
engine.execute({
|
|
29405
29438
|
apiToken,
|
|
29406
29439
|
accountId: accountResult,
|
|
@@ -29433,6 +29466,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29433
29466
|
if (isCancel(presetChoice)) {
|
|
29434
29467
|
cancel("Setup cancelled.");
|
|
29435
29468
|
process.exitCode = 0;
|
|
29469
|
+
return;
|
|
29436
29470
|
}
|
|
29437
29471
|
engine.execute({ preset: presetChoice });
|
|
29438
29472
|
await saveState(engine);
|
|
@@ -29456,6 +29490,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29456
29490
|
if (isCancel(shouldProvision)) {
|
|
29457
29491
|
cancel("Setup cancelled.");
|
|
29458
29492
|
process.exitCode = 0;
|
|
29493
|
+
return;
|
|
29459
29494
|
}
|
|
29460
29495
|
if (shouldProvision) {
|
|
29461
29496
|
log.step("Provisioning infrastructure...");
|
|
@@ -29505,6 +29540,9 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29505
29540
|
process.exitCode = 0;
|
|
29506
29541
|
}
|
|
29507
29542
|
});
|
|
29543
|
+
if (isCancel(collected)) {
|
|
29544
|
+
return;
|
|
29545
|
+
}
|
|
29508
29546
|
collectedSecrets[key] = {};
|
|
29509
29547
|
for (const [secretName] of secretEntries) {
|
|
29510
29548
|
const val = collected[secretName];
|
|
@@ -29532,6 +29570,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29532
29570
|
if (isCancel(shouldDeploy)) {
|
|
29533
29571
|
cancel("Setup cancelled.");
|
|
29534
29572
|
process.exitCode = 0;
|
|
29573
|
+
return;
|
|
29535
29574
|
}
|
|
29536
29575
|
if (shouldDeploy) {
|
|
29537
29576
|
log.step("Deploying workers...");
|
|
@@ -29547,7 +29586,8 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29547
29586
|
}
|
|
29548
29587
|
// src/services/setup/setup-service.ts
|
|
29549
29588
|
import {
|
|
29550
|
-
|
|
29589
|
+
chmodSync as chmodSync3,
|
|
29590
|
+
existsSync as existsSync7,
|
|
29551
29591
|
mkdirSync as mkdirSync3,
|
|
29552
29592
|
readFileSync as readFileSync3,
|
|
29553
29593
|
statSync as statSync2,
|
|
@@ -29607,6 +29647,25 @@ var KEYS_DIR = ".keys";
|
|
|
29607
29647
|
function escapeRegex2(s) {
|
|
29608
29648
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29609
29649
|
}
|
|
29650
|
+
function parseEnvFile(text2) {
|
|
29651
|
+
const map2 = new Map;
|
|
29652
|
+
for (const line of text2.split(`
|
|
29653
|
+
`)) {
|
|
29654
|
+
const trimmed = line.trim();
|
|
29655
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
29656
|
+
continue;
|
|
29657
|
+
const eq = trimmed.indexOf("=");
|
|
29658
|
+
if (eq <= 0)
|
|
29659
|
+
continue;
|
|
29660
|
+
map2.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));
|
|
29661
|
+
}
|
|
29662
|
+
return map2;
|
|
29663
|
+
}
|
|
29664
|
+
function safeChmod(path4, mode) {
|
|
29665
|
+
try {
|
|
29666
|
+
chmodSync3(path4, mode);
|
|
29667
|
+
} catch {}
|
|
29668
|
+
}
|
|
29610
29669
|
|
|
29611
29670
|
class SetupService {
|
|
29612
29671
|
onProgress;
|
|
@@ -29635,35 +29694,53 @@ class SetupService {
|
|
|
29635
29694
|
TRADE_INTERNAL_KEY: internalKey,
|
|
29636
29695
|
API_SERVICE_KEY_BINDING: internalKey
|
|
29637
29696
|
};
|
|
29638
|
-
if (!
|
|
29697
|
+
if (!existsSync7(KEYS_DIR)) {
|
|
29639
29698
|
mkdirSync3(KEYS_DIR, { recursive: true });
|
|
29640
29699
|
} else if (!statSync2(KEYS_DIR).isDirectory()) {
|
|
29641
29700
|
mkdirSync3(KEYS_DIR, { recursive: true });
|
|
29642
29701
|
}
|
|
29702
|
+
safeChmod(KEYS_DIR, 448);
|
|
29703
|
+
const setupEnvPath = join7(KEYS_DIR, "setup.env");
|
|
29643
29704
|
const envLines = Object.entries(keys).map(([k, v]) => `${k}=${v}`);
|
|
29644
|
-
await Bun.write(
|
|
29705
|
+
await Bun.write(setupEnvPath, `# Hoox Setup \u2014 Auto-Generated Keys
|
|
29645
29706
|
` + "# Generated by `hoox setup`. NEVER commit this file.\n" + `# Created: ${new Date().toISOString()}
|
|
29646
29707
|
|
|
29647
29708
|
` + envLines.join(`
|
|
29648
29709
|
`) + `
|
|
29649
29710
|
`);
|
|
29711
|
+
safeChmod(setupEnvPath, 384);
|
|
29650
29712
|
for (const [name, value] of Object.entries(keys)) {
|
|
29651
|
-
|
|
29713
|
+
const keyPath = join7(KEYS_DIR, `${name.toLowerCase()}.env`);
|
|
29714
|
+
await Bun.write(keyPath, `${name}=${value}
|
|
29652
29715
|
`);
|
|
29716
|
+
safeChmod(keyPath, 384);
|
|
29653
29717
|
}
|
|
29654
29718
|
let devVarsCount = 0;
|
|
29655
29719
|
for (const [worker, secretNames] of Object.entries(DEV_VARS_WORKER_KEYS)) {
|
|
29656
29720
|
const path4 = `workers/${workerFsDir(worker)}/.dev.vars`;
|
|
29721
|
+
const meshNames = secretNames;
|
|
29722
|
+
const meshSet = new Set(meshNames);
|
|
29723
|
+
const existing = existsSync7(path4) ? parseEnvFile(readFileSync3(path4, "utf-8")) : new Map;
|
|
29724
|
+
for (const secretName of meshNames) {
|
|
29725
|
+
existing.set(secretName, keys[secretName]);
|
|
29726
|
+
}
|
|
29657
29727
|
let content = `# .dev.vars \u2014 local secrets for ${worker}
|
|
29658
29728
|
`;
|
|
29659
29729
|
content += `# Generated by \`hoox setup\`. NEVER commit this file.
|
|
29660
29730
|
|
|
29661
29731
|
`;
|
|
29662
|
-
for (const secretName of
|
|
29663
|
-
content += `${secretName}=${
|
|
29732
|
+
for (const secretName of meshNames) {
|
|
29733
|
+
content += `${secretName}=${existing.get(secretName)}
|
|
29664
29734
|
`;
|
|
29665
29735
|
}
|
|
29736
|
+
for (const [k, v] of existing) {
|
|
29737
|
+
if (!meshSet.has(k)) {
|
|
29738
|
+
content += `${k}=${v}
|
|
29739
|
+
`;
|
|
29740
|
+
}
|
|
29741
|
+
}
|
|
29666
29742
|
await Bun.write(path4, content);
|
|
29743
|
+
safeChmod(path4, 384);
|
|
29667
29744
|
devVarsCount++;
|
|
29668
29745
|
}
|
|
29669
29746
|
this.onProgress({
|
|
@@ -29992,7 +30069,7 @@ class SetupService {
|
|
|
29992
30069
|
join7(dir, "pyproject.toml"),
|
|
29993
30070
|
join7(dir, "wrangler.jsonc")
|
|
29994
30071
|
];
|
|
29995
|
-
return markers.some((p3) =>
|
|
30072
|
+
return markers.some((p3) => existsSync7(p3));
|
|
29996
30073
|
}
|
|
29997
30074
|
async ensureWorkers() {
|
|
29998
30075
|
this.onProgress({
|
|
@@ -30037,7 +30114,7 @@ class SetupService {
|
|
|
30037
30114
|
step: "workers",
|
|
30038
30115
|
message: `${missing.length} worker(s) not cloned: ${missing.join(", ")}`
|
|
30039
30116
|
});
|
|
30040
|
-
if (!
|
|
30117
|
+
if (!existsSync7(gitmodulesPath)) {
|
|
30041
30118
|
this.onProgress({
|
|
30042
30119
|
type: "step-error",
|
|
30043
30120
|
step: "workers",
|
|
@@ -30433,7 +30510,7 @@ class SetupService {
|
|
|
30433
30510
|
} else {
|
|
30434
30511
|
steps.push({ step: "d1-schema", success: true, message: "Skipped" });
|
|
30435
30512
|
}
|
|
30436
|
-
if (keys) {
|
|
30513
|
+
if (!options.skipSecrets && keys) {
|
|
30437
30514
|
const reconcile = await this.reconcileSecrets(keys);
|
|
30438
30515
|
if (reconcile.warnings.length > 0) {
|
|
30439
30516
|
for (const w of reconcile.warnings) {
|
|
@@ -30441,20 +30518,25 @@ class SetupService {
|
|
|
30441
30518
|
}
|
|
30442
30519
|
}
|
|
30443
30520
|
}
|
|
30444
|
-
|
|
30445
|
-
|
|
30446
|
-
|
|
30447
|
-
|
|
30448
|
-
|
|
30449
|
-
|
|
30450
|
-
|
|
30451
|
-
|
|
30452
|
-
|
|
30453
|
-
|
|
30454
|
-
|
|
30455
|
-
|
|
30456
|
-
|
|
30457
|
-
|
|
30521
|
+
if (options.skipSecrets) {
|
|
30522
|
+
steps.push({ step: "secrets", success: true, message: "Skipped" });
|
|
30523
|
+
results.secrets = [];
|
|
30524
|
+
} else {
|
|
30525
|
+
const secretResults = await this.setSecrets(keys);
|
|
30526
|
+
results.secrets = secretResults;
|
|
30527
|
+
const secretOk = secretResults.filter((r2) => r2.ok).length;
|
|
30528
|
+
const secretFail = secretResults.filter((r2) => !r2.ok).length;
|
|
30529
|
+
steps.push({
|
|
30530
|
+
step: "secrets",
|
|
30531
|
+
success: secretFail === 0,
|
|
30532
|
+
message: `${secretOk} set, ${secretFail} failed`,
|
|
30533
|
+
details: {
|
|
30534
|
+
total: secretResults.length,
|
|
30535
|
+
ok: secretOk,
|
|
30536
|
+
failed: secretFail
|
|
30537
|
+
}
|
|
30538
|
+
});
|
|
30539
|
+
}
|
|
30458
30540
|
const dashResult = await this.rebuildDashboard(options.skipDashboard);
|
|
30459
30541
|
steps.push(dashResult);
|
|
30460
30542
|
if (keys) {
|
|
@@ -30559,12 +30641,27 @@ async function runOnboard(options, fmt) {
|
|
|
30559
30641
|
acceptRisk: options.acceptRisk
|
|
30560
30642
|
};
|
|
30561
30643
|
await runInitCommand(initOpts, { json: fmt.json, quiet: fmt.quiet }, isNonInteractive);
|
|
30644
|
+
if (process.exitCode && process.exitCode !== 0) {
|
|
30645
|
+
return;
|
|
30646
|
+
}
|
|
30647
|
+
if (options.token) {
|
|
30648
|
+
process.env.CLOUDFLARE_API_TOKEN = options.token;
|
|
30649
|
+
}
|
|
30650
|
+
if (options.account) {
|
|
30651
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = options.account;
|
|
30652
|
+
}
|
|
30562
30653
|
if (!quiet) {
|
|
30563
30654
|
process.stdout.write(theme.heading(`
|
|
30564
30655
|
\u2501\u2501\u2501 Step 2/2: Setup (infrastructure bootstrap) \u2501\u2501\u2501
|
|
30565
30656
|
`));
|
|
30566
30657
|
}
|
|
30567
30658
|
const setupSvc = new SetupService;
|
|
30659
|
+
const authOk = await setupSvc.checkAuth();
|
|
30660
|
+
if (!authOk) {
|
|
30661
|
+
formatError2(new CLIError("Not authenticated with Cloudflare. Run 'wrangler login' first.", 1 /* ERROR */, undefined, false, "Run `wrangler login` interactively, or set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID environment variables for CI / non-interactive use."), fmt);
|
|
30662
|
+
process.exitCode = 1 /* ERROR */;
|
|
30663
|
+
return;
|
|
30664
|
+
}
|
|
30568
30665
|
const setupOpts = {
|
|
30569
30666
|
skipKeys: Boolean(options.skipKeys),
|
|
30570
30667
|
skipDb: Boolean(options.skipDb),
|
|
@@ -30576,14 +30673,14 @@ async function runOnboard(options, fmt) {
|
|
|
30576
30673
|
const result = await setupSvc.runAll(setupOpts);
|
|
30577
30674
|
if (result.success) {
|
|
30578
30675
|
if (!quiet) {
|
|
30579
|
-
formatSuccess("Bootstrap complete!
|
|
30676
|
+
formatSuccess("Bootstrap complete! Next: `hoox check setup` then `hoox deploy all`", fmt);
|
|
30580
30677
|
}
|
|
30581
30678
|
} else {
|
|
30582
|
-
formatError2(new CLIError("Bootstrap completed with issues. See logs above.", 1 /* ERROR
|
|
30679
|
+
formatError2(new CLIError("Bootstrap completed with issues. See logs above.", 1 /* ERROR */, undefined, false, "Retry with `hoox setup`, diagnose with `hoox check setup`, or run `hoox repair check`."), fmt);
|
|
30583
30680
|
process.exitCode = 1 /* ERROR */;
|
|
30584
30681
|
}
|
|
30585
30682
|
} catch (e) {
|
|
30586
|
-
formatError2(new CLIError(e instanceof Error ? e.message : String(e), 1 /* ERROR
|
|
30683
|
+
formatError2(new CLIError(e instanceof Error ? e.message : String(e), 1 /* ERROR */, undefined, false, "Retry with `hoox setup`, diagnose with `hoox check setup`, or run `hoox repair check`."), fmt);
|
|
30587
30684
|
process.exitCode = 1 /* ERROR */;
|
|
30588
30685
|
}
|
|
30589
30686
|
}
|
|
@@ -31101,7 +31198,7 @@ function renderDefaultSummary(results) {
|
|
|
31101
31198
|
init_errors4();
|
|
31102
31199
|
import {
|
|
31103
31200
|
statSync as statSync3,
|
|
31104
|
-
existsSync as
|
|
31201
|
+
existsSync as existsSync8,
|
|
31105
31202
|
readFileSync as readFileSync4,
|
|
31106
31203
|
writeFileSync as writeFileSync3,
|
|
31107
31204
|
renameSync
|
|
@@ -31536,7 +31633,7 @@ ${section}:
|
|
|
31536
31633
|
init_main();
|
|
31537
31634
|
function getDashboardBuildInfo(dashboardPath) {
|
|
31538
31635
|
const workerPath = resolve2(dashboardPath, ".open-next", "worker.js");
|
|
31539
|
-
if (!
|
|
31636
|
+
if (!existsSync8(workerPath)) {
|
|
31540
31637
|
return { exists: false };
|
|
31541
31638
|
}
|
|
31542
31639
|
const stats = statSync3(workerPath);
|
|
@@ -31879,7 +31976,7 @@ async function doUpdateInternalUrls(fmt) {
|
|
|
31879
31976
|
const prefix = global.subdomain_prefix ?? "hoox";
|
|
31880
31977
|
const workers = config2.listEnabledWorkers();
|
|
31881
31978
|
const filePath = resolve2(process.cwd(), "workers", "dashboard", "wrangler.jsonc");
|
|
31882
|
-
if (!
|
|
31979
|
+
if (!existsSync8(filePath)) {
|
|
31883
31980
|
formatError2(new CLIError("Dashboard wrangler.jsonc not found at workers/dashboard/wrangler.jsonc", 1 /* ERROR */), fmt);
|
|
31884
31981
|
process.exitCode = 1 /* ERROR */;
|
|
31885
31982
|
return;
|
|
@@ -33956,7 +34053,7 @@ EXAMPLES:
|
|
|
33956
34053
|
}
|
|
33957
34054
|
|
|
33958
34055
|
// src/commands/config/keys-subcommands.ts
|
|
33959
|
-
import { existsSync as
|
|
34056
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
33960
34057
|
init_theme();
|
|
33961
34058
|
function generateKey(bytes = 32) {
|
|
33962
34059
|
const buf = new Uint8Array(bytes);
|
|
@@ -33982,7 +34079,7 @@ EXAMPLES:
|
|
|
33982
34079
|
hoox config keys generate`).action(withErrorHandling(async (_2, cmd) => {
|
|
33983
34080
|
const opts = getFormatOptions(cmd);
|
|
33984
34081
|
const keysDir = ".keys";
|
|
33985
|
-
if (!
|
|
34082
|
+
if (!existsSync9(keysDir)) {
|
|
33986
34083
|
mkdirSync4(keysDir, { recursive: true });
|
|
33987
34084
|
}
|
|
33988
34085
|
const meshKey = generateKey();
|
|
@@ -34016,7 +34113,7 @@ EXAMPLES:
|
|
|
34016
34113
|
hoox config keys list`).action(withErrorHandling(async (_2, cmd) => {
|
|
34017
34114
|
const opts = getFormatOptions(cmd);
|
|
34018
34115
|
const keysDir = ".keys";
|
|
34019
|
-
if (!
|
|
34116
|
+
if (!existsSync9(keysDir)) {
|
|
34020
34117
|
process.stdout.write(`${theme.dim("No .keys/ directory found.")}
|
|
34021
34118
|
`);
|
|
34022
34119
|
return;
|
|
@@ -34657,7 +34754,7 @@ async function runSecretsChecks(secretsService, configService, cf) {
|
|
|
34657
34754
|
async function runDatabaseChecks(cf, configService) {
|
|
34658
34755
|
const checks3 = [];
|
|
34659
34756
|
const d1Worker = configService.getWorker("d1-worker");
|
|
34660
|
-
const dbName = d1Worker?.vars?.database_name ?? "
|
|
34757
|
+
const dbName = d1Worker?.vars?.database_name ?? "trade-data-db";
|
|
34661
34758
|
const d1ListResult = await cf.d1List();
|
|
34662
34759
|
if (d1ListResult.ok) {
|
|
34663
34760
|
const hasDb = d1ListResult.value.includes(dbName);
|
|
@@ -36282,7 +36379,7 @@ init_dist4();
|
|
|
36282
36379
|
// src/services/db/db-service.ts
|
|
36283
36380
|
init_config2();
|
|
36284
36381
|
init_cloudflare_service();
|
|
36285
|
-
import { existsSync as
|
|
36382
|
+
import { existsSync as existsSync10 } from "fs";
|
|
36286
36383
|
import { join as join9 } from "path";
|
|
36287
36384
|
var D1_WRANGLER_CONFIG_CANDIDATES = [
|
|
36288
36385
|
"workers/d1-worker/wrangler.jsonc",
|
|
@@ -36320,7 +36417,7 @@ class DbService {
|
|
|
36320
36417
|
if (vars?.database_name)
|
|
36321
36418
|
return vars.database_name;
|
|
36322
36419
|
} catch {}
|
|
36323
|
-
return "
|
|
36420
|
+
return "trade-data-db";
|
|
36324
36421
|
}
|
|
36325
36422
|
async apply(dbName, remote, schemaPath) {
|
|
36326
36423
|
const path6 = schemaPath ?? this.resolveDefaultSchemaPath();
|
|
@@ -36384,7 +36481,7 @@ class DbService {
|
|
|
36384
36481
|
if (this.wranglerConfigPath)
|
|
36385
36482
|
return this.wranglerConfigPath;
|
|
36386
36483
|
for (const candidate of D1_WRANGLER_CONFIG_CANDIDATES) {
|
|
36387
|
-
if (
|
|
36484
|
+
if (existsSync10(candidate))
|
|
36388
36485
|
return candidate;
|
|
36389
36486
|
}
|
|
36390
36487
|
return;
|
|
@@ -37479,8 +37576,7 @@ function registerSchemaCommand(program2) {
|
|
|
37479
37576
|
const svc = new SchemaService;
|
|
37480
37577
|
const manifest = svc.getManifest(worker);
|
|
37481
37578
|
if (!manifest) {
|
|
37482
|
-
|
|
37483
|
-
return;
|
|
37579
|
+
throw new CLIError(`Unknown worker "${worker}"`, 2 /* INVALID_USAGE */, undefined, false, `Known workers: ${svc.getWorkerNames().join(", ") || "(none)"}. Run: hoox schema list`);
|
|
37484
37580
|
}
|
|
37485
37581
|
const wranglerContent = generateWranglerJsonc(manifest);
|
|
37486
37582
|
const devVarsContent = generateDevVars(manifest);
|
|
@@ -37515,7 +37611,7 @@ import { spawn } from "child_process";
|
|
|
37515
37611
|
import { createRequire } from "module";
|
|
37516
37612
|
import { resolve as resolve6, dirname as dirname3, join as join10 } from "path";
|
|
37517
37613
|
import { fileURLToPath } from "url";
|
|
37518
|
-
import { existsSync as
|
|
37614
|
+
import { existsSync as existsSync12, realpathSync } from "fs";
|
|
37519
37615
|
import { homedir as homedir5 } from "os";
|
|
37520
37616
|
|
|
37521
37617
|
// src/services/perf/endpoint-resolver.ts
|
|
@@ -37579,7 +37675,7 @@ function collectTuiCandidates() {
|
|
|
37579
37675
|
return [...new Set(candidates)];
|
|
37580
37676
|
}
|
|
37581
37677
|
function pushPackageRootEntries(candidates, root) {
|
|
37582
|
-
if (!root || !
|
|
37678
|
+
if (!root || !existsSync12(root))
|
|
37583
37679
|
return;
|
|
37584
37680
|
candidates.push(join10(root, "dist", "main.js"), join10(root, "src", "main.tsx"), join10(root, "bin", "hoox-tui.js"), join10(root, "src", "main.ts"));
|
|
37585
37681
|
}
|
|
@@ -37607,7 +37703,7 @@ function pushFromWhich(candidates, binName) {
|
|
|
37607
37703
|
function resolveTUIEntry() {
|
|
37608
37704
|
const candidates = collectTuiCandidates();
|
|
37609
37705
|
for (const path6 of candidates) {
|
|
37610
|
-
if (
|
|
37706
|
+
if (existsSync12(path6))
|
|
37611
37707
|
return path6;
|
|
37612
37708
|
}
|
|
37613
37709
|
const runtime = resolveHooxRuntimeRoot();
|
|
@@ -37826,13 +37922,13 @@ import { homedir as homedir6 } from "os";
|
|
|
37826
37922
|
|
|
37827
37923
|
// src/services/runtime/runtime-service.ts
|
|
37828
37924
|
init_src();
|
|
37829
|
-
import { existsSync as
|
|
37925
|
+
import { existsSync as existsSync13, lstatSync as lstatSync2, readlinkSync, rmSync } from "fs";
|
|
37830
37926
|
import { mkdir } from "fs/promises";
|
|
37831
37927
|
import { join as join11 } from "path";
|
|
37832
37928
|
var DEFAULT_HOOX_RUNTIME_REPO = "https://github.com/hoox-sh/hoox.git";
|
|
37833
37929
|
function firstExisting(paths) {
|
|
37834
37930
|
for (const p3 of paths) {
|
|
37835
|
-
if (
|
|
37931
|
+
if (existsSync13(p3))
|
|
37836
37932
|
return p3;
|
|
37837
37933
|
}
|
|
37838
37934
|
return null;
|
|
@@ -37846,7 +37942,7 @@ function getRuntimeStatus(cwd = process.cwd()) {
|
|
|
37846
37942
|
repoPath,
|
|
37847
37943
|
runtime,
|
|
37848
37944
|
tuiEntry,
|
|
37849
|
-
repoPresent:
|
|
37945
|
+
repoPresent: existsSync13(repoPath),
|
|
37850
37946
|
isSetupRoot: isHooxSetupRoot(repoPath)
|
|
37851
37947
|
};
|
|
37852
37948
|
}
|
|
@@ -37868,7 +37964,7 @@ function isBrokenSymlink(path6) {
|
|
|
37868
37964
|
try {
|
|
37869
37965
|
if (!lstatSync2(path6).isSymbolicLink())
|
|
37870
37966
|
return false;
|
|
37871
|
-
return !
|
|
37967
|
+
return !existsSync13(path6);
|
|
37872
37968
|
} catch {
|
|
37873
37969
|
return false;
|
|
37874
37970
|
}
|
|
@@ -37881,7 +37977,7 @@ async function ensureGlobalRuntime(options = {}) {
|
|
|
37881
37977
|
await mkdir(hooxHome, { recursive: true });
|
|
37882
37978
|
let cloned = false;
|
|
37883
37979
|
if (!isHooxSetupRoot(repoPath)) {
|
|
37884
|
-
if (
|
|
37980
|
+
if (existsSync13(repoPath) || isBrokenSymlink(repoPath)) {
|
|
37885
37981
|
if (isBrokenSymlink(repoPath)) {
|
|
37886
37982
|
let target = "";
|
|
37887
37983
|
try {
|
|
@@ -37913,8 +38009,8 @@ ${clone2.stderr || clone2.stdout}`.trim());
|
|
|
37913
38009
|
if (!options.skipInstall) {
|
|
37914
38010
|
const nodeModules = join11(repoPath, "node_modules");
|
|
37915
38011
|
const tuiPkg = join11(repoPath, "packages", "tui", "package.json");
|
|
37916
|
-
const needsInstall = !
|
|
37917
|
-
if (cloned || needsInstall || !
|
|
38012
|
+
const needsInstall = !existsSync13(nodeModules) || existsSync13(tuiPkg) && !existsSync13(join11(repoPath, "packages", "tui", "node_modules")) && !existsSync13(join11(nodeModules, "@opentui"));
|
|
38013
|
+
if (cloned || needsInstall || !existsSync13(nodeModules)) {
|
|
37918
38014
|
log2(`Running bun install in ${repoPath}`);
|
|
37919
38015
|
const install = await runCommand(["bun", "install"], repoPath);
|
|
37920
38016
|
if (!install.ok) {
|
|
@@ -39070,7 +39166,7 @@ EXAMPLES:
|
|
|
39070
39166
|
}
|
|
39071
39167
|
// src/commands/pyne/pyne-command.ts
|
|
39072
39168
|
init_config2();
|
|
39073
|
-
import { existsSync as
|
|
39169
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
|
|
39074
39170
|
import { resolve as resolve7 } from "path";
|
|
39075
39171
|
init_errors4();
|
|
39076
39172
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
@@ -39079,7 +39175,7 @@ function getPyneWorkerDir() {
|
|
|
39079
39175
|
}
|
|
39080
39176
|
function requirePyneDir() {
|
|
39081
39177
|
const dir = getPyneWorkerDir();
|
|
39082
|
-
if (!
|
|
39178
|
+
if (!existsSync14(dir)) {
|
|
39083
39179
|
throw new CLIError(`pyne-worker directory not found: ${dir}
|
|
39084
39180
|
` + ` Clone it with: hoox clone pyne-worker
|
|
39085
39181
|
` + ` Or: git submodule update --init workers/pyne-worker`, 1 /* ERROR */);
|
|
@@ -39094,7 +39190,7 @@ function loadDevVars(workerDir) {
|
|
|
39094
39190
|
];
|
|
39095
39191
|
for (const filePath of candidates) {
|
|
39096
39192
|
try {
|
|
39097
|
-
if (!
|
|
39193
|
+
if (!existsSync14(filePath))
|
|
39098
39194
|
continue;
|
|
39099
39195
|
const content = readFileSync8(filePath, "utf-8");
|
|
39100
39196
|
for (const line of content.split(`
|
|
@@ -39312,7 +39408,7 @@ EXAMPLES:
|
|
|
39312
39408
|
body.script = await new Response(Bun.stdin).text();
|
|
39313
39409
|
} else {
|
|
39314
39410
|
const abs = resolve7(process.cwd(), scriptPath);
|
|
39315
|
-
if (!
|
|
39411
|
+
if (!existsSync14(abs)) {
|
|
39316
39412
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39317
39413
|
}
|
|
39318
39414
|
body.script = readFileSync8(abs, "utf-8");
|
|
@@ -39363,7 +39459,7 @@ EXAMPLES:
|
|
|
39363
39459
|
throw new CLIError("API key required for authenticated endpoints", 2 /* INVALID_USAGE */);
|
|
39364
39460
|
}
|
|
39365
39461
|
const abs = resolve7(process.cwd(), scriptPath);
|
|
39366
|
-
if (!
|
|
39462
|
+
if (!existsSync14(abs)) {
|
|
39367
39463
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39368
39464
|
}
|
|
39369
39465
|
const script = readFileSync8(abs, "utf-8");
|
|
@@ -39471,7 +39567,7 @@ Pass script flags after -- :
|
|
|
39471
39567
|
Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorHandling(async () => {
|
|
39472
39568
|
const dir = requirePyneDir();
|
|
39473
39569
|
const script = resolve7(dir, "scripts/sync_vendor.sh");
|
|
39474
|
-
if (!
|
|
39570
|
+
if (!existsSync14(script)) {
|
|
39475
39571
|
throw new CLIError(`sync_vendor.sh not found at ${script}`, 1 /* ERROR */);
|
|
39476
39572
|
}
|
|
39477
39573
|
process.exitCode = await spawnInPyneDir(["bash", script], dir);
|
|
@@ -39480,7 +39576,7 @@ Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorH
|
|
|
39480
39576
|
const dir = requirePyneDir();
|
|
39481
39577
|
if (!opts.skipSync) {
|
|
39482
39578
|
const script = resolve7(dir, "scripts/sync_vendor.sh");
|
|
39483
|
-
if (
|
|
39579
|
+
if (existsSync14(script)) {
|
|
39484
39580
|
const code = await spawnInPyneDir(["bash", script], dir);
|
|
39485
39581
|
if (code !== 0) {
|
|
39486
39582
|
process.exitCode = code;
|
|
@@ -41029,7 +41125,7 @@ function registerCompletionCommand(program2) {
|
|
|
41029
41125
|
// src/ui/banner.ts
|
|
41030
41126
|
init_ansis();
|
|
41031
41127
|
init_theme();
|
|
41032
|
-
import { existsSync as
|
|
41128
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
41033
41129
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41034
41130
|
import { dirname as dirname4, join as join13 } from "path";
|
|
41035
41131
|
var ORANGE = ansis_default.hex("#ff7f2a");
|
|
@@ -41045,7 +41141,7 @@ function findCliVersion() {
|
|
|
41045
41141
|
let dir = dirname4(fileURLToPath2(import.meta.url));
|
|
41046
41142
|
for (let i2 = 0;i2 < 5; i2++) {
|
|
41047
41143
|
const pkgPath = join13(dir, "package.json");
|
|
41048
|
-
if (
|
|
41144
|
+
if (existsSync15(pkgPath)) {
|
|
41049
41145
|
try {
|
|
41050
41146
|
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
41051
41147
|
if (pkg.name === PKG_NAME)
|
|
@@ -41684,6 +41780,13 @@ Hoox CLI \u2014 Cloudflare Workers Platform
|
|
|
41684
41780
|
styleCommandText: (str) => theme.bold(str),
|
|
41685
41781
|
styleOptionText: (str) => str,
|
|
41686
41782
|
styleDescriptionText: (str) => theme.dim(str)
|
|
41783
|
+
}).configureOutput({
|
|
41784
|
+
outputError: (str, write) => {
|
|
41785
|
+
if (/^error: unknown command/i.test(str) || /^error: unknown option/i.test(str) || /^error: missing required argument/i.test(str) || /^error: required option/i.test(str) || /^\(Did you mean /i.test(str)) {
|
|
41786
|
+
return;
|
|
41787
|
+
}
|
|
41788
|
+
write(str);
|
|
41789
|
+
}
|
|
41687
41790
|
});
|
|
41688
41791
|
program2.option("--json", "Output in JSON format");
|
|
41689
41792
|
program2.option("--quiet", "Minimal output");
|
|
@@ -41698,10 +41801,16 @@ program2.hook("preAction", async () => {
|
|
|
41698
41801
|
return;
|
|
41699
41802
|
if (process.env.BUN_TEST === "1")
|
|
41700
41803
|
return;
|
|
41804
|
+
if (process.argv.includes("--json"))
|
|
41805
|
+
return;
|
|
41701
41806
|
try {
|
|
41702
41807
|
const { UpdateService: UpdateService2 } = await Promise.resolve().then(() => (init_update(), exports_update));
|
|
41703
41808
|
const service = new UpdateService2;
|
|
41704
|
-
|
|
41809
|
+
const autoUpdate = process.env.HOOX_AUTO_UPDATE_WRANGLER === "1";
|
|
41810
|
+
await service.checkAndPromptUpdate({
|
|
41811
|
+
yes: autoUpdate,
|
|
41812
|
+
silent: true
|
|
41813
|
+
});
|
|
41705
41814
|
} catch {}
|
|
41706
41815
|
});
|
|
41707
41816
|
program2.hook("postAction", (thisCmd) => {
|
|
@@ -41713,22 +41822,29 @@ program2.hook("postAction", (thisCmd) => {
|
|
|
41713
41822
|
const durationMs = Date.now() - startedAt;
|
|
41714
41823
|
const path6 = getCmdPath(thisCmd);
|
|
41715
41824
|
const suggestion = suggestNextCommand(path6);
|
|
41716
|
-
|
|
41825
|
+
const g2 = program2.opts();
|
|
41826
|
+
formatCompletion("Done", {
|
|
41827
|
+
durationMs,
|
|
41828
|
+
suggestion,
|
|
41829
|
+
json: Boolean(g2.json),
|
|
41830
|
+
quiet: Boolean(g2.quiet),
|
|
41831
|
+
noColor: g2.color === false || Boolean(process.env.NO_COLOR)
|
|
41832
|
+
});
|
|
41717
41833
|
});
|
|
41718
41834
|
program2.exitOverride((err) => {
|
|
41719
41835
|
const globalOpts = program2.opts();
|
|
41720
41836
|
const errFmtOpts = {
|
|
41721
41837
|
json: Boolean(globalOpts.json),
|
|
41722
41838
|
quiet: Boolean(globalOpts.quiet),
|
|
41723
|
-
noColor: Boolean(
|
|
41839
|
+
noColor: globalOpts.color === false || Boolean(process.env.NO_COLOR)
|
|
41724
41840
|
};
|
|
41725
41841
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
41726
41842
|
process.exitCode = 0 /* SUCCESS */;
|
|
41727
|
-
|
|
41843
|
+
throw err;
|
|
41728
41844
|
}
|
|
41729
|
-
if (err.
|
|
41845
|
+
if ((err.message === "(outputHelp)" || err.message?.includes("outputHelp")) && err.code !== "commander.missingArgument") {
|
|
41730
41846
|
process.exitCode = 0 /* SUCCESS */;
|
|
41731
|
-
|
|
41847
|
+
throw err;
|
|
41732
41848
|
}
|
|
41733
41849
|
if (err.code === "commander.unknownCommand") {
|
|
41734
41850
|
const match = err.message.match(/'([^']+)'/);
|
|
@@ -41736,31 +41852,36 @@ program2.exitOverride((err) => {
|
|
|
41736
41852
|
const suggestion = suggestForCommand(program2, badArg);
|
|
41737
41853
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), suggestion ? { ...errFmtOpts, suggestions: [suggestion] } : errFmtOpts);
|
|
41738
41854
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41739
|
-
|
|
41855
|
+
throw err;
|
|
41740
41856
|
}
|
|
41741
41857
|
if (err.code === "commander.unknownOption") {
|
|
41742
41858
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), errFmtOpts);
|
|
41743
41859
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41744
|
-
|
|
41860
|
+
throw err;
|
|
41745
41861
|
}
|
|
41746
|
-
if (err.code === "commander.
|
|
41862
|
+
if (err.code === "commander.missingArgument" || err.code === "commander.missingMandatoryOptionValue") {
|
|
41747
41863
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), errFmtOpts);
|
|
41748
41864
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41749
|
-
|
|
41865
|
+
throw err;
|
|
41750
41866
|
}
|
|
41751
41867
|
if (err instanceof CLIError) {
|
|
41752
41868
|
formatError2(err, errFmtOpts);
|
|
41753
41869
|
process.exitCode = err.code;
|
|
41754
|
-
|
|
41870
|
+
throw err;
|
|
41755
41871
|
}
|
|
41756
41872
|
formatError2(new CLIError(err.message, 1 /* ERROR */, undefined, false), errFmtOpts);
|
|
41757
41873
|
process.exitCode = 1 /* ERROR */;
|
|
41874
|
+
throw err;
|
|
41758
41875
|
});
|
|
41759
41876
|
process.on("uncaughtException", (err) => {
|
|
41877
|
+
if (process.exitCode !== undefined && process.exitCode !== 0)
|
|
41878
|
+
return;
|
|
41760
41879
|
formatError2(err instanceof CLIError ? err : new CLIError(`Uncaught exception: ${err.message}`, 1 /* ERROR */, err.stack, false));
|
|
41761
41880
|
process.exitCode = 1 /* ERROR */;
|
|
41762
41881
|
});
|
|
41763
41882
|
process.on("unhandledRejection", (reason) => {
|
|
41883
|
+
if (process.exitCode !== undefined && process.exitCode !== 0)
|
|
41884
|
+
return;
|
|
41764
41885
|
const err = reason instanceof Error ? reason : new Error(`Unhandled rejection: ${toError(reason)}`);
|
|
41765
41886
|
formatError2(new CLIError(err.message, 1 /* ERROR */, err.stack, false));
|
|
41766
41887
|
process.exitCode = 1 /* ERROR */;
|
|
@@ -41804,17 +41925,31 @@ async function main() {
|
|
|
41804
41925
|
const configFile = Bun.file("wrangler.jsonc");
|
|
41805
41926
|
const hasConfig = await configFile.exists();
|
|
41806
41927
|
const wizardStateFile = Bun.file(WIZARD_STATE_PATH);
|
|
41807
|
-
const hasWizardState = await wizardStateFile.exists();
|
|
41928
|
+
const hasWizardState = await wizardStateFile.exists() && (await wizardStateFile.text()).trim().length > 0;
|
|
41808
41929
|
if (!hasConfig) {
|
|
41809
41930
|
const args = hasWizardState ? ["onboard", "--resume"] : ["onboard"];
|
|
41810
41931
|
await program2.parseAsync(args, { from: "user" });
|
|
41811
41932
|
return;
|
|
41812
41933
|
}
|
|
41813
|
-
if (
|
|
41814
|
-
|
|
41934
|
+
if (await wizardStateFile.exists()) {
|
|
41935
|
+
try {
|
|
41936
|
+
const { unlinkSync } = await import("fs");
|
|
41937
|
+
unlinkSync(WIZARD_STATE_PATH);
|
|
41938
|
+
} catch {
|
|
41939
|
+
await Bun.write(WIZARD_STATE_PATH, "");
|
|
41940
|
+
}
|
|
41815
41941
|
}
|
|
41816
41942
|
await runInteractiveTUI(program2);
|
|
41817
41943
|
}
|
|
41944
|
+
} catch (err) {
|
|
41945
|
+
if (process.exitCode === undefined) {
|
|
41946
|
+
const message = err instanceof Error ? err.message : `Unhandled error: ${String(err)}`;
|
|
41947
|
+
const isCommander = err instanceof Error && "code" in err && typeof err.code === "string" && String(err.code).startsWith("commander.");
|
|
41948
|
+
if (!isCommander) {
|
|
41949
|
+
formatError2(new CLIError(message, 1 /* ERROR */, undefined, false));
|
|
41950
|
+
}
|
|
41951
|
+
process.exitCode = 1 /* ERROR */;
|
|
41952
|
+
}
|
|
41818
41953
|
} finally {
|
|
41819
41954
|
if (typeof process.exit === "function" && process.exitCode !== undefined) {
|
|
41820
41955
|
process.exit(process.exitCode);
|