@jango-blockchained/hoox-cli 0.5.2 → 0.5.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 (114) hide show
  1. package/bin/hoox.js +3 -4
  2. package/dist/index.js +32545 -0
  3. package/package.json +10 -15
  4. package/src/commands/check/check-command.test.ts +0 -476
  5. package/src/commands/check/check-command.ts +0 -1087
  6. package/src/commands/check/index.ts +0 -10
  7. package/src/commands/check/prerequisites-command.test.ts +0 -19
  8. package/src/commands/check/prerequisites-command.ts +0 -97
  9. package/src/commands/check/types.ts +0 -103
  10. package/src/commands/clone/clone-command.test.ts +0 -440
  11. package/src/commands/clone/clone-command.ts +0 -431
  12. package/src/commands/clone/index.ts +0 -1
  13. package/src/commands/config/config-command.test.ts +0 -583
  14. package/src/commands/config/config-command.ts +0 -896
  15. package/src/commands/config/env-command.test.ts +0 -43
  16. package/src/commands/config/env-command.ts +0 -292
  17. package/src/commands/config/index.ts +0 -3
  18. package/src/commands/config/kv-command.test.ts +0 -14
  19. package/src/commands/config/kv-command.ts +0 -290
  20. package/src/commands/dashboard/dashboard-command.test.ts +0 -47
  21. package/src/commands/dashboard/dashboard-command.ts +0 -130
  22. package/src/commands/dashboard/index.ts +0 -1
  23. package/src/commands/db/db-command.test.ts +0 -21
  24. package/src/commands/db/db-command.ts +0 -311
  25. package/src/commands/db/index.ts +0 -1
  26. package/src/commands/deploy/deploy-command.test.ts +0 -324
  27. package/src/commands/deploy/deploy-command.ts +0 -1054
  28. package/src/commands/deploy/index.ts +0 -2
  29. package/src/commands/deploy/telegram-service.ts +0 -76
  30. package/src/commands/deploy/types.ts +0 -34
  31. package/src/commands/dev/dev-command.test.ts +0 -405
  32. package/src/commands/dev/dev-command.ts +0 -398
  33. package/src/commands/dev/index.ts +0 -1
  34. package/src/commands/disclaimer/disclaimer-command.ts +0 -21
  35. package/src/commands/disclaimer/index.ts +0 -1
  36. package/src/commands/infra/index.ts +0 -5
  37. package/src/commands/infra/infra-command.test.ts +0 -719
  38. package/src/commands/infra/infra-command.ts +0 -974
  39. package/src/commands/infra/types.ts +0 -23
  40. package/src/commands/init/__tests__/cli-provisioner.test.ts +0 -17
  41. package/src/commands/init/cli-provisioner.ts +0 -71
  42. package/src/commands/init/index.ts +0 -1
  43. package/src/commands/init/init-command.test.ts +0 -854
  44. package/src/commands/init/init-command.ts +0 -597
  45. package/src/commands/init/types.ts +0 -23
  46. package/src/commands/logs/index.ts +0 -1
  47. package/src/commands/logs/logs-command.test.ts +0 -293
  48. package/src/commands/logs/logs-command.ts +0 -452
  49. package/src/commands/monitor/index.ts +0 -2
  50. package/src/commands/monitor/monitor-command.test.ts +0 -271
  51. package/src/commands/monitor/monitor-command.ts +0 -269
  52. package/src/commands/monitor/monitor-service.ts +0 -65
  53. package/src/commands/monitor/types.ts +0 -13
  54. package/src/commands/repair/index.ts +0 -2
  55. package/src/commands/repair/repair-command.test.ts +0 -243
  56. package/src/commands/repair/repair-command.ts +0 -220
  57. package/src/commands/repair/repair-service.ts +0 -164
  58. package/src/commands/repair/types.ts +0 -13
  59. package/src/commands/schema/index.ts +0 -1
  60. package/src/commands/schema/schema-command.ts +0 -137
  61. package/src/commands/test/index.ts +0 -2
  62. package/src/commands/test/test-command.test.ts +0 -318
  63. package/src/commands/test/test-command.ts +0 -406
  64. package/src/commands/tui/index.ts +0 -1
  65. package/src/commands/tui/tui-command.ts +0 -87
  66. package/src/commands/update/index.ts +0 -1
  67. package/src/commands/update/update-command.ts +0 -109
  68. package/src/commands/waf/index.ts +0 -2
  69. package/src/commands/waf/types.ts +0 -48
  70. package/src/commands/waf/waf-command.test.ts +0 -506
  71. package/src/commands/waf/waf-command.ts +0 -545
  72. package/src/index.ts +0 -261
  73. package/src/services/cloudflare/cloudflare-service.test.ts +0 -658
  74. package/src/services/cloudflare/cloudflare-service.ts +0 -433
  75. package/src/services/cloudflare/index.ts +0 -2
  76. package/src/services/cloudflare/types.ts +0 -30
  77. package/src/services/config/config-service.test.ts +0 -395
  78. package/src/services/config/config-service.ts +0 -202
  79. package/src/services/config/index.ts +0 -9
  80. package/src/services/config/types.ts +0 -66
  81. package/src/services/db/db-service.test.ts +0 -63
  82. package/src/services/db/db-service.ts +0 -131
  83. package/src/services/db/index.ts +0 -1
  84. package/src/services/docker/docker-service.ts +0 -155
  85. package/src/services/docker/index.ts +0 -1
  86. package/src/services/env/env-service.test.ts +0 -259
  87. package/src/services/env/env-service.ts +0 -372
  88. package/src/services/env/index.ts +0 -1
  89. package/src/services/kv/index.ts +0 -1
  90. package/src/services/kv/kv-sync-service.test.ts +0 -38
  91. package/src/services/kv/kv-sync-service.ts +0 -243
  92. package/src/services/prerequisites/index.ts +0 -1
  93. package/src/services/prerequisites/prerequisites-service.test.ts +0 -89
  94. package/src/services/prerequisites/prerequisites-service.ts +0 -377
  95. package/src/services/prerequisites/types.ts +0 -48
  96. package/src/services/schema/index.ts +0 -1
  97. package/src/services/schema/schema-service.ts +0 -99
  98. package/src/services/secrets/index.ts +0 -11
  99. package/src/services/secrets/secrets-service.test.ts +0 -502
  100. package/src/services/secrets/secrets-service.ts +0 -287
  101. package/src/services/secrets/types.ts +0 -50
  102. package/src/services/update/index.ts +0 -2
  103. package/src/services/update/update-service.test.ts +0 -76
  104. package/src/services/update/update-service.ts +0 -193
  105. package/src/ui/banner.ts +0 -141
  106. package/src/ui/index.ts +0 -8
  107. package/src/ui/menu.ts +0 -490
  108. package/src/utils/error-handler.ts +0 -62
  109. package/src/utils/errors.test.ts +0 -69
  110. package/src/utils/errors.ts +0 -24
  111. package/src/utils/formatters.test.ts +0 -180
  112. package/src/utils/formatters.ts +0 -269
  113. package/src/utils/git.ts +0 -134
  114. package/src/utils/theme.ts +0 -92
