@nwire/cli 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/cache-runner.d.ts +0 -1
  2. package/dist/cache-runner.js +107 -9
  3. package/dist/cli.d.ts +3 -6
  4. package/dist/cli.js +5 -7
  5. package/dist/commands/bench.d.ts +0 -1
  6. package/dist/commands/bench.js +0 -1
  7. package/dist/commands/build.d.ts +0 -1
  8. package/dist/commands/build.js +13 -17
  9. package/dist/commands/cache.d.ts +3 -3
  10. package/dist/commands/cache.js +7 -17
  11. package/dist/commands/check.d.ts +10 -3
  12. package/dist/commands/check.js +34 -10
  13. package/dist/commands/dev.d.ts +0 -1
  14. package/dist/commands/dev.js +0 -1
  15. package/dist/commands/doctor.d.ts +1 -2
  16. package/dist/commands/doctor.js +14 -15
  17. package/dist/commands/fmt.d.ts +8 -4
  18. package/dist/commands/fmt.js +35 -12
  19. package/dist/commands/greeting.d.ts +0 -1
  20. package/dist/commands/greeting.js +0 -1
  21. package/dist/commands/infra.d.ts +0 -1
  22. package/dist/commands/infra.js +0 -1
  23. package/dist/commands/lint.d.ts +7 -3
  24. package/dist/commands/lint.js +34 -13
  25. package/dist/commands/logs.d.ts +0 -1
  26. package/dist/commands/logs.js +0 -1
  27. package/dist/commands/ls.d.ts +1 -1
  28. package/dist/commands/ls.js +3 -1
  29. package/dist/commands/mcp.d.ts +0 -1
  30. package/dist/commands/mcp.js +2 -2
  31. package/dist/commands/please.d.ts +0 -1
  32. package/dist/commands/please.js +0 -1
  33. package/dist/commands/ps.d.ts +0 -1
  34. package/dist/commands/ps.js +0 -1
  35. package/dist/commands/replay.d.ts +0 -1
  36. package/dist/commands/replay.js +0 -1
  37. package/dist/commands/run.d.ts +0 -1
  38. package/dist/commands/run.js +0 -1
  39. package/dist/commands/studio.d.ts +0 -1
  40. package/dist/commands/studio.js +16 -6
  41. package/dist/commands/test.d.ts +0 -1
  42. package/dist/commands/test.js +0 -1
  43. package/dist/commands/trace.d.ts +0 -1
  44. package/dist/commands/trace.js +0 -1
  45. package/dist/commands/watch.d.ts +0 -1
  46. package/dist/commands/watch.js +0 -1
  47. package/dist/index.d.ts +0 -1
  48. package/dist/index.js +0 -1
  49. package/dist/lib/colors.d.ts +0 -1
  50. package/dist/lib/colors.js +0 -1
  51. package/dist/lib/dev-entry.d.ts +0 -1
  52. package/dist/lib/dev-entry.js +0 -1
  53. package/dist/lib/ensure-scan.d.ts +28 -0
  54. package/dist/lib/ensure-scan.js +41 -0
  55. package/dist/lib/exec.d.ts +0 -1
  56. package/dist/lib/exec.js +0 -1
  57. package/dist/lib/layout.d.ts +40 -0
  58. package/dist/lib/layout.js +128 -0
  59. package/dist/lib/package-manager.d.ts +17 -0
  60. package/dist/lib/package-manager.js +67 -0
  61. package/dist/lib/process-state.d.ts +0 -1
  62. package/dist/lib/process-state.js +0 -1
  63. package/dist/lib/project.d.ts +3 -4
  64. package/dist/lib/project.js +16 -34
  65. package/dist/lib/run-task.d.ts +0 -1
  66. package/dist/lib/run-task.js +0 -1
  67. package/dist/lib/scan-cache.d.ts +27 -0
  68. package/dist/lib/scan-cache.js +102 -0
  69. package/dist/lib/script-runner.d.ts +42 -0
  70. package/dist/lib/script-runner.js +90 -0
  71. package/dist/lib/sse.d.ts +0 -1
  72. package/dist/lib/sse.js +0 -1
  73. package/dist/lib/version.d.ts +8 -0
  74. package/dist/lib/version.js +29 -0
  75. package/dist/lib/vite-node.d.ts +0 -1
  76. package/dist/lib/vite-node.js +0 -1
  77. package/dist/lib/wire-discovery.d.ts +0 -1
  78. package/dist/lib/wire-discovery.js +0 -1
  79. package/dist/load-config.d.ts +0 -1
  80. package/dist/load-config.js +0 -1
  81. package/dist/ls-runner.d.ts +0 -1
  82. package/dist/ls-runner.js +34 -40
  83. package/dist/ui/dev-dashboard.d.ts +0 -1
  84. package/dist/ui/dev-dashboard.js +0 -1
  85. package/dist/ui/greeting.d.ts +0 -1
  86. package/dist/ui/greeting.js +0 -1
  87. package/dist/ui/process-table.d.ts +0 -1
  88. package/dist/ui/process-table.js +0 -1
  89. package/package.json +5 -6
  90. package/dist/__tests__/bench.test.d.ts +0 -2
  91. package/dist/__tests__/bench.test.d.ts.map +0 -1
  92. package/dist/__tests__/bench.test.js +0 -94
  93. package/dist/__tests__/bench.test.js.map +0 -1
  94. package/dist/__tests__/doctor.test.d.ts +0 -10
  95. package/dist/__tests__/doctor.test.d.ts.map +0 -1
  96. package/dist/__tests__/doctor.test.js +0 -105
  97. package/dist/__tests__/doctor.test.js.map +0 -1
  98. package/dist/__tests__/replay.test.d.ts +0 -2
  99. package/dist/__tests__/replay.test.d.ts.map +0 -1
  100. package/dist/__tests__/replay.test.js +0 -203
  101. package/dist/__tests__/replay.test.js.map +0 -1
  102. package/dist/__tests__/trace.test.d.ts +0 -2
  103. package/dist/__tests__/trace.test.d.ts.map +0 -1
  104. package/dist/__tests__/trace.test.js +0 -136
  105. package/dist/__tests__/trace.test.js.map +0 -1
  106. package/dist/__tests__/watch.test.d.ts +0 -2
  107. package/dist/__tests__/watch.test.d.ts.map +0 -1
  108. package/dist/__tests__/watch.test.js +0 -110
  109. package/dist/__tests__/watch.test.js.map +0 -1
  110. package/dist/cache-runner.d.ts.map +0 -1
  111. package/dist/cache-runner.js.map +0 -1
  112. package/dist/cli.d.ts.map +0 -1
  113. package/dist/cli.js.map +0 -1
  114. package/dist/commands/bench.d.ts.map +0 -1
  115. package/dist/commands/bench.js.map +0 -1
  116. package/dist/commands/build.d.ts.map +0 -1
  117. package/dist/commands/build.js.map +0 -1
  118. package/dist/commands/cache.d.ts.map +0 -1
  119. package/dist/commands/cache.js.map +0 -1
  120. package/dist/commands/check.d.ts.map +0 -1
  121. package/dist/commands/check.js.map +0 -1
  122. package/dist/commands/dev.d.ts.map +0 -1
  123. package/dist/commands/dev.js.map +0 -1
  124. package/dist/commands/doctor.d.ts.map +0 -1
  125. package/dist/commands/doctor.js.map +0 -1
  126. package/dist/commands/fmt.d.ts.map +0 -1
  127. package/dist/commands/fmt.js.map +0 -1
  128. package/dist/commands/greeting.d.ts.map +0 -1
  129. package/dist/commands/greeting.js.map +0 -1
  130. package/dist/commands/infra.d.ts.map +0 -1
  131. package/dist/commands/infra.js.map +0 -1
  132. package/dist/commands/lint.d.ts.map +0 -1
  133. package/dist/commands/lint.js.map +0 -1
  134. package/dist/commands/logs.d.ts.map +0 -1
  135. package/dist/commands/logs.js.map +0 -1
  136. package/dist/commands/ls.d.ts.map +0 -1
  137. package/dist/commands/ls.js.map +0 -1
  138. package/dist/commands/mcp.d.ts.map +0 -1
  139. package/dist/commands/mcp.js.map +0 -1
  140. package/dist/commands/please.d.ts.map +0 -1
  141. package/dist/commands/please.js.map +0 -1
  142. package/dist/commands/ps.d.ts.map +0 -1
  143. package/dist/commands/ps.js.map +0 -1
  144. package/dist/commands/replay.d.ts.map +0 -1
  145. package/dist/commands/replay.js.map +0 -1
  146. package/dist/commands/run.d.ts.map +0 -1
  147. package/dist/commands/run.js.map +0 -1
  148. package/dist/commands/studio.d.ts.map +0 -1
  149. package/dist/commands/studio.js.map +0 -1
  150. package/dist/commands/test.d.ts.map +0 -1
  151. package/dist/commands/test.js.map +0 -1
  152. package/dist/commands/trace.d.ts.map +0 -1
  153. package/dist/commands/trace.js.map +0 -1
  154. package/dist/commands/watch.d.ts.map +0 -1
  155. package/dist/commands/watch.js.map +0 -1
  156. package/dist/index.d.ts.map +0 -1
  157. package/dist/index.js.map +0 -1
  158. package/dist/kernel-instance.d.ts +0 -8
  159. package/dist/kernel-instance.d.ts.map +0 -1
  160. package/dist/kernel-instance.js +0 -13
  161. package/dist/kernel-instance.js.map +0 -1
  162. package/dist/lib/colors.d.ts.map +0 -1
  163. package/dist/lib/colors.js.map +0 -1
  164. package/dist/lib/dev-entry.d.ts.map +0 -1
  165. package/dist/lib/dev-entry.js.map +0 -1
  166. package/dist/lib/exec.d.ts.map +0 -1
  167. package/dist/lib/exec.js.map +0 -1
  168. package/dist/lib/process-state.d.ts.map +0 -1
  169. package/dist/lib/process-state.js.map +0 -1
  170. package/dist/lib/project.d.ts.map +0 -1
  171. package/dist/lib/project.js.map +0 -1
  172. package/dist/lib/run-task.d.ts.map +0 -1
  173. package/dist/lib/run-task.js.map +0 -1
  174. package/dist/lib/sse.d.ts.map +0 -1
  175. package/dist/lib/sse.js.map +0 -1
  176. package/dist/lib/vite-node.d.ts.map +0 -1
  177. package/dist/lib/vite-node.js.map +0 -1
  178. package/dist/lib/wire-discovery.d.ts.map +0 -1
  179. package/dist/lib/wire-discovery.js.map +0 -1
  180. package/dist/load-config.d.ts.map +0 -1
  181. package/dist/load-config.js.map +0 -1
  182. package/dist/ls-runner.d.ts.map +0 -1
  183. package/dist/ls-runner.js.map +0 -1
  184. package/dist/ui/dev-dashboard.d.ts.map +0 -1
  185. package/dist/ui/dev-dashboard.js.map +0 -1
  186. package/dist/ui/greeting.d.ts.map +0 -1
  187. package/dist/ui/greeting.js.map +0 -1
  188. package/dist/ui/process-table.d.ts.map +0 -1
  189. package/dist/ui/process-table.js.map +0 -1
