@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 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.10.1** — operator security plane: fail-closed `tui --remote`, transport profile (Bearer + Access), `doctor --security`, `tunnel check`, management `/v1/*` contract. **v0.9.x** shipped hop-level `perf fastpath` observability and reliability fixes.
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; `hoox tui` launches the full OpenTUI operations center.
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 config init' to create one.` : `Config file not found: ${e.path}. Run 'hoox config init' to create one.`);
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 existsSync10 } from "fs";
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 = existsSync10(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync10(resolve4(this.projectRoot, "workers"));
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
- setup: { command: "hoox deploy all", reason: "ship to Cloudflare" },
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 [rootConfigExists, cliPackageExists] = await Promise.all([
29086
- rootConfig.exists(),
29087
- cliPackage.exists()
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
- if (rootConfigExists && cliPackageExists)
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
- existsSync as existsSync6,
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 (!existsSync6(KEYS_DIR)) {
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(join7(KEYS_DIR, "setup.env"), `# Hoox Setup \u2014 Auto-Generated Keys
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
- await Bun.write(join7(KEYS_DIR, `${name.toLowerCase()}.env`), `${name}=${value}
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 secretNames) {
29663
- content += `${secretName}=${keys[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) => existsSync6(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 (!existsSync6(gitmodulesPath)) {
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
- const secretResults = await this.setSecrets(keys);
30445
- results.secrets = secretResults;
30446
- const secretOk = secretResults.filter((r2) => r2.ok).length;
30447
- const secretFail = secretResults.filter((r2) => !r2.ok).length;
30448
- steps.push({
30449
- step: "secrets",
30450
- success: secretFail === 0,
30451
- message: `${secretOk} set, ${secretFail} failed`,
30452
- details: {
30453
- total: secretResults.length,
30454
- ok: secretOk,
30455
- failed: secretFail
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! Run: hoox check setup to verify.", fmt);
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 */), fmt);
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 */), fmt);
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 existsSync7,
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 (!existsSync7(workerPath)) {
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 (!existsSync7(filePath)) {
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 existsSync8, mkdirSync as mkdirSync4 } from "fs";
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 (!existsSync8(keysDir)) {
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 (!existsSync8(keysDir)) {
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 ?? "my-database";
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 existsSync9 } from "fs";
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 "my-database";
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 (existsSync9(candidate))
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
- formatError2(new CLIError(`Unknown worker "${worker}"`, 2 /* INVALID_USAGE */), fmt);
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 existsSync11, realpathSync } from "fs";
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 || !existsSync11(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 (existsSync11(path6))
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 existsSync12, lstatSync as lstatSync2, readlinkSync, rmSync } from "fs";
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 (existsSync12(p3))
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: existsSync12(repoPath),
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 !existsSync12(path6);
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 (existsSync12(repoPath) || isBrokenSymlink(repoPath)) {
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 = !existsSync12(nodeModules) || existsSync12(tuiPkg) && !existsSync12(join11(repoPath, "packages", "tui", "node_modules")) && !existsSync12(join11(nodeModules, "@opentui"));
37917
- if (cloned || needsInstall || !existsSync12(nodeModules)) {
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 existsSync13, readFileSync as readFileSync8 } from "fs";
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 (!existsSync13(dir)) {
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 (!existsSync13(filePath))
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 (!existsSync13(abs)) {
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 (!existsSync13(abs)) {
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 (!existsSync13(script)) {
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 (existsSync13(script)) {
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 existsSync14, readFileSync as readFileSync9 } from "fs";
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 (existsSync14(pkgPath)) {
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
- await service.checkAndPromptUpdate({ yes: true, silent: true });
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
- formatCompletion("Done", { durationMs, suggestion });
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(globalOpts.noColor)
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
- return;
41843
+ throw err;
41728
41844
  }
41729
- if (err.code === "commander.missingArgument" || err.message === "(outputHelp)" || err.message?.includes("outputHelp")) {
41845
+ if ((err.message === "(outputHelp)" || err.message?.includes("outputHelp")) && err.code !== "commander.missingArgument") {
41730
41846
  process.exitCode = 0 /* SUCCESS */;
41731
- return;
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
- return;
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
- return;
41860
+ throw err;
41745
41861
  }
41746
- if (err.code === "commander.missingMandatoryOptionValue" || err.code === "commander.missingArgument") {
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
- return;
41865
+ throw err;
41750
41866
  }
41751
41867
  if (err instanceof CLIError) {
41752
41868
  formatError2(err, errFmtOpts);
41753
41869
  process.exitCode = err.code;
41754
- return;
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 (hasWizardState) {
41814
- await Bun.write(WIZARD_STATE_PATH, "");
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoox-sh/hoox-cli",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments (@hoox-sh/hoox-cli)",
5
5
  "type": "module",
6
6
  "bin": {