@jango-blockchained/hoox-cli 0.8.0 → 0.9.1
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 +170 -59
- package/dist/index.js +471 -129
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
# @jango-blockchained/hoox-cli
|
|
2
2
|
|
|
3
|
-
> **See also:** [Hoox User Guide](../docs/home.md) · [CLI Command Reference](../docs/reference/cli-commands.
|
|
3
|
+
> **See also:** [Hoox User Guide](../docs/home.md) · [CLI Command Reference](../docs/reference/cli-commands.mdx)
|
|
4
4
|
|
|
5
5
|
> Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments.
|
|
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
|
-
|
|
9
|
+
**v0.9.1** — 411 unit tests, 25 command groups, 60+ subcommands. Modern-minimal visual refresh, completion footer, did-you-mean suggestions, custom help. **v0.9.0** had a banner version-lookup bug in global installs — fixed in 0.9.1.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
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 TUI**: Launch an interactive terminal UI when running `hoox` with no arguments.
|
|
28
|
+
- **Modern-minimal output polish (v0.9.0)**: Refined zinc/indigo palette, completion footer with "next step" suggestions after every command, "did you mean …" for typos, custom help formatter, `--no-color` flag, `NO_COLOR` / `TERM=dumb` honored, `formatNumber` and `formatBytes` for compact tables. All available to plugin authors via the shared `format*` exports.
|
|
29
|
+
- **Shell Completions**: bash, zsh, and fish completion scripts via `hoox completion <shell>`.
|
|
25
30
|
|
|
26
31
|
## Installation
|
|
27
32
|
|
|
@@ -45,43 +50,55 @@ bun run build
|
|
|
45
50
|
## Quick Start
|
|
46
51
|
|
|
47
52
|
```bash
|
|
48
|
-
#
|
|
49
|
-
hoox
|
|
53
|
+
# One-shot onboarding (collects credentials, provisions, deploys)
|
|
54
|
+
hoox onboard
|
|
50
55
|
|
|
51
|
-
# Or
|
|
52
|
-
hoox --help
|
|
56
|
+
# Or step-by-step: write config first, then provision
|
|
53
57
|
hoox init
|
|
54
|
-
hoox
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
hoox setup
|
|
59
|
+
|
|
60
|
+
# Verify the system
|
|
61
|
+
hoox check setup
|
|
62
|
+
hoox check health
|
|
63
|
+
|
|
64
|
+
# Deploy to Cloudflare
|
|
65
|
+
hoox deploy all --auto
|
|
66
|
+
|
|
67
|
+
# Measure fast-path latency
|
|
68
|
+
hoox perf fastpath run --n 50
|
|
57
69
|
```
|
|
58
70
|
|
|
59
71
|
## Available Commands
|
|
60
72
|
|
|
61
|
-
| Command | Description
|
|
62
|
-
| ----------------- |
|
|
63
|
-
| `hoox
|
|
64
|
-
| `hoox
|
|
65
|
-
| `hoox
|
|
66
|
-
| `hoox
|
|
67
|
-
| `hoox
|
|
68
|
-
| `hoox
|
|
69
|
-
| `hoox
|
|
70
|
-
| `hoox
|
|
71
|
-
| `hoox
|
|
72
|
-
| `hoox
|
|
73
|
-
| `hoox
|
|
74
|
-
| `hoox
|
|
75
|
-
| `hoox
|
|
76
|
-
| `hoox
|
|
77
|
-
| `hoox
|
|
78
|
-
| `hoox
|
|
79
|
-
| `hoox
|
|
80
|
-
| `hoox
|
|
81
|
-
| `hoox
|
|
82
|
-
| `hoox
|
|
83
|
-
| `hoox
|
|
84
|
-
| `hoox
|
|
73
|
+
| Command | Description |
|
|
74
|
+
| ----------------- | -------------------------------------------------------------------- |
|
|
75
|
+
| `hoox onboard` | **Recommended entry point.** One-shot full bootstrap (init + setup) |
|
|
76
|
+
| `hoox init` | Interactive setup wizard (writes `wrangler.jsonc`, collects secrets) |
|
|
77
|
+
| `hoox setup` | Auto-bootstrap infrastructure (auth, keys, D1, secrets, dashboard) |
|
|
78
|
+
| `hoox clone` | Clone worker repositories as git submodules |
|
|
79
|
+
| `hoox dev` | Start local development environment for all workers |
|
|
80
|
+
| `hoox deploy` | Deploy workers, dashboard, telegram webhook, and KV config |
|
|
81
|
+
| `hoox infra` | Manage infrastructure (D1, KV, R2, Queues, Vectorize, Analytics) |
|
|
82
|
+
| `hoox config` | Manage `wrangler.jsonc` configuration |
|
|
83
|
+
| `hoox secrets` | Manage Cloudflare Worker secrets |
|
|
84
|
+
| `hoox keys` | Manage internal auth keys |
|
|
85
|
+
| `hoox check` | Validate setup, prerequisites, and worker health |
|
|
86
|
+
| `hoox db` | Manage D1 databases (apply, migrate, query, export, reset) |
|
|
87
|
+
| `hoox monitor` | Monitor trades, logs, kill switch, queue, backup |
|
|
88
|
+
| `hoox workers` | Per-worker operations (list, dev, logs) |
|
|
89
|
+
| `hoox repair` | Diagnose and repair the system (check, rebuild, per-component) |
|
|
90
|
+
| `hoox schema` | Manage D1 schema and migrations |
|
|
91
|
+
| `hoox update` | Self-update the CLI and check wrangler versions |
|
|
92
|
+
| `hoox logs` | Stream and filter Cloudflare Worker logs |
|
|
93
|
+
| `hoox test` | Run tests and CI pipeline |
|
|
94
|
+
| `hoox waf` | Manage Cloudflare WAF rules and policies |
|
|
95
|
+
| `hoox dashboard` | Dashboard operations (`dev`, `deploy`) |
|
|
96
|
+
| `hoox tui` | Launch the OpenTUI terminal dashboard |
|
|
97
|
+
| `hoox agent` | AI agent operations (health probe) |
|
|
98
|
+
| `hoox trace` | Query Cloudflare Workers Observability (events, metrics, traces) |
|
|
99
|
+
| `hoox perf` | Performance measurement tools (`fastpath` probe-based latency) |
|
|
100
|
+
| `hoox disclaimer` | Display legal disclaimer |
|
|
101
|
+
| `hoox completion` | Generate shell completion script (bash, zsh, fish) |
|
|
85
102
|
|
|
86
103
|
### Global Options
|
|
87
104
|
|
|
@@ -94,13 +111,27 @@ All commands support these global options:
|
|
|
94
111
|
|
|
95
112
|
## Usage Examples
|
|
96
113
|
|
|
97
|
-
###
|
|
114
|
+
### Onboard a New Project
|
|
98
115
|
|
|
99
116
|
```bash
|
|
100
|
-
|
|
117
|
+
# One-shot (recommended) — fully automatic, no separate setup step
|
|
118
|
+
hoox onboard --token cfut_xxx --account xxx --preset full
|
|
119
|
+
|
|
120
|
+
# Interactive
|
|
121
|
+
hoox onboard
|
|
101
122
|
```
|
|
102
123
|
|
|
103
|
-
Interactive prompts
|
|
124
|
+
Interactive prompts collect your Cloudflare Account ID, API Token, and subdomain prefix; then it writes the config and provisions infrastructure end-to-end.
|
|
125
|
+
|
|
126
|
+
### Step-by-Step Onboarding
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 1. Write workspace config (wrangler.jsonc, secrets)
|
|
130
|
+
hoox init
|
|
131
|
+
|
|
132
|
+
# 2. Provision infrastructure (keys, D1 schema, push secrets, deploy dashboard)
|
|
133
|
+
hoox setup
|
|
134
|
+
```
|
|
104
135
|
|
|
105
136
|
### Check Prerequisites
|
|
106
137
|
|
|
@@ -114,6 +145,32 @@ hoox check prerequisites --tool bun
|
|
|
114
145
|
|
|
115
146
|
Validates bun ≥1.2, git ≥2.40, wrangler, Docker, Cloudflare auth, and repository integrity.
|
|
116
147
|
|
|
148
|
+
### Manage Secrets
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# List secrets for a worker
|
|
152
|
+
hoox secrets list trade-worker
|
|
153
|
+
|
|
154
|
+
# Set a secret
|
|
155
|
+
hoox secrets set trade-worker BINANCE_KEY_BINDING
|
|
156
|
+
|
|
157
|
+
# Delete a secret
|
|
158
|
+
hoox secrets delete trade-worker BINANCE_KEY_BINDING
|
|
159
|
+
|
|
160
|
+
# Sync local .dev.vars to Cloudflare
|
|
161
|
+
hoox secrets sync
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Manage Internal Keys
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Generate new internal keys (writes to .keys/)
|
|
168
|
+
hoox keys generate
|
|
169
|
+
|
|
170
|
+
# List existing keys
|
|
171
|
+
hoox keys list
|
|
172
|
+
```
|
|
173
|
+
|
|
117
174
|
### Configure Environment
|
|
118
175
|
|
|
119
176
|
```bash
|
|
@@ -130,6 +187,16 @@ hoox config env validate
|
|
|
130
187
|
hoox config env generate-dev-vars
|
|
131
188
|
```
|
|
132
189
|
|
|
190
|
+
### Manage wrangler.jsonc
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Display current configuration
|
|
194
|
+
hoox config show
|
|
195
|
+
|
|
196
|
+
# Update a config value
|
|
197
|
+
hoox config set workers.agent-worker.enabled false
|
|
198
|
+
```
|
|
199
|
+
|
|
133
200
|
### Manage KV Keys
|
|
134
201
|
|
|
135
202
|
```bash
|
|
@@ -171,7 +238,35 @@ hoox deploy kv-config
|
|
|
171
238
|
hoox deploy worker trade-worker
|
|
172
239
|
```
|
|
173
240
|
|
|
174
|
-
###
|
|
241
|
+
### Dashboard Operations
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Start dashboard dev server
|
|
245
|
+
hoox dashboard dev
|
|
246
|
+
# equivalent to: hoox dev dashboard
|
|
247
|
+
|
|
248
|
+
# Build and deploy the dashboard
|
|
249
|
+
hoox dashboard deploy
|
|
250
|
+
# equivalent to: hoox deploy dashboard
|
|
251
|
+
|
|
252
|
+
# Force rebuild before deploy
|
|
253
|
+
hoox dashboard deploy --rebuild
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Health Checks
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Check all worker health endpoints (the single source of truth)
|
|
260
|
+
hoox check health
|
|
261
|
+
|
|
262
|
+
# Try to auto-fix any issues found
|
|
263
|
+
hoox check health --fix
|
|
264
|
+
|
|
265
|
+
# Full system validation (config, infra, secrets, database)
|
|
266
|
+
hoox check setup
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Database Operations
|
|
175
270
|
|
|
176
271
|
```bash
|
|
177
272
|
# Apply schema to local or remote
|
|
@@ -213,9 +308,6 @@ hoox infra analytics list
|
|
|
213
308
|
### Monitor Operations
|
|
214
309
|
|
|
215
310
|
```bash
|
|
216
|
-
# Check all worker health endpoints
|
|
217
|
-
hoox monitor status
|
|
218
|
-
|
|
219
311
|
# Show recent trades
|
|
220
312
|
hoox monitor trades 20
|
|
221
313
|
|
|
@@ -235,6 +327,19 @@ hoox monitor queue-depth
|
|
|
235
327
|
hoox monitor backup
|
|
236
328
|
```
|
|
237
329
|
|
|
330
|
+
### Performance Measurement
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Send 50 synthetic probes and report p50/p95/p99 latency
|
|
334
|
+
hoox perf fastpath run --n 50
|
|
335
|
+
|
|
336
|
+
# Continuous probing for 60 seconds
|
|
337
|
+
hoox perf fastpath tail --duration 60
|
|
338
|
+
|
|
339
|
+
# Query past probe events
|
|
340
|
+
hoox perf fastpath report --from 1h
|
|
341
|
+
```
|
|
342
|
+
|
|
238
343
|
### Repair and Recovery
|
|
239
344
|
|
|
240
345
|
```bash
|
|
@@ -263,8 +368,8 @@ hoox repair rebuild
|
|
|
263
368
|
### JSON Output for Scripting
|
|
264
369
|
|
|
265
370
|
```bash
|
|
371
|
+
hoox check health --json
|
|
266
372
|
hoox check prerequisites --json
|
|
267
|
-
hoox monitor status --json
|
|
268
373
|
hoox infra d1 list --json
|
|
269
374
|
```
|
|
270
375
|
|
|
@@ -330,16 +435,20 @@ packages/cli/
|
|
|
330
435
|
├── src/
|
|
331
436
|
│ ├── index.ts # Main entry point
|
|
332
437
|
│ ├── commands/
|
|
333
|
-
│ │ ├── init/ # Interactive setup wizard
|
|
438
|
+
│ │ ├── init/ # Interactive setup wizard (config)
|
|
334
439
|
│ │ ├── setup/ # Auto-bootstrap infrastructure
|
|
440
|
+
│ │ ├── onboard/ # One-shot init + setup
|
|
441
|
+
│ │ ├── secrets/ # Top-level secrets management
|
|
442
|
+
│ │ ├── keys/ # Top-level internal keys management
|
|
335
443
|
│ │ ├── dev/ # Local development
|
|
336
444
|
│ │ ├── deploy/ # Deploy, telegram-webhook, update-internal-urls
|
|
445
|
+
│ │ ├── dashboard/ # Dashboard dev/deploy
|
|
337
446
|
│ │ ├── infra/ # D1, KV, R2, Queues, Vectorize, Analytics
|
|
338
|
-
│ │ ├── config/ #
|
|
339
|
-
│ │ ├── check/ # Prerequisites, setup, health
|
|
447
|
+
│ │ ├── config/ # wrangler.jsonc, env, kv
|
|
448
|
+
│ │ ├── check/ # Prerequisites, setup, health, fix
|
|
340
449
|
│ │ ├── db/ # Database operations
|
|
341
|
-
│ │ ├── monitor/ #
|
|
342
|
-
│ │ ├── workers/ #
|
|
450
|
+
│ │ ├── monitor/ # Trades, logs, kill-switch, backup
|
|
451
|
+
│ │ ├── workers/ # List, dev, logs
|
|
343
452
|
│ │ ├── repair/ # Check, worker, infra, secrets, rebuild
|
|
344
453
|
│ │ ├── schema/ # Schema management
|
|
345
454
|
│ │ ├── update/ # Self-update
|
|
@@ -347,9 +456,10 @@ packages/cli/
|
|
|
347
456
|
│ │ ├── test/ # CI pipeline
|
|
348
457
|
│ │ ├── waf/ # WAF management
|
|
349
458
|
│ │ ├── clone/ # Submodule cloning
|
|
350
|
-
│ │ ├── dashboard/ # Dashboard operations
|
|
351
459
|
│ │ ├── tui/ # TUI launcher
|
|
352
460
|
│ │ ├── agent/ # AI agent operations
|
|
461
|
+
│ │ ├── trace/ # Cloudflare Observability queries
|
|
462
|
+
│ │ ├── perf/ # Performance measurement
|
|
353
463
|
│ │ └── disclaimer/ # Legal disclaimer
|
|
354
464
|
│ ├── services/
|
|
355
465
|
│ │ ├── cloudflare/ # Wrangler CLI wrapper
|
|
@@ -358,6 +468,7 @@ packages/cli/
|
|
|
358
468
|
│ │ ├── docker/ # Docker compose wrapper
|
|
359
469
|
│ │ ├── env/ # Environment definitions
|
|
360
470
|
│ │ ├── kv/ # KV key management
|
|
471
|
+
│ │ ├── perf/ # Percentile, probe-sender, observability-reader
|
|
361
472
|
│ │ ├── prerequisites/ # Tool version checks
|
|
362
473
|
│ │ └── secrets/ # Secret management
|
|
363
474
|
│ ├── ui/ # Interactive TUI
|
package/dist/index.js
CHANGED
|
@@ -24169,7 +24169,7 @@ var init_schema_service = __esm(() => {
|
|
|
24169
24169
|
});
|
|
24170
24170
|
|
|
24171
24171
|
// src/index.ts
|
|
24172
|
-
import { readFileSync as
|
|
24172
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
24173
24173
|
|
|
24174
24174
|
// ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
|
|
24175
24175
|
class CommanderError extends Error {
|
|
@@ -26249,59 +26249,65 @@ var import__ = __toESM(require_ansis(), 1);
|
|
|
26249
26249
|
var ansis_default = import__.default;
|
|
26250
26250
|
|
|
26251
26251
|
// src/utils/theme.ts
|
|
26252
|
-
var
|
|
26253
|
-
|
|
26254
|
-
|
|
26255
|
-
|
|
26256
|
-
|
|
26257
|
-
|
|
26258
|
-
|
|
26259
|
-
|
|
26260
|
-
|
|
26261
|
-
|
|
26262
|
-
|
|
26263
|
-
|
|
26264
|
-
|
|
26265
|
-
var bgGreen = ansis_default.bgGreen;
|
|
26266
|
-
var bgRed = ansis_default.bgRed;
|
|
26267
|
-
var bgYellow = ansis_default.bgYellow;
|
|
26268
|
-
var bgBlue = ansis_default.bgBlue;
|
|
26252
|
+
var HEX = {
|
|
26253
|
+
text200: "#e4e4e7",
|
|
26254
|
+
text400: "#a1a1aa",
|
|
26255
|
+
text500: "#71717a",
|
|
26256
|
+
text600: "#52525b",
|
|
26257
|
+
text700: "#3f3f46",
|
|
26258
|
+
indigo300: "#a5b4fc",
|
|
26259
|
+
indigo400: "#818cf8",
|
|
26260
|
+
emerald400: "#34d399",
|
|
26261
|
+
rose400: "#fb7185",
|
|
26262
|
+
amber400: "#fbbf24",
|
|
26263
|
+
sky400: "#38bdf8"
|
|
26264
|
+
};
|
|
26269
26265
|
var theme = {
|
|
26270
|
-
|
|
26271
|
-
|
|
26272
|
-
|
|
26273
|
-
|
|
26274
|
-
|
|
26275
|
-
|
|
26276
|
-
|
|
26277
|
-
|
|
26278
|
-
|
|
26279
|
-
|
|
26280
|
-
|
|
26281
|
-
|
|
26282
|
-
|
|
26283
|
-
|
|
26284
|
-
|
|
26285
|
-
|
|
26286
|
-
|
|
26287
|
-
|
|
26288
|
-
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
|
|
26293
|
-
|
|
26294
|
-
|
|
26295
|
-
|
|
26266
|
+
text: ansis_default.hex(HEX.text200),
|
|
26267
|
+
textMuted: ansis_default.hex(HEX.text400),
|
|
26268
|
+
textSubtle: ansis_default.hex(HEX.text500),
|
|
26269
|
+
textFaint: ansis_default.hex(HEX.text600),
|
|
26270
|
+
border: ansis_default.hex(HEX.text700),
|
|
26271
|
+
borderStrong: ansis_default.hex(HEX.text600),
|
|
26272
|
+
success: ansis_default.hex(HEX.emerald400),
|
|
26273
|
+
error: ansis_default.hex(HEX.rose400),
|
|
26274
|
+
warning: ansis_default.hex(HEX.amber400),
|
|
26275
|
+
info: ansis_default.hex(HEX.sky400),
|
|
26276
|
+
accent: ansis_default.hex(HEX.indigo400),
|
|
26277
|
+
highlight: ansis_default.hex(HEX.indigo300),
|
|
26278
|
+
surface: ansis_default.hex("#18181b"),
|
|
26279
|
+
dim: ansis_default.hex(HEX.text400),
|
|
26280
|
+
bold: ansis_default.bold,
|
|
26281
|
+
italic: ansis_default.italic,
|
|
26282
|
+
underline: ansis_default.underline,
|
|
26283
|
+
gray: ansis_default.gray,
|
|
26284
|
+
white: ansis_default.white,
|
|
26285
|
+
black: ansis_default.black,
|
|
26286
|
+
heading: ansis_default.hex(HEX.indigo400).bold,
|
|
26287
|
+
label: ansis_default.hex(HEX.text500),
|
|
26288
|
+
subtle: ansis_default.hex(HEX.text500),
|
|
26289
|
+
muted: ansis_default.hex(HEX.text600),
|
|
26290
|
+
value: ansis_default.hex(HEX.text200),
|
|
26291
|
+
key: ansis_default.hex(HEX.text500),
|
|
26292
|
+
statusOk: ansis_default.hex(HEX.emerald400)("\u2713") + " " + ansis_default.hex(HEX.text200)("ok"),
|
|
26293
|
+
statusWarn: ansis_default.hex(HEX.amber400)("\u26A0") + " " + ansis_default.hex(HEX.text200)("warn"),
|
|
26294
|
+
statusError: ansis_default.hex(HEX.rose400)("\u2717") + " " + ansis_default.hex(HEX.text200)("error"),
|
|
26295
|
+
statusInfo: ansis_default.hex(HEX.sky400)("\u2139") + " " + ansis_default.hex(HEX.text200)("info"),
|
|
26296
|
+
separator: ansis_default.hex(HEX.text600)("\u2500"),
|
|
26297
|
+
pipe: ansis_default.hex(HEX.text600)("\u2502"),
|
|
26298
|
+
corner: ansis_default.hex(HEX.text600)("\u250C\u2510\u2514\u2518")
|
|
26296
26299
|
};
|
|
26297
26300
|
var icons = {
|
|
26298
26301
|
success: "\u2713",
|
|
26299
26302
|
error: "\u2717",
|
|
26300
|
-
warning: "
|
|
26301
|
-
info: "
|
|
26302
|
-
arrow: "
|
|
26303
|
-
spinner: ["
|
|
26304
|
-
dot: "\u25CF"
|
|
26303
|
+
warning: "\u26A0",
|
|
26304
|
+
info: "\u2139",
|
|
26305
|
+
arrow: "\u2192",
|
|
26306
|
+
spinner: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
26307
|
+
dot: "\u25CF",
|
|
26308
|
+
sep: "\xB7",
|
|
26309
|
+
bullet: "\u2022",
|
|
26310
|
+
pipe: "\u2502"
|
|
26305
26311
|
};
|
|
26306
26312
|
function stripAnsi(str) {
|
|
26307
26313
|
return ansis_default.strip(str);
|
|
@@ -26334,7 +26340,11 @@ function startTimer() {
|
|
|
26334
26340
|
|
|
26335
26341
|
// src/utils/format-mode.ts
|
|
26336
26342
|
function isRichMode(opts) {
|
|
26337
|
-
if (opts?.json || opts?.quiet)
|
|
26343
|
+
if (opts?.json || opts?.quiet || opts?.noColor)
|
|
26344
|
+
return false;
|
|
26345
|
+
if (process.env.NO_COLOR)
|
|
26346
|
+
return false;
|
|
26347
|
+
if (process.env.TERM === "dumb")
|
|
26338
26348
|
return false;
|
|
26339
26349
|
return Boolean(process.stdout.isTTY);
|
|
26340
26350
|
}
|
|
@@ -26375,45 +26385,72 @@ function formatSuccess(message, opts) {
|
|
|
26375
26385
|
process.stdout.write(`${theme.success(icons.success)} ${message}
|
|
26376
26386
|
`);
|
|
26377
26387
|
}
|
|
26378
|
-
function formatError2(error51, opts) {
|
|
26388
|
+
function formatError2(error51, opts = {}) {
|
|
26379
26389
|
const message = typeof error51 === "string" ? error51 : error51.message;
|
|
26380
26390
|
const cliError = error51 instanceof CLIError ? error51 : null;
|
|
26381
|
-
if (opts
|
|
26391
|
+
if (opts.json) {
|
|
26382
26392
|
const output = {
|
|
26383
26393
|
success: false,
|
|
26384
26394
|
error: message,
|
|
26385
26395
|
code: cliError?.code ?? 1 /* ERROR */
|
|
26386
26396
|
};
|
|
26387
|
-
if (cliError?.details)
|
|
26397
|
+
if (cliError?.details)
|
|
26388
26398
|
output.details = cliError.details;
|
|
26389
|
-
|
|
26390
|
-
if (cliError?.hint) {
|
|
26399
|
+
if (cliError?.hint)
|
|
26391
26400
|
output.hint = cliError.hint;
|
|
26401
|
+
if (opts.suggestions && opts.suggestions.length > 0) {
|
|
26402
|
+
output.suggestions = opts.suggestions;
|
|
26392
26403
|
}
|
|
26393
26404
|
process.stdout.write(JSON.stringify(output) + `
|
|
26394
26405
|
`);
|
|
26395
26406
|
return;
|
|
26396
26407
|
}
|
|
26397
|
-
if (opts
|
|
26408
|
+
if (opts.quiet) {
|
|
26398
26409
|
process.stdout.write(`${message}
|
|
26399
26410
|
`);
|
|
26400
26411
|
return;
|
|
26401
26412
|
}
|
|
26402
|
-
|
|
26413
|
+
const inCard = opts.inCard !== false;
|
|
26414
|
+
const titleParts = [theme.error(icons.error)];
|
|
26415
|
+
if (cliError?.code !== undefined) {
|
|
26416
|
+
titleParts.push(theme.textSubtle(`[${cliError.code}]`));
|
|
26417
|
+
}
|
|
26418
|
+
titleParts.push(theme.text(message));
|
|
26419
|
+
process.stdout.write(`${titleParts.join(" ")}
|
|
26403
26420
|
`);
|
|
26404
26421
|
if (cliError?.details) {
|
|
26405
|
-
process.stdout.write(` ${theme.
|
|
26422
|
+
process.stdout.write(` ${theme.textMuted(cliError.details)}
|
|
26406
26423
|
`);
|
|
26407
26424
|
}
|
|
26408
|
-
|
|
26409
|
-
|
|
26425
|
+
const hasHint = !!cliError?.hint;
|
|
26426
|
+
const hasSuggestions = !!opts.suggestions && opts.suggestions.length > 0;
|
|
26427
|
+
if (hasHint || hasSuggestions) {
|
|
26428
|
+
if (inCard) {
|
|
26429
|
+
process.stdout.write(` ${theme.border(icons.pipe)}
|
|
26430
|
+
`);
|
|
26431
|
+
}
|
|
26432
|
+
if (hasHint) {
|
|
26433
|
+
process.stdout.write(` ${inCard ? theme.border(icons.pipe) : " "} ${theme.dim("\u21B3 hint:")} ${theme.value(cliError.hint)}
|
|
26434
|
+
`);
|
|
26435
|
+
}
|
|
26436
|
+
if (hasSuggestions) {
|
|
26437
|
+
const sugText = opts.suggestions.map((s) => `'${s}'`).join(", ");
|
|
26438
|
+
process.stdout.write(` ${inCard ? theme.border(icons.pipe) : " "} ${theme.dim("did you mean:")} ${theme.accent(sugText)} ${theme.dim("?")}
|
|
26439
|
+
`);
|
|
26440
|
+
}
|
|
26441
|
+
if (inCard) {
|
|
26442
|
+
process.stdout.write(` ${theme.border(icons.pipe)}
|
|
26443
|
+
`);
|
|
26444
|
+
}
|
|
26445
|
+
} else if (inCard) {
|
|
26446
|
+
process.stdout.write(` ${theme.border(icons.pipe)}
|
|
26410
26447
|
`);
|
|
26411
26448
|
}
|
|
26412
26449
|
}
|
|
26413
|
-
function formatTable(rows, opts) {
|
|
26414
|
-
if (opts
|
|
26450
|
+
function formatTable(rows, opts = {}) {
|
|
26451
|
+
if (opts.quiet)
|
|
26415
26452
|
return;
|
|
26416
|
-
if (opts
|
|
26453
|
+
if (opts.json) {
|
|
26417
26454
|
process.stdout.write(JSON.stringify(rows, null, 2) + `
|
|
26418
26455
|
`);
|
|
26419
26456
|
return;
|
|
@@ -26423,11 +26460,42 @@ function formatTable(rows, opts) {
|
|
|
26423
26460
|
`);
|
|
26424
26461
|
return;
|
|
26425
26462
|
}
|
|
26463
|
+
const zebra = opts.zebra !== false;
|
|
26464
|
+
const alignNumbers = opts.alignNumbers !== false;
|
|
26465
|
+
const colorizeStatus = opts.colorizeStatus !== false;
|
|
26466
|
+
const compact = opts.compact === true;
|
|
26426
26467
|
const keys = Object.keys(rows[0]);
|
|
26468
|
+
const processed = rows.map((row) => {
|
|
26469
|
+
const out = {};
|
|
26470
|
+
for (const k of keys) {
|
|
26471
|
+
const raw = row[k] ?? "";
|
|
26472
|
+
out[k] = colorizeCell(raw, colorizeStatus);
|
|
26473
|
+
}
|
|
26474
|
+
return out;
|
|
26475
|
+
});
|
|
26476
|
+
const numericColumns = new Set;
|
|
26477
|
+
if (alignNumbers) {
|
|
26478
|
+
for (const k of keys) {
|
|
26479
|
+
let allNumeric = true;
|
|
26480
|
+
let anyNonEmpty = false;
|
|
26481
|
+
for (const row of processed) {
|
|
26482
|
+
const v = stripAnsi(row[k] ?? "");
|
|
26483
|
+
if (v.length === 0)
|
|
26484
|
+
continue;
|
|
26485
|
+
anyNonEmpty = true;
|
|
26486
|
+
if (!/^-?\d+(\.\d+)?$/.test(v)) {
|
|
26487
|
+
allNumeric = false;
|
|
26488
|
+
break;
|
|
26489
|
+
}
|
|
26490
|
+
}
|
|
26491
|
+
if (allNumeric && anyNonEmpty)
|
|
26492
|
+
numericColumns.add(k);
|
|
26493
|
+
}
|
|
26494
|
+
}
|
|
26427
26495
|
const widths = {};
|
|
26428
26496
|
for (const key of keys) {
|
|
26429
26497
|
widths[key] = stripAnsi(key).length;
|
|
26430
|
-
for (const row of
|
|
26498
|
+
for (const row of processed) {
|
|
26431
26499
|
const value = row[key] ?? "";
|
|
26432
26500
|
const stripped = stripAnsi(value).length;
|
|
26433
26501
|
widths[key] = Math.max(widths[key], stripped);
|
|
@@ -26439,44 +26507,285 @@ function formatTable(rows, opts) {
|
|
|
26439
26507
|
const botBorder = `\u2514${topParts.join("\u2534")}\u2518`;
|
|
26440
26508
|
const headerCells = keys.map((k) => theme.bold(k.padEnd(widths[k])).toString());
|
|
26441
26509
|
const headerRow = `\u2502 ${headerCells.join(" \u2502 ")} \u2502`;
|
|
26442
|
-
const dataRows =
|
|
26510
|
+
const dataRows = processed.map((row, rowIdx) => {
|
|
26511
|
+
const isAlt = zebra && rowIdx % 2 === 0;
|
|
26443
26512
|
const cells = keys.map((k) => {
|
|
26444
26513
|
const value = row[k] ?? "";
|
|
26445
|
-
|
|
26514
|
+
const padded = numericColumns.has(k) ? value.padStart(widths[k]) : value.padEnd(widths[k]);
|
|
26515
|
+
if (isAlt && !value.includes("\x1B")) {
|
|
26516
|
+
return theme.textMuted(padded);
|
|
26517
|
+
}
|
|
26518
|
+
return padded;
|
|
26446
26519
|
});
|
|
26447
26520
|
return `\u2502 ${cells.join(" \u2502 ")} \u2502`;
|
|
26448
26521
|
});
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26452
|
-
` + `${dataRows.join(`
|
|
26522
|
+
const borderOut = compact ? `${headerRow}
|
|
26523
|
+
${theme.dim("\u2500".repeat(stripAnsi(headerRow).length))}
|
|
26524
|
+
${dataRows.join(`
|
|
26453
26525
|
`)}
|
|
26454
|
-
`
|
|
26455
|
-
|
|
26526
|
+
` : `${theme.dim(topBorder)}
|
|
26527
|
+
${headerRow}
|
|
26528
|
+
${theme.dim(sepBorder)}
|
|
26529
|
+
${dataRows.join(`
|
|
26530
|
+
`)}
|
|
26531
|
+
${theme.dim(botBorder)}
|
|
26532
|
+
`;
|
|
26533
|
+
process.stdout.write(borderOut);
|
|
26534
|
+
}
|
|
26535
|
+
function colorizeCell(value, colorizeStatus) {
|
|
26536
|
+
if (!colorizeStatus)
|
|
26537
|
+
return value;
|
|
26538
|
+
const v = value.trim();
|
|
26539
|
+
const lower = v.toLowerCase();
|
|
26540
|
+
if ([
|
|
26541
|
+
"ok",
|
|
26542
|
+
"pass",
|
|
26543
|
+
"healthy",
|
|
26544
|
+
"operational",
|
|
26545
|
+
"up",
|
|
26546
|
+
"active",
|
|
26547
|
+
"enabled"
|
|
26548
|
+
].includes(lower)) {
|
|
26549
|
+
return `${theme.success(icons.success)} ${theme.text(v)}`;
|
|
26550
|
+
}
|
|
26551
|
+
if (["warn", "warning", "degraded", "partial", "pending"].includes(lower)) {
|
|
26552
|
+
return `${theme.warning(icons.warning)} ${theme.text(v)}`;
|
|
26553
|
+
}
|
|
26554
|
+
if ([
|
|
26555
|
+
"err",
|
|
26556
|
+
"error",
|
|
26557
|
+
"fail",
|
|
26558
|
+
"failed",
|
|
26559
|
+
"down",
|
|
26560
|
+
"unreachable",
|
|
26561
|
+
"disabled"
|
|
26562
|
+
].includes(lower)) {
|
|
26563
|
+
return `${theme.error(icons.error)} ${theme.text(v)}`;
|
|
26564
|
+
}
|
|
26565
|
+
return value;
|
|
26456
26566
|
}
|
|
26457
26567
|
function formatJson(data, opts) {
|
|
26458
26568
|
const json2 = opts?.quiet ? JSON.stringify(data) : JSON.stringify(data, null, 2);
|
|
26459
26569
|
process.stdout.write(`${json2}
|
|
26460
26570
|
`);
|
|
26461
26571
|
}
|
|
26462
|
-
function formatKeyValue(pairs, opts) {
|
|
26463
|
-
if (opts
|
|
26572
|
+
function formatKeyValue(pairs, opts = {}) {
|
|
26573
|
+
if (opts.quiet)
|
|
26464
26574
|
return;
|
|
26465
|
-
if (opts
|
|
26575
|
+
if (opts.json) {
|
|
26466
26576
|
process.stdout.write(JSON.stringify(pairs, null, 2) + `
|
|
26467
26577
|
`);
|
|
26468
26578
|
return;
|
|
26469
26579
|
}
|
|
26470
|
-
const maxKeyLen = Math.max(...Object.keys(pairs).map((k) => stripAnsi(k).length));
|
|
26580
|
+
const maxKeyLen = Math.max(...Object.keys(pairs).map((k) => stripAnsi(k).length), 0);
|
|
26471
26581
|
for (const [key, value] of Object.entries(pairs)) {
|
|
26472
26582
|
const paddedKey = key.padEnd(maxKeyLen);
|
|
26473
|
-
process.stdout.write(` ${theme.key(paddedKey)} ${theme.
|
|
26583
|
+
process.stdout.write(` ${theme.key(paddedKey)} ${theme.textMuted(":")} ${value}
|
|
26474
26584
|
`);
|
|
26475
26585
|
}
|
|
26476
26586
|
}
|
|
26477
26587
|
function getFormatOptions(cmd) {
|
|
26478
26588
|
const opts = cmd.optsWithGlobals();
|
|
26479
|
-
return {
|
|
26589
|
+
return {
|
|
26590
|
+
json: Boolean(opts.json),
|
|
26591
|
+
quiet: Boolean(opts.quiet),
|
|
26592
|
+
noColor: Boolean(opts.color === false)
|
|
26593
|
+
};
|
|
26594
|
+
}
|
|
26595
|
+
function formatCompletion(message, opts = {}) {
|
|
26596
|
+
if (opts.json || opts.quiet)
|
|
26597
|
+
return;
|
|
26598
|
+
if (process.exitCode && process.exitCode !== 0)
|
|
26599
|
+
return;
|
|
26600
|
+
if (!isRichMode(opts))
|
|
26601
|
+
return;
|
|
26602
|
+
const parts = [theme.success(icons.success), theme.text(message)];
|
|
26603
|
+
if (opts.durationMs !== undefined) {
|
|
26604
|
+
parts.push(theme.textMuted(formatDuration3(opts.durationMs)));
|
|
26605
|
+
}
|
|
26606
|
+
process.stdout.write(`${parts.join(" ")}
|
|
26607
|
+
`);
|
|
26608
|
+
if (opts.suggestion) {
|
|
26609
|
+
const reason = opts.suggestion.reason ? ` ${theme.textMuted(`(${opts.suggestion.reason})`)}` : "";
|
|
26610
|
+
process.stdout.write(` ${theme.textMuted("\u2192")} ${theme.textMuted("next:")} ${theme.accent(opts.suggestion.command)}${reason}
|
|
26611
|
+
`);
|
|
26612
|
+
}
|
|
26613
|
+
}
|
|
26614
|
+
|
|
26615
|
+
// src/utils/string.ts
|
|
26616
|
+
function levenshtein(a2, b) {
|
|
26617
|
+
if (a2 === b)
|
|
26618
|
+
return 0;
|
|
26619
|
+
if (a2.length === 0)
|
|
26620
|
+
return b.length;
|
|
26621
|
+
if (b.length === 0)
|
|
26622
|
+
return a2.length;
|
|
26623
|
+
const [s, t] = a2.length <= b.length ? [a2, b] : [b, a2];
|
|
26624
|
+
const m = s.length;
|
|
26625
|
+
const n = t.length;
|
|
26626
|
+
let prev = new Array(m + 1);
|
|
26627
|
+
for (let i = 0;i <= m; i++)
|
|
26628
|
+
prev[i] = i;
|
|
26629
|
+
let curr = new Array(m + 1);
|
|
26630
|
+
for (let j = 1;j <= n; j++) {
|
|
26631
|
+
curr[0] = j;
|
|
26632
|
+
for (let i = 1;i <= m; i++) {
|
|
26633
|
+
const cost = s.charCodeAt(i - 1) === t.charCodeAt(j - 1) ? 0 : 1;
|
|
26634
|
+
curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
|
|
26635
|
+
}
|
|
26636
|
+
[prev, curr] = [curr, prev];
|
|
26637
|
+
}
|
|
26638
|
+
return prev[m];
|
|
26639
|
+
}
|
|
26640
|
+
|
|
26641
|
+
// src/utils/error-handler.ts
|
|
26642
|
+
var SUGGESTION_THRESHOLD = 2;
|
|
26643
|
+
function collectCommandNames(cmd, acc = new Set) {
|
|
26644
|
+
for (const sub of cmd.commands) {
|
|
26645
|
+
if (sub.name() && !sub.hidden) {
|
|
26646
|
+
acc.add(sub.name());
|
|
26647
|
+
collectCommandNames(sub, acc);
|
|
26648
|
+
}
|
|
26649
|
+
}
|
|
26650
|
+
return acc;
|
|
26651
|
+
}
|
|
26652
|
+
function suggestForCommand(program2, unknown2) {
|
|
26653
|
+
if (unknown2.length < 3)
|
|
26654
|
+
return;
|
|
26655
|
+
const candidates = collectCommandNames(program2);
|
|
26656
|
+
let best;
|
|
26657
|
+
for (const candidate of candidates) {
|
|
26658
|
+
const d = levenshtein(unknown2, candidate);
|
|
26659
|
+
if (d > SUGGESTION_THRESHOLD)
|
|
26660
|
+
continue;
|
|
26661
|
+
if (!best || d < best.dist) {
|
|
26662
|
+
best = { name: candidate, dist: d };
|
|
26663
|
+
}
|
|
26664
|
+
}
|
|
26665
|
+
return best?.name;
|
|
26666
|
+
}
|
|
26667
|
+
function withErrorHandling(handler, options) {
|
|
26668
|
+
return async (...args) => {
|
|
26669
|
+
try {
|
|
26670
|
+
await handler(...args);
|
|
26671
|
+
} catch (error51) {
|
|
26672
|
+
const service = options?.service ?? "cli";
|
|
26673
|
+
if (error51 instanceof CLIError) {
|
|
26674
|
+
formatError2(error51, options?.opts);
|
|
26675
|
+
process.exitCode = error51.code;
|
|
26676
|
+
process.exit(error51.code);
|
|
26677
|
+
return;
|
|
26678
|
+
} else if (error51 instanceof Error) {
|
|
26679
|
+
formatError2(`[${service}] ${error51.message}`, options?.opts);
|
|
26680
|
+
process.exitCode = 1 /* ERROR */;
|
|
26681
|
+
process.exit(1 /* ERROR */);
|
|
26682
|
+
return;
|
|
26683
|
+
} else {
|
|
26684
|
+
formatError2(`[${service}] Unknown error: ${String(error51)}`, options?.opts);
|
|
26685
|
+
process.exitCode = -1 /* CommandFailed */;
|
|
26686
|
+
process.exit(-1 /* CommandFailed */);
|
|
26687
|
+
return;
|
|
26688
|
+
}
|
|
26689
|
+
}
|
|
26690
|
+
};
|
|
26691
|
+
}
|
|
26692
|
+
|
|
26693
|
+
// src/utils/help-formatter.ts
|
|
26694
|
+
function renderHelp(cmd, helper) {
|
|
26695
|
+
const subcommands = cmd.commands.filter((c) => !c._hidden).map((c) => ({ name: c.name(), desc: c.description() ?? "" }));
|
|
26696
|
+
const blocks = [];
|
|
26697
|
+
const argNames = cmd.registeredArguments.map((a2) => a2.name()).join(" ");
|
|
26698
|
+
const titleName = argNames ? `${cmd.name()} ${argNames}` : cmd.name();
|
|
26699
|
+
blocks.push(theme.heading(` ${titleName}`));
|
|
26700
|
+
if (cmd.description()) {
|
|
26701
|
+
blocks.push(` ${theme.textMuted(cmd.description())}`);
|
|
26702
|
+
}
|
|
26703
|
+
blocks.push(theme.textFaint("\u2500".repeat(60)));
|
|
26704
|
+
const usageLine = buildUsage(cmd);
|
|
26705
|
+
blocks.push(headerLine("Usage"));
|
|
26706
|
+
blocks.push(` ${theme.accent(usageLine)}`);
|
|
26707
|
+
const options = cmd.options.filter((o) => !o.hidden);
|
|
26708
|
+
if (options.length > 0) {
|
|
26709
|
+
blocks.push("");
|
|
26710
|
+
blocks.push(headerLine("Options"));
|
|
26711
|
+
const flagWidth = Math.max(...options.map((o) => o.flags.length));
|
|
26712
|
+
for (const o of options) {
|
|
26713
|
+
const padded = o.flags.padEnd(flagWidth);
|
|
26714
|
+
const desc = o.description ? theme.textMuted(o.description) : "";
|
|
26715
|
+
blocks.push(` ${theme.text(padded)} ${desc}`);
|
|
26716
|
+
}
|
|
26717
|
+
}
|
|
26718
|
+
if (subcommands.length > 0) {
|
|
26719
|
+
blocks.push("");
|
|
26720
|
+
blocks.push(headerLine("Commands"));
|
|
26721
|
+
const nameWidth = Math.max(...subcommands.map((s) => s.name.length));
|
|
26722
|
+
for (const s of subcommands) {
|
|
26723
|
+
const padded = s.name.padEnd(nameWidth);
|
|
26724
|
+
blocks.push(` ${theme.text(padded)} ${theme.textMuted(s.desc)}`);
|
|
26725
|
+
}
|
|
26726
|
+
}
|
|
26727
|
+
const afterText = captureHelpEvent(cmd, "afterHelp");
|
|
26728
|
+
if (afterText.trim()) {
|
|
26729
|
+
blocks.push("");
|
|
26730
|
+
blocks.push(headerLine("Examples"));
|
|
26731
|
+
blocks.push(` ${theme.textMuted(afterText.trim())}`);
|
|
26732
|
+
}
|
|
26733
|
+
const out = blocks.join(`
|
|
26734
|
+
`) + `
|
|
26735
|
+
`;
|
|
26736
|
+
return isRichMode() ? out : stripAnsi(out);
|
|
26737
|
+
}
|
|
26738
|
+
function headerLine(text) {
|
|
26739
|
+
return ` ${theme.textSubtle(text)}`;
|
|
26740
|
+
}
|
|
26741
|
+
function buildUsage(cmd) {
|
|
26742
|
+
const parts = [];
|
|
26743
|
+
let c = cmd;
|
|
26744
|
+
while (c && c.name()) {
|
|
26745
|
+
parts.unshift(c.name());
|
|
26746
|
+
c = c.parent;
|
|
26747
|
+
}
|
|
26748
|
+
for (const arg of cmd.registeredArguments) {
|
|
26749
|
+
parts.push(arg.name());
|
|
26750
|
+
}
|
|
26751
|
+
return `${parts.join(" ")} [options]`;
|
|
26752
|
+
}
|
|
26753
|
+
function captureHelpEvent(cmd, eventName) {
|
|
26754
|
+
const parts = [];
|
|
26755
|
+
const context = {
|
|
26756
|
+
error: false,
|
|
26757
|
+
command: cmd,
|
|
26758
|
+
write: (str) => {
|
|
26759
|
+
parts.push(str);
|
|
26760
|
+
}
|
|
26761
|
+
};
|
|
26762
|
+
const emitter = cmd;
|
|
26763
|
+
emitter.emit(eventName, context);
|
|
26764
|
+
return parts.join("");
|
|
26765
|
+
}
|
|
26766
|
+
|
|
26767
|
+
// src/utils/completion.ts
|
|
26768
|
+
var SUGGEST_NEXT = {
|
|
26769
|
+
init: { command: "hoox setup", reason: "provision infrastructure" },
|
|
26770
|
+
setup: { command: "hoox deploy all", reason: "ship to Cloudflare" },
|
|
26771
|
+
"deploy all": { command: "hoox check health", reason: "verify the deploy" },
|
|
26772
|
+
"check health": { command: "hoox monitor status", reason: "keep watching" },
|
|
26773
|
+
"monitor kill-switch off": {
|
|
26774
|
+
command: "hoox check health",
|
|
26775
|
+
reason: "re-enable trading"
|
|
26776
|
+
}
|
|
26777
|
+
};
|
|
26778
|
+
function suggestNextCommand(commandPath) {
|
|
26779
|
+
return SUGGEST_NEXT[commandPath];
|
|
26780
|
+
}
|
|
26781
|
+
function getCmdPath(cmd) {
|
|
26782
|
+
const parts = [];
|
|
26783
|
+
let current2 = cmd;
|
|
26784
|
+
while (current2 && current2.name() && current2.parent) {
|
|
26785
|
+
parts.unshift(current2.name());
|
|
26786
|
+
current2 = current2.parent;
|
|
26787
|
+
}
|
|
26788
|
+
return parts.join(" ");
|
|
26480
26789
|
}
|
|
26481
26790
|
|
|
26482
26791
|
// src/commands/init/init-command.ts
|
|
@@ -26781,30 +27090,6 @@ class CloudflareService {
|
|
|
26781
27090
|
return;
|
|
26782
27091
|
}
|
|
26783
27092
|
}
|
|
26784
|
-
// src/utils/error-handler.ts
|
|
26785
|
-
function withErrorHandling(handler, options) {
|
|
26786
|
-
return async (...args) => {
|
|
26787
|
-
try {
|
|
26788
|
-
await handler(...args);
|
|
26789
|
-
} catch (error51) {
|
|
26790
|
-
const service = options?.service ?? "cli";
|
|
26791
|
-
if (error51 instanceof CLIError) {
|
|
26792
|
-
formatError2(error51, options?.opts);
|
|
26793
|
-
process.exitCode = error51.code;
|
|
26794
|
-
process.exit(error51.code);
|
|
26795
|
-
} else if (error51 instanceof Error) {
|
|
26796
|
-
formatError2(`[${service}] ${error51.message}`, options?.opts);
|
|
26797
|
-
process.exitCode = 1 /* ERROR */;
|
|
26798
|
-
process.exit(1 /* ERROR */);
|
|
26799
|
-
} else {
|
|
26800
|
-
formatError2(`[${service}] Unknown error: ${String(error51)}`, options?.opts);
|
|
26801
|
-
process.exitCode = -1 /* CommandFailed */;
|
|
26802
|
-
process.exit(-1 /* CommandFailed */);
|
|
26803
|
-
}
|
|
26804
|
-
}
|
|
26805
|
-
};
|
|
26806
|
-
}
|
|
26807
|
-
|
|
26808
27093
|
// src/commands/init/cli-provisioner.ts
|
|
26809
27094
|
class CLIProvisioner {
|
|
26810
27095
|
async provision(plan) {
|
|
@@ -29046,7 +29331,7 @@ function renderDefaultSummary(results) {
|
|
|
29046
29331
|
if (results.length === 0)
|
|
29047
29332
|
return;
|
|
29048
29333
|
const rows = results.map((r2) => ({
|
|
29049
|
-
Task: r2.title,
|
|
29334
|
+
Task: theme.text(r2.title),
|
|
29050
29335
|
Status: r2.ok ? theme.success(icons.success) : theme.error(icons.error),
|
|
29051
29336
|
Duration: formatDuration2(r2.ms)
|
|
29052
29337
|
}));
|
|
@@ -36764,8 +37049,30 @@ EXAMPLES:
|
|
|
36764
37049
|
registerFastpathCommand(cmd);
|
|
36765
37050
|
}
|
|
36766
37051
|
// src/ui/banner.ts
|
|
37052
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
37053
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
37054
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
36767
37055
|
var TAGLINE = "Cloudflare Workers Platform";
|
|
36768
|
-
|
|
37056
|
+
function findCliVersion() {
|
|
37057
|
+
const PKG_NAME = "@jango-blockchained/hoox-cli";
|
|
37058
|
+
let dir = dirname3(fileURLToPath2(import.meta.url));
|
|
37059
|
+
for (let i2 = 0;i2 < 5; i2++) {
|
|
37060
|
+
const pkgPath = join8(dir, "package.json");
|
|
37061
|
+
if (existsSync8(pkgPath)) {
|
|
37062
|
+
try {
|
|
37063
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
37064
|
+
if (pkg.name === PKG_NAME)
|
|
37065
|
+
return pkg.version;
|
|
37066
|
+
} catch {}
|
|
37067
|
+
}
|
|
37068
|
+
const parent = dirname3(dir);
|
|
37069
|
+
if (parent === dir)
|
|
37070
|
+
break;
|
|
37071
|
+
dir = parent;
|
|
37072
|
+
}
|
|
37073
|
+
return "unknown";
|
|
37074
|
+
}
|
|
37075
|
+
var VERSION = findCliVersion();
|
|
36769
37076
|
var DISCLAIMER2 = "DISCLAIMER: Trading cryptocurrencies involves substantial risk of loss. Use at your own risk.";
|
|
36770
37077
|
var LEGACY_LINES = [
|
|
36771
37078
|
"\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
@@ -36777,12 +37084,12 @@ var LEGACY_LINES = [
|
|
|
36777
37084
|
];
|
|
36778
37085
|
function renderLegacy() {
|
|
36779
37086
|
const bw = 52;
|
|
36780
|
-
const line = ` ${theme.
|
|
36781
|
-
const top = ` ${theme.
|
|
36782
|
-
const bottom = ` ${theme.
|
|
37087
|
+
const line = ` ${theme.textFaint("\u2500").repeat(bw - 2)}`;
|
|
37088
|
+
const top = ` ${theme.textFaint("\u250C")}${line.slice(2)}${theme.textFaint("\u2510")}`;
|
|
37089
|
+
const bottom = ` ${theme.textFaint("\u2514")}${line.slice(2)}${theme.textFaint("\u2518")}`;
|
|
36783
37090
|
const ascii = LEGACY_LINES.map((l2) => ` ${theme.heading(l2)}`);
|
|
36784
37091
|
const gap = Math.floor((bw - TAGLINE.length - VERSION.length - 2) / 2);
|
|
36785
|
-
const tag = ` ${" ".repeat(gap)}${theme.
|
|
37092
|
+
const tag = ` ${" ".repeat(gap)}${theme.textMuted(TAGLINE)} ${theme.textMuted(`v${VERSION}`)}`;
|
|
36786
37093
|
return [top, ...ascii, line, tag, bottom].join(`
|
|
36787
37094
|
`);
|
|
36788
37095
|
}
|
|
@@ -36796,13 +37103,19 @@ var HORIZON_LINES = [
|
|
|
36796
37103
|
];
|
|
36797
37104
|
function renderBannerHorizon() {
|
|
36798
37105
|
const bw = 56;
|
|
36799
|
-
const inner = theme.
|
|
36800
|
-
const top = ` ${theme.
|
|
36801
|
-
const bottom = ` ${theme.
|
|
37106
|
+
const inner = theme.textFaint("\u2500").repeat(bw - 2);
|
|
37107
|
+
const top = ` ${theme.textFaint("\u256D")}${inner}${theme.textFaint("\u256E")}`;
|
|
37108
|
+
const bottom = ` ${theme.textFaint("\u2570")}${inner}${theme.textFaint("\u256F")}`;
|
|
36802
37109
|
const ascii = HORIZON_LINES.map((l2) => ` ${theme.accent(l2)}`);
|
|
36803
37110
|
const gap = Math.floor((bw - TAGLINE.length - VERSION.length - 4) / 2);
|
|
36804
|
-
const tag = ` ${" ".repeat(gap)}${theme.
|
|
36805
|
-
return [
|
|
37111
|
+
const tag = ` ${" ".repeat(gap)}${theme.textMuted(TAGLINE)} ${theme.textMuted(`v${VERSION}`)}`;
|
|
37112
|
+
return [
|
|
37113
|
+
top,
|
|
37114
|
+
...ascii,
|
|
37115
|
+
` ${theme.textFaint("\u2500").repeat(bw)}`,
|
|
37116
|
+
tag,
|
|
37117
|
+
bottom
|
|
37118
|
+
].join(`
|
|
36806
37119
|
`);
|
|
36807
37120
|
}
|
|
36808
37121
|
var SIGNAL_LINES = [
|
|
@@ -36814,38 +37127,44 @@ var SIGNAL_LINES = [
|
|
|
36814
37127
|
];
|
|
36815
37128
|
function renderBannerSignal() {
|
|
36816
37129
|
const bw = 54;
|
|
36817
|
-
const line = theme.
|
|
36818
|
-
const top = ` ${theme.
|
|
36819
|
-
const bottom = ` ${theme.
|
|
37130
|
+
const line = theme.textFaint("\u2500").repeat(bw);
|
|
37131
|
+
const top = ` ${theme.textFaint("\u250C")}${line.slice(2)}${theme.textFaint("\u2510")}`;
|
|
37132
|
+
const bottom = ` ${theme.textFaint("\u2514")}${line.slice(2)}${theme.textFaint("\u2518")}`;
|
|
36820
37133
|
const wordmark = SIGNAL_LINES.map((l2) => {
|
|
36821
|
-
return ` ${theme.heading(l2.slice(0, 26))}${theme.
|
|
37134
|
+
return ` ${theme.heading(l2.slice(0, 26))}${theme.textFaint(l2.slice(26))}`;
|
|
36822
37135
|
});
|
|
36823
|
-
const wave = ` ${theme.accent("~~")}${theme.
|
|
36824
|
-
return [
|
|
37136
|
+
const wave = ` ${theme.accent("~~")}${theme.textFaint("~")}${theme.accent("_")}${theme.textFaint(".")}${theme.accent("/\\")}${theme.textFaint("~")}${theme.accent("\\/")}${theme.textFaint("..")}${theme.accent("/~~\\")}${theme.textFaint("~")} ${theme.textMuted(TAGLINE)} ${theme.textMuted(`v${VERSION}`)}`;
|
|
37137
|
+
return [
|
|
37138
|
+
top,
|
|
37139
|
+
...wordmark,
|
|
37140
|
+
` ${theme.textFaint("\u2500").repeat(bw)}`,
|
|
37141
|
+
wave,
|
|
37142
|
+
bottom
|
|
37143
|
+
].join(`
|
|
36825
37144
|
`);
|
|
36826
37145
|
}
|
|
36827
37146
|
function renderBannerMinimal() {
|
|
36828
37147
|
const bw = 50;
|
|
36829
|
-
const rule = theme.
|
|
37148
|
+
const rule = theme.textFaint("\u2501").repeat(bw);
|
|
36830
37149
|
const leftPad = Math.floor((bw - TAGLINE.length - VERSION.length - 8) / 2);
|
|
36831
|
-
const titleLine = " ".repeat(leftPad) + theme.heading("H O O X") + " " + theme.
|
|
37150
|
+
const titleLine = " ".repeat(leftPad) + theme.heading("H O O X") + " " + theme.textMuted(TAGLINE) + " " + theme.textMuted(`v${VERSION}`);
|
|
36832
37151
|
return [
|
|
36833
37152
|
` ${rule}`,
|
|
36834
|
-
` ${theme.
|
|
36835
|
-
|
|
36836
|
-
` ${theme.
|
|
37153
|
+
` ${theme.textFaint("\u2502")}${" ".repeat(bw - 2)}${theme.textFaint("\u2502")}`,
|
|
37154
|
+
` ${theme.textFaint("\u2502")}${titleLine}${" ".repeat(Math.max(0, bw - stripAnsi(titleLine).length - 2))}${theme.textFaint("\u2502")}`,
|
|
37155
|
+
` ${theme.textFaint("\u2502")}${" ".repeat(bw - 2)}${theme.textFaint("\u2502")}`,
|
|
36837
37156
|
` ${rule}`
|
|
36838
37157
|
].join(`
|
|
36839
37158
|
`);
|
|
36840
37159
|
}
|
|
36841
37160
|
var BANNER_VARIANTS = {
|
|
37161
|
+
minimal: renderBannerMinimal,
|
|
36842
37162
|
legacy: renderLegacy,
|
|
36843
37163
|
horizon: renderBannerHorizon,
|
|
36844
|
-
signal: renderBannerSignal
|
|
36845
|
-
minimal: renderBannerMinimal
|
|
37164
|
+
signal: renderBannerSignal
|
|
36846
37165
|
};
|
|
36847
37166
|
function renderBanner(variant) {
|
|
36848
|
-
return variant ? BANNER_VARIANTS[variant]() :
|
|
37167
|
+
return variant ? BANNER_VARIANTS[variant]() : renderBannerMinimal();
|
|
36849
37168
|
}
|
|
36850
37169
|
// src/ui/menu.ts
|
|
36851
37170
|
init_dist4();
|
|
@@ -37197,13 +37516,14 @@ async function runCommand(program2, commandStr) {
|
|
|
37197
37516
|
}
|
|
37198
37517
|
}
|
|
37199
37518
|
// src/index.ts
|
|
37200
|
-
var pkgVersion = JSON.parse(
|
|
37519
|
+
var pkgVersion = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf-8")).version;
|
|
37201
37520
|
var program2 = new Command;
|
|
37202
37521
|
program2.name("hoox").description("Hoox CLI \u2014 manage Cloudflare Workers, infrastructure, secrets, and deployments").version(`${pkgVersion}
|
|
37203
37522
|
|
|
37204
37523
|
${COPYRIGHT}`).addHelpText("beforeAll", theme.heading(`
|
|
37205
37524
|
Hoox CLI \u2014 Cloudflare Workers Platform
|
|
37206
37525
|
`)).configureHelp({
|
|
37526
|
+
formatHelp: (cmd, helper) => renderHelp(cmd, helper),
|
|
37207
37527
|
styleTitle: (str) => theme.heading(str),
|
|
37208
37528
|
styleCommandText: (str) => theme.bold(str),
|
|
37209
37529
|
styleOptionText: (str) => str,
|
|
@@ -37211,7 +37531,22 @@ Hoox CLI \u2014 Cloudflare Workers Platform
|
|
|
37211
37531
|
});
|
|
37212
37532
|
program2.option("--json", "Output in JSON format");
|
|
37213
37533
|
program2.option("--quiet", "Minimal output");
|
|
37534
|
+
program2.option("--no-color", "Disable color output");
|
|
37214
37535
|
program2.option("-y, --yes", "Skip confirmation prompts");
|
|
37536
|
+
program2.hook("preAction", (thisCmd) => {
|
|
37537
|
+
thisCmd._hooxStartedAt = Date.now();
|
|
37538
|
+
});
|
|
37539
|
+
program2.hook("postAction", (thisCmd) => {
|
|
37540
|
+
if (process.exitCode && process.exitCode !== 0)
|
|
37541
|
+
return;
|
|
37542
|
+
const startedAt = thisCmd._hooxStartedAt;
|
|
37543
|
+
if (startedAt === undefined)
|
|
37544
|
+
return;
|
|
37545
|
+
const durationMs = Date.now() - startedAt;
|
|
37546
|
+
const path6 = getCmdPath(thisCmd);
|
|
37547
|
+
const suggestion = suggestNextCommand(path6);
|
|
37548
|
+
formatCompletion("Done", { durationMs, suggestion });
|
|
37549
|
+
});
|
|
37215
37550
|
program2.exitOverride((err) => {
|
|
37216
37551
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
37217
37552
|
process.exit(0 /* SUCCESS */);
|
|
@@ -37219,7 +37554,14 @@ program2.exitOverride((err) => {
|
|
|
37219
37554
|
if (err.code === "commander.missingArgument" || err.message === "(outputHelp)" || err.message?.includes("outputHelp")) {
|
|
37220
37555
|
process.exit(0 /* SUCCESS */);
|
|
37221
37556
|
}
|
|
37222
|
-
if (err.code === "commander.unknownCommand"
|
|
37557
|
+
if (err.code === "commander.unknownCommand") {
|
|
37558
|
+
const match = err.message.match(/'([^']+)'/);
|
|
37559
|
+
const badArg = match?.[1] ?? "";
|
|
37560
|
+
const suggestion = suggestForCommand(program2, badArg);
|
|
37561
|
+
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false), suggestion ? { suggestions: [suggestion] } : undefined);
|
|
37562
|
+
process.exit(2 /* INVALID_USAGE */);
|
|
37563
|
+
}
|
|
37564
|
+
if (err.code === "commander.unknownOption") {
|
|
37223
37565
|
formatError2(new CLIError(err.message, 2 /* INVALID_USAGE */, undefined, false));
|
|
37224
37566
|
process.exit(2 /* INVALID_USAGE */);
|
|
37225
37567
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jango-blockchained/hoox-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments (@jango-blockchained/hoox-cli)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"ansis": "^4.2.0",
|
|
21
21
|
"commander": "^15.0.0",
|
|
22
22
|
"jsonc-parser": "^3.3.1",
|
|
23
|
-
"wrangler": "^4.
|
|
23
|
+
"wrangler": "^4.104.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@jango-blockchained/hoox-shared": "^1.0.9",
|