@hoox-sh/hoox-cli 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +567 -0
  2. package/bin/hoox.js +110 -0
  3. package/dist/index.js +41689 -0
  4. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,567 @@
1
+ # @hoox-sh/hoox-cli
2
+
3
+ > **See also:** [Docs home](../../docs/index.mdx) · [CLI Command Reference](../../docs/enduser/reference/cli-commands.mdx) · [Monorepo README](../../README.md)
4
+
5
+ > Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments.
6
+
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
+
9
+ **v0.10.1** — operator security plane: fail-closed `tui --remote`, transport profile (Bearer + Access), `doctor --security`, `tunnel check`, management `/v1/*` contract. **v0.9.x** shipped hop-level `perf fastpath` observability and reliability fixes.
10
+
11
+ ## Features
12
+
13
+ - **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
+ - **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
+ - **Infrastructure as Code**: Manage D1, KV, R2, Queues, Vectorize, and Analytics via `hoox infra`.
16
+ - **Environment Management**: Declarative 27-key env matrix via `hoox config env`.
17
+ - **KV Config Sync**: 16-key manifest with `apply-manifest` for CONFIG_KV.
18
+ - **Database Operations**: Schema apply, migrations, query, export, reset via `hoox db`.
19
+ - **Deploy Automation**: Workers + dashboard + telegram webhook + KV config in one flow.
20
+ - **Performance Measurement** (`hoox perf`): `fastpath` subcommand sends synthetic probes and reports p50/p95/p99 per-hop latency.
21
+ - **Observability** (`hoox trace`): Query Cloudflare Workers Observability REST API for events, metrics, and traces.
22
+ - **Health Checks** (`hoox check health`): The single source of truth for worker health probes. Run after deployments or in CI.
23
+ - **Operational Monitoring** (`hoox monitor`): Recent trades, kill switch, queue depth, backup, system logs.
24
+ - **Repair & Recovery** (`hoox repair`): Comprehensive system check, guided rebuild, per-component repair.
25
+ - **Top-level Secrets & Keys**: `hoox secrets` and `hoox keys` for Cloudflare Worker secrets and internal auth keys.
26
+ - **Unified Dashboard** (`hoox dashboard dev | deploy`): Start the dev server or build & deploy the Next.js dashboard.
27
+ - **Interactive menu & TUI**: Running `hoox` with no arguments opens the interactive menu; `hoox tui` launches the full OpenTUI operations center.
28
+ - **Operator security plane** (`hoox doctor`, `hoox tunnel`): Path/TUI hygiene, fail-closed remote transport (Bearer + Access), and private-ingress checks.
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
+ - **Shell Completions**: bash, zsh, and fish completion scripts via `hoox completion <shell>`.
31
+
32
+ ## Installation
33
+
34
+ ### Global Install (Recommended)
35
+
36
+ ```bash
37
+ # Using bun (the only supported runtime)
38
+ bun add -g @hoox-sh/hoox-cli
39
+ ```
40
+
41
+ > The CLI is a Bun bundle — `npm install -g` will not produce a working binary.
42
+
43
+ ### Local Development
44
+
45
+ ```bash
46
+ cd packages/cli
47
+ bun install
48
+ bun run build # produces dist/index.js — required for `hoox` after global install
49
+ ```
50
+
51
+ > `bin/hoox.js` resolves `dist/index.js` first and falls back to `src/index.ts`
52
+ > when `dist/` is missing, so contributors who skip the build step can still
53
+ > run the CLI via `bun bin/hoox.js …` or a `bun link`-based install. Production
54
+ > releases and the `prepublishOnly` script always build first.
55
+
56
+ ## Quick Start
57
+
58
+ ```bash
59
+ # One-shot onboarding (collects credentials, provisions, deploys)
60
+ hoox onboard
61
+
62
+ # Or step-by-step: write config first, then provision
63
+ hoox init
64
+ hoox setup
65
+
66
+ # Verify the system
67
+ hoox check setup
68
+ hoox check health
69
+
70
+ # Deploy to Cloudflare
71
+ hoox deploy all --auto
72
+
73
+ # Measure fast-path latency
74
+ hoox perf fastpath run --n 50
75
+ ```
76
+
77
+ ## Available Commands
78
+
79
+ | Command | Description |
80
+ | ----------------- | -------------------------------------------------------------------- |
81
+ | `hoox onboard` | **Recommended entry point.** One-shot full bootstrap (init + setup) |
82
+ | `hoox init` | Interactive setup wizard (writes `wrangler.jsonc`, collects secrets) |
83
+ | `hoox setup` | Auto-bootstrap infrastructure (auth, keys, D1, secrets, dashboard) |
84
+ | `hoox clone` | Clone worker repositories as git submodules |
85
+ | `hoox dev` | Start local development environment for all workers |
86
+ | `hoox deploy` | Deploy workers, dashboard, telegram webhook, and KV config |
87
+ | `hoox infra` | Manage infrastructure (D1, KV, R2, Queues, Vectorize, Analytics) |
88
+ | `hoox config` | Manage `wrangler.jsonc` configuration |
89
+ | `hoox secrets` | Manage secrets (`sync --system` for mesh keys only) |
90
+ | `hoox keys` | Manage internal auth keys |
91
+ | `hoox check` | Validate setup, prerequisites, and worker health |
92
+ | `hoox db` | Manage D1 databases (apply, migrate, query, export, reset) |
93
+ | `hoox monitor` | Monitor trades, logs, kill switch, queue, backup |
94
+ | `hoox workers` | Per-worker operations (list, dev, logs) |
95
+ | `hoox repair` | Diagnose and repair the system (check, rebuild, per-component) |
96
+ | `hoox schema` | Validate/generate worker wrangler manifests against canonical specs |
97
+ | `hoox update` | Pull repo/submodule updates or update wrangler |
98
+ | `hoox logs` | Stream and filter Cloudflare Worker logs |
99
+ | `hoox test` | Run tests and CI pipeline |
100
+ | `hoox waf` | Manage Cloudflare WAF rules and policies |
101
+ | `hoox dashboard` | Dashboard operations (`dev`, `deploy`) |
102
+ | `hoox tui` | Launch the OpenTUI terminal dashboard |
103
+ | `hoox doctor` | Check paths, TUI entry, and operator security hygiene |
104
+ | `hoox tunnel` | Private operator ingress helpers (cloudflared + Access) |
105
+ | `hoox agent` | AI agent ops (`health`, optional `--probe` live checks) |
106
+ | `hoox pyne` | PYNE edge evaluate (`health`, `run`, `scripts`, `deploy`, …) |
107
+ | `hoox trace` | Query Cloudflare Workers Observability (events, metrics, traces) |
108
+ | `hoox perf` | Performance measurement tools (`fastpath` probe-based latency) |
109
+ | `hoox disclaimer` | Display legal disclaimer |
110
+ | `hoox completion` | Generate shell completion script (bash, zsh, fish) |
111
+
112
+ ### Global Options
113
+
114
+ All commands support these global options:
115
+
116
+ | Option | Description |
117
+ | ------------ | -------------------------------------------- |
118
+ | `--json` | Output in JSON format (useful for scripting) |
119
+ | `--quiet` | Minimal output mode |
120
+ | `--no-color` | Disable ANSI colors (`NO_COLOR` also works) |
121
+
122
+ ## Usage Examples
123
+
124
+ ### Onboard a New Project
125
+
126
+ ```bash
127
+ # One-shot (recommended) — fully automatic, no separate setup step
128
+ hoox onboard --token cfut_xxx --account xxx --preset full
129
+
130
+ # Interactive
131
+ hoox onboard
132
+ ```
133
+
134
+ Interactive prompts collect your Cloudflare Account ID, API Token, and subdomain prefix; then it writes the config and provisions infrastructure end-to-end.
135
+
136
+ ### Step-by-Step Onboarding
137
+
138
+ ```bash
139
+ # 1. Write workspace config (wrangler.jsonc, secrets)
140
+ hoox init
141
+
142
+ # 2. Provision infrastructure (keys, D1 schema, push secrets, deploy dashboard)
143
+ hoox setup
144
+ ```
145
+
146
+ ### Check Prerequisites
147
+
148
+ ```bash
149
+ # Check all tools
150
+ hoox check prerequisites
151
+
152
+ # Check specific tool
153
+ hoox check prerequisites --tool bun
154
+ ```
155
+
156
+ Validates bun ≥1.2, git ≥2.40, wrangler, Docker, Cloudflare auth, and repository integrity.
157
+
158
+ ### Manage Secrets
159
+
160
+ ```bash
161
+ # List secrets for a worker
162
+ hoox secrets list trade-worker
163
+
164
+ # Set a secret
165
+ hoox secrets set trade-worker BINANCE_KEY_BINDING
166
+
167
+ # Delete a secret
168
+ hoox secrets delete trade-worker BINANCE_KEY_BINDING
169
+
170
+ # Sync system/mesh secrets only (recommended after key rotation)
171
+ hoox secrets sync --system
172
+ # Alias: hoox secrets sync --required
173
+
174
+ # Sync all declared secrets from .dev.vars
175
+ # Reports partial results: synced / skipped (placeholders) / failed
176
+ hoox secrets sync
177
+ ```
178
+
179
+ ### Manage Internal Keys
180
+
181
+ ```bash
182
+ # Generate new internal keys (writes to .keys/)
183
+ hoox keys generate
184
+
185
+ # List existing keys
186
+ hoox keys list
187
+ ```
188
+
189
+ ### Configure Environment
190
+
191
+ ```bash
192
+ # Interactive env setup (all 27 vars across 8 sections)
193
+ hoox config env init
194
+
195
+ # Show current env (secrets redacted)
196
+ hoox config env show
197
+
198
+ # Validate required vars
199
+ hoox config env validate
200
+
201
+ # Generate per-worker .dev.vars
202
+ hoox config env generate-dev-vars
203
+ ```
204
+
205
+ ### Manage wrangler.jsonc
206
+
207
+ ```bash
208
+ # Display current configuration
209
+ hoox config show
210
+
211
+ # Update a config value
212
+ hoox config set workers.agent-worker.enabled false
213
+ ```
214
+
215
+ ### Manage KV Keys
216
+
217
+ ```bash
218
+ # Apply manifest defaults (16 keys)
219
+ hoox config kv apply-manifest
220
+
221
+ # Show expected manifest
222
+ hoox config kv manifest
223
+
224
+ # Individual key operations
225
+ hoox config kv list
226
+ hoox config kv get trade:kill_switch
227
+ hoox config kv set trade:kill_switch "false"
228
+ hoox config kv delete trade:kill_switch
229
+ ```
230
+
231
+ ### Deploy to Cloudflare
232
+
233
+ ```bash
234
+ # Deploy all workers then dashboard
235
+ hoox deploy all
236
+
237
+ # Deploy all — skip rebuild prompt, use existing build
238
+ hoox deploy all --auto
239
+
240
+ # Deploy with force rebuild
241
+ hoox deploy all --rebuild
242
+
243
+ # Post-deploy: set Telegram webhook
244
+ hoox deploy telegram-webhook
245
+
246
+ # Post-deploy: update dashboard service URLs
247
+ hoox deploy update-internal-urls
248
+
249
+ # Post-deploy: apply KV manifest
250
+ hoox deploy kv-config
251
+
252
+ # Deploy specific worker
253
+ hoox deploy worker trade-worker
254
+ ```
255
+
256
+ ### Dashboard Operations
257
+
258
+ ```bash
259
+ # Start dashboard dev server
260
+ hoox dashboard dev
261
+ # equivalent to: hoox dev dashboard
262
+
263
+ # Build and deploy the dashboard
264
+ hoox dashboard deploy
265
+ # equivalent to: hoox deploy dashboard
266
+
267
+ # Force rebuild before deploy
268
+ hoox dashboard deploy --rebuild
269
+ ```
270
+
271
+ ### Health Checks
272
+
273
+ ```bash
274
+ # Check all worker health endpoints (the single source of truth)
275
+ hoox check health
276
+
277
+ # Try to auto-fix any issues found
278
+ hoox check health --fix
279
+
280
+ # Full system validation (config, infra, secrets, database)
281
+ hoox check setup
282
+ ```
283
+
284
+ ### Database Operations
285
+
286
+ ```bash
287
+ # Apply schema to local or remote
288
+ hoox db apply
289
+ hoox db apply --remote
290
+
291
+ # Run tracking migrations
292
+ hoox db migrate --remote
293
+
294
+ # List tables
295
+ hoox db list --remote
296
+
297
+ # Execute read-only queries
298
+ hoox db query "SELECT COUNT(*) FROM trades" --remote
299
+
300
+ # Export to timestamped .sql
301
+ hoox db export
302
+
303
+ # Reset D1 (DESTRUCTIVE)
304
+ hoox db reset --confirm
305
+ ```
306
+
307
+ ### Manage Infrastructure
308
+
309
+ ```bash
310
+ # Auto-provision from wrangler.jsonc
311
+ hoox infra provision
312
+
313
+ # Individual resource management
314
+ hoox infra d1 list
315
+ hoox infra kv create my-namespace
316
+ hoox infra r2 list
317
+ hoox infra queues create my-queue
318
+ hoox infra vectorize list
319
+ hoox infra vectorize create my-index
320
+ hoox infra analytics list
321
+ ```
322
+
323
+ ### Monitor Operations
324
+
325
+ ```bash
326
+ # Show recent trades
327
+ hoox monitor trades 20
328
+
329
+ # Show system logs
330
+ hoox monitor logs
331
+ hoox monitor logs hoox
332
+
333
+ # Kill switch operations
334
+ hoox monitor kill-switch show
335
+ hoox monitor kill-switch on # Halt all trading
336
+ hoox monitor kill-switch off # Resume trading
337
+
338
+ # Queue depth
339
+ hoox monitor queue-depth
340
+
341
+ # Backup D1 database
342
+ hoox monitor backup
343
+ ```
344
+
345
+ ### Performance Measurement
346
+
347
+ ```bash
348
+ # Send 50 synthetic probes and report p50/p95/p99 latency
349
+ hoox perf fastpath run --n 50
350
+
351
+ # Continuous probing for 60 seconds
352
+ hoox perf fastpath tail --duration 60
353
+
354
+ # Query past probe events
355
+ hoox perf fastpath report --from 1h
356
+ ```
357
+
358
+ ### Operator Security & Private Ingress
359
+
360
+ ```bash
361
+ # Paths, TUI entry, and runtime layout
362
+ hoox doctor
363
+
364
+ # Hygiene + optional management /v1/health probes
365
+ hoox doctor --security
366
+ hoox doctor --security --api-url https://mgmt.example.com
367
+
368
+ # cloudflared presence + private-ingress guidance
369
+ hoox tunnel check
370
+ hoox tunnel check --api-url https://mgmt.example.com --probe
371
+ ```
372
+
373
+ ### Repair and Recovery
374
+
375
+ ```bash
376
+ # Comprehensive system check (5 steps)
377
+ hoox repair check
378
+
379
+ # Redeploy a single worker
380
+ hoox repair worker trade-worker
381
+
382
+ # Verify infrastructure exists
383
+ hoox repair infra
384
+
385
+ # Re-upload all secrets
386
+ hoox repair secrets
387
+
388
+ # Reset KV keys to defaults
389
+ hoox repair kv
390
+
391
+ # Re-apply schema + migrations
392
+ hoox repair db
393
+
394
+ # Full guided rebuild (interactive, WARNING: destructive)
395
+ hoox repair rebuild
396
+ ```
397
+
398
+ ### JSON Output for Scripting
399
+
400
+ ```bash
401
+ hoox check health --json
402
+ hoox check prerequisites --json
403
+ hoox infra d1 list --json
404
+ ```
405
+
406
+ ## Development Setup
407
+
408
+ ### Prerequisites
409
+
410
+ - [Bun](https://bun.sh) >= 1.2
411
+ - [Cloudflare account](https://dash.cloudflare.com/sign-up)
412
+ - Wrangler CLI (installed automatically with dependencies)
413
+
414
+ ### Build from Source
415
+
416
+ ```bash
417
+ # Clone the repository (workers are submodules)
418
+ git clone --recursive https://github.com/hoox-sh/hoox.git
419
+ cd hoox
420
+
421
+ # Install dependencies
422
+ bun install
423
+
424
+ # Build the CLI
425
+ cd packages/cli
426
+ bun run build
427
+ ```
428
+
429
+ ### Running Tests
430
+
431
+ ```bash
432
+ # Run all tests
433
+ bun test
434
+
435
+ # Run with coverage
436
+ bun run test:coverage
437
+
438
+ # Run specific test file
439
+ bun test path/to/test.test.ts
440
+ ```
441
+
442
+ ### Linting and Type Checking
443
+
444
+ ```bash
445
+ # Lint code
446
+ bun run lint
447
+
448
+ # Type check
449
+ bun run typecheck
450
+ ```
451
+
452
+ ### CI Pipeline
453
+
454
+ The CI pipeline runs in this order:
455
+
456
+ 1. `bun run lint` — ESLint check
457
+ 2. `bun run typecheck` — TypeScript check (`tsc --noEmit`)
458
+ 3. `bun test packages/cli --coverage` — Run tests with coverage (80% threshold)
459
+ 4. `bun run build` — TypeScript build check
460
+
461
+ ## Project Structure
462
+
463
+ ```
464
+ packages/cli/
465
+ ├── src/
466
+ │ ├── index.ts # Main entry point
467
+ │ ├── commands/
468
+ │ │ ├── init/ # Interactive setup wizard (config)
469
+ │ │ ├── setup/ # Auto-bootstrap infrastructure
470
+ │ │ ├── onboard/ # One-shot init + setup
471
+ │ │ ├── secrets/ # Top-level secrets management
472
+ │ │ ├── keys/ # Top-level internal keys management
473
+ │ │ ├── dev/ # Local development
474
+ │ │ ├── deploy/ # Deploy, telegram-webhook, update-internal-urls
475
+ │ │ ├── dashboard/ # Dashboard dev/deploy
476
+ │ │ ├── infra/ # D1, KV, R2, Queues, Vectorize, Analytics
477
+ │ │ ├── config/ # wrangler.jsonc, env, kv
478
+ │ │ ├── check/ # Prerequisites, setup, health, fix
479
+ │ │ ├── db/ # Database operations
480
+ │ │ ├── monitor/ # Trades, logs, kill-switch, backup
481
+ │ │ ├── workers/ # List, dev, logs
482
+ │ │ ├── repair/ # Check, worker, infra, secrets, rebuild
483
+ │ │ ├── schema/ # Manifest validate/generate
484
+ │ │ ├── update/ # Repo/submodule/wrangler update
485
+ │ │ ├── logs/ # Worker log tailing
486
+ │ │ ├── test/ # CI pipeline
487
+ │ │ ├── waf/ # WAF management
488
+ │ │ ├── clone/ # Submodule cloning
489
+ │ │ ├── tui/ # TUI launcher
490
+ │ │ ├── doctor/ # Runtime paths + operator security
491
+ │ │ ├── tunnel/ # Private ingress helpers
492
+ │ │ ├── agent/ # AI agent operations
493
+ │ │ ├── trace/ # Cloudflare Observability queries
494
+ │ │ ├── perf/ # Performance measurement
495
+ │ │ └── disclaimer/ # Legal disclaimer
496
+ │ ├── services/
497
+ │ │ ├── cloudflare/ # Wrangler CLI wrapper
498
+ │ │ ├── config/ # wrangler.jsonc reader
499
+ │ │ ├── db/ # D1 operations
500
+ │ │ ├── docker/ # Docker compose wrapper
501
+ │ │ ├── env/ # Environment definitions
502
+ │ │ ├── kv/ # KV key management
503
+ │ │ ├── operator-security/# Access / tunnel probes
504
+ │ │ ├── perf/ # Percentile, probe-sender, observability-reader
505
+ │ │ ├── prerequisites/ # Tool version checks
506
+ │ │ ├── runtime/ # Global ~/.hoox layout
507
+ │ │ └── secrets/ # Secret management
508
+ │ ├── ui/ # Interactive menu (clack)
509
+ │ └── utils/ # Errors, formatters, theme
510
+ ├── bin/
511
+ │ └── hoox.js # CLI binary entry point
512
+ ├── package.json
513
+ └── README.md
514
+ ```
515
+
516
+ ## Key Dependencies
517
+
518
+ | Package | Purpose |
519
+ | ---------------------- | -------------------------------------------------- |
520
+ | `commander` | CLI framework for command registration and parsing |
521
+ | `@clack/prompts` | Interactive prompts for the TUI |
522
+ | `ansis` | Terminal styling and colors |
523
+ | `jsonc-parser` | Parse `wrangler.jsonc` configuration files |
524
+ | `@hoox-sh/hoox-shared` | Shared types and utilities |
525
+
526
+ ## Contributing
527
+
528
+ Contributions are welcome! Please follow these steps:
529
+
530
+ 1. Fork the repository
531
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
532
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
533
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
534
+ 5. Open a Pull Request
535
+
536
+ Please ensure your code passes linting, type checking, and all tests before submitting.
537
+
538
+ ## License
539
+
540
+ MIT License
541
+
542
+ Copyright (c) 2026 Hoox Team
543
+
544
+ Permission is hereby granted, free of charge, to any person obtaining a copy
545
+ of this software and associated documentation files (the "Software"), to deal
546
+ in the Software without restriction, including without limitation the rights
547
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
548
+ copies of the Software, and to permit persons to whom the Software is
549
+ furnished to do so, subject to the following conditions:
550
+
551
+ The above copyright notice and this permission notice shall be included in all
552
+ copies or substantial portions of the Software.
553
+
554
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
555
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
556
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
557
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
558
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
559
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
560
+ SOFTWARE.
561
+
562
+ ## Links
563
+
564
+ - [GitHub Repository](https://github.com/hoox-sh/hoox)
565
+ - [Issue Tracker](https://github.com/hoox-sh/hoox/issues)
566
+ - [Product docs](https://docs.hoox.sh)
567
+ - [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/)
package/bin/hoox.js ADDED
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Copyright (c) 2026 HOOX · HOOX · jango-blockchained (hoox-sh)
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * Hoox CLI binary entry point.
8
+ *
9
+ * Resolution order (first match wins):
10
+ * 1. `../dist/index.js` — bundled output from `bun run build`
11
+ * 2. `../src/index.ts` — dev mode (run from a fresh `bun install` without
12
+ * running the build first; Bun compiles TS on import)
13
+ * 3. Clear error message instructing the user to run `bun run build`
14
+ *
15
+ * The dev fallback lets contributors and CI jobs that haven't yet run
16
+ * `bun run build` still execute the CLI directly via `bun bin/hoox.js` or
17
+ * `hoox` after a `bun link`.
18
+ *
19
+ * When both exist and `src/` is newer than `dist/`, a one-line stderr warning
20
+ * is printed (unless HOOX_CLI_SILENT=1). Set HOOX_CLI_SRC=1 to force source.
21
+ *
22
+ * `main` is exported from `src/index.ts` so we can call it explicitly —
23
+ * the `import.meta.main` guard inside that file would otherwise be false
24
+ * when the module is loaded as a side effect from here.
25
+ */
26
+
27
+ import { existsSync, statSync, readdirSync } from "node:fs";
28
+ import { fileURLToPath } from "node:url";
29
+ import { dirname, resolve, join } from "node:path";
30
+
31
+ const here = dirname(fileURLToPath(import.meta.url));
32
+ const distEntry = resolve(here, "..", "dist", "index.js");
33
+ const srcEntry = resolve(here, "..", "src", "index.ts");
34
+ const srcRoot = resolve(here, "..", "src");
35
+
36
+ /** Newest mtime (ms) under dir for .ts/.tsx files (shallow walk, capped). */
37
+ function newestSrcMtime(dir, depth = 0) {
38
+ if (depth > 6 || !existsSync(dir)) return 0;
39
+ let newest = 0;
40
+ let entries;
41
+ try {
42
+ entries = readdirSync(dir, { withFileTypes: true });
43
+ } catch {
44
+ return 0;
45
+ }
46
+ for (const ent of entries) {
47
+ const p = join(dir, ent.name);
48
+ if (ent.isDirectory()) {
49
+ if (ent.name === "node_modules" || ent.name === "dist") continue;
50
+ newest = Math.max(newest, newestSrcMtime(p, depth + 1));
51
+ } else if (/\.(ts|tsx)$/.test(ent.name)) {
52
+ try {
53
+ newest = Math.max(newest, statSync(p).mtimeMs);
54
+ } catch {
55
+ // ignore
56
+ }
57
+ }
58
+ }
59
+ return newest;
60
+ }
61
+
62
+ async function loadAndRun(entry) {
63
+ // Bun caches imports; the first import wins for the lifetime of the
64
+ // process. The dist build and the source file are the same module
65
+ // logically, so a second entry would be a no-op.
66
+ const mod = await import(entry);
67
+ if (typeof mod.main === "function") {
68
+ await mod.main();
69
+ }
70
+ }
71
+
72
+ const forceSrc = process.env.HOOX_CLI_SRC === "1";
73
+ const silent = process.env.HOOX_CLI_SILENT === "1";
74
+
75
+ if (forceSrc && existsSync(srcEntry)) {
76
+ await loadAndRun(srcEntry);
77
+ } else if (existsSync(distEntry)) {
78
+ // Warn when source is newer than the bundle (common monorepo gotcha).
79
+ if (!silent && existsSync(srcEntry)) {
80
+ try {
81
+ const distM = statSync(distEntry).mtimeMs;
82
+ const srcM = Math.max(
83
+ statSync(srcEntry).mtimeMs,
84
+ newestSrcMtime(srcRoot)
85
+ );
86
+ if (srcM > distM + 1000) {
87
+ process.stderr.write(
88
+ "hoox: warning: packages/cli/src is newer than dist/ — " +
89
+ "run `bun run build` in packages/cli (or HOOX_CLI_SRC=1 for source).\n"
90
+ );
91
+ }
92
+ } catch {
93
+ // ignore mtime issues
94
+ }
95
+ }
96
+ await loadAndRun(distEntry);
97
+ } else if (existsSync(srcEntry)) {
98
+ // Dev path — Bun transpiles on the fly. Useful for `bun link` and CI
99
+ // smoke tests that run before the build step.
100
+ await loadAndRun(srcEntry);
101
+ } else {
102
+ console.error(
103
+ `hoox: could not find an entry point. Looked for:\n` +
104
+ ` - ${distEntry}\n` +
105
+ ` - ${srcEntry}\n\n` +
106
+ `Run \`bun run build\` in packages/cli/ to produce the bundled dist/, ` +
107
+ `or install from source so src/index.ts is present.`
108
+ );
109
+ process.exit(1);
110
+ }