@jango-blockchained/hoox-cli 0.3.4 → 0.3.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.
Files changed (48) hide show
  1. package/README.md +2 -0
  2. package/package.json +5 -3
  3. package/src/commands/check/check-command.test.ts +28 -20
  4. package/src/commands/check/prerequisites-command.ts +9 -5
  5. package/src/commands/clone/clone-command.ts +1 -10
  6. package/src/commands/config/config-command.ts +7 -11
  7. package/src/commands/config/env-command.ts +16 -35
  8. package/src/commands/config/kv-command.ts +33 -72
  9. package/src/commands/db/db-command.ts +23 -25
  10. package/src/commands/deploy/deploy-command.ts +133 -52
  11. package/src/commands/deploy/telegram-service.ts +21 -6
  12. package/src/commands/dev/dev-command.ts +7 -16
  13. package/src/commands/infra/infra-command.test.ts +2 -2
  14. package/src/commands/infra/infra-command.ts +45 -11
  15. package/src/commands/init/init-command.test.ts +2 -2
  16. package/src/commands/monitor/monitor-command.test.ts +44 -16
  17. package/src/commands/monitor/monitor-command.ts +45 -21
  18. package/src/commands/monitor/monitor-service.ts +19 -4
  19. package/src/commands/repair/repair-command.test.ts +35 -15
  20. package/src/commands/repair/repair-command.ts +39 -18
  21. package/src/commands/repair/repair-service.ts +48 -12
  22. package/src/commands/test/test-command.ts +4 -10
  23. package/src/commands/tui/index.ts +1 -0
  24. package/src/commands/tui/tui-command.ts +87 -0
  25. package/src/commands/update/index.ts +1 -0
  26. package/src/commands/update/update-command.ts +51 -0
  27. package/src/commands/waf/waf-command.test.ts +1 -1
  28. package/src/commands/waf/waf-command.ts +11 -11
  29. package/src/index.ts +52 -1
  30. package/src/services/cloudflare/cloudflare-service.test.ts +12 -8
  31. package/src/services/cloudflare/cloudflare-service.ts +8 -10
  32. package/src/services/cloudflare/types.ts +6 -5
  33. package/src/services/db/db-service.ts +8 -17
  34. package/src/services/env/env-service.test.ts +41 -15
  35. package/src/services/env/env-service.ts +276 -46
  36. package/src/services/kv/kv-sync-service.ts +117 -34
  37. package/src/services/prerequisites/prerequisites-service.ts +137 -29
  38. package/src/services/secrets/index.ts +0 -1
  39. package/src/services/secrets/secrets-service.test.ts +34 -25
  40. package/src/services/secrets/secrets-service.ts +10 -16
  41. package/src/services/secrets/types.ts +4 -11
  42. package/src/services/update/index.ts +2 -0
  43. package/src/services/update/update-service.test.ts +76 -0
  44. package/src/services/update/update-service.ts +193 -0
  45. package/src/ui/banner.ts +5 -5
  46. package/src/ui/menu.ts +6 -1
  47. package/src/utils/formatters.ts +21 -4
  48. package/src/utils/theme.ts +1 -1
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @jango-blockchained/hoox-cli
2
2
 
3
+ > **See also:** [Hoox User Guide](../docs/home.md) · [CLI Command Reference](../docs/reference/cli-commands.md)
4
+
3
5
  Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments.
4
6
 
5
7
  381 unit tests, 15 command groups, 50+ subcommands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jango-blockchained/hoox-cli",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments (@jango-blockchained/hoox-cli)",
5
5
  "type": "module",
6
6
  "main": "./bin/hoox.js",
@@ -9,7 +9,8 @@
9
9
  ".": "./bin/hoox.js"
10
10
  },
11
11
  "bin": {
12
- "hoox": "./bin/hoox.js"
12
+ "hoox": "./bin/hoox.js",
13
+ "hx": "./bin/hoox.js"
13
14
  },
14
15
  "scripts": {
15
16
  "test": "bun test",
@@ -24,7 +25,8 @@
24
25
  "@jango-blockchained/hoox-shared": "workspace:*",
25
26
  "ansis": "^4.2.0",
26
27
  "commander": "^14.0.3",
27
- "jsonc-parser": "^3.3.1"
28
+ "jsonc-parser": "^3.3.1",
29
+ "wrangler": "^4.92.0"
28
30
  },