@@ -1,43 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { EnvService } from "../../services/env/index.js";
3
-
4
- describe("env command", () => {
5
- describe("EnvService integration", () => {
6
- it("validate catches missing required vars", () => {
7
- const result = EnvService.validate({});
8
- expect(result.missing.length).toBeGreaterThan(0);
9
- expect(result.missing).toContain("CLOUDFLARE_API_TOKEN");
10
- });
11
-
12
- it("validate passes with all required vars", () => {
13
- const vars: Record<string, string> = {
14
- CLOUDFLARE_API_TOKEN: "cfut_xxx",
15
- CLOUDFLARE_ACCOUNT_ID: "abc123",
16
- SUBDOMAIN_PREFIX: "myapp",
17
- TRADE_INTERNAL_KEY: "trade-key",
18
- AGENT_INTERNAL_KEY: "agent-key",
19
- WEBHOOK_API_KEY_BINDING: "webhook-key",
20
- INTERNAL_KEY_BINDING: "inter-key",
21
- API_SERVICE_KEY_BINDING: "api-key",
22
- TELEGRAM_INTERNAL_KEY: "tg-key",
23
- DASHBOARD_USER: "admin",
24
- DASHBOARD_PASS: "pass123",
25
- SESSION_SECRET: "a".repeat(32),
26
- };
27
- const result = EnvService.validate(vars);
28
- expect(result.missing.length).toBe(0);
29
- });
30
-
31
- it("generateEnvLocal produces valid output", () => {
32
- const content = EnvService.generateEnvLocal();
33
- expect(content).toContain("CLOUDFLARE_API_TOKEN");
34
- expect(content).toContain("# NEVER commit this file");
35
- });
36
-
37
- it("show redacts secrets", () => {
38
- const output = EnvService.show({ CLOUDFLARE_API_TOKEN: "s3kr3t" });
39
- expect(output).toContain("********");
40
- expect(output).not.toContain("s3kr3t");
41
- });
42
- });
43
- });
@@ -1,292 +0,0 @@
1
- /**
2
- * `hoox config env` subcommand group — environment variable management.
3
- *
4
- * Subcommands:
5
- * init — Interactive wizard to generate .env.local and .dev.vars
6
- * show — Display current .env.local (secrets redacted)
7
- * validate — Check required vars are set
8
- * generate-dev-vars — Create/update per-worker .dev.vars from .env.local
9
- */
10
-
11
- import { Command } from "commander";
12
- import * as p from "@clack/prompts";
13
-
14
- import { EnvService } from "../../services/env/index.js";
15
- import { CLIError, ExitCode } from "../../utils/errors.js";
16
- import { formatSuccess, formatJson } from "../../utils/formatters.js";
17
- import { withErrorHandling } from "../../utils/error-handler.js";
18
- import type { FormatOptions } from "../../utils/formatters.js";
19
-
20
- // ---------------------------------------------------------------------------
21
- // Helpers
22
- // ---------------------------------------------------------------------------
23
-
24
- /**
25
- * Get FormatOptions from the command opts using optsWithGlobals() so that
26
- * globally defined flags (--json, --quiet) are resolved correctly even when
27
- * called from deeply nested subcommands.
28
- */
29
- function formatOpts(cmd: Command): FormatOptions {
30
- const opts = cmd.optsWithGlobals<{ json?: boolean; quiet?: boolean }>();
31
- return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
32
- }
33
-
34
- // ---------------------------------------------------------------------------
35
- // env init — interactive wizard
36
- // ---------------------------------------------------------------------------
37
-
38
- async function handleInit(opts: FormatOptions): Promise<void> {
39
- p.intro("Environment Setup");
40
-
41
- // Warn if .env.local already exists
42
- const existingEnv = Bun.file(".env.local");
43
- if (await existingEnv.exists()) {
44
- const overwrite = await p.confirm({
45
- message: ".env.local already exists. Overwrite?",
46
- initialValue: false,
47
- });
48
- if (p.isCancel(overwrite)) {
49
- p.cancel("Setup cancelled.");
50
- process.exitCode = 0;
51
- }
52
- if (!overwrite) {
53
- p.outro("Setup cancelled. Existing .env.local preserved.");
54
- return;
55
- }
56
- }
57
-
58
- const collected: Record<string, string> = {};
59
- const sections = EnvService.getSections();
60
-
61
- for (const section of sections) {
62
- const sectionDefs = EnvService.getDefinitions().filter(
63
- (d) => d.section === section
64
- );
65
- if (sectionDefs.length === 0) continue;
66
-
67
- p.log.step(`Configuring ${section}...`);
68
-
69
- for (const def of sectionDefs) {
70
- let value: string | symbol;
71
- if (def.secret) {
72
- value = await p.password({
73
- message: `${def.name}:${def.hint ? ` (${def.hint})` : ""}`,
74
- validate: def.required
75
- ? (v: string | undefined) => (v ? undefined : "Required")
76
- : undefined,
77
- });
78
- } else {
79
- value = await p.text({
80
- message: `${def.name}:${def.hint ? ` (${def.hint})` : ""}`,
81
- defaultValue: def.default ?? "",
82
- validate: def.required
83
- ? (v: string | undefined) => (v ? undefined : "Required")
84
- : undefined,
85
- });
86
- }
87
- if (p.isCancel(value)) {
88
- p.cancel("Setup cancelled.");
89
- process.exitCode = 0;
90
- }
91
- collected[def.name] = typeof value === "string" ? value : "";
92
- }
93
- }
94
-
95
- p.log.step("Writing .env.local...");
96
- const envContent = EnvService.generateEnvLocal(collected);
97
- await Bun.write(".env.local", envContent);
98
- if (!opts.quiet) formatSuccess(".env.local written", opts);
99
-
100
- p.log.step("Writing .dev.vars files...");
101
- const devVars = EnvService.getWorkerDevVars(collected);
102
- for (const [workerPath, vars] of Object.entries(devVars)) {
103
- const content = [
104
- `# .dev.vars - local secrets for ${workerPath}`,
105
- "# Generated by `hoox config env init`. NEVER commit this file.",
106
- "",
107
- ...Object.entries(vars).map(([k, v]) => `${k}=${v}`),
108
- "",
109
- ].join("\n");
110
- await Bun.write(`${workerPath}/.dev.vars`, content);
111
- if (!opts.quiet) formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
112
- }
113
-
114
- p.outro("Environment setup complete!");
115
- }
116
-
117
- // ---------------------------------------------------------------------------
118
- // env show
119
- // ---------------------------------------------------------------------------
120
-
121
- async function handleShow(opts: FormatOptions): Promise<void> {
122
- const file = Bun.file(".env.local");
123
- if (!(await file.exists())) {
124
- throw new CLIError(
125
- ".env.local not found. Run `hoox config env init`.",
126
- ExitCode.INVALID_USAGE
127
- );
128
- }
129
-
130
- const vars = await EnvService.loadDotEnvAsync(".env.local");
131
-
132
- if (opts.json) {
133
- formatJson(vars, opts);
134
- } else {
135
- process.stdout.write(EnvService.show(vars));
136
- }
137
- }
138
-
139
- // ---------------------------------------------------------------------------
140
- // env validate
141
- // ---------------------------------------------------------------------------
142
-
143
- async function handleValidate(opts: FormatOptions): Promise<void> {
144
- let vars: Record<string, string> = {};
145
- const file = Bun.file(".env.local");
146
- if (await file.exists()) {
147
- vars = await EnvService.loadDotEnvAsync(".env.local");
148
- }
149
-
150
- const result = EnvService.validate(vars);
151
-
152
- if (opts.json) {
153
- formatJson(result, opts);
154
- } else if (!opts.quiet) {
155
- if (!(await file.exists())) {
156
- process.stdout.write(
157
- ".env.local not found. Run `hoox config env init` first.\n\n"
158
- );
159
- }
160
- if (result.missing.length > 0) {
161
- process.stdout.write("Missing required variables:\n");
162
- for (const v of result.missing) {
163
- process.stdout.write(` ${v}\n`);
164
- }
165
- }
166
- if (result.warnings.length > 0) {
167
- process.stdout.write("Warnings:\n");
168
- for (const w of result.warnings) {
169
- process.stdout.write(` ${w}\n`);
170
- }
171
- }
172
- if (result.missing.length === 0 && result.warnings.length === 0) {
173
- formatSuccess("All required environment variables are set", opts);
174
- }
175
- }
176
-
177
- if (result.missing.length > 0) {
178
- process.exitCode = ExitCode.ERROR;
179
- }
180
- }
181
-
182
- // ---------------------------------------------------------------------------
183
- // env generate-dev-vars
184
- // ---------------------------------------------------------------------------
185
-
186
- async function handleGenerateDevVars(opts: FormatOptions): Promise<void> {
187
- const file = Bun.file(".env.local");
188
- if (!(await file.exists())) {
189
- throw new CLIError(
190
- ".env.local not found. Run `hoox config env init`.",
191
- ExitCode.INVALID_USAGE
192
- );
193
- }
194
-
195
- const vars = await EnvService.loadDotEnvAsync(".env.local");
196
- const devVars = EnvService.getWorkerDevVars(vars);
197
-
198
- let count = 0;
199
- for (const [workerPath, workerVars] of Object.entries(devVars)) {
200
- const content = [
201
- `# .dev.vars - local secrets for ${workerPath}`,
202
- "# Generated by `hoox config env generate-dev-vars`. NEVER commit this file.",
203
- "",
204
- ...Object.entries(workerVars).map(([k, v]) => `${k}=${v}`),
205
- "",
206
- ].join("\n");
207
- await Bun.write(`${workerPath}/.dev.vars`, content);
208
- count++;
209
- }
210
-
211
- formatSuccess(`Generated .dev.vars for ${count} worker(s)`, opts);
212
- }
213
-
214
- // ---------------------------------------------------------------------------
215
- // Registration
216
- // ---------------------------------------------------------------------------
217
-
218
- /**
219
- * Register the `hoox config env` subcommand group.
220
- */
221
- export function registerEnvCommand(parentCmd: Command): void {
222
- const envCmd = parentCmd
223
- .command("env")
224
- .summary("Manage environment variables")
225
- .description(
226
- `Manage environment variables for the Hoox trading system.
227
-
228
- SUBCOMMANDS:
229
- init Interactive wizard to generate .env.local and .dev.vars
230
- show Display current .env.local (secrets redacted)
231
- validate Check required environment variables
232
- generate-dev-vars Create per-worker .dev.vars from .env.local
233
-
234
- EXAMPLES:
235
- hoox config env init
236
- hoox config env show
237
- hoox config env validate
238
- hoox config env generate-dev-vars`
239
- );
240
-
241
- envCmd
242
- .command("init")
243
- .description("Interactive wizard to generate .env.local and .dev.vars")
244
- .action(
245
- withErrorHandling(
246
- async (_, cmd: Command) => {
247
- const opts = formatOpts(cmd);
248
- await handleInit(opts);
249
- },
250
- { service: "env" }
251
- )
252
- );
253
-
254
- envCmd
255
- .command("show")
256
- .description("Display current .env.local (secrets redacted)")
257
- .action(
258
- withErrorHandling(
259
- async (_, cmd: Command) => {
260
- const opts = formatOpts(cmd);
261
- await handleShow(opts);
262
- },
263
- { service: "env" }
264
- )
265
- );
266
-
267
- envCmd
268
- .command("validate")
269
- .description("Check required environment variables")
270
- .action(
271
- withErrorHandling(
272
- async (_, cmd: Command) => {
273
- const opts = formatOpts(cmd);
274
- await handleValidate(opts);
275
- },
276
- { service: "env" }
277
- )
278
- );
279
-
280
- envCmd
281
- .command("generate-dev-vars")
282
- .description("Create per-worker .dev.vars from .env.local")
283
- .action(
284
- withErrorHandling(
285
- async (_, cmd: Command) => {
286
- const opts = formatOpts(cmd);
287
- await handleGenerateDevVars(opts);
288
- },
289
- { service: "env" }
290
- )
291
- );
292
- }
@@ -1,3 +0,0 @@
1
- export { registerConfigCommand } from "./config-command.js";
2
- export { registerEnvCommand } from "./env-command.js";
3
- export { registerKvCommand } from "./kv-command.js";
@@ -1,14 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { KvSyncService } from "../../services/kv/index.js";
3
-
4
- describe("kv command", () => {
5
- describe("manifest", () => {
6
- it("returns known KV keys from manifest", () => {
7
- const keys = KvSyncService.getManifestKeys();
8
- expect(keys.length).toBe(16);
9
- expect(keys.some((k) => k.key === "trade:kill_switch")).toBe(true);
10
- expect(keys.some((k) => k.key === "agent:openai_key")).toBe(true);
11
- expect(keys.some((k) => k.key === "email:use_imap")).toBe(true);
12
- });
13
- });
14
- });
@@ -1,290 +0,0 @@
1
- /**
2
- * `hoox config kv` subcommand group — KV namespace key management.
3
- *
4
- * Subcommands:
5
- * list — List all keys
6
- * get <key> — Get a key's value
7
- * set <key> <value> — Set a key's value
8
- * delete <key> — Delete a key
9
- * apply-manifest — Apply manifest defaults
10
- * manifest — Show expected manifest keys
11
- */
12
-
13
- import { Command } from "commander";
14
- import { KvSyncService } from "../../services/kv/index.js";
15
- import {
16
- formatSuccess,
17
- formatTable,
18
- formatJson,
19
- } from "../../utils/formatters.js";
20
- import { CLIError, ExitCode } from "../../utils/errors.js";
21
- import { withErrorHandling } from "../../utils/error-handler.js";
22
- import { theme } from "../../utils/theme.js";
23
- import type { FormatOptions } from "../../utils/formatters.js";
24
-
25
- function formatOpts(cmd: Command): FormatOptions {
26
- const opts = cmd.optsWithGlobals<{ json?: boolean; quiet?: boolean }>();
27
- return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
28
- }
29
-
30
- async function resolveNs(cmd: Command): Promise<string> {
31
- const svc = new KvSyncService();
32
- const opts = cmd.optsWithGlobals<{ namespaceId?: string }>();
33
- return await svc.resolveNamespaceId(opts.namespaceId);
34
- }
35
-
36
- // ---------------------------------------------------------------------------
37
- // kv list
38
- // ---------------------------------------------------------------------------
39
-
40
- async function handleList(opts: FormatOptions, nsId: string): Promise<void> {
41
- const svc = new KvSyncService();
42
- const keys = await svc.list(nsId);
43
-
44
- if (opts.json) {
45
- formatJson(keys, opts);
46
- } else if (!opts.quiet) {
47
- if (keys.length === 0) {
48
- process.stdout.write("No keys found in KV namespace.\n");
49
- return;
50
- }
51
- const rows = keys.map((k) => ({ Key: k.name }));
52
- formatTable(rows, opts);
53
- }
54
- }
55
-
56
- // ---------------------------------------------------------------------------
57
- // kv get
58
- // ---------------------------------------------------------------------------
59
-
60
- async function handleGet(
61
- opts: FormatOptions,
62
- nsId: string,
63
- key: string
64
- ): Promise<void> {
65
- const svc = new KvSyncService();
66
- const value = await svc.get(nsId, key);
67
-
68
- if (value === null) {
69
- throw new CLIError(
70
- `Key "${key}" not found in KV namespace`,
71
- ExitCode.ERROR
72
- );
73
- }
74
-
75
- if (opts.json) {
76
- formatJson({ key, value }, opts);
77
- } else {
78
- process.stdout.write(`${value}\n`);
79
- }
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // kv set
84
- // ---------------------------------------------------------------------------
85
-
86
- async function handleSet(
87
- opts: FormatOptions,
88
- nsId: string,
89
- key: string,
90
- value: string
91
- ): Promise<void> {
92
- const svc = new KvSyncService();
93
- await svc.set(nsId, key, value);
94
- formatSuccess(`Set "${key}" in KV namespace`, opts);
95
- }
96
-
97
- // ---------------------------------------------------------------------------
98
- // kv delete
99
- // ---------------------------------------------------------------------------
100
-
101
- async function handleDelete(
102
- opts: FormatOptions,
103
- nsId: string,
104
- key: string
105
- ): Promise<void> {
106
- const svc = new KvSyncService();
107
- await svc.delete(nsId, key);
108
- formatSuccess(`Deleted "${key}" from KV namespace`, opts);
109
- }
110
-
111
- // ---------------------------------------------------------------------------
112
- // kv apply-manifest
113
- // ---------------------------------------------------------------------------
114
-
115
- async function handleApplyManifest(
116
- opts: FormatOptions,
117
- nsId: string
118
- ): Promise<void> {
119
- const svc = new KvSyncService();
120
- const manifest = KvSyncService.getManifest();
121
- let setCount = 0;
122
- const errors: string[] = [];
123
-
124
- for (const keyDef of manifest.keys) {
125
- if (keyDef.default !== undefined && keyDef.default !== "") {
126
- try {
127
- await svc.set(nsId, keyDef.key, keyDef.default);
128
- setCount++;
129
- } catch (err) {
130
- errors.push(
131
- `${keyDef.key}: ${err instanceof Error ? err.message : String(err)}`
132
- );
133
- }
134
- }
135
- }
136
-
137
- formatSuccess(
138
- `Applied ${setCount}/${manifest.keys.length} manifest keys (${errors.length} errors)`,
139
- opts
140
- );
141
- }
142
-
143
- // ---------------------------------------------------------------------------
144
- // kv manifest
145
- // ---------------------------------------------------------------------------
146
-
147
- async function handleManifest(opts: FormatOptions): Promise<void> {
148
- const manifest = KvSyncService.getManifest();
149
-
150
- if (opts.json) {
151
- formatJson(manifest, opts);
152
- } else if (!opts.quiet) {
153
- process.stdout.write(
154
- `${theme.heading(`KV Manifest: ${manifest.namespace}`)}\n\n`
155
- );
156
- const rows = manifest.keys.map((k) => ({
157
- Key: k.key,
158
- Type: k.type,
159
- Default: k.default || "-",
160
- Secret: k.secret ? "yes" : "no",
161
- Description: k.description,
162
- }));
163
- formatTable(rows, opts);
164
- }
165
- }
166
-
167
- // ---------------------------------------------------------------------------
168
- // Registration
169
- // ---------------------------------------------------------------------------
170
-
171
- export function registerKvCommand(parentCmd: Command): void {
172
- const kvCmd = parentCmd
173
- .command("kv")
174
- .summary("Manage KV namespace keys")
175
- .description(
176
- `Manage Cloudflare KV namespace keys and apply the key manifest.
177
-
178
- SUBCOMMANDS:
179
- list List all keys in the KV namespace
180
- get <key> Get a key's value
181
- set <key> <value> Set a key's value
182
- delete <key> Delete a key
183
- apply-manifest Apply manifest key defaults to KV
184
- manifest Show expected KV keys from manifest
185
-
186
- OPTIONS:
187
- --namespace-id <id> KV namespace ID (auto-detected from wrangler if omitted)
188
-
189
- EXAMPLES:
190
- hoox config kv list
191
- hoox config kv set trade:kill_switch true
192
- hoox config kv get trade:kill_switch
193
- hoox config kv delete trade:kill_switch
194
- hoox config kv apply-manifest
195
- hoox config kv manifest`
196
- )
197
- .option(
198
- "--namespace-id <id>",
199
- "KV namespace ID (auto-detected if omitted)"
200
- );
201
-
202
- // -- list
203
- kvCmd
204
- .command("list")
205
- .description("List all keys in the KV namespace")
206
- .action(
207
- withErrorHandling(
208
- async (_, cmd: Command) => {
209
- const opts = formatOpts(cmd);
210
- const nsId = await resolveNs(cmd);
211
- await handleList(opts, nsId);
212
- },
213
- { service: "kv" }
214
- )
215
- );
216
-
217
- // -- get
218
- kvCmd
219
- .command("get <key>")
220
- .description("Get a key's value from the KV namespace")
221
- .action(
222
- withErrorHandling(
223
- async (key: string, _, cmd: Command) => {
224
- const opts = formatOpts(cmd);
225
- const nsId = await resolveNs(cmd);
226
- await handleGet(opts, nsId, key);
227
- },
228
- { service: "kv" }
229
- )
230
- );
231
-
232
- // -- set
233
- kvCmd
234
- .command("set <key> <value>")
235
- .description("Set a key's value in the KV namespace")
236
- .action(
237
- withErrorHandling(
238
- async (key: string, value: string, _, cmd: Command) => {
239
- const opts = formatOpts(cmd);
240
- const nsId = await resolveNs(cmd);
241
- await handleSet(opts, nsId, key, value);
242
- },
243
- { service: "kv" }
244
- )
245
- );
246
-
247
- // -- delete
248
- kvCmd
249
- .command("delete <key>")
250
- .description("Delete a key from the KV namespace")
251
- .action(
252
- withErrorHandling(
253
- async (key: string, _, cmd: Command) => {
254
- const opts = formatOpts(cmd);
255
- const nsId = await resolveNs(cmd);
256
- await handleDelete(opts, nsId, key);
257
- },
258
- { service: "kv" }
259
- )
260
- );
261
-
262
- // -- apply-manifest
263
- kvCmd
264
- .command("apply-manifest")
265
- .description("Apply manifest key defaults to the KV namespace")
266
- .action(
267
- withErrorHandling(
268
- async (_, cmd: Command) => {
269
- const opts = formatOpts(cmd);
270
- const nsId = await resolveNs(cmd);
271
- await handleApplyManifest(opts, nsId);
272
- },
273
- { service: "kv" }
274
- )
275
- );
276
-
277
- // -- manifest
278
- kvCmd
279
- .command("manifest")
280
- .description("Show expected KV keys from manifest")
281
- .action(
282
- withErrorHandling(
283
- async (_, cmd: Command) => {
284
- const opts = formatOpts(cmd);
285
- await handleManifest(opts);
286
- },
287
- { service: "kv" }
288
- )
289
- );
290
- }
@@ -1,47 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import type { Command } from "commander";
3
-
4
- const { registerDashboardCommand } = await import("./dashboard-command.js");
5
-
6
- describe("registerDashboardCommand", () => {
7
- it("registers dashboard command group on program", () => {
8
- const commands: { name: string; description: string }[] = [];
9
- const subcommands: { parent: string; name: string; description: string }[] =
10
- [];
11
-
12
- const mockProgram = {
13
- command: (name: string) => {
14
- commands.push({ name, description: "" });
15
- const desc = (d: string) => {
16
- commands[commands.length - 1].description = d;
17
- return {
18
- command: (subName: string) => {
19
- subcommands.push({
20
- parent: name,
21
- name: subName,
22
- description: "",
23
- });
24
- return {
25
- description: (d2: string) => {
26
- subcommands[subcommands.length - 1].description = d2;
27
- return {
28
- option: () => ({ action: () => {} }),
29
- };
30
- },
31
- };
32
- },
33
- };
34
- };
35
- return { description: desc };
36
- },
37
- opts: () => ({ json: false, quiet: false }),
38
- } as unknown as Command;
39
-
40
- registerDashboardCommand(mockProgram);
41
-
42
- expect(commands.length).toBe(1);
43
- expect(commands[0].name).toBe("dashboard");
44
- expect(subcommands.length).toBe(1);
45
- expect(subcommands[0].name).toBe("update-urls");
46
- });
47
- });