@hoox-sh/hoox-cli 0.11.4 → 0.11.6
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 +46 -5
- package/dist/index.js +293 -130
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
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.11.x** — operator security plane (`doctor --security`, `tunnel check
|
|
9
|
+
**v0.11.x** — monorepo auto-detect + remember (run `hx` from any directory), Linear Rail banner, quieter secrets check, operator security plane (`doctor --security`, `tunnel check`), PYNE (`hoox pyne`), schema validate/generate, wrangler **4.x**.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
+
- **Monorepo auto-detect & remember**: On every start the CLI finds the hoox monorepo (`HOOX_REPO` → walk up from cwd → `~/.hoox/config/monorepo.json` → `~/.hoox/repo`), saves the path, and `chdir`s into it so `hx` / `hoox` work from `~/Videos` or any other folder after you have run once from the monorepo.
|
|
13
14
|
- **One-shot Onboarding** (`hoox onboard`): Full bootstrap from a fresh clone — collects credentials, configures workers, provisions D1/KV, generates keys, pushes secrets, deploys dashboard. The recommended entry point for new users.
|
|
14
15
|
- **Config & Setup Wizards** (`hoox init`, `hoox setup`): Split into two steps — `init` writes `wrangler.jsonc` and collects integration secrets; `setup` generates keys, applies D1 schema, and pushes secrets to Cloudflare. Run separately when you need fine-grained control.
|
|
15
16
|
- **Infrastructure as Code**: Manage D1, KV, R2, Queues, Vectorize, and Analytics via `hoox infra`.
|
|
@@ -56,6 +57,10 @@ bun run build # produces dist/index.js — required for `hoox` after global in
|
|
|
56
57
|
## Quick Start
|
|
57
58
|
|
|
58
59
|
```bash
|
|
60
|
+
# From the monorepo root (first time — path is remembered)
|
|
61
|
+
cd /path/to/hoox
|
|
62
|
+
hoox doctor # shows Remembered + Runtime root
|
|
63
|
+
|
|
59
64
|
# One-shot onboarding (collects credentials, provisions, deploys)
|
|
60
65
|
hoox onboard
|
|
61
66
|
|
|
@@ -70,8 +75,42 @@ hoox check health
|
|
|
70
75
|
# Deploy to Cloudflare
|
|
71
76
|
hoox deploy all --auto
|
|
72
77
|
|
|
73
|
-
#
|
|
74
|
-
|
|
78
|
+
# Later: works from any directory (uses remembered monorepo)
|
|
79
|
+
cd ~/Videos
|
|
80
|
+
hx check health
|
|
81
|
+
hx doctor # Source: remembered
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Monorepo resolution (any cwd)
|
|
85
|
+
|
|
86
|
+
Resolution order at CLI startup:
|
|
87
|
+
|
|
88
|
+
1. **`HOOX_REPO`** — absolute path override (highest priority)
|
|
89
|
+
2. **Walk up from cwd** — discovers a local checkout (`packages/cli` + repo markers)
|
|
90
|
+
3. **Remembered path** — `~/.hoox/config/monorepo.json` (written when discovered via cwd/env)
|
|
91
|
+
4. **Global clone** — `~/.hoox/repo` (create with `hoox doctor --fix-runtime`)
|
|
92
|
+
|
|
93
|
+
When a root is found, the CLI:
|
|
94
|
+
|
|
95
|
+
- refreshes the remembered path (when source is `cwd` / `env` / `remembered`)
|
|
96
|
+
- sets session `HOOX_REPO` for child processes
|
|
97
|
+
- `chdir`s into the monorepo so relative paths (`wrangler.jsonc`, `workers/`, …) work
|
|
98
|
+
|
|
99
|
+
Markers for a valid monorepo: `packages/cli/package.json` **plus** one of `wrangler.jsonc`, `wrangler.jsonc.example`, `workers/`, or `.gitmodules`.
|
|
100
|
+
|
|
101
|
+
| Env / path | Purpose |
|
|
102
|
+
| ------------------------------ | ------------------------------------------------------ |
|
|
103
|
+
| `HOOX_REPO` | Force monorepo root |
|
|
104
|
+
| `HOOX_HOME` | Override `~/.hoox` (default home for config/data/repo) |
|
|
105
|
+
| `HOOX_CLI_SILENT=1` | Suppress “using monorepo at …” notice |
|
|
106
|
+
| `~/.hoox/config/monorepo.json` | Persisted root `{ "root", "updatedAt" }` |
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Inspect layout
|
|
110
|
+
hoox doctor
|
|
111
|
+
# Remembered /home/you/Git/hoox
|
|
112
|
+
# Runtime root /home/you/Git/hoox
|
|
113
|
+
# Source remembered
|
|
75
114
|
```
|
|
76
115
|
|
|
77
116
|
## Available Commands
|
|
@@ -358,8 +397,9 @@ hoox perf fastpath report --from 1h
|
|
|
358
397
|
### Operator Security & Private Ingress
|
|
359
398
|
|
|
360
399
|
```bash
|
|
361
|
-
# Paths, TUI entry,
|
|
400
|
+
# Paths, TUI entry, remembered monorepo, runtime layout
|
|
362
401
|
hoox doctor
|
|
402
|
+
hoox doctor --fix-runtime # clone monorepo into ~/.hoox/repo if needed
|
|
363
403
|
|
|
364
404
|
# Hygiene + optional management /v1/health probes
|
|
365
405
|
hoox doctor --security
|
|
@@ -504,8 +544,9 @@ packages/cli/
|
|
|
504
544
|
│ │ ├── perf/ # Percentile, probe-sender, observability-reader
|
|
505
545
|
│ │ ├── prerequisites/ # Tool version checks
|
|
506
546
|
│ │ ├── runtime/ # Global ~/.hoox layout
|
|
547
|
+
│ │ ├── workspace/ # Monorepo detect, remember, chdir
|
|
507
548
|
│ │ └── secrets/ # Secret management
|
|
508
|
-
│ ├── ui/ # Interactive menu
|
|
549
|
+
│ ├── ui/ # Interactive menu + Linear Rail banner
|
|
509
550
|
│ └── utils/ # Errors, formatters, theme
|
|
510
551
|
├── bin/
|
|
511
552
|
│ └── hoox.js # CLI binary entry point
|
package/dist/index.js
CHANGED
|
@@ -16200,7 +16200,13 @@ var init_sse = __esm(() => {
|
|
|
16200
16200
|
});
|
|
16201
16201
|
|
|
16202
16202
|
// ../shared/src/path-utils.ts
|
|
16203
|
-
import {
|
|
16203
|
+
import {
|
|
16204
|
+
existsSync as existsSync2,
|
|
16205
|
+
mkdirSync as mkdirSync2,
|
|
16206
|
+
readFileSync as readFileSync2,
|
|
16207
|
+
writeFileSync as writeFileSync2,
|
|
16208
|
+
chmodSync as chmodSync2
|
|
16209
|
+
} from "fs";
|
|
16204
16210
|
import { homedir as homedir2 } from "os";
|
|
16205
16211
|
import { dirname, join as join2, resolve } from "path";
|
|
16206
16212
|
function createHooxPath(path2) {
|
|
@@ -16226,7 +16232,55 @@ function isHooxSetupRoot(dir) {
|
|
|
16226
16232
|
return false;
|
|
16227
16233
|
try {
|
|
16228
16234
|
const root = resolve(dir);
|
|
16229
|
-
|
|
16235
|
+
if (!existsSync2(join2(root, "packages", "cli", "package.json"))) {
|
|
16236
|
+
return false;
|
|
16237
|
+
}
|
|
16238
|
+
return existsSync2(join2(root, "wrangler.jsonc")) || existsSync2(join2(root, "wrangler.jsonc.example")) || existsSync2(join2(root, "workers")) || existsSync2(join2(root, ".gitmodules"));
|
|
16239
|
+
} catch {
|
|
16240
|
+
return false;
|
|
16241
|
+
}
|
|
16242
|
+
}
|
|
16243
|
+
function getRememberedMonorepoPath() {
|
|
16244
|
+
return resolveHooxPath("config/monorepo.json");
|
|
16245
|
+
}
|
|
16246
|
+
function getRememberedMonorepoRoot() {
|
|
16247
|
+
try {
|
|
16248
|
+
const path2 = getRememberedMonorepoPath();
|
|
16249
|
+
if (!existsSync2(path2))
|
|
16250
|
+
return null;
|
|
16251
|
+
const raw = readFileSync2(path2, "utf-8");
|
|
16252
|
+
const data = JSON.parse(raw);
|
|
16253
|
+
if (!data.root || typeof data.root !== "string")
|
|
16254
|
+
return null;
|
|
16255
|
+
const resolved = resolve(data.root);
|
|
16256
|
+
return isHooxSetupRoot(resolved) ? resolved : null;
|
|
16257
|
+
} catch {
|
|
16258
|
+
return null;
|
|
16259
|
+
}
|
|
16260
|
+
}
|
|
16261
|
+
function rememberMonorepoRoot(root) {
|
|
16262
|
+
try {
|
|
16263
|
+
const resolved = resolve(root);
|
|
16264
|
+
if (!isHooxSetupRoot(resolved))
|
|
16265
|
+
return false;
|
|
16266
|
+
const configDir = getHooxConfigDir();
|
|
16267
|
+
mkdirSync2(configDir, { recursive: true, mode: 448 });
|
|
16268
|
+
try {
|
|
16269
|
+
chmodSync2(configDir, 448);
|
|
16270
|
+
} catch {}
|
|
16271
|
+
const payload = {
|
|
16272
|
+
root: resolved,
|
|
16273
|
+
updatedAt: new Date().toISOString()
|
|
16274
|
+
};
|
|
16275
|
+
const path2 = getRememberedMonorepoPath();
|
|
16276
|
+
writeFileSync2(path2, JSON.stringify(payload, null, 2) + `
|
|
16277
|
+
`, {
|
|
16278
|
+
mode: 384
|
|
16279
|
+
});
|
|
16280
|
+
try {
|
|
16281
|
+
chmodSync2(path2, 384);
|
|
16282
|
+
} catch {}
|
|
16283
|
+
return true;
|
|
16230
16284
|
} catch {
|
|
16231
16285
|
return false;
|
|
16232
16286
|
}
|
|
@@ -16246,6 +16300,7 @@ function resolveHooxRuntimeRoot(options) {
|
|
|
16246
16300
|
const env = options?.env ?? process.env;
|
|
16247
16301
|
const cwd = resolve(options?.cwd ?? process.cwd());
|
|
16248
16302
|
const globalRepo = getHooxRepoPath();
|
|
16303
|
+
const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
|
|
16249
16304
|
const envRepo = env.HOOX_REPO?.trim();
|
|
16250
16305
|
if (envRepo) {
|
|
16251
16306
|
const resolved = resolve(envRepo);
|
|
@@ -16256,6 +16311,7 @@ function resolveHooxRuntimeRoot(options) {
|
|
|
16256
16311
|
checked: {
|
|
16257
16312
|
env: resolved,
|
|
16258
16313
|
cwd: findHooxSetupRoot(cwd),
|
|
16314
|
+
remembered,
|
|
16259
16315
|
global: globalRepo
|
|
16260
16316
|
}
|
|
16261
16317
|
};
|
|
@@ -16266,6 +16322,7 @@ function resolveHooxRuntimeRoot(options) {
|
|
|
16266
16322
|
checked: {
|
|
16267
16323
|
env: resolved,
|
|
16268
16324
|
cwd: findHooxSetupRoot(cwd),
|
|
16325
|
+
remembered,
|
|
16269
16326
|
global: globalRepo
|
|
16270
16327
|
}
|
|
16271
16328
|
};
|
|
@@ -16275,20 +16332,27 @@ function resolveHooxRuntimeRoot(options) {
|
|
|
16275
16332
|
return {
|
|
16276
16333
|
root: local,
|
|
16277
16334
|
source: "cwd",
|
|
16278
|
-
checked: { cwd: local, global: globalRepo }
|
|
16335
|
+
checked: { cwd: local, remembered, global: globalRepo }
|
|
16336
|
+
};
|
|
16337
|
+
}
|
|
16338
|
+
if (remembered) {
|
|
16339
|
+
return {
|
|
16340
|
+
root: remembered,
|
|
16341
|
+
source: "remembered",
|
|
16342
|
+
checked: { cwd: null, remembered, global: globalRepo }
|
|
16279
16343
|
};
|
|
16280
16344
|
}
|
|
16281
16345
|
if (isHooxSetupRoot(globalRepo)) {
|
|
16282
16346
|
return {
|
|
16283
16347
|
root: globalRepo,
|
|
16284
16348
|
source: "global",
|
|
16285
|
-
checked: { cwd: null, global: globalRepo }
|
|
16349
|
+
checked: { cwd: null, remembered: null, global: globalRepo }
|
|
16286
16350
|
};
|
|
16287
16351
|
}
|
|
16288
16352
|
return {
|
|
16289
16353
|
root: null,
|
|
16290
16354
|
source: "none",
|
|
16291
|
-
checked: { cwd: null, global: globalRepo }
|
|
16355
|
+
checked: { cwd: null, remembered: null, global: globalRepo }
|
|
16292
16356
|
};
|
|
16293
16357
|
}
|
|
16294
16358
|
function getTuiEntryCandidates(runtimeRoot) {
|
|
@@ -16468,7 +16532,7 @@ function formatRelativeTime2(timestampMs, nowMs) {
|
|
|
16468
16532
|
}
|
|
16469
16533
|
|
|
16470
16534
|
// ../shared/src/dashboard-manifest.ts
|
|
16471
|
-
import { existsSync as existsSync3, readdirSync, readFileSync as
|
|
16535
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
16472
16536
|
import { join as join3 } from "path";
|
|
16473
16537
|
function isDashboardSectionFlatKv(sectionId) {
|
|
16474
16538
|
return !DASHBOARD_SECTIONS_NOT_FLAT_KV.has(sectionId);
|
|
@@ -16702,7 +16766,7 @@ function tryReadFile(path2) {
|
|
|
16702
16766
|
try {
|
|
16703
16767
|
if (!existsSync3(path2))
|
|
16704
16768
|
return null;
|
|
16705
|
-
return
|
|
16769
|
+
return readFileSync3(path2, "utf-8");
|
|
16706
16770
|
} catch {
|
|
16707
16771
|
return null;
|
|
16708
16772
|
}
|
|
@@ -21897,7 +21961,7 @@ var init_middleware = __esm(() => {
|
|
|
21897
21961
|
});
|
|
21898
21962
|
|
|
21899
21963
|
// ../shared/src/stores/config-store.ts
|
|
21900
|
-
import { chmodSync as
|
|
21964
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
|
|
21901
21965
|
import { homedir as homedir3 } from "os";
|
|
21902
21966
|
import { join as join4 } from "path";
|
|
21903
21967
|
var bunConfigStorage, DEFAULT_SHORTCUTS, DEFAULT_LOG_FILTER, DEFAULT_NOTIFICATIONS, defaults, useConfigStore;
|
|
@@ -21921,15 +21985,15 @@ var init_config_store = __esm(() => {
|
|
|
21921
21985
|
setItem: async (_name, value) => {
|
|
21922
21986
|
const dir = join4(homedir3(), ".hoox");
|
|
21923
21987
|
if (!existsSync4(dir)) {
|
|
21924
|
-
|
|
21988
|
+
mkdirSync3(dir, { recursive: true, mode: HOOX_DIR_MODE });
|
|
21925
21989
|
}
|
|
21926
21990
|
try {
|
|
21927
|
-
|
|
21991
|
+
chmodSync3(dir, HOOX_DIR_MODE);
|
|
21928
21992
|
} catch {}
|
|
21929
21993
|
const filePath = join4(dir, "config.json");
|
|
21930
21994
|
await Bun.write(filePath, value);
|
|
21931
21995
|
try {
|
|
21932
|
-
|
|
21996
|
+
chmodSync3(filePath, HOOX_CONFIG_FILE_MODE);
|
|
21933
21997
|
} catch {}
|
|
21934
21998
|
},
|
|
21935
21999
|
removeItem: async (_name) => {}
|
|
@@ -22049,6 +22113,7 @@ __export(exports_src, {
|
|
|
22049
22113
|
resolveHooxRuntimeRoot: () => resolveHooxRuntimeRoot,
|
|
22050
22114
|
resolveHooxPath: () => resolveHooxPath,
|
|
22051
22115
|
resolveDependencies: () => resolveDependencies,
|
|
22116
|
+
rememberMonorepoRoot: () => rememberMonorepoRoot,
|
|
22052
22117
|
readConfigSync: () => readConfigSync,
|
|
22053
22118
|
readConfig: () => readConfig,
|
|
22054
22119
|
parseDashboardManifest: () => parseDashboardManifest,
|
|
@@ -22073,6 +22138,8 @@ __export(exports_src, {
|
|
|
22073
22138
|
headersToObject: () => headersToObject,
|
|
22074
22139
|
hasOperatorClientCredentials: () => hasOperatorClientCredentials,
|
|
22075
22140
|
getTuiEntryCandidates: () => getTuiEntryCandidates,
|
|
22141
|
+
getRememberedMonorepoRoot: () => getRememberedMonorepoRoot,
|
|
22142
|
+
getRememberedMonorepoPath: () => getRememberedMonorepoPath,
|
|
22076
22143
|
getRelativeHooxPath: () => getRelativeHooxPath,
|
|
22077
22144
|
getHooxWranglerPath: () => getHooxWranglerPath,
|
|
22078
22145
|
getHooxStatePath: () => getHooxStatePath,
|
|
@@ -25557,15 +25624,15 @@ __export(exports_fs_secure, {
|
|
|
25557
25624
|
SECRET_FILE_MODE: () => SECRET_FILE_MODE,
|
|
25558
25625
|
SECRET_DIR_MODE: () => SECRET_DIR_MODE
|
|
25559
25626
|
});
|
|
25560
|
-
import { chmodSync as
|
|
25627
|
+
import { chmodSync as chmodSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
25561
25628
|
function secureChmod(path4, mode) {
|
|
25562
25629
|
try {
|
|
25563
|
-
|
|
25630
|
+
chmodSync4(path4, mode);
|
|
25564
25631
|
} catch {}
|
|
25565
25632
|
}
|
|
25566
25633
|
function ensureSecretDir(dir) {
|
|
25567
25634
|
try {
|
|
25568
|
-
|
|
25635
|
+
mkdirSync4(dir, { recursive: true, mode: SECRET_DIR_MODE });
|
|
25569
25636
|
} catch {}
|
|
25570
25637
|
secureChmod(dir, SECRET_DIR_MODE);
|
|
25571
25638
|
}
|
|
@@ -26171,7 +26238,7 @@ var exports_schema_service = {};
|
|
|
26171
26238
|
__export(exports_schema_service, {
|
|
26172
26239
|
SchemaService: () => SchemaService
|
|
26173
26240
|
});
|
|
26174
|
-
import { readFileSync as
|
|
26241
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11 } from "fs";
|
|
26175
26242
|
import { resolve as resolve4 } from "path";
|
|
26176
26243
|
|
|
26177
26244
|
class SchemaService {
|
|
@@ -26207,7 +26274,7 @@ class SchemaService {
|
|
|
26207
26274
|
const errors4 = [];
|
|
26208
26275
|
const isHooxProject = existsSync11(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync11(resolve4(this.projectRoot, "workers"));
|
|
26209
26276
|
try {
|
|
26210
|
-
const wranglerContent =
|
|
26277
|
+
const wranglerContent = readFileSync6(workerWranglerPath, "utf-8");
|
|
26211
26278
|
errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
|
|
26212
26279
|
} catch (e) {
|
|
26213
26280
|
const isErrnoException = e instanceof Error && "code" in e;
|
|
@@ -26221,7 +26288,7 @@ class SchemaService {
|
|
|
26221
26288
|
});
|
|
26222
26289
|
}
|
|
26223
26290
|
try {
|
|
26224
|
-
const rootContent =
|
|
26291
|
+
const rootContent = readFileSync6(rootWranglerPath, "utf-8");
|
|
26225
26292
|
errors4.push(...validateRootSecrets(name, manifest, rootContent));
|
|
26226
26293
|
} catch (e) {
|
|
26227
26294
|
const errMessage = e instanceof Error ? e.message : String(e);
|
|
@@ -26232,7 +26299,7 @@ class SchemaService {
|
|
|
26232
26299
|
});
|
|
26233
26300
|
}
|
|
26234
26301
|
try {
|
|
26235
|
-
const devVarsContent =
|
|
26302
|
+
const devVarsContent = readFileSync6(devVarsPath, "utf-8");
|
|
26236
26303
|
errors4.push(...validateDevVars(name, manifest, devVarsContent));
|
|
26237
26304
|
} catch (e) {
|
|
26238
26305
|
const errMessage = e instanceof Error ? e.message : String(e);
|
|
@@ -26491,7 +26558,7 @@ var init_trace_service = __esm(() => {
|
|
|
26491
26558
|
});
|
|
26492
26559
|
|
|
26493
26560
|
// src/index.ts
|
|
26494
|
-
import { readFileSync as
|
|
26561
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
26495
26562
|
|
|
26496
26563
|
// ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
|
|
26497
26564
|
class CommanderError extends Error {
|
|
@@ -29621,13 +29688,13 @@ async function runInitCommand(options, globalOpts, isNonInteractive) {
|
|
|
29621
29688
|
}
|
|
29622
29689
|
// src/services/setup/setup-service.ts
|
|
29623
29690
|
import {
|
|
29624
|
-
chmodSync as
|
|
29691
|
+
chmodSync as chmodSync5,
|
|
29625
29692
|
existsSync as existsSync7,
|
|
29626
|
-
mkdirSync as
|
|
29693
|
+
mkdirSync as mkdirSync5,
|
|
29627
29694
|
readdirSync as readdirSync3,
|
|
29628
|
-
readFileSync as
|
|
29695
|
+
readFileSync as readFileSync4,
|
|
29629
29696
|
statSync as statSync2,
|
|
29630
|
-
writeFileSync as
|
|
29697
|
+
writeFileSync as writeFileSync3
|
|
29631
29698
|
} from "fs";
|
|
29632
29699
|
import { homedir as homedir4 } from "os";
|
|
29633
29700
|
import { join as join7 } from "path";
|
|
@@ -29699,7 +29766,7 @@ function parseEnvFile(text2) {
|
|
|
29699
29766
|
}
|
|
29700
29767
|
function safeChmod(path4, mode) {
|
|
29701
29768
|
try {
|
|
29702
|
-
|
|
29769
|
+
chmodSync5(path4, mode);
|
|
29703
29770
|
} catch {}
|
|
29704
29771
|
}
|
|
29705
29772
|
function loadExistingKeysFromDisk() {
|
|
@@ -29708,7 +29775,7 @@ function loadExistingKeysFromDisk() {
|
|
|
29708
29775
|
return null;
|
|
29709
29776
|
let text2;
|
|
29710
29777
|
try {
|
|
29711
|
-
text2 =
|
|
29778
|
+
text2 = readFileSync4(setupEnv, "utf-8");
|
|
29712
29779
|
} catch {
|
|
29713
29780
|
return null;
|
|
29714
29781
|
}
|
|
@@ -29773,9 +29840,9 @@ class SetupService {
|
|
|
29773
29840
|
API_SERVICE_KEY_BINDING: internalKey
|
|
29774
29841
|
};
|
|
29775
29842
|
if (!existsSync7(KEYS_DIR)) {
|
|
29776
|
-
|
|
29843
|
+
mkdirSync5(KEYS_DIR, { recursive: true });
|
|
29777
29844
|
} else if (!statSync2(KEYS_DIR).isDirectory()) {
|
|
29778
|
-
|
|
29845
|
+
mkdirSync5(KEYS_DIR, { recursive: true });
|
|
29779
29846
|
}
|
|
29780
29847
|
safeChmod(KEYS_DIR, 448);
|
|
29781
29848
|
const setupEnvPath = join7(KEYS_DIR, "setup.env");
|
|
@@ -29798,7 +29865,7 @@ class SetupService {
|
|
|
29798
29865
|
const path4 = `workers/${workerFsDir(worker)}/.dev.vars`;
|
|
29799
29866
|
const meshNames = secretNames;
|
|
29800
29867
|
const meshSet = new Set(meshNames);
|
|
29801
|
-
const existing = existsSync7(path4) ? parseEnvFile(
|
|
29868
|
+
const existing = existsSync7(path4) ? parseEnvFile(readFileSync4(path4, "utf-8")) : new Map;
|
|
29802
29869
|
for (const secretName of meshNames) {
|
|
29803
29870
|
existing.set(secretName, keys[secretName]);
|
|
29804
29871
|
}
|
|
@@ -29958,7 +30025,7 @@ class SetupService {
|
|
|
29958
30025
|
const wranglerPath = join7("workers", workerFsDir(worker), "wrangler.jsonc");
|
|
29959
30026
|
let wranglerContent;
|
|
29960
30027
|
try {
|
|
29961
|
-
wranglerContent =
|
|
30028
|
+
wranglerContent = readFileSync4(wranglerPath, "utf-8");
|
|
29962
30029
|
} catch {
|
|
29963
30030
|
return { ok: false, error: errMsg };
|
|
29964
30031
|
}
|
|
@@ -29976,7 +30043,7 @@ class SetupService {
|
|
|
29976
30043
|
let fixed = wranglerContent.replace(new RegExp(`(\\s*//[^\\n]*\\n)?\\s*"${escapeRegex2(secretName)}"\\s*:\\s*null\\s*,?\\s*\\n?`, "g"), `
|
|
29977
30044
|
`);
|
|
29978
30045
|
fixed = fixed.replace(/"vars"\s*:\s*\{\s*\}/, '"vars": {}');
|
|
29979
|
-
|
|
30046
|
+
writeFileSync3(wranglerPath, fixed, "utf-8");
|
|
29980
30047
|
this.onProgress({
|
|
29981
30048
|
type: "info",
|
|
29982
30049
|
step: "secrets",
|
|
@@ -30159,7 +30226,7 @@ class SetupService {
|
|
|
30159
30226
|
for (const name of workerDirs) {
|
|
30160
30227
|
const dir = `workers/${workerFsDir(name)}`;
|
|
30161
30228
|
try {
|
|
30162
|
-
const gitEntry =
|
|
30229
|
+
const gitEntry = readFileSync4(join7(dir, ".git"), "utf-8").trim();
|
|
30163
30230
|
if (gitEntry.startsWith("gitdir:") || gitEntry.length > 0) {
|
|
30164
30231
|
if (!this.isWorkerTreePopulated(dir, name))
|
|
30165
30232
|
missing.push(name);
|
|
@@ -30308,7 +30375,7 @@ class SetupService {
|
|
|
30308
30375
|
const wranglerPath = `workers/${workerFsDir(worker)}/wrangler.jsonc`;
|
|
30309
30376
|
let content;
|
|
30310
30377
|
try {
|
|
30311
|
-
content =
|
|
30378
|
+
content = readFileSync4(wranglerPath, "utf-8");
|
|
30312
30379
|
} catch {
|
|
30313
30380
|
continue;
|
|
30314
30381
|
}
|
|
@@ -30340,7 +30407,7 @@ class SetupService {
|
|
|
30340
30407
|
}
|
|
30341
30408
|
if (modified) {
|
|
30342
30409
|
content = content.replace(/"vars"\s*:\s*\{\s*\}/, '"vars": {}');
|
|
30343
|
-
|
|
30410
|
+
writeFileSync3(wranglerPath, content, "utf-8");
|
|
30344
30411
|
fixed.push(worker);
|
|
30345
30412
|
}
|
|
30346
30413
|
}
|
|
@@ -30495,7 +30562,7 @@ class SetupService {
|
|
|
30495
30562
|
const devVarsPath = `workers/${workerFsDir(worker)}/.dev.vars`;
|
|
30496
30563
|
let devVarsContent;
|
|
30497
30564
|
try {
|
|
30498
|
-
devVarsContent =
|
|
30565
|
+
devVarsContent = readFileSync4(devVarsPath, "utf-8");
|
|
30499
30566
|
} catch {
|
|
30500
30567
|
missing.push(`${worker}:.dev.vars (missing file)`);
|
|
30501
30568
|
continue;
|
|
@@ -31300,8 +31367,8 @@ init_errors4();
|
|
|
31300
31367
|
import {
|
|
31301
31368
|
statSync as statSync3,
|
|
31302
31369
|
existsSync as existsSync8,
|
|
31303
|
-
readFileSync as
|
|
31304
|
-
writeFileSync as
|
|
31370
|
+
readFileSync as readFileSync5,
|
|
31371
|
+
writeFileSync as writeFileSync4,
|
|
31305
31372
|
renameSync
|
|
31306
31373
|
} from "fs";
|
|
31307
31374
|
import { resolve as resolve2 } from "path";
|
|
@@ -32082,7 +32149,7 @@ async function doUpdateInternalUrls(fmt) {
|
|
|
32082
32149
|
process.exitCode = 1 /* ERROR */;
|
|
32083
32150
|
return;
|
|
32084
32151
|
}
|
|
32085
|
-
const content =
|
|
32152
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
32086
32153
|
const errors4 = [];
|
|
32087
32154
|
const parsed = parse6(content, errors4);
|
|
32088
32155
|
if (errors4.length > 0) {
|
|
@@ -32108,12 +32175,12 @@ async function doUpdateInternalUrls(fmt) {
|
|
|
32108
32175
|
formatSuccess("All service URLs already up to date.", fmt);
|
|
32109
32176
|
return;
|
|
32110
32177
|
}
|
|
32111
|
-
const fresh =
|
|
32178
|
+
const fresh = readFileSync5(filePath, "utf-8");
|
|
32112
32179
|
const edits = modify(fresh, ["vars"], vars, {
|
|
32113
32180
|
formattingOptions: { tabSize: 2, insertSpaces: true }
|
|
32114
32181
|
});
|
|
32115
32182
|
const tmpPath = `${filePath}.tmp-${process.pid}`;
|
|
32116
|
-
|
|
32183
|
+
writeFileSync4(tmpPath, applyEdits(fresh, edits), "utf-8");
|
|
32117
32184
|
renameSync(tmpPath, filePath);
|
|
32118
32185
|
formatSuccess(`Updated ${changesCount} service URL(s) in dashboard wrangler.jsonc`, fmt);
|
|
32119
32186
|
} catch (err) {
|
|
@@ -34824,6 +34891,22 @@ async function runInfraChecks(cf) {
|
|
|
34824
34891
|
});
|
|
34825
34892
|
return { name: "Infrastructure", checks: checks3 };
|
|
34826
34893
|
}
|
|
34894
|
+
function parseRemoteSecretNames(raw) {
|
|
34895
|
+
try {
|
|
34896
|
+
const parsed = JSON.parse(raw);
|
|
34897
|
+
if (!Array.isArray(parsed))
|
|
34898
|
+
return null;
|
|
34899
|
+
const names = new Set;
|
|
34900
|
+
for (const item of parsed) {
|
|
34901
|
+
if (item && typeof item === "object" && typeof item.name === "string") {
|
|
34902
|
+
names.add(item.name);
|
|
34903
|
+
}
|
|
34904
|
+
}
|
|
34905
|
+
return names;
|
|
34906
|
+
} catch {
|
|
34907
|
+
return null;
|
|
34908
|
+
}
|
|
34909
|
+
}
|
|
34827
34910
|
async function runSecretsChecks(secretsService, configService, cf) {
|
|
34828
34911
|
const checks3 = [];
|
|
34829
34912
|
const enabledWorkers = configService.listEnabledWorkers();
|
|
@@ -34832,11 +34915,11 @@ async function runSecretsChecks(secretsService, configService, cf) {
|
|
|
34832
34915
|
for (const workerName of enabledWorkers) {
|
|
34833
34916
|
const result = await secretsService.checkLocalSecrets(workerName);
|
|
34834
34917
|
if (result.missing.length > 0) {
|
|
34835
|
-
errors4.push(`Worker "${workerName}" missing secrets: ${result.missing.join(", ")}`);
|
|
34918
|
+
errors4.push(`Worker "${workerName}" missing secrets: ${result.missing.join(", ")}. ` + `Fix: hoox setup --skip-db --skip-dashboard (mesh keys) or ` + `hoox secrets set ${workerName} <NAME>`);
|
|
34836
34919
|
}
|
|
34837
34920
|
for (const secret of result.secrets) {
|
|
34838
|
-
if (secret.set && secret.source) {
|
|
34839
|
-
warnings.push(`Worker "${workerName}": ${secret.name} is
|
|
34921
|
+
if (!secret.set && secret.source) {
|
|
34922
|
+
warnings.push(`Worker "${workerName}": ${secret.name} is present in ${secret.source} but empty/placeholder`);
|
|
34840
34923
|
}
|
|
34841
34924
|
}
|
|
34842
34925
|
}
|
|
@@ -34849,14 +34932,22 @@ async function runSecretsChecks(secretsService, configService, cf) {
|
|
|
34849
34932
|
const remoteErrors = [];
|
|
34850
34933
|
const remoteWarnings = [];
|
|
34851
34934
|
for (const workerName of enabledWorkers) {
|
|
34852
|
-
const
|
|
34853
|
-
if (
|
|
34935
|
+
const expected = secretsService.listSecrets(workerName);
|
|
34936
|
+
if (expected.length === 0)
|
|
34854
34937
|
continue;
|
|
34855
34938
|
const result = await cf.secretList(workerName);
|
|
34856
34939
|
if (!result.ok) {
|
|
34857
34940
|
remoteErrors.push(`Worker "${workerName}": ${result.error}`);
|
|
34858
|
-
|
|
34859
|
-
|
|
34941
|
+
continue;
|
|
34942
|
+
}
|
|
34943
|
+
const remoteNames = parseRemoteSecretNames(result.value);
|
|
34944
|
+
if (!remoteNames) {
|
|
34945
|
+
remoteWarnings.push(`Worker "${workerName}": could not parse remote secret list (raw length ${result.value.length})`);
|
|
34946
|
+
continue;
|
|
34947
|
+
}
|
|
34948
|
+
const missingRemote = expected.filter((n3) => !remoteNames.has(n3));
|
|
34949
|
+
if (missingRemote.length > 0) {
|
|
34950
|
+
remoteErrors.push(`Worker "${workerName}" missing on Cloudflare: ${missingRemote.join(", ")}. ` + `Fix: hoox secrets sync ${workerName}`);
|
|
34860
34951
|
}
|
|
34861
34952
|
}
|
|
34862
34953
|
checks3.push({
|
|
@@ -37731,10 +37822,10 @@ import { existsSync as existsSync12, realpathSync } from "fs";
|
|
|
37731
37822
|
import { homedir as homedir5 } from "os";
|
|
37732
37823
|
|
|
37733
37824
|
// src/services/perf/endpoint-resolver.ts
|
|
37734
|
-
import { readFileSync as
|
|
37825
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
37735
37826
|
function readSubdomainPrefix() {
|
|
37736
37827
|
try {
|
|
37737
|
-
const raw =
|
|
37828
|
+
const raw = readFileSync7("wrangler.jsonc", "utf8");
|
|
37738
37829
|
const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
37739
37830
|
const parsed = JSON.parse(stripped);
|
|
37740
37831
|
const prefix = parsed.global?.subdomain_prefix;
|
|
@@ -38139,6 +38230,62 @@ ${install.stderr || install.stdout}`.trim());
|
|
|
38139
38230
|
const tuiEntry = firstExisting(getTuiEntryCandidates(repoPath));
|
|
38140
38231
|
return { repoPath, cloned, installed, tuiEntry };
|
|
38141
38232
|
}
|
|
38233
|
+
// src/commands/doctor/doctor-command.ts
|
|
38234
|
+
init_src();
|
|
38235
|
+
|
|
38236
|
+
// src/services/workspace/workspace-context.ts
|
|
38237
|
+
init_src();
|
|
38238
|
+
import { resolve as resolve7 } from "path";
|
|
38239
|
+
var lastWorkspaceContext = null;
|
|
38240
|
+
function getLastWorkspaceContext() {
|
|
38241
|
+
return lastWorkspaceContext;
|
|
38242
|
+
}
|
|
38243
|
+
function ensureWorkspaceContext(options) {
|
|
38244
|
+
const previousCwd = resolve7(options?.cwd ?? process.cwd());
|
|
38245
|
+
const inTest = process.env.BUN_TEST === "1" || false || typeof process.env.BUN_TEST !== "undefined";
|
|
38246
|
+
const allowChdir = options?.force === true || !inTest;
|
|
38247
|
+
const runtime = resolveHooxRuntimeRoot({ cwd: previousCwd });
|
|
38248
|
+
const quiet = options?.quiet === true || process.env.HOOX_CLI_SILENT === "1" || process.argv.includes("--json") || process.argv.includes("--quiet");
|
|
38249
|
+
if (!runtime.root) {
|
|
38250
|
+
const empty = {
|
|
38251
|
+
root: null,
|
|
38252
|
+
source: runtime.source,
|
|
38253
|
+
chdir: false,
|
|
38254
|
+
previousCwd,
|
|
38255
|
+
runtime
|
|
38256
|
+
};
|
|
38257
|
+
lastWorkspaceContext = empty;
|
|
38258
|
+
return empty;
|
|
38259
|
+
}
|
|
38260
|
+
if (runtime.source === "cwd" || runtime.source === "env") {
|
|
38261
|
+
rememberMonorepoRoot(runtime.root);
|
|
38262
|
+
} else if (runtime.source === "remembered") {
|
|
38263
|
+
rememberMonorepoRoot(runtime.root);
|
|
38264
|
+
}
|
|
38265
|
+
if (!process.env.HOOX_REPO) {
|
|
38266
|
+
process.env.HOOX_REPO = runtime.root;
|
|
38267
|
+
}
|
|
38268
|
+
let didChdir = false;
|
|
38269
|
+
const target = resolve7(runtime.root);
|
|
38270
|
+
if (allowChdir && resolve7(process.cwd()) !== target) {
|
|
38271
|
+
process.chdir(target);
|
|
38272
|
+
didChdir = true;
|
|
38273
|
+
if (!quiet) {
|
|
38274
|
+
const label = runtime.source === "remembered" ? "remembered monorepo" : runtime.source === "global" ? "global runtime" : runtime.source === "env" ? "HOOX_REPO" : "monorepo";
|
|
38275
|
+
process.stderr.write(`hoox: using ${label} at ${target}
|
|
38276
|
+
`);
|
|
38277
|
+
}
|
|
38278
|
+
}
|
|
38279
|
+
const ctx = {
|
|
38280
|
+
root: target,
|
|
38281
|
+
source: runtime.source,
|
|
38282
|
+
chdir: didChdir,
|
|
38283
|
+
previousCwd,
|
|
38284
|
+
runtime
|
|
38285
|
+
};
|
|
38286
|
+
lastWorkspaceContext = ctx;
|
|
38287
|
+
return ctx;
|
|
38288
|
+
}
|
|
38142
38289
|
// src/services/operator-security/operator-security-service.ts
|
|
38143
38290
|
init_src();
|
|
38144
38291
|
function collectSecurityHygiene(env = process.env, options) {
|
|
@@ -38389,14 +38536,19 @@ function printCheckIcon(severity) {
|
|
|
38389
38536
|
function printStatus() {
|
|
38390
38537
|
const status = getRuntimeStatus();
|
|
38391
38538
|
const { runtime } = status;
|
|
38539
|
+
const remembered = getRememberedMonorepoRoot();
|
|
38540
|
+
const session = getLastWorkspaceContext();
|
|
38541
|
+
const sourceLabel = session?.source ?? runtime.source;
|
|
38542
|
+
const rootLabel = session?.root ?? runtime.root;
|
|
38392
38543
|
process.stdout.write(theme.heading(`
|
|
38393
38544
|
Hoox doctor
|
|
38394
38545
|
|
|
38395
38546
|
`));
|
|
38396
38547
|
process.stdout.write(`${theme.dim("HOOX_HOME")} ${status.hooxHome}
|
|
38397
38548
|
` + `${theme.dim("Global repo")} ${status.repoPath}
|
|
38398
|
-
` + `${theme.dim("
|
|
38399
|
-
` + `${theme.dim("
|
|
38549
|
+
` + `${theme.dim("Remembered")} ${remembered ?? theme.dim("(none \u2014 run hx once from the monorepo)")}
|
|
38550
|
+
` + `${theme.dim("Runtime root")} ${rootLabel ?? theme.warning("(none)")}
|
|
38551
|
+
` + `${theme.dim("Source")} ${sourceLabel}
|
|
38400
38552
|
` + `${theme.dim("TUI entry")} ${status.tuiEntry ?? theme.warning("(not found)")}
|
|
38401
38553
|
|
|
38402
38554
|
`);
|
|
@@ -38415,10 +38567,10 @@ Hoox doctor
|
|
|
38415
38567
|
detail: status.isSetupRoot ? "monorepo markers present" : status.repoPresent ? "path exists but is not a setup monorepo" : runtime.root ? "optional (runtime resolved elsewhere)" : "missing \u2014 run: hoox doctor --fix-runtime"
|
|
38416
38568
|
},
|
|
38417
38569
|
{
|
|
38418
|
-
ok:
|
|
38570
|
+
ok: rootLabel !== null,
|
|
38419
38571
|
required: true,
|
|
38420
38572
|
label: "Resolved runtime root",
|
|
38421
|
-
detail:
|
|
38573
|
+
detail: rootLabel === null ? "set HOOX_REPO, run hx once inside the monorepo (remembers path), or: hoox doctor --fix-runtime" : `${sourceLabel}: ${rootLabel}`
|
|
38422
38574
|
},
|
|
38423
38575
|
{
|
|
38424
38576
|
ok: status.tuiEntry !== null,
|
|
@@ -38717,7 +38869,7 @@ function registerDisclaimerCommand(program2) {
|
|
|
38717
38869
|
}));
|
|
38718
38870
|
}
|
|
38719
38871
|
// src/commands/agent/agent-command.ts
|
|
38720
|
-
import { readFileSync as
|
|
38872
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
38721
38873
|
init_errors4();
|
|
38722
38874
|
var PROVIDERS = [
|
|
38723
38875
|
{
|
|
@@ -38751,7 +38903,7 @@ function checkDevVars() {
|
|
|
38751
38903
|
const candidates = ["workers/agent-worker/.dev.vars", ".dev.vars"];
|
|
38752
38904
|
for (const filePath of candidates) {
|
|
38753
38905
|
try {
|
|
38754
|
-
const content =
|
|
38906
|
+
const content = readFileSync8(filePath, "utf-8");
|
|
38755
38907
|
for (const line of content.split(`
|
|
38756
38908
|
`)) {
|
|
38757
38909
|
const trimmed = line.trim();
|
|
@@ -39282,12 +39434,12 @@ EXAMPLES:
|
|
|
39282
39434
|
}
|
|
39283
39435
|
// src/commands/pyne/pyne-command.ts
|
|
39284
39436
|
init_config2();
|
|
39285
|
-
import { existsSync as existsSync14, readFileSync as
|
|
39286
|
-
import { resolve as
|
|
39437
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
|
|
39438
|
+
import { resolve as resolve8 } from "path";
|
|
39287
39439
|
init_errors4();
|
|
39288
39440
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
39289
39441
|
function getPyneWorkerDir() {
|
|
39290
|
-
return
|
|
39442
|
+
return resolve8(process.cwd(), "workers/pyne-worker");
|
|
39291
39443
|
}
|
|
39292
39444
|
function requirePyneDir() {
|
|
39293
39445
|
const dir = getPyneWorkerDir();
|
|
@@ -39301,14 +39453,14 @@ function requirePyneDir() {
|
|
|
39301
39453
|
function loadDevVars(workerDir) {
|
|
39302
39454
|
const out = {};
|
|
39303
39455
|
const candidates = [
|
|
39304
|
-
|
|
39305
|
-
|
|
39456
|
+
resolve8(workerDir, ".dev.vars"),
|
|
39457
|
+
resolve8(process.cwd(), ".dev.vars")
|
|
39306
39458
|
];
|
|
39307
39459
|
for (const filePath of candidates) {
|
|
39308
39460
|
try {
|
|
39309
39461
|
if (!existsSync14(filePath))
|
|
39310
39462
|
continue;
|
|
39311
|
-
const content =
|
|
39463
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
39312
39464
|
for (const line of content.split(`
|
|
39313
39465
|
`)) {
|
|
39314
39466
|
const trimmed = line.trim();
|
|
@@ -39523,11 +39675,11 @@ EXAMPLES:
|
|
|
39523
39675
|
} else if (scriptPath === "-") {
|
|
39524
39676
|
body.script = await new Response(Bun.stdin).text();
|
|
39525
39677
|
} else {
|
|
39526
|
-
const abs =
|
|
39678
|
+
const abs = resolve8(process.cwd(), scriptPath);
|
|
39527
39679
|
if (!existsSync14(abs)) {
|
|
39528
39680
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39529
39681
|
}
|
|
39530
|
-
body.script =
|
|
39682
|
+
body.script = readFileSync9(abs, "utf-8");
|
|
39531
39683
|
}
|
|
39532
39684
|
const res = await pyneFetch(baseUrl, "/run", {
|
|
39533
39685
|
method: "POST",
|
|
@@ -39574,11 +39726,11 @@ EXAMPLES:
|
|
|
39574
39726
|
if (!apiKey) {
|
|
39575
39727
|
throw new CLIError("API key required for authenticated endpoints", 2 /* INVALID_USAGE */);
|
|
39576
39728
|
}
|
|
39577
|
-
const abs =
|
|
39729
|
+
const abs = resolve8(process.cwd(), scriptPath);
|
|
39578
39730
|
if (!existsSync14(abs)) {
|
|
39579
39731
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39580
39732
|
}
|
|
39581
|
-
const script =
|
|
39733
|
+
const script = readFileSync9(abs, "utf-8");
|
|
39582
39734
|
const baseName = abs.split(/[/\\]/).pop() ?? "script.pine";
|
|
39583
39735
|
const scriptId = opts.id ?? baseName.replace(/\.pine$/i, "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
39584
39736
|
const res = await pyneFetch(baseUrl, "/scripts", {
|
|
@@ -39682,7 +39834,7 @@ Pass script flags after -- :
|
|
|
39682
39834
|
pyneCmd.command("sync-vendor").summary("Sync pynescript into python_modules/ for Cloudflare deploy").description(`Runs workers/pyne-worker/scripts/sync_vendor.sh.
|
|
39683
39835
|
Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorHandling(async () => {
|
|
39684
39836
|
const dir = requirePyneDir();
|
|
39685
|
-
const script =
|
|
39837
|
+
const script = resolve8(dir, "scripts/sync_vendor.sh");
|
|
39686
39838
|
if (!existsSync14(script)) {
|
|
39687
39839
|
throw new CLIError(`sync_vendor.sh not found at ${script}`, 1 /* ERROR */);
|
|
39688
39840
|
}
|
|
@@ -39691,7 +39843,7 @@ Required before wrangler deploy after pulling new PYNE APIs.`).action(withErrorH
|
|
|
39691
39843
|
pyneCmd.command("deploy").summary("sync-vendor then wrangler deploy pyne-worker").option("--skip-sync", "Skip scripts/sync_vendor.sh").action(withErrorHandling(async (opts) => {
|
|
39692
39844
|
const dir = requirePyneDir();
|
|
39693
39845
|
if (!opts.skipSync) {
|
|
39694
|
-
const script =
|
|
39846
|
+
const script = resolve8(dir, "scripts/sync_vendor.sh");
|
|
39695
39847
|
if (existsSync14(script)) {
|
|
39696
39848
|
const code = await spawnInPyneDir(["bash", script], dir);
|
|
39697
39849
|
if (code !== 0) {
|
|
@@ -40253,7 +40405,7 @@ ${theme.dim("Live tail duration reached. Exiting.")}
|
|
|
40253
40405
|
`);
|
|
40254
40406
|
}
|
|
40255
40407
|
} catch {}
|
|
40256
|
-
await new Promise((
|
|
40408
|
+
await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
|
|
40257
40409
|
await poll();
|
|
40258
40410
|
};
|
|
40259
40411
|
await poll();
|
|
@@ -41241,7 +41393,7 @@ function registerCompletionCommand(program2) {
|
|
|
41241
41393
|
// src/ui/banner.ts
|
|
41242
41394
|
init_ansis();
|
|
41243
41395
|
init_theme();
|
|
41244
|
-
import { existsSync as existsSync15, readFileSync as
|
|
41396
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
|
|
41245
41397
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41246
41398
|
import { dirname as dirname4, join as join13 } from "path";
|
|
41247
41399
|
var ORANGE = ansis_default.hex("#ff7f2a");
|
|
@@ -41259,7 +41411,7 @@ function findCliVersion() {
|
|
|
41259
41411
|
const pkgPath = join13(dir, "package.json");
|
|
41260
41412
|
if (existsSync15(pkgPath)) {
|
|
41261
41413
|
try {
|
|
41262
|
-
const pkg = JSON.parse(
|
|
41414
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
41263
41415
|
if (pkg.name === PKG_NAME)
|
|
41264
41416
|
return pkg.version;
|
|
41265
41417
|
} catch {}
|
|
@@ -41273,68 +41425,78 @@ function findCliVersion() {
|
|
|
41273
41425
|
}
|
|
41274
41426
|
var VERSION = findCliVersion();
|
|
41275
41427
|
var DISCLAIMER2 = "DISCLAIMER: Trading cryptocurrencies involves substantial risk of loss. Use at your own risk.";
|
|
41276
|
-
var
|
|
41277
|
-
|
|
41278
|
-
"| | | |/ _ \\ / _ \\ \\/ / ",
|
|
41279
|
-
"| |_| | (_) | (_) > < ",
|
|
41280
|
-
" \\___/ \\___/ \\___/_/\\_\\ "
|
|
41281
|
-
];
|
|
41282
|
-
var WORD_W = WORDMARK[0].length;
|
|
41283
|
-
function colorWordmark(phase, mode) {
|
|
41284
|
-
return WORDMARK.map((line, row) => {
|
|
41285
|
-
if (mode === "assemble") {
|
|
41286
|
-
const local = Math.max(0, Math.min(1, phase));
|
|
41287
|
-
const cut = Math.floor(local * line.length);
|
|
41288
|
-
let out = "";
|
|
41289
|
-
for (let col = 0;col < line.length; col++) {
|
|
41290
|
-
const ch = line[col];
|
|
41291
|
-
if (ch === " ") {
|
|
41292
|
-
out += " ";
|
|
41293
|
-
continue;
|
|
41294
|
-
}
|
|
41295
|
-
if (col > cut)
|
|
41296
|
-
out += ZINC_FAINT("\xB7");
|
|
41297
|
-
else if (local < 0.85)
|
|
41298
|
-
out += ZINC(ch);
|
|
41299
|
-
else
|
|
41300
|
-
out += theme.heading(ch);
|
|
41301
|
-
}
|
|
41302
|
-
return out;
|
|
41303
|
-
}
|
|
41304
|
-
if (mode === "pulse") {
|
|
41305
|
-
let out = "";
|
|
41306
|
-
for (let col = 0;col < line.length; col++) {
|
|
41307
|
-
const ch = line[col];
|
|
41308
|
-
if (ch === " ") {
|
|
41309
|
-
out += " ";
|
|
41310
|
-
continue;
|
|
41311
|
-
}
|
|
41312
|
-
const t2 = (phase * 1.5 + col * 0.05 + row * 0.06) % 1;
|
|
41313
|
-
if (t2 < 0.12)
|
|
41314
|
-
out += AMBER(ch);
|
|
41315
|
-
else if (t2 < 0.25)
|
|
41316
|
-
out += ORANGE(ch);
|
|
41317
|
-
else if (t2 < 0.4)
|
|
41318
|
-
out += INDIGO_SOFT(ch);
|
|
41319
|
-
else
|
|
41320
|
-
out += INDIGO.bold(ch);
|
|
41321
|
-
}
|
|
41322
|
-
return out;
|
|
41323
|
-
}
|
|
41324
|
-
return theme.heading(line);
|
|
41325
|
-
});
|
|
41326
|
-
}
|
|
41428
|
+
var LETTERS = ["H", "O", "O", "X"];
|
|
41429
|
+
var RULE_W = 38;
|
|
41327
41430
|
var PAD = " ";
|
|
41431
|
+
function colorDiamond(phase, mode) {
|
|
41432
|
+
if (mode === "assemble") {
|
|
41433
|
+
if (phase < 0.05)
|
|
41434
|
+
return " ";
|
|
41435
|
+
if (phase < 0.2)
|
|
41436
|
+
return ZINC_FAINT("\u25C6");
|
|
41437
|
+
return AMBER("\u25C6");
|
|
41438
|
+
}
|
|
41439
|
+
if (mode === "pulse") {
|
|
41440
|
+
const t2 = phase * 2 % 1;
|
|
41441
|
+
return t2 < 0.5 ? AMBER("\u25C6") : ORANGE("\u25C6");
|
|
41442
|
+
}
|
|
41443
|
+
return AMBER("\u25C6");
|
|
41444
|
+
}
|
|
41445
|
+
function colorLetter(letter, index, phase, mode) {
|
|
41446
|
+
if (mode === "assemble") {
|
|
41447
|
+
const start = 0.12;
|
|
41448
|
+
const span = 0.88;
|
|
41449
|
+
const letterPhase = (phase - start) / span;
|
|
41450
|
+
const revealAt = index / LETTERS.length;
|
|
41451
|
+
if (letterPhase < revealAt)
|
|
41452
|
+
return " ";
|
|
41453
|
+
if (letterPhase < revealAt + 0.12)
|
|
41454
|
+
return ZINC(letter);
|
|
41455
|
+
return INDIGO.bold(letter);
|
|
41456
|
+
}
|
|
41457
|
+
if (mode === "pulse") {
|
|
41458
|
+
const t2 = (phase * 1.4 + index * 0.18) % 1;
|
|
41459
|
+
if (t2 < 0.15)
|
|
41460
|
+
return INDIGO_SOFT(letter);
|
|
41461
|
+
if (t2 < 0.3)
|
|
41462
|
+
return AMBER(letter);
|
|
41463
|
+
return INDIGO.bold(letter);
|
|
41464
|
+
}
|
|
41465
|
+
return INDIGO.bold(letter);
|
|
41466
|
+
}
|
|
41467
|
+
function colorDot(afterLetterIndex, phase, mode) {
|
|
41468
|
+
if (mode === "assemble") {
|
|
41469
|
+
const start = 0.12;
|
|
41470
|
+
const span = 0.88;
|
|
41471
|
+
const letterPhase = (phase - start) / span;
|
|
41472
|
+
const revealAt = (afterLetterIndex + 1) / LETTERS.length;
|
|
41473
|
+
if (letterPhase < revealAt - 0.02)
|
|
41474
|
+
return " ";
|
|
41475
|
+
return ZINC_FAINT("\xB7");
|
|
41476
|
+
}
|
|
41477
|
+
return ZINC_FAINT("\xB7");
|
|
41478
|
+
}
|
|
41479
|
+
function composeTitleLine(phase, mode) {
|
|
41480
|
+
const diamond = colorDiamond(phase, mode);
|
|
41481
|
+
const parts = [diamond, " "];
|
|
41482
|
+
for (let i2 = 0;i2 < LETTERS.length; i2++) {
|
|
41483
|
+
parts.push(colorLetter(LETTERS[i2], i2, phase, mode));
|
|
41484
|
+
if (i2 < LETTERS.length - 1) {
|
|
41485
|
+
parts.push(" ");
|
|
41486
|
+
parts.push(colorDot(i2, phase, mode));
|
|
41487
|
+
parts.push(" ");
|
|
41488
|
+
}
|
|
41489
|
+
}
|
|
41490
|
+
return PAD + parts.join("");
|
|
41491
|
+
}
|
|
41492
|
+
function composeMetaLine() {
|
|
41493
|
+
return PAD + ZINC_SOFT(TAGLINE) + " " + ZINC_FAINT("\xB7") + " " + INDIGO_SOFT(`v${VERSION}`);
|
|
41494
|
+
}
|
|
41328
41495
|
function composeFrame(phase, mode) {
|
|
41329
|
-
const
|
|
41330
|
-
const
|
|
41331
|
-
const
|
|
41332
|
-
|
|
41333
|
-
const metaInner = ZINC_SOFT(TAGLINE) + " " + ZINC_FAINT("\xB7") + " " + INDIGO_SOFT(`v${VERSION}`);
|
|
41334
|
-
const metaVis = stripAnsi(metaInner).length;
|
|
41335
|
-
const metaPad = Math.max(0, Math.floor((contentW - metaVis) / 2));
|
|
41336
|
-
const meta3 = PAD + " ".repeat(metaPad) + metaInner;
|
|
41337
|
-
return [rule, ...body, rule, meta3].join(`
|
|
41496
|
+
const title = composeTitleLine(phase, mode);
|
|
41497
|
+
const rule = PAD + ZINC_SOFT("\xB7") + " " + ZINC_FAINT("\u2500".repeat(RULE_W - 2));
|
|
41498
|
+
const meta3 = composeMetaLine();
|
|
41499
|
+
return [title, rule, meta3].join(`
|
|
41338
41500
|
`);
|
|
41339
41501
|
}
|
|
41340
41502
|
function canAnimate() {
|
|
@@ -41884,7 +42046,7 @@ if (typeof Bun === "undefined") {
|
|
|
41884
42046
|
`);
|
|
41885
42047
|
process.exit(1);
|
|
41886
42048
|
}
|
|
41887
|
-
var pkgVersion = JSON.parse(
|
|
42049
|
+
var pkgVersion = JSON.parse(readFileSync11(new URL("../package.json", import.meta.url), "utf-8")).version;
|
|
41888
42050
|
var program2 = new Command;
|
|
41889
42051
|
program2.name("hoox").description("Hoox CLI \u2014 manage Cloudflare Workers, infrastructure, secrets, and deployments").version(`${pkgVersion}
|
|
41890
42052
|
|
|
@@ -42035,6 +42197,7 @@ registerPerfCommand(program2);
|
|
|
42035
42197
|
registerCompletionCommand(program2);
|
|
42036
42198
|
async function main() {
|
|
42037
42199
|
try {
|
|
42200
|
+
ensureWorkspaceContext();
|
|
42038
42201
|
const hasArgs = process.argv.slice(2).length > 0;
|
|
42039
42202
|
if (hasArgs) {
|
|
42040
42203
|
await program2.parseAsync(process.argv);
|