29
31
  "devDependencies": {
30
32
  "@types/node": "^25.6.0",
@@ -244,16 +244,20 @@ describe("registerCheckCommand", () => {
244
244
  // -- check setup ----------------------------------------------------------
245
245
 
246
246
  describe("check setup", () => {
247
- it("loads config and runs all 4 categories", { timeout: 30000 }, async () => {
248
- const program = await createProgram();
249
- await program.parseAsync(["check", "setup"], { from: "user" });
250
-
251
- expect(loadMock).toHaveBeenCalled();
252
- expect(d1ListMock).toHaveBeenCalled();
253
- expect(kvListMock).toHaveBeenCalled();
254
- expect(r2ListMock).toHaveBeenCalled();
255
- expect(queueListMock).toHaveBeenCalled();
256
- });
247
+ it(
248
+ "loads config and runs all 4 categories",
249
+ { timeout: 30000 },
250
+ async () => {
251
+ const program = await createProgram();
252
+ await program.parseAsync(["check", "setup"], { from: "user" });
253
+
254
+ expect(loadMock).toHaveBeenCalled();
255
+ expect(d1ListMock).toHaveBeenCalled();
256
+ expect(kvListMock).toHaveBeenCalled();
257
+ expect(r2ListMock).toHaveBeenCalled();
258
+ expect(queueListMock).toHaveBeenCalled();
259
+ }
260
+ );
257
261
 
258
262
  it("outputs JSON when --json flag is set", { timeout: 30000 }, async () => {
259
263
  const program = await createProgram();
@@ -285,18 +289,22 @@ describe("registerCheckCommand", () => {
285
289
  }
286
290
  });
287
291
 
288
- it("sets exitCode to ERROR when validation fails", { timeout: 30000 }, async () => {
289
- validateMock = mock(() => ({
290
- valid: false,
291
- errors: ["global.cloudflare_account_id is required"],
292
- }));
293
- ConfigService.prototype.validate = validateMock;
292
+ it(
293
+ "sets exitCode to ERROR when validation fails",
294
+ { timeout: 30000 },
295
+ async () => {
296
+ validateMock = mock(() => ({
297
+ valid: false,
298
+ errors: ["global.cloudflare_account_id is required"],
299
+ }));
300
+ ConfigService.prototype.validate = validateMock;
294
301
 
295
- const program = await createProgram();
296
- await program.parseAsync(["check", "setup"], { from: "user" });
302
+ const program = await createProgram();
303
+ await program.parseAsync(["check", "setup"], { from: "user" });
297
304
 
298
- expect(process.exitCode).toBe(ExitCode.ERROR);
299
- });
305
+ expect(process.exitCode).toBe(ExitCode.ERROR);
306
+ }
307
+ );
300
308
 
301
309
  it("sets exitCode to ERROR when infra check fails", async () => {
302
310
  d1ListMock = mock(async () => ({
@@ -7,7 +7,7 @@ import { CLIError, ExitCode } from "../../utils/errors.js";
7
7
  import type { FormatOptions } from "../../utils/formatters.js";
8
8
 
9
9
  export async function runPrerequisitesCheck(
10
- service?: PrerequisitesService,
10
+ service?: PrerequisitesService
11
11
  ): Promise<PrerequisitesReport> {
12
12
  const svc = service ?? new PrerequisitesService();
13
13
  return await svc.runAll();
@@ -15,12 +15,16 @@ export async function runPrerequisitesCheck(
15
15
 
16
16
  function renderReport(report: PrerequisitesReport): void {
17
17
  for (const check of report.checks) {
18
- const icon = check.passed ? theme.success(icons.success) : theme.error(icons.error);
18
+ const icon = check.passed
19
+ ? theme.success(icons.success)
20
+ : theme.error(icons.error);
19
21
  process.stdout.write(`${icon} ${check.name}\n`);
20
22
  process.stdout.write(` ${theme.dim("Version:")} ${check.version}\n`);
21
23
  process.stdout.write(` ${theme.dim("Required:")} ${check.required}\n`);
22
24
  if (check.hint) {
23
- process.stdout.write(` ${theme.warning(`${icons.warning} ${check.hint}`)}\n`);
25
+ process.stdout.write(
26
+ ` ${theme.warning(`${icons.warning} ${check.hint}`)}\n`
27
+ );
24
28
  }
25
29
  process.stdout.write("\n");
26
30
  }
@@ -33,7 +37,7 @@ function renderReport(report: PrerequisitesReport): void {
33
37
 
34
38
  async function handlePrerequisites(
35
39
  opts: FormatOptions,
36
- tool?: string,
40
+ tool?: string
37
41
  ): Promise<void> {
38
42
  try {
39
43
  const svc = new PrerequisitesService();
@@ -78,7 +82,7 @@ OPTIONS:
78
82
  EXAMPLES:
79
83
  hoox check prerequisites
80
84
  hoox check prerequisites --tool bun
81
- hoox check prerequisites --json`,
85
+ hoox check prerequisites --json`
82
86
  )
83
87
  .option("--tool <name>", "Only check a specific tool")
84
88
  .action(async (options: { tool?: string }, cmd: Command) => {
@@ -20,6 +20,7 @@ import {
20
20
  formatError,
21
21
  formatTable,
22
22
  formatJson,
23
+ getFormatOptions,
23
24
  } from "../../utils/formatters.js";
24
25
  import { CLIError, ExitCode } from "../../utils/errors.js";
25
26
 
@@ -36,16 +37,6 @@ interface CloneStatus {
36
37
  error?: string;
37
38
  }
38
39
 
39
- // ---------------------------------------------------------------------------
40
- // Helpers
41
- // ---------------------------------------------------------------------------
42
-
43
- /** Extract --json / --quiet from the global program options. */
44
- function getFormatOptions(cmd: Command) {
45
- const opts = cmd.optsWithGlobals();
46
- return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
47
- }
48
-
49
40
  /**
50
41
  * Resolve the base GitHub URL for worker repos.
51
42
  * Tries `git remote get-url origin` first, falls back to a sensible default.
@@ -490,12 +490,10 @@ EXAMPLES:
490
490
  const syncSpin = spinner();
491
491
  syncSpin.start("Syncing to Cloudflare...");
492
492
  const result = await svc.syncToCloudflare(workerName);
493
- if (result.success) {
493
+ if (result.ok) {
494
494
  syncSpin.stop(`Secret "${secretName}" synced to Cloudflare`);
495
495
  } else {
496
- syncSpin.stop(
497
- `Sync partial: ${result.error ?? "unknown error"}`
498
- );
496
+ syncSpin.stop(`Sync partial: ${result.error ?? "unknown error"}`);
499
497
  formatError(
500
498
  new CLIError(
501
499
  `Sync partial: ${result.error ?? "unknown error"}`,
@@ -619,14 +617,12 @@ EXAMPLES:
619
617
  const syncSpin = spinner();
620
618
  syncSpin.start(`Syncing secrets for "${workerName}"...`);
621
619
  const result = await svc.syncToCloudflare(workerName);
622
- if (result.success) {
620
+ if (result.ok) {
623
621
  syncSpin.stop(
624
- `Synced ${result.data?.length ?? 0} secrets for "${workerName}"`
622
+ `Synced ${result.value?.length ?? 0} secrets for "${workerName}"`
625
623
  );
626
624
  } else {
627
- syncSpin.stop(
628
- `Sync failed: ${result.error ?? "unknown error"}`
629
- );
625
+ syncSpin.stop(`Sync failed: ${result.error ?? "unknown error"}`);
630
626
  formatError(
631
627
  new CLIError(
632
628
  `Sync failed: ${result.error ?? "unknown error"}`,
@@ -651,9 +647,9 @@ EXAMPLES:
651
647
  for (const name of workers) {
652
648
  syncSpin.start(`Syncing ${name}...`);
653
649
  const result = await svc.syncToCloudflare(name);
654
- if (result.success) {
650
+ if (result.ok) {
655
651
  syncSpin.stop(
656
- `${theme.success("synced")} ${result.data?.length ?? 0} for ${name}`
652
+ `${theme.success("synced")} ${result.value?.length ?? 0} for ${name}`
657
653
  );
658
654
  synced++;
659
655
  } else {
@@ -63,7 +63,7 @@ async function handleInit(opts: FormatOptions): Promise<void> {
63
63
 
64
64
  for (const section of sections) {
65
65
  const sectionDefs = EnvService.getDefinitions().filter(
66
- (d) => d.section === section,
66
+ (d) => d.section === section
67
67
  );
68
68
  if (sectionDefs.length === 0) continue;
69
69
 
@@ -111,8 +111,7 @@ async function handleInit(opts: FormatOptions): Promise<void> {
111
111
  "",
112
112
  ].join("\n");
113
113
  await Bun.write(`${workerPath}/.dev.vars`, content);
114
- if (!opts.quiet)
115
- formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
114
+ if (!opts.quiet) formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
116
115
  }
117
116
 
118
117
  p.outro("Environment setup complete!");
@@ -127,7 +126,7 @@ async function handleShow(opts: FormatOptions): Promise<void> {
127
126
  if (!(await file.exists())) {
128
127
  throw new CLIError(
129
128
  ".env.local not found. Run `hoox config env init`.",
130
- ExitCode.INVALID_USAGE,
129
+ ExitCode.INVALID_USAGE
131
130
  );
132
131
  }
133
132
 
@@ -157,7 +156,9 @@ async function handleValidate(opts: FormatOptions): Promise<void> {
157
156
  formatJson(result, opts);
158
157
  } else if (!opts.quiet) {
159
158
  if (!(await file.exists())) {
160
- process.stdout.write(".env.local not found. Run `hoox config env init` first.\n\n");
159
+ process.stdout.write(
160
+ ".env.local not found. Run `hoox config env init` first.\n\n"
161
+ );
161
162
  }
162
163
  if (result.missing.length > 0) {
163
164
  process.stdout.write("Missing required variables:\n");
@@ -190,7 +191,7 @@ async function handleGenerateDevVars(opts: FormatOptions): Promise<void> {
190
191
  if (!(await file.exists())) {
191
192
  throw new CLIError(
192
193
  ".env.local not found. Run `hoox config env init`.",
193
- ExitCode.INVALID_USAGE,
194
+ ExitCode.INVALID_USAGE
194
195
  );
195
196
  }
196
197
 
@@ -237,7 +238,7 @@ EXAMPLES:
237
238
  hoox config env init
238
239
  hoox config env show
239
240
  hoox config env validate
240
- hoox config env generate-dev-vars`,
241
+ hoox config env generate-dev-vars`
241
242
  );
242
243
 
243
244
  envCmd
@@ -248,13 +249,8 @@ EXAMPLES:
248
249
  try {
249
250
  await handleInit(opts);
250
251
  } catch (err) {
251
- formatError(
252
- err instanceof Error ? err : String(err),
253
- opts,
254
- );
255
- process.exit(
256
- err instanceof CLIError ? err.code : ExitCode.ERROR,
257
- );
252
+ formatError(err instanceof Error ? err : String(err), opts);
253
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
258
254
  }
259
255
  });
260
256
 
@@ -266,13 +262,8 @@ EXAMPLES:
266
262
  try {
267
263
  await handleShow(opts);
268
264
  } catch (err) {
269
- formatError(
270
- err instanceof Error ? err : String(err),
271
- opts,
272
- );
273
- process.exit(
274
- err instanceof CLIError ? err.code : ExitCode.ERROR,
275
- );
265
+ formatError(err instanceof Error ? err : String(err), opts);
266
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
276
267
  }
277
268
  });
278
269
 
@@ -284,13 +275,8 @@ EXAMPLES:
284
275
  try {
285
276
  await handleValidate(opts);
286
277
  } catch (err) {
287
- formatError(
288
- err instanceof Error ? err : String(err),
289
- opts,
290
- );
291
- process.exit(
292
- err instanceof CLIError ? err.code : ExitCode.ERROR,
293
- );
278
+ formatError(err instanceof Error ? err : String(err), opts);
279
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
294
280
  }
295
281
  });
296
282
 
@@ -302,13 +288,8 @@ EXAMPLES:
302
288
  try {
303
289
  await handleGenerateDevVars(opts);
304
290
  } catch (err) {
305
- formatError(
306
- err instanceof Error ? err : String(err),
307
- opts,
308
- );
309
- process.exit(
310
- err instanceof CLIError ? err.code : ExitCode.ERROR,
311
- );
291
+ formatError(err instanceof Error ? err : String(err), opts);
292
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
312
293
  }
313
294
  });
314
295
  }
@@ -27,9 +27,7 @@ function formatOpts(cmd: Command): FormatOptions {
27
27
  return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
28
28
  }
29
29
 
30
- async function resolveNs(
31
- cmd: Command,
32
- ): Promise<string> {
30
+ async function resolveNs(cmd: Command): Promise<string> {
33
31
  const svc = new KvSyncService();
34
32
  const opts = cmd.optsWithGlobals<{ namespaceId?: string }>();
35
33
  return await svc.resolveNamespaceId(opts.namespaceId);
@@ -39,10 +37,7 @@ async function resolveNs(
39
37
  // kv list
40
38
  // ---------------------------------------------------------------------------
41
39
 
42
- async function handleList(
43
- opts: FormatOptions,
44
- nsId: string,
45
- ): Promise<void> {
40
+ async function handleList(opts: FormatOptions, nsId: string): Promise<void> {
46
41
  const svc = new KvSyncService();
47
42
  const keys = await svc.list(nsId);
48
43
 
@@ -65,7 +60,7 @@ async function handleList(
65
60
  async function handleGet(
66
61
  opts: FormatOptions,
67
62
  nsId: string,
68
- key: string,
63
+ key: string
69
64
  ): Promise<void> {
70
65
  const svc = new KvSyncService();
71
66
  const value = await svc.get(nsId, key);
@@ -73,7 +68,7 @@ async function handleGet(
73
68
  if (value === null) {
74
69
  throw new CLIError(
75
70
  `Key "${key}" not found in KV namespace`,
76
- ExitCode.ERROR,
71
+ ExitCode.ERROR
77
72
  );
78
73
  }
79
74
 
@@ -92,7 +87,7 @@ async function handleSet(
92
87
  opts: FormatOptions,
93
88
  nsId: string,
94
89
  key: string,
95
- value: string,
90
+ value: string
96
91
  ): Promise<void> {
97
92
  const svc = new KvSyncService();
98
93
  await svc.set(nsId, key, value);
@@ -106,7 +101,7 @@ async function handleSet(
106
101
  async function handleDelete(
107
102
  opts: FormatOptions,
108
103
  nsId: string,
109
- key: string,
104
+ key: string
110
105
  ): Promise<void> {
111
106
  const svc = new KvSyncService();
112
107
  await svc.delete(nsId, key);
@@ -119,7 +114,7 @@ async function handleDelete(
119
114
 
120
115
  async function handleApplyManifest(
121
116
  opts: FormatOptions,
122
- nsId: string,
117
+ nsId: string
123
118
  ): Promise<void> {
124
119
  const svc = new KvSyncService();
125
120
  const manifest = KvSyncService.getManifest();
@@ -133,7 +128,7 @@ async function handleApplyManifest(
133
128
  setCount++;
134
129
  } catch (err) {
135
130
  errors.push(
136
- `${keyDef.key}: ${err instanceof Error ? err.message : String(err)}`,
131
+ `${keyDef.key}: ${err instanceof Error ? err.message : String(err)}`
137
132
  );
138
133
  }
139
134
  }
@@ -141,7 +136,7 @@ async function handleApplyManifest(
141
136
 
142
137
  formatSuccess(
143
138
  `Applied ${setCount}/${manifest.keys.length} manifest keys (${errors.length} errors)`,
144
- opts,
139
+ opts
145
140
  );
146
141
  }
147
142
 
@@ -156,7 +151,7 @@ async function handleManifest(opts: FormatOptions): Promise<void> {
156
151
  formatJson(manifest, opts);
157
152
  } else if (!opts.quiet) {
158
153
  process.stdout.write(
159
- `${theme.heading(`KV Manifest: ${manifest.namespace}`)}\n\n`,
154
+ `${theme.heading(`KV Manifest: ${manifest.namespace}`)}\n\n`
160
155
  );
161
156
  const rows = manifest.keys.map((k) => ({
162
157
  Key: k.key,
@@ -197,11 +192,11 @@ EXAMPLES:
197
192
  hoox config kv get trade:kill_switch
198
193
  hoox config kv delete trade:kill_switch
199
194
  hoox config kv apply-manifest
200
- hoox config kv manifest`,
195
+ hoox config kv manifest`
201
196
  )
202
197
  .option(
203
198
  "--namespace-id <id>",
204
- "KV namespace ID (auto-detected if omitted)",
199
+ "KV namespace ID (auto-detected if omitted)"
205
200
  );
206
201
 
207
202
  // -- list
@@ -214,13 +209,8 @@ EXAMPLES:
214
209
  const nsId = await resolveNs(cmd);
215
210
  await handleList(opts, nsId);
216
211
  } catch (err) {
217
- formatError(
218
- err instanceof Error ? err : String(err),
219
- opts,
220
- );
221
- process.exit(
222
- err instanceof CLIError ? err.code : ExitCode.ERROR,
223
- );
212
+ formatError(err instanceof Error ? err : String(err), opts);
213
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
224
214
  }
225
215
  });
226
216
 
@@ -234,13 +224,8 @@ EXAMPLES:
234
224
  const nsId = await resolveNs(cmd);
235
225
  await handleGet(opts, nsId, key);
236
226
  } catch (err) {
237
- formatError(
238
- err instanceof Error ? err : String(err),
239
- opts,
240
- );
241
- process.exit(
242
- err instanceof CLIError ? err.code : ExitCode.ERROR,
243
- );
227
+ formatError(err instanceof Error ? err : String(err), opts);
228
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
244
229
  }
245
230
  });
246
231
 
@@ -248,23 +233,16 @@ EXAMPLES:
248
233
  kvCmd
249
234
  .command("set <key> <value>")
250
235
  .description("Set a key's value in the KV namespace")
251
- .action(
252
- async (key: string, value: string, _, cmd: Command) => {
253
- const opts = formatOpts(cmd);
254
- try {
255
- const nsId = await resolveNs(cmd);
256
- await handleSet(opts, nsId, key, value);
257
- } catch (err) {
258
- formatError(
259
- err instanceof Error ? err : String(err),
260
- opts,
261
- );
262
- process.exit(
263
- err instanceof CLIError ? err.code : ExitCode.ERROR,
264
- );
265
- }
266
- },
267
- );
236
+ .action(async (key: string, value: string, _, cmd: Command) => {
237
+ const opts = formatOpts(cmd);
238
+ try {
239
+ const nsId = await resolveNs(cmd);
240
+ await handleSet(opts, nsId, key, value);
241
+ } catch (err) {
242
+ formatError(err instanceof Error ? err : String(err), opts);
243
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
244
+ }
245
+ });
268
246
 
269
247
  // -- delete
270
248
  kvCmd
@@ -276,35 +254,23 @@ EXAMPLES:
276
254
  const nsId = await resolveNs(cmd);
277
255
  await handleDelete(opts, nsId, key);
278
256
  } catch (err) {
279
- formatError(
280
- err instanceof Error ? err : String(err),
281
- opts,
282
- );
283
- process.exit(
284
- err instanceof CLIError ? err.code : ExitCode.ERROR,
285
- );
257
+ formatError(err instanceof Error ? err : String(err), opts);
258
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
286
259
  }
287
260
  });
288
261
 
289
262
  // -- apply-manifest
290
263
  kvCmd
291
264
  .command("apply-manifest")
292
- .description(
293
- "Apply manifest key defaults to the KV namespace",
294
- )
265
+ .description("Apply manifest key defaults to the KV namespace")
295
266
  .action(async (_, cmd: Command) => {
296
267
  const opts = formatOpts(cmd);
297
268
  try {
298
269
  const nsId = await resolveNs(cmd);
299
270
  await handleApplyManifest(opts, nsId);
300
271
  } catch (err) {
301
- formatError(
302
- err instanceof Error ? err : String(err),
303
- opts,
304
- );
305
- process.exit(
306
- err instanceof CLIError ? err.code : ExitCode.ERROR,
307
- );
272
+ formatError(err instanceof Error ? err : String(err), opts);
273
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
308
274
  }
309
275
  });
310
276
 
@@ -317,13 +283,8 @@ EXAMPLES:
317
283
  try {
318
284
  await handleManifest(opts);
319
285
  } catch (err) {
320
- formatError(
321
- err instanceof Error ? err : String(err),
322
- opts,
323
- );
324
- process.exit(
325
- err instanceof CLIError ? err.code : ExitCode.ERROR,
326
- );
286
+ formatError(err instanceof Error ? err : String(err), opts);
287
+ process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
327
288
  }
328
289
  });
329
290
  }