@@ -10,4 +10,3 @@ interface ProcessTableProps {
10
10
  }
11
11
  export declare function ProcessTable({ records }: ProcessTableProps): React.ReactElement;
12
12
  export {};
13
- //# sourceMappingURL=process-table.d.ts.map
@@ -23,4 +23,3 @@ export function ProcessTable({ records }) {
23
23
  }
24
24
  return (_jsxs(Box, { flexDirection: "column", paddingY: 1, paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: "ID" }) }), _jsx(Box, { width: 24, children: _jsx(Text, { dimColor: true, children: "NAME" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: "STATUS" }) }), _jsx(Box, { width: 8, children: _jsx(Text, { dimColor: true, children: "PORT" }) }), _jsx(Box, { width: 8, children: _jsx(Text, { dimColor: true, children: "PID" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "STARTED" }) })] }), records.map((r) => (_jsxs(Box, { children: [_jsx(Box, { width: 10, children: _jsx(Text, { children: shortId(r.id) }) }), _jsx(Box, { width: 24, children: _jsx(Text, { children: r.name }) }), _jsx(Box, { width: 10, children: _jsx(Text, { color: statusColor(r.status), children: r.status }) }), _jsx(Box, { width: 8, children: _jsx(Text, { children: r.port ?? "—" }) }), _jsx(Box, { width: 8, children: _jsx(Text, { children: r.pid }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: r.startedAt }) })] }, r.id)))] }));
