@jango-blockchained/hoox-cli 0.5.2 → 0.5.7

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 +32989 -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,137 +0,0 @@
1
- import { resolve } from "path";
2
- import { Command } from "commander";
3
- import { SchemaService } from "../../services/schema/schema-service.js";
4
- import {
5
- formatSuccess,
6
- formatError,
7
- formatKeyValue,
8
- formatTable,
9
- getFormatOptions,
10
- } from "../../utils/formatters.js";
11
- import { CLIError, ExitCode } from "../../utils/errors.js";
12
- import { withErrorHandling } from "../../utils/error-handler.js";
13
- import {
14
- generateWranglerJsonc,
15
- generateDevVars,
16
- } from "@jango-blockchained/hoox-shared";
17
-
18
- export function registerSchemaCommand(program: Command): void {
19
- const schemaCmd = program
20
- .command("schema")
21
- .summary("Validate and manage worker configuration")
22
- .description(
23
- "Validate, generate, and repair worker wrangler.jsonc against canonical manifests."
24
- );
25
-
26
- schemaCmd
27
- .command("validate [worker]")
28
- .description(
29
- "Validate worker(s) against manifest (omit worker to validate all)"
30
- )
31
- .action(
32
- withErrorHandling(async (worker?: string) => {
33
- const fmt = getFormatOptions(schemaCmd);
34
- const svc = new SchemaService();
35
- const results = worker
36
- ? [svc.validateWorker(worker)]
37
- : svc.validateAll();
38
- let totalErrors = 0;
39
- for (const r of results) {
40
- if (r.passed) {
41
- formatSuccess(`${r.worker}: ✅ passed`, fmt);
42
- } else {
43
- formatError(
44
- new CLIError(
45
- `${r.worker}: ❌ failed (${r.errors.length} issues)`,
46
- ExitCode.ERROR
47
- ),
48
- fmt
49
- );
50
- for (const e of r.errors.filter((e) => e.severity === "error")) {
51
- process.stderr.write(` ✗ ${e.message}\n`);
52
- }
53
- totalErrors += r.errors.filter(
54
- (e) => e.severity === "error"
55
- ).length;
56
- }
57
- }
58
- if (totalErrors > 0) process.exitCode = ExitCode.ERROR;
59
- })
60
- );
61
-
62
- schemaCmd
63
- .command("list")
64
- .description("List all workers with their binding counts")
65
- .action(
66
- withErrorHandling(async () => {
67
- const fmt = getFormatOptions(schemaCmd);
68
- const svc = new SchemaService();
69
- const rows: Record<string, string>[] = [];
70
- for (const name of svc.getWorkerNames()) {
71
- const m = svc.getManifest(name)!;
72
- const secretCount = Object.values(m.vars).filter(
73
- (v) => v.type === "secret"
74
- ).length;
75
- const svcCount = m.services.length;
76
- const infraCount = Object.keys(m.infrastructure).length;
77
- const middleware = m.middleware.length
78
- ? m.middleware.join(", ")
79
- : "\u2014";
80
- rows.push({
81
- worker: name,
82
- secrets: String(secretCount),
83
- services: String(svcCount),
84
- infra: String(infraCount),
85
- middleware,
86
- });
87
- }
88
- formatTable(rows, fmt);
89
- })
90
- );
91
-
92
- schemaCmd
93
- .command("generate <worker>")
94
- .description("Generate wrangler.jsonc and .dev.vars from manifest")
95
- .option("--dry-run", "Print generated content without writing")
96
- .action(
97
- withErrorHandling(async (worker: string, opts: { dryRun?: boolean }) => {
98
- const fmt = getFormatOptions(schemaCmd);
99
- const svc = new SchemaService();
100
- const manifest = svc.getManifest(worker);
101
- if (!manifest) {
102
- formatError(
103
- new CLIError(`Unknown worker "${worker}"`, ExitCode.INVALID_USAGE),
104
- fmt
105
- );
106
- return;
107
- }
108
-
109
- const wranglerContent = generateWranglerJsonc(manifest);
110
- const devVarsContent = generateDevVars(manifest);
111
-
112
- if (opts.dryRun) {
113
- process.stdout.write(`--- wrangler.jsonc (${worker}) ---\n`);
114
- process.stdout.write(wranglerContent + "\n");
115
- process.stdout.write(`--- .dev.vars (${worker}) ---\n`);
116
- process.stdout.write(devVarsContent + "\n");
117
- return;
118
- }
119
-
120
- const workersDir = resolve(process.cwd(), "workers", worker);
121
- const wranglerPath = resolve(workersDir, "wrangler.jsonc");
122
- const devVarsPath = resolve(workersDir, ".dev.vars");
123
-
124
- await Bun.write(wranglerPath, wranglerContent);
125
- await Bun.write(devVarsPath, devVarsContent);
126
-
127
- formatKeyValue(
128
- {
129
- "wrangler.jsonc": wranglerPath,
130
- ".dev.vars": devVarsPath,
131
- },
132
- { ...fmt, json: false }
133
- );
134
- formatSuccess(`Generated files for ${worker}`, fmt);
135
- })
136
- );
137
- }
@@ -1,2 +0,0 @@
1
- export { registerTestCommand } from "./test-command.js";
2
- export type { TestStepResult, TestSummary } from "./test-command.js";
@@ -1,318 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, mock } from "bun:test";
2
- import { Command } from "commander";
3
- import { registerTestCommand, runStep, printSummary } from "./test-command.js";
4
- import type { TestSummary } from "./test-command.js";
5
- import { ExitCode } from "../../utils/errors.js";
6
-
7
- // ---------------------------------------------------------------------------
8
- // Helpers
9
- // ---------------------------------------------------------------------------
10
-
11
- const originalSpawn = Bun.spawn;
12
-
13
- /** Create a mock Bun.spawn that returns the given exit code and output. */
14
- function mockSpawn(exitCode: number, stdout = "", stderr = "") {
15
- return mock(() => ({
16
- exited: Promise.resolve(exitCode),
17
- stdout: new Blob([stdout]),
18
- stderr: new Blob([stderr]),
19
- }));
20
- }
21
-
22
- /** Capture stdout for assertion. */
23
- function captureStdout(): { output: () => string; restore: () => void } {
24
- const chunks: string[] = [];
25
- const originalWrite = process.stdout.write.bind(process.stdout);
26
- const writeMock = mock((chunk: string | Buffer) => {
27
- chunks.push(typeof chunk === "string" ? chunk : chunk.toString());
28
- return true;
29
- });
30
- process.stdout.write = writeMock as unknown as typeof process.stdout.write;
31
- return {
32
- output: () => chunks.join(""),
33
- restore: () => {
34
- process.stdout.write = originalWrite;
35
- },
36
- };
37
- }
38
-
39
- /** Create a fresh Commander program with global --json / --quiet options. */
40
- function makeProgram(): Command {
41
- const program = new Command();
42
- program.name("hoox");
43
- program.option("--json", "");
44
- program.option("--quiet", "");
45
- return program;
46
- }
47
-
48
- // ---------------------------------------------------------------------------
49
- // runStep
50
- // ---------------------------------------------------------------------------
51
-
52
- describe("runStep", () => {
53
- afterEach(() => {
54
- (Bun as any).spawn = originalSpawn;
55
- });
56
-
57
- it("returns success when exit code is 0", async () => {
58
- (Bun as any).spawn = mockSpawn(0, "all tests passed");
59
- const result = await runStep(["bun", "test"]);
60
- expect(result.success).toBe(true);
61
- expect(result.exitCode).toBe(0);
62
- expect(result.output).toBe("all tests passed");
63
- });
64
-
65
- it("returns failure when exit code is non-zero", async () => {
66
- (Bun as any).spawn = mockSpawn(1, "", "3 tests failed");
67
- const result = await runStep(["bun", "test"]);
68
- expect(result.success).toBe(false);
69
- expect(result.exitCode).toBe(1);
70
- expect(result.error).toBe("3 tests failed");
71
- });
72
-
73
- it("captures both stdout and stderr", async () => {
74
- (Bun as any).spawn = mockSpawn(0, "stdout text", "stderr text");
75
- const result = await runStep(["echo", "hello"]);
76
- expect(result.output).toBe("stdout text");
77
- expect(result.error).toBe("stderr text");
78
- });
79
-
80
- it("records duration", async () => {
81
- (Bun as any).spawn = mockSpawn(0);
82
- const result = await runStep(["bun", "test"]);
83
- expect(result.duration).toBeGreaterThanOrEqual(0);
84
- });
85
-
86
- it("returns the command string", async () => {
87
- (Bun as any).spawn = mockSpawn(0);
88
- const result = await runStep([
89
- "vitest",
90
- "run",
91
- "--config",
92
- "vite.config.ts",
93
- ]);
94
- expect(result.command).toBe("vitest run --config vite.config.ts");
95
- });
96
-
97
- it("handles spawn errors gracefully", async () => {
98
- (Bun as any).spawn = mock(() => {
99
- throw new Error("ENOENT: no such file");
100
- });
101
- const result = await runStep(["nonexistent"]);
102
- expect(result.success).toBe(false);
103
- expect(result.exitCode).toBeNull();
104
- expect(result.error).toContain("ENOENT");
105
- });
106
- });
107
-
108
- // ---------------------------------------------------------------------------
109
- // printSummary
110
- // ---------------------------------------------------------------------------
111
-
112
- describe("printSummary", () => {
113
- let capture: ReturnType<typeof captureStdout>;
114
-
115
- beforeEach(() => {
116
- capture = captureStdout();
117
- });
118
-
119
- afterEach(() => {
120
- capture.restore();
121
- });
122
-
123
- const passingSummary: TestSummary = {
124
- total: 4,
125
- passed: 4,
126
- failed: 0,
127
- results: [
128
- {
129
- step: "Lint",
130
- command: "bun run lint",
131
- success: true,
132
- exitCode: 0,
133
- duration: 1200,
134
- },
135
- {
136
- step: "TypeCheck",
137
- command: "bun run typecheck",
138
- success: true,
139
- exitCode: 0,
140
- duration: 3400,
141
- },
142
- {
143
- step: "Unit Tests",
144
- command: "bun test --coverage",
145
- success: true,
146
- exitCode: 0,
147
- duration: 8900,
148
- },
149
- {
150
- step: "Integration Tests",
151
- command: "vitest run...",
152
- success: true,
153
- exitCode: 0,
154
- duration: 15000,
155
- },
156
- ],
157
- };
158
-
159
- const failingSummary: TestSummary = {
160
- total: 2,
161
- passed: 1,
162
- failed: 1,
163
- results: [
164
- {
165
- step: "Lint",
166
- command: "bun run lint",
167
- success: true,
168
- exitCode: 0,
169
- duration: 500,
170
- },
171
- {
172
- step: "TypeCheck",
173
- command: "bun run typecheck",
174
- success: false,
175
- exitCode: 2,
176
- duration: 800,
177
- error: "TS2322: type error",
178
- },
179
- ],
180
- };
181
-
182
- it("prints a table for human output", () => {
183
- printSummary(passingSummary, {});
184
- const out = capture.output();
185
- expect(out).toContain("All 4 steps passed");
186
- expect(out).toContain("Lint");
187
- expect(out).toContain("passed");
188
- });
189
-
190
- it("shows failure count when some steps fail", () => {
191
- printSummary(failingSummary, {});
192
- const out = capture.output();
193
- expect(out).toContain("1/2 passed");
194
- expect(out).toContain("TypeCheck");
195
- expect(out).toContain("failed");
196
- });
197
-
198
- it("outputs JSON when json=true", () => {
199
- printSummary(passingSummary, { json: true });
200
- const out = capture.output();
201
- const parsed = JSON.parse(out);
202
- expect(parsed.total).toBe(4);
203
- expect(parsed.passed).toBe(4);
204
- expect(parsed.failed).toBe(0);
205
- expect(parsed.results).toHaveLength(4);
206
- });
207
-
208
- it("outputs nothing when quiet=true", () => {
209
- printSummary(passingSummary, { quiet: true });
210
- expect(capture.output()).toBe("");
211
- });
212
- });
213
-
214
- // ---------------------------------------------------------------------------
215
- // registerTestCommand — structure verification
216
- // ---------------------------------------------------------------------------
217
-
218
- describe("registerTestCommand", () => {
219
- it("registers test command with all subcommands", () => {
220
- const program = makeProgram();
221
- registerTestCommand(program);
222
-
223
- const testCmd = program.commands.find((c) => c.name() === "test");
224
- expect(testCmd).toBeDefined();
225
- expect(testCmd?.description()).toContain("Run tests");
226
-
227
- const subNames = testCmd?.commands.map((c) => c.name()) ?? [];
228
- expect(subNames).toContain("all");
229
- expect(subNames).toContain("unit");
230
- expect(subNames).toContain("integration");
231
- expect(subNames).toContain("worker");
232
- });
233
-
234
- it("all subcommand has --json option", () => {
235
- const program = makeProgram();
236
- registerTestCommand(program);
237
-
238
- const testCmd = program.commands.find((c) => c.name() === "test");
239
- const allCmd = testCmd?.commands.find((c) => c.name() === "all");
240
- expect(allCmd).toBeDefined();
241
-
242
- // Commander stores options; verify --json is registered
243
- const optionNames = allCmd?.options.map((o) => o.long) ?? [];
244
- expect(optionNames).toContain("--json");
245
- });
246
-
247
- it("unit subcommand has --coverage option", () => {
248
- const program = makeProgram();
249
- registerTestCommand(program);
250
-
251
- const testCmd = program.commands.find((c) => c.name() === "test");
252
- const unitCmd = testCmd?.commands.find((c) => c.name() === "unit");
253
- expect(unitCmd).toBeDefined();
254
-
255
- const optionNames = unitCmd?.options.map((o) => o.long) ?? [];
256
- expect(optionNames).toContain("--coverage");
257
- });
258
-
259
- it("integration subcommand has --coverage option", () => {
260
- const program = makeProgram();
261
- registerTestCommand(program);
262
-
263
- const testCmd = program.commands.find((c) => c.name() === "test");
264
- const intCmd = testCmd?.commands.find((c) => c.name() === "integration");
265
- expect(intCmd).toBeDefined();
266
-
267
- const optionNames = intCmd?.options.map((o) => o.long) ?? [];
268
- expect(optionNames).toContain("--coverage");
269
- });
270
-
271
- it("worker subcommand requires a name argument and has --coverage option", () => {
272
- const program = makeProgram();
273
- registerTestCommand(program);
274
-
275
- const testCmd = program.commands.find((c) => c.name() === "test");
276
- const workerCmd = testCmd?.commands.find((c) => c.name() === "worker");
277
- expect(workerCmd).toBeDefined();
278
-
279
- // Verify it expects a required argument
280
- const args = workerCmd?.registeredArguments ?? [];
281
- expect(args.length).toBeGreaterThan(0);
282
-
283
- const optionNames = workerCmd?.options.map((o) => o.long) ?? [];
284
- expect(optionNames).toContain("--coverage");
285
- });
286
-
287
- it("all subcommand runs pipeline steps and stops on first failure", async () => {
288
- const program = makeProgram();
289
- registerTestCommand(program);
290
-
291
- // First lint passes, typecheck fails → should stop after 2 steps
292
- let callCount = 0;
293
- const mockSpawnFn = mock((args: string[]) => {
294
- callCount++;
295
- const cmd = args.join(" ");
296
- // Lint passes (call 1), TypeCheck fails (call 2)
297
- const exitCode = cmd.includes("lint") ? 0 : 1;
298
- const stderr = cmd.includes("lint") ? "" : "TS2322: type error";
299
- return {
300
- exited: Promise.resolve(exitCode),
301
- stdout: new Blob([]),
302
- stderr: new Blob([stderr]),
303
- };
304
- });
305
- (Bun as any).spawn = mockSpawnFn;
306
-
307
- // Suppress spinner output by running without tty-like env
308
- await program.parseAsync(["test", "all"], {
309
- from: "user",
310
- });
311
-
312
- // Should only run 2 steps (lint + typecheck) before stopping
313
- expect(callCount).toBe(2);
314
- expect(process.exitCode).toBe(ExitCode.ERROR);
315
-
316
- (Bun as any).spawn = originalSpawn;
317
- });
318
- });