@hoox-sh/hoox-cli 0.11.2 → 0.11.4
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 +372 -120
- 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(`
|
|
@@ -25548,6 +25548,33 @@ var init_cloudflare_service = __esm(() => {
|
|
|
25548
25548
|
init_wrangler_output();
|
|
25549
25549
|
});
|
|
25550
25550
|
|
|
25551
|
+
// src/utils/fs-secure.ts
|
|
25552
|
+
var exports_fs_secure = {};
|
|
25553
|
+
__export(exports_fs_secure, {
|
|
25554
|
+
secureSecretFile: () => secureSecretFile,
|
|
25555
|
+
secureChmod: () => secureChmod,
|
|
25556
|
+
ensureSecretDir: () => ensureSecretDir,
|
|
25557
|
+
SECRET_FILE_MODE: () => SECRET_FILE_MODE,
|
|
25558
|
+
SECRET_DIR_MODE: () => SECRET_DIR_MODE
|
|
25559
|
+
});
|
|
25560
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
25561
|
+
function secureChmod(path4, mode) {
|
|
25562
|
+
try {
|
|
25563
|
+
chmodSync3(path4, mode);
|
|
25564
|
+
} catch {}
|
|
25565
|
+
}
|
|
25566
|
+
function ensureSecretDir(dir) {
|
|
25567
|
+
try {
|
|
25568
|
+
mkdirSync3(dir, { recursive: true, mode: SECRET_DIR_MODE });
|
|
25569
|
+
} catch {}
|
|
25570
|
+
secureChmod(dir, SECRET_DIR_MODE);
|
|
25571
|
+
}
|
|
25572
|
+
function secureSecretFile(path4) {
|
|
25573
|
+
secureChmod(path4, SECRET_FILE_MODE);
|
|
25574
|
+
}
|
|
25575
|
+
var SECRET_FILE_MODE = 384, SECRET_DIR_MODE = 448;
|
|
25576
|
+
var init_fs_secure = () => {};
|
|
25577
|
+
|
|
25551
25578
|
// src/services/prerequisites/prerequisites-service.ts
|
|
25552
25579
|
class PrerequisitesService {
|
|
25553
25580
|
MINIMUM_WRANGLER = "3.88.0";
|
|
@@ -25891,6 +25918,7 @@ class UpdateService {
|
|
|
25891
25918
|
}
|
|
25892
25919
|
async checkAndPromptUpdate(options) {
|
|
25893
25920
|
const silent = options?.silent === true;
|
|
25921
|
+
const yes = options?.yes === true;
|
|
25894
25922
|
try {
|
|
25895
25923
|
const versionCheck = await this.prereqs.checkWranglerVersion();
|
|
25896
25924
|
if (!versionCheck.outdated) {
|
|
@@ -25900,6 +25928,9 @@ class UpdateService {
|
|
|
25900
25928
|
}
|
|
25901
25929
|
return { updated: false };
|
|
25902
25930
|
}
|
|
25931
|
+
if (silent && !yes) {
|
|
25932
|
+
return { updated: false };
|
|
25933
|
+
}
|
|
25903
25934
|
const current2 = versionCheck.current ?? "unknown";
|
|
25904
25935
|
const minimum = versionCheck.minimum ?? "unknown";
|
|
25905
25936
|
const latest2 = await this.checkLatestVersion();
|
|
@@ -26140,7 +26171,7 @@ var exports_schema_service = {};
|
|
|
26140
26171
|
__export(exports_schema_service, {
|
|
26141
26172
|
SchemaService: () => SchemaService
|
|
26142
26173
|
});
|
|
26143
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
26174
|
+
import { readFileSync as readFileSync5, existsSync as existsSync11 } from "fs";
|
|
26144
26175
|
import { resolve as resolve4 } from "path";
|
|
26145
26176
|
|
|
26146
26177
|
class SchemaService {
|
|
@@ -26174,7 +26205,7 @@ class SchemaService {
|
|
|
26174
26205
|
const workerWranglerPath = resolve4(workersDir, name, "wrangler.jsonc");
|
|
26175
26206
|
const devVarsPath = resolve4(workersDir, name, ".dev.vars");
|
|
26176
26207
|
const errors4 = [];
|
|
26177
|
-
const isHooxProject =
|
|
26208
|
+
const isHooxProject = existsSync11(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync11(resolve4(this.projectRoot, "workers"));
|
|
26178
26209
|
try {
|
|
26179
26210
|
const wranglerContent = readFileSync5(workerWranglerPath, "utf-8");
|
|
26180
26211
|
errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
|
|
@@ -28579,6 +28610,10 @@ function formatSuccess(message, opts) {
|
|
|
28579
28610
|
function formatError2(error51, opts = {}) {
|
|
28580
28611
|
const message = typeof error51 === "string" ? error51 : error51.message;
|
|
28581
28612
|
const cliError = error51 instanceof CLIError ? error51 : null;
|
|
28613
|
+
const write = (s) => {
|
|
28614
|
+
process.stderr.write(s);
|
|
28615
|
+
process.stdout.write(s);
|
|
28616
|
+
};
|
|
28582
28617
|
if (opts.json) {
|
|
28583
28618
|
const output = {
|
|
28584
28619
|
success: false,
|
|
@@ -28592,12 +28627,12 @@ function formatError2(error51, opts = {}) {
|
|
|
28592
28627
|
if (opts.suggestions && opts.suggestions.length > 0) {
|
|
28593
28628
|
output.suggestions = opts.suggestions;
|
|
28594
28629
|
}
|
|
28595
|
-
|
|
28630
|
+
write(JSON.stringify(output) + `
|
|
28596
28631
|
`);
|
|
28597
28632
|
return;
|
|
28598
28633
|
}
|
|
28599
28634
|
if (opts.quiet) {
|
|
28600
|
-
|
|
28635
|
+
write(`${message}
|
|
28601
28636
|
`);
|
|
28602
28637
|
return;
|
|
28603
28638
|
}
|
|
@@ -28607,13 +28642,13 @@ function formatError2(error51, opts = {}) {
|
|
|
28607
28642
|
titleParts.push(theme.textSubtle(`[${cliError.code}]`));
|
|
28608
28643
|
}
|
|
28609
28644
|
titleParts.push(theme.text(message));
|
|
28610
|
-
|
|
28645
|
+
write(`${titleParts.join(" ")}
|
|
28611
28646
|
`);
|
|
28612
28647
|
if (cliError?.details) {
|
|
28613
28648
|
const detailLines = cliError.details.split(`
|
|
28614
28649
|
`).filter((l) => l.length > 0);
|
|
28615
28650
|
for (const line of detailLines) {
|
|
28616
|
-
|
|
28651
|
+
write(` ${theme.textMuted(line)}
|
|
28617
28652
|
`);
|
|
28618
28653
|
}
|
|
28619
28654
|
}
|
|
@@ -28621,24 +28656,24 @@ function formatError2(error51, opts = {}) {
|
|
|
28621
28656
|
const hasSuggestions = !!opts.suggestions && opts.suggestions.length > 0;
|
|
28622
28657
|
if (hasHint || hasSuggestions) {
|
|
28623
28658
|
if (inCard) {
|
|
28624
|
-
|
|
28659
|
+
write(` ${theme.border(icons.pipe)}
|
|
28625
28660
|
`);
|
|
28626
28661
|
}
|
|
28627
28662
|
if (hasHint) {
|
|
28628
|
-
|
|
28663
|
+
write(` ${inCard ? theme.border(icons.pipe) : " "} ${theme.dim("\u21B3 hint:")} ${theme.value(cliError.hint)}
|
|
28629
28664
|
`);
|
|
28630
28665
|
}
|
|
28631
28666
|
if (hasSuggestions) {
|
|
28632
28667
|
const sugText = opts.suggestions.map((s) => `'${s}'`).join(", ");
|
|
28633
|
-
|
|
28668
|
+
write(` ${inCard ? theme.border(icons.pipe) : " "} ${theme.dim("did you mean:")} ${theme.accent(sugText)} ${theme.dim("?")}
|
|
28634
28669
|
`);
|
|
28635
28670
|
}
|
|
28636
28671
|
if (inCard) {
|
|
28637
|
-
|
|
28672
|
+
write(` ${theme.border(icons.pipe)}
|
|
28638
28673
|
`);
|
|
28639
28674
|
}
|
|
28640
28675
|
} else if (inCard && !cliError?.details) {
|
|
28641
|
-
|
|
28676
|
+
write(` ${theme.border(icons.pipe)}
|
|
28642
28677
|
`);
|
|
28643
28678
|
}
|
|
28644
28679
|
}
|
|
@@ -28979,7 +29014,12 @@ function captureHelpEvent(cmd, eventName) {
|
|
|
28979
29014
|
// src/utils/completion.ts
|
|
28980
29015
|
var SUGGEST_NEXT = {
|
|
28981
29016
|
init: { command: "hoox setup", reason: "provision infrastructure" },
|
|
28982
|
-
|
|
29017
|
+
onboard: { command: "hoox check setup", reason: "verify bootstrap" },
|
|
29018
|
+
setup: { command: "hoox check setup", reason: "verify infrastructure" },
|
|
29019
|
+
"check setup": {
|
|
29020
|
+
command: "hoox deploy all",
|
|
29021
|
+
reason: "ship workers to Cloudflare"
|
|
29022
|
+
},
|
|
28983
29023
|
"deploy all": { command: "hoox check health", reason: "verify the deploy" },
|
|
28984
29024
|
"check health": {
|
|
28985
29025
|
command: "hoox monitor trades",
|
|
@@ -29014,6 +29054,7 @@ function getCmdPath(cmd) {
|
|
|
29014
29054
|
// src/commands/init/init-command.ts
|
|
29015
29055
|
init_dist4();
|
|
29016
29056
|
init_src();
|
|
29057
|
+
import * as fs2 from "fs";
|
|
29017
29058
|
|
|
29018
29059
|
// src/services/cloudflare/index.ts
|
|
29019
29060
|
init_cloudflare_service();
|
|
@@ -29080,21 +29121,32 @@ class CLIProvisioner {
|
|
|
29080
29121
|
|
|
29081
29122
|
// src/commands/init/init-command.ts
|
|
29082
29123
|
async function verifyRepoRoot() {
|
|
29083
|
-
const rootConfig = Bun.file("wrangler.jsonc");
|
|
29084
29124
|
const cliPackage = Bun.file("packages/cli/package.json");
|
|
29085
|
-
const
|
|
29086
|
-
|
|
29087
|
-
|
|
29125
|
+
const wranglerExample = Bun.file("wrangler.jsonc.example");
|
|
29126
|
+
const wranglerConfig = Bun.file("wrangler.jsonc");
|
|
29127
|
+
const gitmodules = Bun.file(".gitmodules");
|
|
29128
|
+
const [
|
|
29129
|
+
cliPackageExists,
|
|
29130
|
+
wranglerExampleExists,
|
|
29131
|
+
wranglerConfigExists,
|
|
29132
|
+
gitmodulesExists
|
|
29133
|
+
] = await Promise.all([
|
|
29134
|
+
cliPackage.exists(),
|
|
29135
|
+
wranglerExample.exists(),
|
|
29136
|
+
wranglerConfig.exists(),
|
|
29137
|
+
gitmodules.exists()
|
|
29088
29138
|
]);
|
|
29089
|
-
|
|
29139
|
+
const workersDirExists = fs2.existsSync("workers");
|
|
29140
|
+
const hasRepoSignal = wranglerExampleExists || wranglerConfigExists || workersDirExists || gitmodulesExists;
|
|
29141
|
+
if (cliPackageExists && hasRepoSignal)
|
|
29090
29142
|
return;
|
|
29091
29143
|
const reasons = [];
|
|
29092
|
-
if (!rootConfigExists) {
|
|
29093
|
-
reasons.push("no root `wrangler.jsonc` found in the current directory");
|
|
29094
|
-
}
|
|
29095
29144
|
if (!cliPackageExists) {
|
|
29096
29145
|
reasons.push("no `packages/cli` workspace found (this is not the hoox monorepo)");
|
|
29097
29146
|
}
|
|
29147
|
+
if (cliPackageExists && !hasRepoSignal) {
|
|
29148
|
+
reasons.push("missing Hoox repo markers (expected one of: `wrangler.jsonc.example`, `wrangler.jsonc`, `workers/`, or `.gitmodules`)");
|
|
29149
|
+
}
|
|
29098
29150
|
const cloneHint = " Clone first: git clone --recursive " + "https://github.com/hoox-sh/hoox.git";
|
|
29099
29151
|
throw new CLIError(`Not inside a Hoox repository root.
|
|
29100
29152
|
` + reasons.join(`
|
|
@@ -29168,6 +29220,8 @@ async function createDevVars(config2, secrets, opts) {
|
|
|
29168
29220
|
const dir = `${worker.path}`;
|
|
29169
29221
|
try {
|
|
29170
29222
|
await Bun.write(filePath, content);
|
|
29223
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
29224
|
+
secureSecretFile2(filePath);
|
|
29171
29225
|
if (!opts?.quiet) {
|
|
29172
29226
|
formatSuccess(`Created ${filePath}`, opts);
|
|
29173
29227
|
}
|
|
@@ -29175,6 +29229,8 @@ async function createDevVars(config2, secrets, opts) {
|
|
|
29175
29229
|
const { mkdir } = await import("fs/promises");
|
|
29176
29230
|
await mkdir(dir, { recursive: true });
|
|
29177
29231
|
await Bun.write(filePath, content);
|
|
29232
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
29233
|
+
secureSecretFile2(filePath);
|
|
29178
29234
|
if (!opts?.quiet) {
|
|
29179
29235
|
formatSuccess(`Created ${filePath}`, opts);
|
|
29180
29236
|
}
|
|
@@ -29267,7 +29323,10 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29267
29323
|
if (error51) {
|
|
29268
29324
|
formatError2(new CLIError(error51, 1 /* ERROR */), globalOpts);
|
|
29269
29325
|
process.exitCode = 1 /* ERROR */;
|
|
29326
|
+
return;
|
|
29270
29327
|
}
|
|
29328
|
+
process.env.CLOUDFLARE_API_TOKEN = token;
|
|
29329
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = account;
|
|
29271
29330
|
if (!globalOpts.quiet) {
|
|
29272
29331
|
formatSuccess("Cloudflare API token validated", globalOpts);
|
|
29273
29332
|
}
|
|
@@ -29305,6 +29364,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29305
29364
|
if (isCancel(resumed)) {
|
|
29306
29365
|
cancel("Setup cancelled.");
|
|
29307
29366
|
process.exitCode = 0;
|
|
29367
|
+
return;
|
|
29308
29368
|
}
|
|
29309
29369
|
if (!resumed) {
|
|
29310
29370
|
engine = null;
|
|
@@ -29324,10 +29384,12 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29324
29384
|
if (isCancel(accepted)) {
|
|
29325
29385
|
cancel("Setup cancelled.");
|
|
29326
29386
|
process.exitCode = 0;
|
|
29387
|
+
return;
|
|
29327
29388
|
}
|
|
29328
29389
|
if (!accepted) {
|
|
29329
29390
|
outro("Setup cancelled. See DISCLAIMER.md for full terms.");
|
|
29330
29391
|
process.exitCode = 0;
|
|
29392
|
+
return;
|
|
29331
29393
|
}
|
|
29332
29394
|
}
|
|
29333
29395
|
engine.execute({ checksPassed: true });
|
|
@@ -29349,6 +29411,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29349
29411
|
if (isCancel(apiToken)) {
|
|
29350
29412
|
cancel("Setup cancelled.");
|
|
29351
29413
|
process.exitCode = 0;
|
|
29414
|
+
return;
|
|
29352
29415
|
}
|
|
29353
29416
|
log.step("Validating Cloudflare API token...");
|
|
29354
29417
|
const tokenError = await validateApiToken(cf, apiToken);
|
|
@@ -29357,6 +29420,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29357
29420
|
log.warn("Please check your token and try again.");
|
|
29358
29421
|
} else {
|
|
29359
29422
|
tokenValid = true;
|
|
29423
|
+
process.env.CLOUDFLARE_API_TOKEN = apiToken;
|
|
29360
29424
|
formatSuccess("Cloudflare API token validated", globalOpts);
|
|
29361
29425
|
}
|
|
29362
29426
|
}
|
|
@@ -29377,6 +29441,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29377
29441
|
if (isCancel(accountResult)) {
|
|
29378
29442
|
cancel("Setup cancelled.");
|
|
29379
29443
|
process.exitCode = 0;
|
|
29444
|
+
return;
|
|
29380
29445
|
}
|
|
29381
29446
|
const secretStoreResult = await text({
|
|
29382
29447
|
message: "Cloudflare Secret Store ID:",
|
|
@@ -29386,6 +29451,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29386
29451
|
if (isCancel(secretStoreResult)) {
|
|
29387
29452
|
cancel("Setup cancelled.");
|
|
29388
29453
|
process.exitCode = 0;
|
|
29454
|
+
return;
|
|
29389
29455
|
}
|
|
29390
29456
|
const prefixResult = await text({
|
|
29391
29457
|
message: "Subdomain prefix:",
|
|
@@ -29400,7 +29466,9 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29400
29466
|
if (isCancel(prefixResult)) {
|
|
29401
29467
|
cancel("Setup cancelled.");
|
|
29402
29468
|
process.exitCode = 0;
|
|
29469
|
+
return;
|
|
29403
29470
|
}
|
|
29471
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = accountResult;
|
|
29404
29472
|
engine.execute({
|
|
29405
29473
|
apiToken,
|
|
29406
29474
|
accountId: accountResult,
|
|
@@ -29433,6 +29501,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29433
29501
|
if (isCancel(presetChoice)) {
|
|
29434
29502
|
cancel("Setup cancelled.");
|
|
29435
29503
|
process.exitCode = 0;
|
|
29504
|
+
return;
|
|
29436
29505
|
}
|
|
29437
29506
|
engine.execute({ preset: presetChoice });
|
|
29438
29507
|
await saveState(engine);
|
|
@@ -29456,6 +29525,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29456
29525
|
if (isCancel(shouldProvision)) {
|
|
29457
29526
|
cancel("Setup cancelled.");
|
|
29458
29527
|
process.exitCode = 0;
|
|
29528
|
+
return;
|
|
29459
29529
|
}
|
|
29460
29530
|
if (shouldProvision) {
|
|
29461
29531
|
log.step("Provisioning infrastructure...");
|
|
@@ -29505,6 +29575,9 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29505
29575
|
process.exitCode = 0;
|
|
29506
29576
|
}
|
|
29507
29577
|
});
|
|
29578
|
+
if (isCancel(collected)) {
|
|
29579
|
+
return;
|
|
29580
|
+
}
|
|
29508
29581
|
collectedSecrets[key] = {};
|
|
29509
29582
|
for (const [secretName] of secretEntries) {
|
|
29510
29583
|
const val = collected[secretName];
|
|
@@ -29532,6 +29605,7 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29532
29605
|
if (isCancel(shouldDeploy)) {
|
|
29533
29606
|
cancel("Setup cancelled.");
|
|
29534
29607
|
process.exitCode = 0;
|
|
29608
|
+
return;
|
|
29535
29609
|
}
|
|
29536
29610
|
if (shouldDeploy) {
|
|
29537
29611
|
log.step("Deploying workers...");
|
|
@@ -29547,8 +29621,10 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29547
29621
|
}
|
|
29548
29622
|
// src/services/setup/setup-service.ts
|
|
29549
29623
|
import {
|
|
29550
|
-
|
|
29551
|
-
|
|
29624
|
+
chmodSync as chmodSync4,
|
|
29625
|
+
existsSync as existsSync7,
|
|
29626
|
+
mkdirSync as mkdirSync4,
|
|
29627
|
+
readdirSync as readdirSync3,
|
|
29552
29628
|
readFileSync as readFileSync3,
|
|
29553
29629
|
statSync as statSync2,
|
|
29554
29630
|
writeFileSync as writeFileSync2
|
|
@@ -29607,6 +29683,54 @@ var KEYS_DIR = ".keys";
|
|
|
29607
29683
|
function escapeRegex2(s) {
|
|
29608
29684
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29609
29685
|
}
|
|
29686
|
+
function parseEnvFile(text2) {
|
|
29687
|
+
const map2 = new Map;
|
|
29688
|
+
for (const line of text2.split(`
|
|
29689
|
+
`)) {
|
|
29690
|
+
const trimmed = line.trim();
|
|
29691
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
29692
|
+
continue;
|
|
29693
|
+
const eq = trimmed.indexOf("=");
|
|
29694
|
+
if (eq <= 0)
|
|
29695
|
+
continue;
|
|
29696
|
+
map2.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));
|
|
29697
|
+
}
|
|
29698
|
+
return map2;
|
|
29699
|
+
}
|
|
29700
|
+
function safeChmod(path4, mode) {
|
|
29701
|
+
try {
|
|
29702
|
+
chmodSync4(path4, mode);
|
|
29703
|
+
} catch {}
|
|
29704
|
+
}
|
|
29705
|
+
function loadExistingKeysFromDisk() {
|
|
29706
|
+
const setupEnv = join7(KEYS_DIR, "setup.env");
|
|
29707
|
+
if (!existsSync7(setupEnv))
|
|
29708
|
+
return null;
|
|
29709
|
+
let text2;
|
|
29710
|
+
try {
|
|
29711
|
+
text2 = readFileSync3(setupEnv, "utf-8");
|
|
29712
|
+
} catch {
|
|
29713
|
+
return null;
|
|
29714
|
+
}
|
|
29715
|
+
const map2 = parseEnvFile(text2);
|
|
29716
|
+
const required2 = [
|
|
29717
|
+
"INTERNAL_KEY_BINDING",
|
|
29718
|
+
"AGENT_INTERNAL_KEY",
|
|
29719
|
+
"SESSION_SECRET",
|
|
29720
|
+
"WEBHOOK_API_KEY_BINDING",
|
|
29721
|
+
"TELEGRAM_INTERNAL_KEY_BINDING",
|
|
29722
|
+
"TRADE_INTERNAL_KEY",
|
|
29723
|
+
"API_SERVICE_KEY_BINDING"
|
|
29724
|
+
];
|
|
29725
|
+
const keys = {};
|
|
29726
|
+
for (const name of required2) {
|
|
29727
|
+
const v = map2.get(name);
|
|
29728
|
+
if (!v)
|
|
29729
|
+
return null;
|
|
29730
|
+
keys[name] = v;
|
|
29731
|
+
}
|
|
29732
|
+
return keys;
|
|
29733
|
+
}
|
|
29610
29734
|
|
|
29611
29735
|
class SetupService {
|
|
29612
29736
|
onProgress;
|
|
@@ -29617,7 +29741,20 @@ class SetupService {
|
|
|
29617
29741
|
}
|
|
29618
29742
|
async generateKeys(skip = false) {
|
|
29619
29743
|
if (skip) {
|
|
29620
|
-
|
|
29744
|
+
const existing = loadExistingKeysFromDisk();
|
|
29745
|
+
if (existing) {
|
|
29746
|
+
this.onProgress({
|
|
29747
|
+
type: "info",
|
|
29748
|
+
step: "keys",
|
|
29749
|
+
message: "Using existing keys from .keys/setup.env (--skip-keys)"
|
|
29750
|
+
});
|
|
29751
|
+
return existing;
|
|
29752
|
+
}
|
|
29753
|
+
this.onProgress({
|
|
29754
|
+
type: "info",
|
|
29755
|
+
step: "keys",
|
|
29756
|
+
message: "Skipped (no existing .keys/setup.env)"
|
|
29757
|
+
});
|
|
29621
29758
|
return null;
|
|
29622
29759
|
}
|
|
29623
29760
|
this.onProgress({
|
|
@@ -29635,35 +29772,53 @@ class SetupService {
|
|
|
29635
29772
|
TRADE_INTERNAL_KEY: internalKey,
|
|
29636
29773
|
API_SERVICE_KEY_BINDING: internalKey
|
|
29637
29774
|
};
|
|
29638
|
-
if (!
|
|
29639
|
-
|
|
29775
|
+
if (!existsSync7(KEYS_DIR)) {
|
|
29776
|
+
mkdirSync4(KEYS_DIR, { recursive: true });
|
|
29640
29777
|
} else if (!statSync2(KEYS_DIR).isDirectory()) {
|
|
29641
|
-
|
|
29778
|
+
mkdirSync4(KEYS_DIR, { recursive: true });
|
|
29642
29779
|
}
|
|
29780
|
+
safeChmod(KEYS_DIR, 448);
|
|
29781
|
+
const setupEnvPath = join7(KEYS_DIR, "setup.env");
|
|
29643
29782
|
const envLines = Object.entries(keys).map(([k, v]) => `${k}=${v}`);
|
|
29644
|
-
await Bun.write(
|
|
29783
|
+
await Bun.write(setupEnvPath, `# Hoox Setup \u2014 Auto-Generated Keys
|
|
29645
29784
|
` + "# Generated by `hoox setup`. NEVER commit this file.\n" + `# Created: ${new Date().toISOString()}
|
|
29646
29785
|
|
|
29647
29786
|
` + envLines.join(`
|
|
29648
29787
|
`) + `
|
|
29649
29788
|
`);
|
|
29789
|
+
safeChmod(setupEnvPath, 384);
|
|
29650
29790
|
for (const [name, value] of Object.entries(keys)) {
|
|
29651
|
-
|
|
29791
|
+
const keyPath = join7(KEYS_DIR, `${name.toLowerCase()}.env`);
|
|
29792
|
+
await Bun.write(keyPath, `${name}=${value}
|
|
29652
29793
|
`);
|
|
29794
|
+
safeChmod(keyPath, 384);
|
|
29653
29795
|
}
|
|
29654
29796
|
let devVarsCount = 0;
|
|
29655
29797
|
for (const [worker, secretNames] of Object.entries(DEV_VARS_WORKER_KEYS)) {
|
|
29656
29798
|
const path4 = `workers/${workerFsDir(worker)}/.dev.vars`;
|
|
29799
|
+
const meshNames = secretNames;
|
|
29800
|
+
const meshSet = new Set(meshNames);
|
|
29801
|
+
const existing = existsSync7(path4) ? parseEnvFile(readFileSync3(path4, "utf-8")) : new Map;
|
|
29802
|
+
for (const secretName of meshNames) {
|
|
29803
|
+
existing.set(secretName, keys[secretName]);
|
|
29804
|
+
}
|
|
29657
29805
|
let content = `# .dev.vars \u2014 local secrets for ${worker}
|
|
29658
29806
|
`;
|
|
29659
29807
|
content += `# Generated by \`hoox setup\`. NEVER commit this file.
|
|
29660
29808
|
|
|
29661
29809
|
`;
|
|
29662
|
-
for (const secretName of
|
|
29663
|
-
content += `${secretName}=${
|
|
29810
|
+
for (const secretName of meshNames) {
|
|
29811
|
+
content += `${secretName}=${existing.get(secretName)}
|
|
29664
29812
|
`;
|
|
29665
29813
|
}
|
|
29814
|
+
for (const [k, v] of existing) {
|
|
29815
|
+
if (!meshSet.has(k)) {
|
|
29816
|
+
content += `${k}=${v}
|
|
29817
|
+
`;
|
|
29818
|
+
}
|
|
29819
|
+
}
|
|
29666
29820
|
await Bun.write(path4, content);
|
|
29821
|
+
safeChmod(path4, 384);
|
|
29667
29822
|
devVarsCount++;
|
|
29668
29823
|
}
|
|
29669
29824
|
this.onProgress({
|
|
@@ -29992,38 +30147,40 @@ class SetupService {
|
|
|
29992
30147
|
join7(dir, "pyproject.toml"),
|
|
29993
30148
|
join7(dir, "wrangler.jsonc")
|
|
29994
30149
|
];
|
|
29995
|
-
return markers.some((p3) =>
|
|
30150
|
+
return markers.some((p3) => existsSync7(p3));
|
|
29996
30151
|
}
|
|
29997
|
-
|
|
29998
|
-
this.onProgress({
|
|
29999
|
-
type: "step-start",
|
|
30000
|
-
step: "workers",
|
|
30001
|
-
message: "Checking worker submodules..."
|
|
30002
|
-
});
|
|
30152
|
+
listMissingWorkers() {
|
|
30003
30153
|
const workerDirs = [
|
|
30004
30154
|
...ALL_WORKERS,
|
|
30005
30155
|
...TOOLING_WORKERS,
|
|
30006
30156
|
"dashboard"
|
|
30007
30157
|
];
|
|
30008
30158
|
const missing = [];
|
|
30009
|
-
const gitmodulesPath = ".gitmodules";
|
|
30010
30159
|
for (const name of workerDirs) {
|
|
30011
30160
|
const dir = `workers/${workerFsDir(name)}`;
|
|
30012
30161
|
try {
|
|
30013
30162
|
const gitEntry = readFileSync3(join7(dir, ".git"), "utf-8").trim();
|
|
30014
30163
|
if (gitEntry.startsWith("gitdir:") || gitEntry.length > 0) {
|
|
30015
|
-
if (!this.isWorkerTreePopulated(dir, name))
|
|
30164
|
+
if (!this.isWorkerTreePopulated(dir, name))
|
|
30016
30165
|
missing.push(name);
|
|
30017
|
-
}
|
|
30018
30166
|
} else if (!this.isWorkerTreePopulated(dir, name)) {
|
|
30019
30167
|
missing.push(name);
|
|
30020
30168
|
}
|
|
30021
30169
|
} catch {
|
|
30022
|
-
if (!this.isWorkerTreePopulated(dir, name))
|
|
30170
|
+
if (!this.isWorkerTreePopulated(dir, name))
|
|
30023
30171
|
missing.push(name);
|
|
30024
|
-
}
|
|
30025
30172
|
}
|
|
30026
30173
|
}
|
|
30174
|
+
return missing;
|
|
30175
|
+
}
|
|
30176
|
+
async ensureWorkers() {
|
|
30177
|
+
this.onProgress({
|
|
30178
|
+
type: "step-start",
|
|
30179
|
+
step: "workers",
|
|
30180
|
+
message: "Checking worker submodules..."
|
|
30181
|
+
});
|
|
30182
|
+
const missing = this.listMissingWorkers();
|
|
30183
|
+
const gitmodulesPath = ".gitmodules";
|
|
30027
30184
|
if (missing.length === 0) {
|
|
30028
30185
|
this.onProgress({
|
|
30029
30186
|
type: "step-complete",
|
|
@@ -30037,7 +30194,7 @@ class SetupService {
|
|
|
30037
30194
|
step: "workers",
|
|
30038
30195
|
message: `${missing.length} worker(s) not cloned: ${missing.join(", ")}`
|
|
30039
30196
|
});
|
|
30040
|
-
if (!
|
|
30197
|
+
if (!existsSync7(gitmodulesPath)) {
|
|
30041
30198
|
this.onProgress({
|
|
30042
30199
|
type: "step-error",
|
|
30043
30200
|
step: "workers",
|
|
@@ -30078,14 +30235,17 @@ class SetupService {
|
|
|
30078
30235
|
];
|
|
30079
30236
|
const toBuild = [];
|
|
30080
30237
|
for (const pkg of packages) {
|
|
30238
|
+
let built = false;
|
|
30081
30239
|
try {
|
|
30082
|
-
|
|
30083
|
-
|
|
30084
|
-
|
|
30240
|
+
if (existsSync7(pkg.dist) && statSync2(pkg.dist).isDirectory()) {
|
|
30241
|
+
const entries = readdirSync3(pkg.dist);
|
|
30242
|
+
built = entries.some((e) => e.endsWith(".js"));
|
|
30085
30243
|
}
|
|
30086
30244
|
} catch {
|
|
30087
|
-
|
|
30245
|
+
built = false;
|
|
30088
30246
|
}
|
|
30247
|
+
if (!built)
|
|
30248
|
+
toBuild.push(pkg.name);
|
|
30089
30249
|
}
|
|
30090
30250
|
if (toBuild.length === 0) {
|
|
30091
30251
|
this.onProgress({
|
|
@@ -30402,13 +30562,21 @@ class SetupService {
|
|
|
30402
30562
|
results.success = false;
|
|
30403
30563
|
return results;
|
|
30404
30564
|
}
|
|
30405
|
-
const
|
|
30406
|
-
|
|
30565
|
+
const missingAfterClone = await this.ensureWorkers();
|
|
30566
|
+
const stillMissing = this.listMissingWorkers();
|
|
30567
|
+
if (stillMissing.length > 0) {
|
|
30568
|
+
steps.push({
|
|
30569
|
+
step: "workers",
|
|
30570
|
+
success: false,
|
|
30571
|
+
message: `Missing worker trees: ${stillMissing.join(", ")}. Run: git submodule update --init --recursive`
|
|
30572
|
+
});
|
|
30407
30573
|
this.onProgress({
|
|
30408
|
-
type: "
|
|
30574
|
+
type: "step-error",
|
|
30409
30575
|
step: "workers",
|
|
30410
|
-
message: "
|
|
30576
|
+
message: missingAfterClone.length > 0 ? "Workers still missing after clone attempt \u2014 aborting setup." : "Workers missing \u2014 aborting setup."
|
|
30411
30577
|
});
|
|
30578
|
+
results.success = false;
|
|
30579
|
+
return results;
|
|
30412
30580
|
}
|
|
30413
30581
|
const built = await this.ensurePackages();
|
|
30414
30582
|
if (!built) {
|
|
@@ -30417,6 +30585,8 @@ class SetupService {
|
|
|
30417
30585
|
success: false,
|
|
30418
30586
|
message: "Package build failed \u2014 check dependencies"
|
|
30419
30587
|
});
|
|
30588
|
+
results.success = false;
|
|
30589
|
+
return results;
|
|
30420
30590
|
}
|
|
30421
30591
|
this.fixWranglerConfigs();
|
|
30422
30592
|
const keys = await this.generateKeys(options.skipKeys);
|
|
@@ -30433,7 +30603,7 @@ class SetupService {
|
|
|
30433
30603
|
} else {
|
|
30434
30604
|
steps.push({ step: "d1-schema", success: true, message: "Skipped" });
|
|
30435
30605
|
}
|
|
30436
|
-
if (keys) {
|
|
30606
|
+
if (!options.skipSecrets && keys) {
|
|
30437
30607
|
const reconcile = await this.reconcileSecrets(keys);
|
|
30438
30608
|
if (reconcile.warnings.length > 0) {
|
|
30439
30609
|
for (const w of reconcile.warnings) {
|
|
@@ -30441,20 +30611,25 @@ class SetupService {
|
|
|
30441
30611
|
}
|
|
30442
30612
|
}
|
|
30443
30613
|
}
|
|
30444
|
-
|
|
30445
|
-
|
|
30446
|
-
|
|
30447
|
-
|
|
30448
|
-
|
|
30449
|
-
|
|
30450
|
-
|
|
30451
|
-
|
|
30452
|
-
|
|
30453
|
-
|
|
30454
|
-
|
|
30455
|
-
|
|
30456
|
-
|
|
30457
|
-
|
|
30614
|
+
if (options.skipSecrets) {
|
|
30615
|
+
steps.push({ step: "secrets", success: true, message: "Skipped" });
|
|
30616
|
+
results.secrets = [];
|
|
30617
|
+
} else {
|
|
30618
|
+
const secretResults = await this.setSecrets(keys);
|
|
30619
|
+
results.secrets = secretResults;
|
|
30620
|
+
const secretOk = secretResults.filter((r2) => r2.ok).length;
|
|
30621
|
+
const secretFail = secretResults.filter((r2) => !r2.ok).length;
|
|
30622
|
+
steps.push({
|
|
30623
|
+
step: "secrets",
|
|
30624
|
+
success: secretFail === 0,
|
|
30625
|
+
message: `${secretOk} set, ${secretFail} failed`,
|
|
30626
|
+
details: {
|
|
30627
|
+
total: secretResults.length,
|
|
30628
|
+
ok: secretOk,
|
|
30629
|
+
failed: secretFail
|
|
30630
|
+
}
|
|
30631
|
+
});
|
|
30632
|
+
}
|
|
30458
30633
|
const dashResult = await this.rebuildDashboard(options.skipDashboard);
|
|
30459
30634
|
steps.push(dashResult);
|
|
30460
30635
|
if (keys) {
|
|
@@ -30559,12 +30734,35 @@ async function runOnboard(options, fmt) {
|
|
|
30559
30734
|
acceptRisk: options.acceptRisk
|
|
30560
30735
|
};
|
|
30561
30736
|
await runInitCommand(initOpts, { json: fmt.json, quiet: fmt.quiet }, isNonInteractive);
|
|
30737
|
+
if (process.exitCode && process.exitCode !== 0) {
|
|
30738
|
+
return;
|
|
30739
|
+
}
|
|
30740
|
+
const configReady = await Bun.file("wrangler.jsonc").exists();
|
|
30741
|
+
if (!configReady) {
|
|
30742
|
+
if (!quiet) {
|
|
30743
|
+
formatError2(new CLIError("Onboard stopped: workspace config was not written (init cancelled or incomplete).", 1 /* ERROR */, undefined, false, "Re-run `hoox onboard` or `hoox init` to finish configuration, then `hoox setup`."), fmt);
|
|
30744
|
+
}
|
|
30745
|
+
process.exitCode = 1 /* ERROR */;
|
|
30746
|
+
return;
|
|
30747
|
+
}
|
|
30748
|
+
if (options.token) {
|
|
30749
|
+
process.env.CLOUDFLARE_API_TOKEN = options.token;
|
|
30750
|
+
}
|
|
30751
|
+
if (options.account) {
|
|
30752
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = options.account;
|
|
30753
|
+
}
|
|
30562
30754
|
if (!quiet) {
|
|
30563
30755
|
process.stdout.write(theme.heading(`
|
|
30564
30756
|
\u2501\u2501\u2501 Step 2/2: Setup (infrastructure bootstrap) \u2501\u2501\u2501
|
|
30565
30757
|
`));
|
|
30566
30758
|
}
|
|
30567
30759
|
const setupSvc = new SetupService;
|
|
30760
|
+
const authOk = await setupSvc.checkAuth();
|
|
30761
|
+
if (!authOk) {
|
|
30762
|
+
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);
|
|
30763
|
+
process.exitCode = 1 /* ERROR */;
|
|
30764
|
+
return;
|
|
30765
|
+
}
|
|
30568
30766
|
const setupOpts = {
|
|
30569
30767
|
skipKeys: Boolean(options.skipKeys),
|
|
30570
30768
|
skipDb: Boolean(options.skipDb),
|
|
@@ -30576,14 +30774,14 @@ async function runOnboard(options, fmt) {
|
|
|
30576
30774
|
const result = await setupSvc.runAll(setupOpts);
|
|
30577
30775
|
if (result.success) {
|
|
30578
30776
|
if (!quiet) {
|
|
30579
|
-
formatSuccess("Bootstrap complete!
|
|
30777
|
+
formatSuccess("Bootstrap complete! Next: `hoox check setup` then `hoox deploy all`", fmt);
|
|
30580
30778
|
}
|
|
30581
30779
|
} else {
|
|
30582
|
-
formatError2(new CLIError("Bootstrap completed with issues. See logs above.", 1 /* ERROR
|
|
30780
|
+
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
30781
|
process.exitCode = 1 /* ERROR */;
|
|
30584
30782
|
}
|
|
30585
30783
|
} catch (e) {
|
|
30586
|
-
formatError2(new CLIError(e instanceof Error ? e.message : String(e), 1 /* ERROR
|
|
30784
|
+
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
30785
|
process.exitCode = 1 /* ERROR */;
|
|
30588
30786
|
}
|
|
30589
30787
|
}
|
|
@@ -31101,7 +31299,7 @@ function renderDefaultSummary(results) {
|
|
|
31101
31299
|
init_errors4();
|
|
31102
31300
|
import {
|
|
31103
31301
|
statSync as statSync3,
|
|
31104
|
-
existsSync as
|
|
31302
|
+
existsSync as existsSync8,
|
|
31105
31303
|
readFileSync as readFileSync4,
|
|
31106
31304
|
writeFileSync as writeFileSync3,
|
|
31107
31305
|
renameSync
|
|
@@ -31536,7 +31734,7 @@ ${section}:
|
|
|
31536
31734
|
init_main();
|
|
31537
31735
|
function getDashboardBuildInfo(dashboardPath) {
|
|
31538
31736
|
const workerPath = resolve2(dashboardPath, ".open-next", "worker.js");
|
|
31539
|
-
if (!
|
|
31737
|
+
if (!existsSync8(workerPath)) {
|
|
31540
31738
|
return { exists: false };
|
|
31541
31739
|
}
|
|
31542
31740
|
const stats = statSync3(workerPath);
|
|
@@ -31879,7 +32077,7 @@ async function doUpdateInternalUrls(fmt) {
|
|
|
31879
32077
|
const prefix = global.subdomain_prefix ?? "hoox";
|
|
31880
32078
|
const workers = config2.listEnabledWorkers();
|
|
31881
32079
|
const filePath = resolve2(process.cwd(), "workers", "dashboard", "wrangler.jsonc");
|
|
31882
|
-
if (!
|
|
32080
|
+
if (!existsSync8(filePath)) {
|
|
31883
32081
|
formatError2(new CLIError("Dashboard wrangler.jsonc not found at workers/dashboard/wrangler.jsonc", 1 /* ERROR */), fmt);
|
|
31884
32082
|
process.exitCode = 1 /* ERROR */;
|
|
31885
32083
|
return;
|
|
@@ -33033,6 +33231,8 @@ async function handleInit(opts) {
|
|
|
33033
33231
|
await Bun.write(tmpPath, envContent);
|
|
33034
33232
|
await Bun.write(".env.local", envContent);
|
|
33035
33233
|
await Bun.file(tmpPath).delete().catch(() => {});
|
|
33234
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
33235
|
+
secureSecretFile2(".env.local");
|
|
33036
33236
|
if (!opts.quiet)
|
|
33037
33237
|
formatSuccess(".env.local written", opts);
|
|
33038
33238
|
log.step("Writing .dev.vars files...");
|
|
@@ -33047,6 +33247,8 @@ async function handleInit(opts) {
|
|
|
33047
33247
|
].join(`
|
|
33048
33248
|
`);
|
|
33049
33249
|
await Bun.write(`${workerPath}/.dev.vars`, content);
|
|
33250
|
+
const { secureSecretFile: chmodDev } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
33251
|
+
chmodDev(`${workerPath}/.dev.vars`);
|
|
33050
33252
|
if (!opts.quiet)
|
|
33051
33253
|
formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
|
|
33052
33254
|
}
|
|
@@ -33123,6 +33325,8 @@ async function handleGenerateDevVars(opts) {
|
|
|
33123
33325
|
].join(`
|
|
33124
33326
|
`);
|
|
33125
33327
|
await Bun.write(`${workerPath}/.dev.vars`, content);
|
|
33328
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
33329
|
+
secureSecretFile2(`${workerPath}/.dev.vars`);
|
|
33126
33330
|
count++;
|
|
33127
33331
|
}
|
|
33128
33332
|
formatSuccess(`Generated .dev.vars for ${count} worker(s)`, opts);
|
|
@@ -33370,7 +33574,7 @@ class SecretsService {
|
|
|
33370
33574
|
const path5 = configPath ?? "wrangler.jsonc";
|
|
33371
33575
|
const file2 = Bun.file(path5);
|
|
33372
33576
|
if (!await file2.exists()) {
|
|
33373
|
-
throw new Error(`Config file not found: ${path5}
|
|
33577
|
+
throw new Error(`Config file not found: ${path5}. Run 'hoox onboard' (or 'hoox init') to create one.`);
|
|
33374
33578
|
}
|
|
33375
33579
|
const text2 = await file2.text();
|
|
33376
33580
|
const config2 = parse6(text2);
|
|
@@ -33453,6 +33657,8 @@ class SecretsService {
|
|
|
33453
33657
|
const devVarsPath = `${worker.path}/.dev.vars`;
|
|
33454
33658
|
try {
|
|
33455
33659
|
await Bun.write(devVarsPath, content);
|
|
33660
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
33661
|
+
secureSecretFile2(devVarsPath);
|
|
33456
33662
|
return { ok: true, value: devVarsPath };
|
|
33457
33663
|
} catch (err) {
|
|
33458
33664
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -33700,6 +33906,8 @@ async function updateDevVars(filePath, key, value) {
|
|
|
33700
33906
|
await Bun.write(filePath, `${key}=${value}
|
|
33701
33907
|
`);
|
|
33702
33908
|
}
|
|
33909
|
+
const { secureSecretFile: secureSecretFile2 } = await Promise.resolve().then(() => (init_fs_secure(), exports_fs_secure));
|
|
33910
|
+
secureSecretFile2(filePath);
|
|
33703
33911
|
}
|
|
33704
33912
|
function registerSecretsSubcommands(secretsCmd, service = "config") {
|
|
33705
33913
|
secretsCmd.command("list [worker]").summary("List secrets for all workers or a specific worker").description(`List the secrets declared in wrangler.jsonc for workers.
|
|
@@ -33773,7 +33981,7 @@ EXAMPLES:
|
|
|
33773
33981
|
const svc = await SecretsService.create();
|
|
33774
33982
|
const declared = svc.listSecrets(workerName);
|
|
33775
33983
|
if (!declared.includes(secretName) && declared.length > 0) {
|
|
33776
|
-
throw new CLIError(`Secret "${secretName}" is not declared for worker "${workerName}".
|
|
33984
|
+
throw new CLIError(`Secret "${secretName}" is not declared for worker "${workerName}". Declared secrets: ${declared.join(", ")}`, 2 /* INVALID_USAGE */);
|
|
33777
33985
|
}
|
|
33778
33986
|
const value = await promptSecret(`Enter value for "${secretName}"`);
|
|
33779
33987
|
if (!value) {
|
|
@@ -33956,7 +34164,8 @@ EXAMPLES:
|
|
|
33956
34164
|
}
|
|
33957
34165
|
|
|
33958
34166
|
// src/commands/config/keys-subcommands.ts
|
|
33959
|
-
import { existsSync as
|
|
34167
|
+
import { existsSync as existsSync9 } from "fs";
|
|
34168
|
+
init_fs_secure();
|
|
33960
34169
|
init_theme();
|
|
33961
34170
|
function generateKey(bytes = 32) {
|
|
33962
34171
|
const buf = new Uint8Array(bytes);
|
|
@@ -33982,9 +34191,7 @@ EXAMPLES:
|
|
|
33982
34191
|
hoox config keys generate`).action(withErrorHandling(async (_2, cmd) => {
|
|
33983
34192
|
const opts = getFormatOptions(cmd);
|
|
33984
34193
|
const keysDir = ".keys";
|
|
33985
|
-
|
|
33986
|
-
mkdirSync4(keysDir, { recursive: true });
|
|
33987
|
-
}
|
|
34194
|
+
ensureSecretDir(keysDir);
|
|
33988
34195
|
const meshKey = generateKey();
|
|
33989
34196
|
const keys = {
|
|
33990
34197
|
INTERNAL_KEY_BINDING: meshKey,
|
|
@@ -33999,7 +34206,13 @@ EXAMPLES:
|
|
|
33999
34206
|
const filePath = `${keysDir}/${name.toLowerCase()}.env`;
|
|
34000
34207
|
await Bun.write(filePath, `${name}=${value}
|
|
34001
34208
|
`);
|
|
34209
|
+
secureSecretFile(filePath);
|
|
34002
34210
|
}
|
|
34211
|
+
await Bun.write(`${keysDir}/setup.env`, `# Generated by hoox keys generate
|
|
34212
|
+
` + Object.entries(keys).map(([k, v]) => `${k}=${v}`).join(`
|
|
34213
|
+
`) + `
|
|
34214
|
+
`);
|
|
34215
|
+
secureSecretFile(`${keysDir}/setup.env`);
|
|
34003
34216
|
formatSuccess(`Generated ${Object.keys(keys).length} keys in ${keysDir}/`, opts);
|
|
34004
34217
|
if (!opts.quiet && !opts.json) {
|
|
34005
34218
|
process.stdout.write(`${theme.warning("!")} Keep these keys secret. Add ${keysDir}/ to .gitignore.
|
|
@@ -34016,7 +34229,7 @@ EXAMPLES:
|
|
|
34016
34229
|
hoox config keys list`).action(withErrorHandling(async (_2, cmd) => {
|
|
34017
34230
|
const opts = getFormatOptions(cmd);
|
|
34018
34231
|
const keysDir = ".keys";
|
|
34019
|
-
if (!
|
|
34232
|
+
if (!existsSync9(keysDir)) {
|
|
34020
34233
|
process.stdout.write(`${theme.dim("No .keys/ directory found.")}
|
|
34021
34234
|
`);
|
|
34022
34235
|
return;
|
|
@@ -34657,7 +34870,7 @@ async function runSecretsChecks(secretsService, configService, cf) {
|
|
|
34657
34870
|
async function runDatabaseChecks(cf, configService) {
|
|
34658
34871
|
const checks3 = [];
|
|
34659
34872
|
const d1Worker = configService.getWorker("d1-worker");
|
|
34660
|
-
const dbName = d1Worker?.vars?.database_name ?? "
|
|
34873
|
+
const dbName = d1Worker?.vars?.database_name ?? "trade-data-db";
|
|
34661
34874
|
const d1ListResult = await cf.d1List();
|
|
34662
34875
|
if (d1ListResult.ok) {
|
|
34663
34876
|
const hasDb = d1ListResult.value.includes(dbName);
|
|
@@ -36282,7 +36495,7 @@ init_dist4();
|
|
|
36282
36495
|
// src/services/db/db-service.ts
|
|
36283
36496
|
init_config2();
|
|
36284
36497
|
init_cloudflare_service();
|
|
36285
|
-
import { existsSync as
|
|
36498
|
+
import { existsSync as existsSync10 } from "fs";
|
|
36286
36499
|
import { join as join9 } from "path";
|
|
36287
36500
|
var D1_WRANGLER_CONFIG_CANDIDATES = [
|
|
36288
36501
|
"workers/d1-worker/wrangler.jsonc",
|
|
@@ -36320,7 +36533,7 @@ class DbService {
|
|
|
36320
36533
|
if (vars?.database_name)
|
|
36321
36534
|
return vars.database_name;
|
|
36322
36535
|
} catch {}
|
|
36323
|
-
return "
|
|
36536
|
+
return "trade-data-db";
|
|
36324
36537
|
}
|
|
36325
36538
|
async apply(dbName, remote, schemaPath) {
|
|
36326
36539
|
const path6 = schemaPath ?? this.resolveDefaultSchemaPath();
|
|
@@ -36384,7 +36597,7 @@ class DbService {
|
|
|
36384
36597
|
if (this.wranglerConfigPath)
|
|
36385
36598
|
return this.wranglerConfigPath;
|
|
36386
36599
|
for (const candidate of D1_WRANGLER_CONFIG_CANDIDATES) {
|
|
36387
|
-
if (
|
|
36600
|
+
if (existsSync10(candidate))
|
|
36388
36601
|
return candidate;
|
|
36389
36602
|
}
|
|
36390
36603
|
return;
|
|
@@ -37479,8 +37692,7 @@ function registerSchemaCommand(program2) {
|
|
|
37479
37692
|
const svc = new SchemaService;
|
|
37480
37693
|
const manifest = svc.getManifest(worker);
|
|
37481
37694
|
if (!manifest) {
|
|
37482
|
-
|
|
37483
|
-
return;
|
|
37695
|
+
throw new CLIError(`Unknown worker "${worker}"`, 2 /* INVALID_USAGE */, undefined, false, `Known workers: ${svc.getWorkerNames().join(", ") || "(none)"}. Run: hoox schema list`);
|
|
37484
37696
|
}
|
|
37485
37697
|
const wranglerContent = generateWranglerJsonc(manifest);
|
|
37486
37698
|
const devVarsContent = generateDevVars(manifest);
|
|
@@ -37515,7 +37727,7 @@ import { spawn } from "child_process";
|
|
|
37515
37727
|
import { createRequire } from "module";
|
|
37516
37728
|
import { resolve as resolve6, dirname as dirname3, join as join10 } from "path";
|
|
37517
37729
|
import { fileURLToPath } from "url";
|
|
37518
|
-
import { existsSync as
|
|
37730
|
+
import { existsSync as existsSync12, realpathSync } from "fs";
|
|
37519
37731
|
import { homedir as homedir5 } from "os";
|
|
37520
37732
|
|
|
37521
37733
|
// src/services/perf/endpoint-resolver.ts
|
|
@@ -37579,7 +37791,7 @@ function collectTuiCandidates() {
|
|
|
37579
37791
|
return [...new Set(candidates)];
|
|
37580
37792
|
}
|
|
37581
37793
|
function pushPackageRootEntries(candidates, root) {
|
|
37582
|
-
if (!root || !
|
|
37794
|
+
if (!root || !existsSync12(root))
|
|
37583
37795
|
return;
|
|
37584
37796
|
candidates.push(join10(root, "dist", "main.js"), join10(root, "src", "main.tsx"), join10(root, "bin", "hoox-tui.js"), join10(root, "src", "main.ts"));
|
|
37585
37797
|
}
|
|
@@ -37607,7 +37819,7 @@ function pushFromWhich(candidates, binName) {
|
|
|
37607
37819
|
function resolveTUIEntry() {
|
|
37608
37820
|
const candidates = collectTuiCandidates();
|
|
37609
37821
|
for (const path6 of candidates) {
|
|
37610
|
-
if (
|
|
37822
|
+
if (existsSync12(path6))
|
|
37611
37823
|
return path6;
|
|
37612
37824
|
}
|
|
37613
37825
|
const runtime = resolveHooxRuntimeRoot();
|
|
@@ -37826,13 +38038,13 @@ import { homedir as homedir6 } from "os";
|
|
|
37826
38038
|
|
|
37827
38039
|
// src/services/runtime/runtime-service.ts
|
|
37828
38040
|
init_src();
|
|
37829
|
-
import { existsSync as
|
|
38041
|
+
import { existsSync as existsSync13, lstatSync as lstatSync2, readlinkSync, rmSync } from "fs";
|
|
37830
38042
|
import { mkdir } from "fs/promises";
|
|
37831
38043
|
import { join as join11 } from "path";
|
|
37832
38044
|
var DEFAULT_HOOX_RUNTIME_REPO = "https://github.com/hoox-sh/hoox.git";
|
|
37833
38045
|
function firstExisting(paths) {
|
|
37834
38046
|
for (const p3 of paths) {
|
|
37835
|
-
if (
|
|
38047
|
+
if (existsSync13(p3))
|
|
37836
38048
|
return p3;
|
|
37837
38049
|
}
|
|
37838
38050
|
return null;
|
|
@@ -37846,7 +38058,7 @@ function getRuntimeStatus(cwd = process.cwd()) {
|
|
|
37846
38058
|
repoPath,
|
|
37847
38059
|
runtime,
|
|
37848
38060
|
tuiEntry,
|
|
37849
|
-
repoPresent:
|
|
38061
|
+
repoPresent: existsSync13(repoPath),
|
|
37850
38062
|
isSetupRoot: isHooxSetupRoot(repoPath)
|
|
37851
38063
|
};
|
|
37852
38064
|
}
|
|
@@ -37868,7 +38080,7 @@ function isBrokenSymlink(path6) {
|
|
|
37868
38080
|
try {
|
|
37869
38081
|
if (!lstatSync2(path6).isSymbolicLink())
|
|
37870
38082
|
return false;
|
|
37871
|
-
return !
|
|
38083
|
+
return !existsSync13(path6);
|
|
37872
38084
|
} catch {
|
|
37873
38085
|
return false;
|
|
37874
38086
|
}
|
|
@@ -37881,7 +38093,7 @@ async function ensureGlobalRuntime(options = {}) {
|
|
|
37881
38093
|
await mkdir(hooxHome, { recursive: true });
|
|
37882
38094
|
let cloned = false;
|
|
37883
38095
|
if (!isHooxSetupRoot(repoPath)) {
|
|
37884
|
-
if (
|
|
38096
|
+
if (existsSync13(repoPath) || isBrokenSymlink(repoPath)) {
|
|
37885
38097
|
if (isBrokenSymlink(repoPath)) {
|
|
37886
38098
|
let target = "";
|
|
37887
38099
|
try {
|
|
@@ -37913,8 +38125,8 @@ ${clone2.stderr || clone2.stdout}`.trim());
|
|
|
37913
38125
|
if (!options.skipInstall) {
|
|
37914
38126
|
const nodeModules = join11(repoPath, "node_modules");
|
|
37915
38127
|
const tuiPkg = join11(repoPath, "packages", "tui", "package.json");
|
|
37916
|
-
const needsInstall = !
|
|
37917
|
-
if (cloned || needsInstall || !
|
|
38128
|
+
const needsInstall = !existsSync13(nodeModules) || existsSync13(tuiPkg) && !existsSync13(join11(repoPath, "packages", "tui", "node_modules")) && !existsSync13(join11(nodeModules, "@opentui"));
|
|
38129
|
+
if (cloned || needsInstall || !existsSync13(nodeModules)) {
|
|
37918
38130
|
log2(`Running bun install in ${repoPath}`);
|
|
37919
38131
|
const install = await runCommand(["bun", "install"], repoPath);
|
|
37920
38132
|
if (!install.ok) {
|
|
@@ -39070,7 +39282,7 @@ EXAMPLES:
|
|
|
39070
39282
|
}
|
|
39071
39283
|
// src/commands/pyne/pyne-command.ts
|
|
39072
39284
|
init_config2();
|
|
39073
|
-
import { existsSync as
|
|
39285
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
|
|
39074
39286
|
import { resolve as resolve7 } from "path";
|
|
39075
39287
|
init_errors4();
|
|
39076
39288
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
@@ -39079,7 +39291,7 @@ function getPyneWorkerDir() {
|
|
|
39079
39291
|
}
|
|
39080
39292
|
function requirePyneDir() {
|
|
39081
39293
|
const dir = getPyneWorkerDir();
|
|
39082
|
-
if (!
|
|
39294
|
+
if (!existsSync14(dir)) {
|
|
39083
39295
|
throw new CLIError(`pyne-worker directory not found: ${dir}
|
|
39084
39296
|
` + ` Clone it with: hoox clone pyne-worker
|
|
39085
39297
|
` + ` Or: git submodule update --init workers/pyne-worker`, 1 /* ERROR */);
|
|
@@ -39094,7 +39306,7 @@ function loadDevVars(workerDir) {
|
|
|
39094
39306
|
];
|
|
39095
39307
|
for (const filePath of candidates) {
|
|
39096
39308
|
try {
|
|
39097
|
-
if (!
|
|
39309
|
+
if (!existsSync14(filePath))
|
|
39098
39310
|
continue;
|
|
39099
39311
|
const content = readFileSync8(filePath, "utf-8");
|
|
39100
39312
|
for (const line of content.split(`
|
|
@@ -39312,7 +39524,7 @@ EXAMPLES:
|
|
|
39312
39524
|
body.script = await new Response(Bun.stdin).text();
|
|
39313
39525
|
} else {
|
|
39314
39526
|
const abs = resolve7(process.cwd(), scriptPath);
|
|
39315
|
-
if (!
|
|
39527
|
+
if (!existsSync14(abs)) {
|
|
39316
39528
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39317
39529
|
}
|
|
39318
39530
|
body.script = readFileSync8(abs, "utf-8");
|
|
@@ -39363,7 +39575,7 @@ EXAMPLES:
|
|
|
39363
39575
|
throw new CLIError("API key required for authenticated endpoints", 2 /* INVALID_USAGE */);
|
|
39364
39576
|
}
|
|
39365
39577
|
const abs = resolve7(process.cwd(), scriptPath);
|
|
39366
|
-
if (!
|
|
39578
|
+
if (!existsSync14(abs)) {
|
|
39367
39579
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39368
39580
|
}
|
|
39369
39581
|
const script = readFileSync8(abs, "utf-8");
|
|
@@ -39471,7 +39683,7 @@ Pass script flags after -- :
|
|
|
39471
39683
|
Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorHandling(async () => {
|
|
39472
39684
|
const dir = requirePyneDir();
|
|
39473
39685
|
const script = resolve7(dir, "scripts/sync_vendor.sh");
|
|
39474
|
-
if (!
|
|
39686
|
+
if (!existsSync14(script)) {
|
|
39475
39687
|
throw new CLIError(`sync_vendor.sh not found at ${script}`, 1 /* ERROR */);
|
|
39476
39688
|
}
|
|
39477
39689
|
process.exitCode = await spawnInPyneDir(["bash", script], dir);
|
|
@@ -39480,7 +39692,7 @@ Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorH
|
|
|
39480
39692
|
const dir = requirePyneDir();
|
|
39481
39693
|
if (!opts.skipSync) {
|
|
39482
39694
|
const script = resolve7(dir, "scripts/sync_vendor.sh");
|
|
39483
|
-
if (
|
|
39695
|
+
if (existsSync14(script)) {
|
|
39484
39696
|
const code = await spawnInPyneDir(["bash", script], dir);
|
|
39485
39697
|
if (code !== 0) {
|
|
39486
39698
|
process.exitCode = code;
|
|
@@ -41029,7 +41241,7 @@ function registerCompletionCommand(program2) {
|
|
|
41029
41241
|
// src/ui/banner.ts
|
|
41030
41242
|
init_ansis();
|
|
41031
41243
|
init_theme();
|
|
41032
|
-
import { existsSync as
|
|
41244
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
41033
41245
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41034
41246
|
import { dirname as dirname4, join as join13 } from "path";
|
|
41035
41247
|
var ORANGE = ansis_default.hex("#ff7f2a");
|
|
@@ -41045,7 +41257,7 @@ function findCliVersion() {
|
|
|
41045
41257
|
let dir = dirname4(fileURLToPath2(import.meta.url));
|
|
41046
41258
|
for (let i2 = 0;i2 < 5; i2++) {
|
|
41047
41259
|
const pkgPath = join13(dir, "package.json");
|
|
41048
|
-
if (
|
|
41260
|
+
if (existsSync15(pkgPath)) {
|
|
41049
41261
|
try {
|
|
41050
41262
|
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
41051
41263
|
if (pkg.name === PKG_NAME)
|
|
@@ -41684,6 +41896,13 @@ Hoox CLI \u2014 Cloudflare Workers Platform
|
|
|
41684
41896
|
styleCommandText: (str) => theme.bold(str),
|
|
41685
41897
|
styleOptionText: (str) => str,
|
|
41686
41898
|
styleDescriptionText: (str) => theme.dim(str)
|
|
41899
|
+
}).configureOutput({
|
|
41900
|
+
outputError: (str, write) => {
|
|
41901
|
+
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)) {
|
|
41902
|
+
return;
|
|
41903
|
+
}
|
|
41904
|
+
write(str);
|
|
41905
|
+
}
|
|
41687
41906
|
});
|
|
41688
41907
|
program2.option("--json", "Output in JSON format");
|
|
41689
41908
|
program2.option("--quiet", "Minimal output");
|
|
@@ -41698,10 +41917,16 @@ program2.hook("preAction", async () => {
|
|
|
41698
41917
|
return;
|
|
41699
41918
|
if (process.env.BUN_TEST === "1")
|
|
41700
41919
|
return;
|
|
41920
|
+
if (process.argv.includes("--json"))
|
|
41921
|
+
return;
|
|
41701
41922
|
try {
|
|
41702
41923
|
const { UpdateService: UpdateService2 } = await Promise.resolve().then(() => (init_update(), exports_update));
|
|
41703
41924
|
const service = new UpdateService2;
|
|
41704
|
-
|
|
41925
|
+
const autoUpdate = process.env.HOOX_AUTO_UPDATE_WRANGLER === "1";
|
|
41926
|
+
await service.checkAndPromptUpdate({
|
|
41927
|
+
yes: autoUpdate,
|
|
41928
|
+
silent: true
|
|
41929
|
+
});
|
|
41705
41930
|
} catch {}
|
|
41706
41931
|
});
|
|
41707
41932
|
program2.hook("postAction", (thisCmd) => {
|
|
@@ -41713,54 +41938,67 @@ program2.hook("postAction", (thisCmd) => {
|
|
|
41713
41938
|
const durationMs = Date.now() - startedAt;
|
|
41714
41939
|
const path6 = getCmdPath(thisCmd);
|
|
41715
41940
|
const suggestion = suggestNextCommand(path6);
|
|
41716
|
-
|
|
41941
|
+
const g2 = program2.opts();
|
|
41942
|
+
formatCompletion("Done", {
|
|
41943
|
+
durationMs,
|
|
41944
|
+
suggestion,
|
|
41945
|
+
json: Boolean(g2.json),
|
|
41946
|
+
quiet: Boolean(g2.quiet),
|
|
41947
|
+
noColor: g2.color === false || Boolean(process.env.NO_COLOR)
|
|
41948
|
+
});
|
|
41717
41949
|
});
|
|
41718
41950
|
program2.exitOverride((err) => {
|
|
41719
41951
|
const globalOpts = program2.opts();
|
|
41720
41952
|
const errFmtOpts = {
|
|
41721
41953
|
json: Boolean(globalOpts.json),
|
|
41722
41954
|
quiet: Boolean(globalOpts.quiet),
|
|
41723
|
-
noColor: Boolean(
|
|
41955
|
+
noColor: globalOpts.color === false || Boolean(process.env.NO_COLOR)
|
|
41724
41956
|
};
|
|
41725
41957
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
41726
41958
|
process.exitCode = 0 /* SUCCESS */;
|
|
41727
|
-
|
|
41959
|
+
throw err;
|
|
41728
41960
|
}
|
|
41729
|
-
if (err.
|
|
41961
|
+
if ((err.message === "(outputHelp)" || err.message?.includes("outputHelp")) && err.code !== "commander.missingArgument") {
|
|
41730
41962
|
process.exitCode = 0 /* SUCCESS */;
|
|
41731
|
-
|
|
41963
|
+
throw err;
|
|
41732
41964
|
}
|
|
41733
41965
|
if (err.code === "commander.unknownCommand") {
|
|
41734
41966
|
const match = err.message.match(/'([^']+)'/);
|
|
41735
41967
|
const badArg = match?.[1] ?? "";
|
|
41736
41968
|
const suggestion = suggestForCommand(program2, badArg);
|
|
41737
|
-
|
|
41969
|
+
const cleanMsg = err.message.replace(/\n?\(Did you mean[^)]*\)\s*/gi, "").trim();
|
|
41970
|
+
formatError2(new CLIError(cleanMsg, 2 /* INVALID_USAGE */, undefined, false), suggestion ? { ...errFmtOpts, suggestions: [suggestion] } : errFmtOpts);
|
|
41738
41971
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41739
|
-
|
|
41972
|
+
throw err;
|
|
41740
41973
|
}
|
|
41741
41974
|
if (err.code === "commander.unknownOption") {
|
|
41742
41975
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), errFmtOpts);
|
|
41743
41976
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41744
|
-
|
|
41977
|
+
throw err;
|
|
41745
41978
|
}
|
|
41746
|
-
if (err.code === "commander.
|
|
41979
|
+
if (err.code === "commander.missingArgument" || err.code === "commander.missingMandatoryOptionValue") {
|
|
41747
41980
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), errFmtOpts);
|
|
41748
41981
|
process.exitCode = 2 /* INVALID_USAGE */;
|
|
41749
|
-
|
|
41982
|
+
throw err;
|
|
41750
41983
|
}
|
|
41751
41984
|
if (err instanceof CLIError) {
|
|
41752
41985
|
formatError2(err, errFmtOpts);
|
|
41753
41986
|
process.exitCode = err.code;
|
|
41754
|
-
|
|
41987
|
+
throw err;
|
|
41755
41988
|
}
|
|
41756
41989
|
formatError2(new CLIError(err.message, 1 /* ERROR */, undefined, false), errFmtOpts);
|
|
41757
41990
|
process.exitCode = 1 /* ERROR */;
|
|
41991
|
+
throw err;
|
|
41758
41992
|
});
|
|
41759
41993
|
process.on("uncaughtException", (err) => {
|
|
41994
|
+
if (process.exitCode !== undefined && process.exitCode !== 0)
|
|
41995
|
+
return;
|
|
41760
41996
|
formatError2(err instanceof CLIError ? err : new CLIError(`Uncaught exception: ${err.message}`, 1 /* ERROR */, err.stack, false));
|
|
41761
41997
|
process.exitCode = 1 /* ERROR */;
|
|
41762
41998
|
});
|
|
41763
41999
|
process.on("unhandledRejection", (reason) => {
|
|
42000
|
+
if (process.exitCode !== undefined && process.exitCode !== 0)
|
|
42001
|
+
return;
|
|
41764
42002
|
const err = reason instanceof Error ? reason : new Error(`Unhandled rejection: ${toError(reason)}`);
|
|
41765
42003
|
formatError2(new CLIError(err.message, 1 /* ERROR */, err.stack, false));
|
|
41766
42004
|
process.exitCode = 1 /* ERROR */;
|
|
@@ -41804,17 +42042,31 @@ async function main() {
|
|
|
41804
42042
|
const configFile = Bun.file("wrangler.jsonc");
|
|
41805
42043
|
const hasConfig = await configFile.exists();
|
|
41806
42044
|
const wizardStateFile = Bun.file(WIZARD_STATE_PATH);
|
|
41807
|
-
const hasWizardState = await wizardStateFile.exists();
|
|
42045
|
+
const hasWizardState = await wizardStateFile.exists() && (await wizardStateFile.text()).trim().length > 0;
|
|
41808
42046
|
if (!hasConfig) {
|
|
41809
42047
|
const args = hasWizardState ? ["onboard", "--resume"] : ["onboard"];
|
|
41810
42048
|
await program2.parseAsync(args, { from: "user" });
|
|
41811
42049
|
return;
|
|
41812
42050
|
}
|
|
41813
|
-
if (
|
|
41814
|
-
|
|
42051
|
+
if (await wizardStateFile.exists()) {
|
|
42052
|
+
try {
|
|
42053
|
+
const { unlinkSync } = await import("fs");
|
|
42054
|
+
unlinkSync(WIZARD_STATE_PATH);
|
|
42055
|
+
} catch {
|
|
42056
|
+
await Bun.write(WIZARD_STATE_PATH, "");
|
|
42057
|
+
}
|
|
41815
42058
|
}
|
|
41816
42059
|
await runInteractiveTUI(program2);
|
|
41817
42060
|
}
|
|
42061
|
+
} catch (err) {
|
|
42062
|
+
if (process.exitCode === undefined) {
|
|
42063
|
+
const message = err instanceof Error ? err.message : `Unhandled error: ${String(err)}`;
|
|
42064
|
+
const isCommander = err instanceof Error && "code" in err && typeof err.code === "string" && String(err.code).startsWith("commander.");
|
|
42065
|
+
if (!isCommander) {
|
|
42066
|
+
formatError2(new CLIError(message, 1 /* ERROR */, undefined, false));
|
|
42067
|
+
}
|
|
42068
|
+
process.exitCode = 1 /* ERROR */;
|
|
42069
|
+
}
|
|
41818
42070
|
} finally {
|
|
41819
42071
|
if (typeof process.exit === "function" && process.exitCode !== undefined) {
|
|
41820
42072
|
process.exit(process.exitCode);
|