25
25
  }
26
- //# sourceMappingURL=process-table.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nwire/cli",
3
- "version": "0.9.1",
4
- "description": "Nwire CLI — branded TUI on top of @nwire/kernel. Dev, run, please, build, test, fmt, lint, check, ps, logs, cache, ls, studio. One surface for the whole framework.",
3
+ "version": "0.10.0",
4
+ "description": "Nwire CLI — branded TUI. Dev, run, please, build, test, fmt, lint, check, ps, logs, cache, ls, studio. One surface for the whole framework.",
5
5
  "keywords": [
6
6
  "cli",
7
7
  "dev-tool",
@@ -36,10 +36,9 @@
36
36
  "listr2": "^9.0.4",
37
37
  "picocolors": "^1.1.1",
38
38
  "react": "^18.3.1",
39
- "@nwire/kernel": "0.9.1",
40
- "@nwire/mcp": "0.9.1",
41
- "@nwire/scan": "0.9.1",
42
- "@nwire/hooks": "0.9.1"
39
+ "@nwire/hooks": "0.10.0",
40
+ "@nwire/mcp": "0.10.0",
41
+ "@nwire/scan": "0.10.0"
43
42
  },
44
43
  "devDependencies": {
45
44
  "@types/node": "^22.19.9",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=bench.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bench.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/bench.test.ts"],"names":[],"mappings":""}
@@ -1,94 +0,0 @@
1
- /**
2
- * Unit tests for `nwire bench`.
3
- *
4
- * The command shells out to a real `k6` binary at runtime, so we don't
5
- * exercise the full execution path here. We do test the pieces that
6
- * deserve assertions:
7
- *
8
- * - scenario path resolution (walks up from CWD and finds the right file)
9
- * - the k6 argv builder (env flags + script tail)
10
- * - the command meta + arg shape
11
- */
12
- import { describe, it, expect, afterEach, beforeEach } from "vitest";
13
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
14
- import { tmpdir } from "node:os";
15
- import { join } from "node:path";
16
- import { benchCommand, buildK6Args, resolveScenarioPath } from "../commands/bench.js";
17
- let target;
18
- beforeEach(() => {
19
- target = mkdtempSync(join(tmpdir(), "bench-test-"));
20
- });
21
- afterEach(() => {
22
- if (target)
23
- rmSync(target, { recursive: true, force: true });
24
- });
25
- describe("nwire bench — command meta", () => {
26
- it("registers a `bench` subcommand with the expected flags", () => {
27
- const meta = benchCommand.meta;
28
- expect(meta.name).toBe("bench");
29
- expect(benchCommand.args).toMatchObject({
30
- scenario: expect.any(Object),
31
- vus: expect.any(Object),
32
- duration: expect.any(Object),
33
- ramp: expect.any(Object),
34
- "base-url": expect.any(Object),
35
- out: expect.any(Object),
36
- });
37
- });
38
- });
39
- describe("resolveScenarioPath", () => {
40
- it("returns null when no scripts/k6 folder exists anywhere in the walk", () => {
41
- expect(resolveScenarioPath("action", target, [target])).toBeNull();
42
- });
43
- it("finds a script when scripts/k6/<file> exists in CWD", () => {
44
- mkdirSync(join(target, "scripts", "k6"), { recursive: true });
45
- writeFileSync(join(target, "scripts", "k6", "action-dispatch.js"), "// stub\n");
46
- const found = resolveScenarioPath("action", target, [target]);
47
- expect(found).toBe(join(target, "scripts", "k6", "action-dispatch.js"));
48
- });
49
- it("walks up from a root to find the framework's scripts/k6", () => {
50
- mkdirSync(join(target, "scripts", "k6"), { recursive: true });
51
- writeFileSync(join(target, "scripts", "k6", "mixed-workload.js"), "// stub\n");
52
- mkdirSync(join(target, "nested", "deeper"), { recursive: true });
53
- const found = resolveScenarioPath("mixed", target, [join(target, "nested", "deeper")]);
54
- expect(found).toBe(join(target, "scripts", "k6", "mixed-workload.js"));
55
- });
56
- });
57
- describe("buildK6Args", () => {
58
- it("emits run + env vars + script path", () => {
59
- const argv = buildK6Args({
60
- script: "/path/to/action-dispatch.js",
61
- args: {
62
- scenario: "action",
63
- vus: 50,
64
- duration: "30s",
65
- ramp: "10s",
66
- baseUrl: "http://localhost:3030",
67
- },
68
- });
69
- expect(argv[0]).toBe("run");
70
- expect(argv).toContain("-e");
71
- expect(argv).toContain("VUS=50");
72
- expect(argv).toContain("DURATION=30s");
73
- expect(argv).toContain("RAMP=10s");
74
- expect(argv).toContain("BASE_URL=http://localhost:3030");
75
- expect(argv[argv.length - 1]).toBe("/path/to/action-dispatch.js");
76
- });
77
- it("inserts --summary-export when a summaryOut path is provided", () => {
78
- const argv = buildK6Args({
79
- script: "/x.js",
80
- args: {
81
- scenario: "read",
82
- vus: 1,
83
- duration: "1s",
84
- ramp: "1s",
85
- baseUrl: "http://localhost:1",
86
- },
87
- summaryOut: "/tmp/read.json",
88
- });
89
- expect(argv).toContain("--summary-export");
90
- const i = argv.indexOf("--summary-export");
91
- expect(argv[i + 1]).toBe("/tmp/read.json");
92
- });
93
- });
94
- //# sourceMappingURL=bench.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bench.test.js","sourceRoot":"","sources":["../../src/__tests__/bench.test.ts"],"names":[],"mappings":"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"}
@@ -1,10 +0,0 @@
1
- /**
2
- * `nwire doctor` — checks run cleanly against fixture directories.
3
- *
4
- * Each test builds a tmpdir with the right shape (empty / L4-with-inspect /
5
- * L4-without-inspect / docker-compose-collision) and asserts the relevant
6
- * check produces the expected status. Live port probes are exercised
7
- * against ephemeral bindings.
8
- */
9
- export {};
10
- //# sourceMappingURL=doctor.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"doctor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/doctor.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -1,105 +0,0 @@
1
- /**
2
- * `nwire doctor` — checks run cleanly against fixture directories.
3
- *
4
- * Each test builds a tmpdir with the right shape (empty / L4-with-inspect /
5
- * L4-without-inspect / docker-compose-collision) and asserts the relevant
6
- * check produces the expected status. Live port probes are exercised
7
- * against ephemeral bindings.
8
- */
9
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
10
- import { tmpdir } from "node:os";
11
- import { join } from "node:path";
12
- import { createServer } from "node:net";
13
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
14
- import { runDoctor } from "../commands/doctor.js";
15
- let target;
16
- beforeEach(() => {
17
- target = mkdtempSync(join(tmpdir(), "doctor-test-"));
18
- });
19
- afterEach(() => {
20
- if (target)
21
- rmSync(target, { recursive: true, force: true });
22
- });
23
- function pickCheck(results, name) {
24
- const hit = results.find((r) => r.check.name === name);
25
- if (!hit)
26
- throw new Error(`expected check "${name}" in results`);
27
- return hit.result;
28
- }
29
- describe("nwire doctor — workspace shape detection", () => {
30
- it("workspace fails on a totally empty dir", async () => {
31
- const results = await runDoctor({ cwd: target });
32
- expect(pickCheck(results, "workspace").status).toBe("fail");
33
- });
34
- it("workspace warns when package.json exists but no apps/src/nwire.config", async () => {
35
- writeFileSync(join(target, "package.json"), JSON.stringify({ name: "x" }));
36
- const results = await runDoctor({ cwd: target });
37
- expect(pickCheck(results, "workspace").status).toBe("warn");
38
- });
39
- it("workspace passes when apps/ is present", async () => {
40
- writeFileSync(join(target, "package.json"), JSON.stringify({ name: "x" }));
41
- mkdirSync(join(target, "apps"));
42
- const results = await runDoctor({ cwd: target });
43
- expect(pickCheck(results, "workspace").status).toBe("pass");
44
- });
45
- });
46
- describe("nwire doctor — inspect-mount audit", () => {
47
- it("warns when an L4-shaped main.ts is missing api.inspect(app)", async () => {
48
- writeFileSync(join(target, "package.json"), "{}");
49
- mkdirSync(join(target, "apps", "svc"), { recursive: true });
50
- writeFileSync(join(target, "apps", "svc", "main.ts"), `import { createApp } from "@nwire/forge";\n` +
51
- `const app = createApp({ modules: [] });\n` +
52
- `await app.start();\n`);
53
- const results = await runDoctor({ cwd: target, filter: "inspect-mount" });
54
- const r = pickCheck(results, "inspect-mount");
55
- expect(r.status).toBe("warn");
56
- expect(r.hint).toContain("apps/svc/main.ts");
57
- });
58
- it("passes when L4 main.ts calls .inspect(app)", async () => {
59
- writeFileSync(join(target, "package.json"), "{}");
60
- mkdirSync(join(target, "apps", "svc"), { recursive: true });
61
- writeFileSync(join(target, "apps", "svc", "main.ts"), `import { createApp } from "@nwire/forge";\n` +
62
- `const app = createApp({ modules: [] });\n` +
63
- `await app.start();\n` +
64
- `api.inspect(app);\n`);
65
- const results = await runDoctor({ cwd: target, filter: "inspect-mount" });
66
- expect(pickCheck(results, "inspect-mount").status).toBe("pass");
67
- });
68
- });
69
- describe("nwire doctor — port collision detection", () => {
70
- it("warns when probe port 9_400 is taken", async () => {
71
- const srv = createServer();
72
- await new Promise((res) => srv.listen(9_400, "127.0.0.1", res));
73
- try {
74
- const results = await runDoctor({ cwd: target, filter: "probe-port" });
75
- expect(pickCheck(results, "probe-port").status).toBe("warn");
76
- }
77
- finally {
78
- await new Promise((res) => srv.close(() => res()));
79
- }
80
- });
81
- it("compose-port-collisions fails when docker-compose maps :9400", async () => {
82
- writeFileSync(join(target, "package.json"), "{}");
83
- writeFileSync(join(target, "docker-compose.yml"), `services:\n badservice:\n image: foo\n ports:\n - "9400:9400"\n`);
84
- const results = await runDoctor({ cwd: target, filter: "compose" });
85
- const r = pickCheck(results, "compose-port-collisions");
86
- expect(r.status).toBe("fail");
87
- expect(r.message).toContain("9400");
88
- });
89
- it("compose check passes with no compose file", async () => {
90
- const results = await runDoctor({ cwd: target, filter: "compose" });
91
- expect(pickCheck(results, "compose-port-collisions").status).toBe("info");
92
- });
93
- });
94
- describe("nwire doctor — filter", () => {
95
- it("returns only matching checks", async () => {
96
- const results = await runDoctor({ cwd: target, filter: "node-version" });
97
- expect(results.length).toBe(1);
98
- expect(results[0].check.name).toBe("node-version");
99
- });
100
- it("returns empty array when nothing matches", async () => {
101
- const results = await runDoctor({ cwd: target, filter: "zzzzzz" });
102
- expect(results.length).toBe(0);
103
- });
104
- });
105
- //# sourceMappingURL=doctor.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"doctor.test.js","sourceRoot":"","sources":["../../src/__tests__/doctor.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=replay.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"replay.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/replay.test.ts"],"names":[],"mappings":""}
@@ -1,203 +0,0 @@
1
- /**
2
- * Unit tests for `nwire replay`.
3
- *
4
- * Same shape as `trace.test.ts`: we don't drive the full citty command
5
- * end-to-end (it calls `process.exit`), we exercise the composable parts:
6
- *
7
- * • command meta + arg shape
8
- * • loadRecording() against real fixture files
9
- * • postReplay() happy path against a stubbed wire
10
- * • postReplay() returns null when wire answers 404 / 501 (graceful fallback)
11
- * • renderOfflineDiff() output (offline fallback)
12
- */
13
- import { describe, it, expect, afterEach } from "vitest";
14
- import { createServer } from "node:http";
15
- import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
16
- import { tmpdir } from "node:os";
17
- import { join } from "node:path";
18
- import { replayCommand, loadRecording, postReplay, renderOfflineDiff, renderReplayResult, } from "../commands/replay.js";
19
- let server;
20
- let tmp;
21
- afterEach(async () => {
22
- if (server) {
23
- await new Promise((res) => server.close(() => res()));
24
- server = undefined;
25
- }
26
- if (tmp) {
27
- rmSync(tmp, { recursive: true, force: true });
28
- tmp = undefined;
29
- }
30
- });
31
- function fixtureRecording() {
32
- return {
33
- hookId: "h_test",
34
- hookName: "submission.submit",
35
- runId: "r_1",
36
- outcome: "completed",
37
- steps: [
38
- {
39
- hookName: "submission.submit",
40
- hookId: "h_test",
41
- runId: "r_1",
42
- stepId: 0,
43
- stepKind: "chain",
44
- stepName: "validate",
45
- phase: "start",
46
- ts: 0,
47
- },
48
- {
49
- hookName: "submission.submit",
50
- hookId: "h_test",
51
- runId: "r_1",
52
- stepId: 0,
53
- stepKind: "chain",
54
- stepName: "validate",
55
- phase: "end",
56
- ts: 1,
57
- durationMs: 1,
58
- },
59
- ],
60
- ctxIn: { studentId: "s1" },
61
- ctxOut: { studentId: "s1", validated: true },
62
- capturedAt: "2026-05-29T10:00:00.000Z",
63
- };
64
- }
65
- function writeFixture(rec) {
66
- tmp = mkdtempSync(join(tmpdir(), "replay-test-"));
67
- const path = join(tmp, "rec.json");
68
- writeFileSync(path, JSON.stringify(rec));
69
- return path;
70
- }
71
- describe("nwire replay — command meta", () => {
72
- it("registers a `replay` subcommand with a positional file + optional --hook", () => {
73
- expect(replayCommand.meta).toBeDefined();
74
- const meta = replayCommand.meta;
75
- expect(meta.name).toBe("replay");
76
- const args = replayCommand
77
- .args;
78
- expect(args.file).toMatchObject({ type: "positional", required: true });
79
- expect(args.hook).toMatchObject({ type: "string" });
80
- });
81
- });
82
- describe("loadRecording", () => {
83
- it("loads + parses a recording JSON file", () => {
84
- const rec = fixtureRecording();
85
- const path = writeFixture(rec);
86
- const out = loadRecording(path);
87
- expect(out.hookName).toBe("submission.submit");
88
- expect(out.steps).toHaveLength(2);
89
- });
90
- it("rejects a file whose shape doesn't look like a Recording", () => {
91
- tmp = mkdtempSync(join(tmpdir(), "replay-test-"));
92
- const path = join(tmp, "bad.json");
93
- writeFileSync(path, JSON.stringify({ hello: "world" }));
94
- expect(() => loadRecording(path)).toThrow(/not a Recording/);
95
- });
96
- });
97
- describe("postReplay — happy path against a stubbed wire", () => {
98
- it("POSTs the recording and parses the wire response", async () => {
99
- const rec = fixtureRecording();
100
- server = createServer((req, res) => {
101
- if (req.method === "POST" && req.url === "/_nwire/hooks/replay") {
102
- const chunks = [];
103
- req.on("data", (c) => chunks.push(c));
104
- req.on("end", () => {
105
- const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
106
- expect(body.recording.hookName).toBe("submission.submit");
107
- res.writeHead(200, { "content-type": "application/json" });
108
- res.end(JSON.stringify({
109
- matches: true,
110
- drift: [],
111
- recorded: body.recording,
112
- replayed: { stepCount: 2, outcome: "completed" },
113
- }));
114
- });
115
- return;
116
- }
117
- res.writeHead(404);
118
- res.end();
119
- });
120
- await new Promise((res) => server.listen(0, "127.0.0.1", res));
121
- const port = server.address().port;
122
- const result = await postReplay({
123
- url: `http://127.0.0.1:${port}`,
124
- recording: rec,
125
- });
126
- expect(result).not.toBeNull();
127
- expect(result.matches).toBe(true);
128
- expect(result.replayed.stepCount).toBe(2);
129
- });
130
- });
131
- describe("postReplay — graceful fallback when endpoint is missing", () => {
132
- it("returns null on 404 (no /_nwire/hooks/replay mount)", async () => {
133
- server = createServer((_req, res) => {
134
- res.writeHead(404);
135
- res.end();
136
- });
137
- await new Promise((res) => server.listen(0, "127.0.0.1", res));
138
- const port = server.address().port;
139
- const result = await postReplay({
140
- url: `http://127.0.0.1:${port}`,
141
- recording: fixtureRecording(),
142
- });
143
- expect(result).toBeNull();
144
- });
145
- it("returns null on 501 Not Implemented", async () => {
146
- server = createServer((_req, res) => {
147
- res.writeHead(501);
148
- res.end();
149
- });
150
- await new Promise((res) => server.listen(0, "127.0.0.1", res));
151
- const port = server.address().port;
152
- const result = await postReplay({
153
- url: `http://127.0.0.1:${port}`,
154
- recording: fixtureRecording(),
155
- });
156
- expect(result).toBeNull();
157
- });
158
- it("throws on other non-OK statuses (5xx that isn't 501)", async () => {
159
- server = createServer((_req, res) => {
160
- res.writeHead(500);
161
- res.end("boom");
162
- });
163
- await new Promise((res) => server.listen(0, "127.0.0.1", res));
164
- const port = server.address().port;
165
- await expect(postReplay({ url: `http://127.0.0.1:${port}`, recording: fixtureRecording() })).rejects.toThrow(/500/);
166
- });
167
- });
168
- describe("renderOfflineDiff", () => {
169
- it("includes the offline-only banner + the step trace", () => {
170
- const out = renderOfflineDiff(fixtureRecording());
171
- expect(out).toContain("/_nwire/hooks/replay");
172
- expect(out).toContain("offline-only");
173
- expect(out).toContain("submission.submit");
174
- expect(out).toContain("validate");
175
- expect(out).toContain("outcome=completed");
176
- });
177
- });
178
- describe("renderReplayResult", () => {
179
- it("prints the match banner + step alignment", () => {
180
- const rec = fixtureRecording();
181
- const out = renderReplayResult({
182
- matches: true,
183
- drift: [],
184
- recorded: rec,
185
- replayed: { stepCount: rec.steps.length, outcome: "completed" },
186
- });
187
- expect(out).toContain("matches");
188
- expect(out).toContain("validate");
189
- });
190
- it("surfaces drift entries when matches=false", () => {
191
- const rec = fixtureRecording();
192
- const out = renderReplayResult({
193
- matches: false,
194
- drift: ["step[1]: recorded=chain/validate/end replayed=chain/validate/error"],
195
- recorded: rec,
196
- replayed: { stepCount: 2, outcome: "failed" },
197
- });
198
- expect(out).toContain("drift");
199
- expect(out).toContain("validate/error");
200
- expect(out).toContain("outcome=failed");
201
- });
202
- });
203
- //# sourceMappingURL=replay.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"replay.test.js","sourceRoot":"","sources":["../../src/__tests__/replay.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=trace.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trace.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/trace.test.ts"],"names":[],"mappings":""}
@@ -1,136 +0,0 @@
1
- /**
2
- * Unit tests for `nwire trace`.
3
- *
4
- * Long-running stream behaviour is intentionally NOT exercised end-to-end
5
- * (timing-flakey). We test the small composable pieces: command meta,
6
- * wire discovery against a real loopback HTTP server, the SSE parser,
7
- * and the line/tree formatters.
8
- */
9
- import { describe, it, expect, afterEach } from "vitest";
10
- import { createServer } from "node:http";
11
- import { traceCommand, formatSummaryLine, renderTree, shortId, formatTimestamp, } from "../commands/trace.js";
12
- import { SseParser } from "../lib/sse.js";
13
- import { findWireUrl } from "../lib/wire-discovery.js";
14
- let server;
15
- afterEach(async () => {
16
- if (server) {
17
- await new Promise((res) => server.close(() => res()));
18
- server = undefined;
19
- }
20
- delete process.env.NWIRE_INSPECT_URL;
21
- });
22
- describe("nwire trace — command meta", () => {
23
- it("registers a `trace` subcommand with optional --correlation and --limit", () => {
24
- expect(traceCommand.meta).toBeDefined();
25
- const meta = traceCommand.meta;
26
- expect(meta.name).toBe("trace");
27
- expect(traceCommand.args).toMatchObject({
28
- correlation: expect.any(Object),
29
- limit: expect.any(Object),
30
- });
31
- });
32
- });
33
- describe("findWireUrl — port-probe discovery", () => {
34
- it("returns the URL of a stubbed HTTP server that answers /_nwire/events/recent", async () => {
35
- server = createServer((req, res) => {
36
- if (req.url?.startsWith("/_nwire/events/recent")) {
37
- res.writeHead(200, { "content-type": "application/json" });
38
- res.end("[]");
39
- return;
40
- }
41
- res.writeHead(404);
42
- res.end();
43
- });
44
- await new Promise((res) => server.listen(0, "127.0.0.1", res));
45
- const port = server.address().port;
46
- process.env.NWIRE_INSPECT_URL = `http://127.0.0.1:${port}`;
47
- const url = await findWireUrl();
48
- expect(url).toBe(`http://127.0.0.1:${port}`);
49
- });
50
- it("strips a trailing slash from NWIRE_INSPECT_URL", async () => {
51
- process.env.NWIRE_INSPECT_URL = "http://127.0.0.1:9999/";
52
- expect(await findWireUrl()).toBe("http://127.0.0.1:9999");
53
- });
54
- });
55
- describe("SseParser — frame extraction", () => {
56
- it("parses a single complete frame", () => {
57
- const parser = new SseParser();
58
- const out = parser.feed(`data: {"a":1}\n\n`);
59
- expect(out).toEqual([{ a: 1 }]);
60
- });
61
- it("parses multiple frames in one feed call", () => {
62
- const parser = new SseParser();
63
- const out = parser.feed(`data: {"a":1}\n\ndata: {"b":2}\n\ndata: {"c":3}\n\n`);
64
- expect(out).toEqual([{ a: 1 }, { b: 2 }, { c: 3 }]);
65
- });
66
- it("buffers a partial frame across two feed calls", () => {
67
- const parser = new SseParser();
68
- expect(parser.feed(`data: {"a":`)).toEqual([]);
69
- expect(parser.feed(`1}\n\n`)).toEqual([{ a: 1 }]);
70
- });
71
- it("ignores SSE comment / heartbeat frames", () => {
72
- const parser = new SseParser();
73
- const out = parser.feed(`: heartbeat\n\ndata: {"k":"v"}\n\n`);
74
- expect(out).toEqual([{ k: "v" }]);
75
- });
76
- it("joins multi-line data: payloads with newline", () => {
77
- const parser = new SseParser();
78
- const out = parser.feed(`data: {"a":\ndata: 1}\n\n`);
79
- expect(out).toEqual([{ a: 1 }]);
80
- });
81
- it("tolerates \\r\\n line endings", () => {
82
- const parser = new SseParser();
83
- const out = parser.feed(`data: {"a":1}\r\n\r\n`);
84
- expect(out).toEqual([{ a: 1 }]);
85
- });
86
- it("drops frames whose JSON is malformed", () => {
87
- const parser = new SseParser();
88
- expect(parser.feed(`data: {not-json}\n\n`)).toEqual([]);
89
- });
90
- });
91
- describe("trace — formatters", () => {
92
- it("formatTimestamp pads to HH:MM:SS.mmm", () => {
93
- const ts = formatTimestamp("2026-05-29T10:05:03.040Z");
94
- expect(ts).toMatch(/^\d{2}:\d{2}:\d{2}\.\d{3}$/);
95
- });
96
- it("shortId returns 8 chars (strips known prefixes)", () => {
97
- expect(shortId("evt_abc12345678")).toBe("12345678");
98
- expect(shortId(undefined)).toBe("--------");
99
- });
100
- it("formatSummaryLine includes the event name", () => {
101
- const line = formatSummaryLine({
102
- name: "Submission.Submitted",
103
- envelope: {
104
- messageId: "m_abcdefgh",
105
- causationId: "c_zyxwvuts",
106
- correlationId: "k_corrcorr",
107
- occurredAt: "2026-05-29T10:00:00.000Z",
108
- },
109
- });
110
- // strip ANSI for readability — picocolors emits codes only when stdout is a TTY,
111
- // so under vitest most colours are dropped already.
112
- expect(line).toContain("Submission.Submitted");
113
- expect(line).toMatch(/\d{2}:\d{2}:\d{2}\.\d{3}/);
114
- });
115
- it("renderTree nests children under their causation parent", () => {
116
- const tree = renderTree([
117
- { name: "Root", envelope: { messageId: "ROOT" } },
118
- { name: "ChildA", envelope: { messageId: "A", causationId: "ROOT" } },
119
- { name: "ChildB", envelope: { messageId: "B", causationId: "ROOT" } },
120
- { name: "GrandA", envelope: { messageId: "GA", causationId: "A" } },
121
- ]);
122
- expect(tree).toContain("Root");
123
- expect(tree).toContain("ChildA");
124
- expect(tree).toContain("ChildB");
125
- expect(tree).toContain("GrandA");
126
- // ChildA appears before GrandA in the output (parent before child)
127
- expect(tree.indexOf("ChildA")).toBeLessThan(tree.indexOf("GrandA"));
128
- });
129
- it("renderTree treats orphans as additional roots", () => {
130
- const tree = renderTree([
131
- { name: "Orphan", envelope: { messageId: "X", causationId: "missing-parent" } },
132
- ]);
133
- expect(tree).toContain("Orphan");
134
- });
135
- });
136
- //# sourceMappingURL=trace.test.js.map