cgraphx 1.2.0 → 1.3.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 (136) hide show
  1. package/dist/.claude-template/hooks/precommit-check/precommit-check.cjs +90 -0
  2. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +99 -78
  3. package/dist/.claude-template/skills/precommit-review/SKILL.md +50 -0
  4. package/dist/.claude-template/skills/run-api-test/SKILL.md +187 -0
  5. package/dist/.claude-template/skills/run-api-test/assets/template-test-report.md +103 -0
  6. package/dist/.claude-template/skills/run-api-test/assets/template-test-verify.jsonl +5 -0
  7. package/dist/.claude-template/skills/run-api-test/references/bru-run.md +60 -0
  8. package/dist/.claude-template/skills/run-api-test/references/db-verification.md +81 -0
  9. package/dist/.claude-template/skills/run-api-test/references/report-format.md +104 -0
  10. package/dist/.claude-template/skills/run-api-test/references/service-readiness.md +61 -0
  11. package/dist/.claude-template/skills/run-api-test/references/test-scope.md +64 -0
  12. package/dist/.claude-template/skills/write-api/SKILL.md +150 -0
  13. package/dist/.claude-template/skills/write-api/assets/template-api-spec.md +112 -0
  14. package/dist/.claude-template/skills/write-api/assets/template-request.bru +75 -0
  15. package/dist/.claude-template/skills/write-api/references/ai-prompts.md +133 -0
  16. package/dist/.claude-template/skills/write-api/references/api-spec-format.md +108 -0
  17. package/dist/.claude-template/skills/write-api/references/bru-format.md +144 -0
  18. package/dist/.claude-template/skills/write-api/references/collection-layout.md +81 -0
  19. package/dist/.claude-template/skills/write-api/references/environment-setup.md +105 -0
  20. package/dist/.claude-template/skills/write-api/references/interface-scope.md +74 -0
  21. package/dist/api-test/ai-fields.d.ts +37 -0
  22. package/dist/api-test/ai-fields.d.ts.map +1 -0
  23. package/dist/api-test/ai-fields.js +114 -0
  24. package/dist/api-test/ai-fields.js.map +1 -0
  25. package/dist/api-test/assemble.d.ts +76 -0
  26. package/dist/api-test/assemble.d.ts.map +1 -0
  27. package/dist/api-test/assemble.js +185 -0
  28. package/dist/api-test/assemble.js.map +1 -0
  29. package/dist/api-test/bru-cli-invoker.d.ts +72 -0
  30. package/dist/api-test/bru-cli-invoker.d.ts.map +1 -0
  31. package/dist/api-test/bru-cli-invoker.js +169 -0
  32. package/dist/api-test/bru-cli-invoker.js.map +1 -0
  33. package/dist/api-test/bru-report-parser.d.ts +24 -0
  34. package/dist/api-test/bru-report-parser.d.ts.map +1 -0
  35. package/dist/api-test/bru-report-parser.js +110 -0
  36. package/dist/api-test/bru-report-parser.js.map +1 -0
  37. package/dist/api-test/bru-runner.d.ts +101 -0
  38. package/dist/api-test/bru-runner.d.ts.map +1 -0
  39. package/dist/api-test/bru-runner.js +316 -0
  40. package/dist/api-test/bru-runner.js.map +1 -0
  41. package/dist/api-test/bru-writer.d.ts +52 -0
  42. package/dist/api-test/bru-writer.d.ts.map +1 -0
  43. package/dist/api-test/bru-writer.js +159 -0
  44. package/dist/api-test/bru-writer.js.map +1 -0
  45. package/dist/api-test/call-chain-extractor.d.ts +80 -0
  46. package/dist/api-test/call-chain-extractor.d.ts.map +1 -0
  47. package/dist/api-test/call-chain-extractor.js +179 -0
  48. package/dist/api-test/call-chain-extractor.js.map +1 -0
  49. package/dist/api-test/cli.d.ts +133 -0
  50. package/dist/api-test/cli.d.ts.map +1 -0
  51. package/dist/api-test/cli.js +1009 -0
  52. package/dist/api-test/cli.js.map +1 -0
  53. package/dist/api-test/config.d.ts +75 -0
  54. package/dist/api-test/config.d.ts.map +1 -0
  55. package/dist/api-test/config.js +406 -0
  56. package/dist/api-test/config.js.map +1 -0
  57. package/dist/api-test/db-query-cli.d.ts +51 -0
  58. package/dist/api-test/db-query-cli.d.ts.map +1 -0
  59. package/dist/api-test/db-query-cli.js +119 -0
  60. package/dist/api-test/db-query-cli.js.map +1 -0
  61. package/dist/api-test/enhance-prepare.d.ts +111 -0
  62. package/dist/api-test/enhance-prepare.d.ts.map +1 -0
  63. package/dist/api-test/enhance-prepare.js +425 -0
  64. package/dist/api-test/enhance-prepare.js.map +1 -0
  65. package/dist/api-test/enhance-write.d.ts +28 -0
  66. package/dist/api-test/enhance-write.d.ts.map +1 -0
  67. package/dist/api-test/enhance-write.js +145 -0
  68. package/dist/api-test/enhance-write.js.map +1 -0
  69. package/dist/api-test/errors.d.ts +48 -0
  70. package/dist/api-test/errors.d.ts.map +1 -0
  71. package/dist/api-test/errors.js +76 -0
  72. package/dist/api-test/errors.js.map +1 -0
  73. package/dist/api-test/field-extractor.d.ts +98 -0
  74. package/dist/api-test/field-extractor.d.ts.map +1 -0
  75. package/dist/api-test/field-extractor.js +327 -0
  76. package/dist/api-test/field-extractor.js.map +1 -0
  77. package/dist/api-test/impl-finder.d.ts +37 -0
  78. package/dist/api-test/impl-finder.d.ts.map +1 -0
  79. package/dist/api-test/impl-finder.js +54 -0
  80. package/dist/api-test/impl-finder.js.map +1 -0
  81. package/dist/api-test/index.d.ts +41 -0
  82. package/dist/api-test/index.d.ts.map +1 -0
  83. package/dist/api-test/index.js +124 -0
  84. package/dist/api-test/index.js.map +1 -0
  85. package/dist/api-test/java-parser.d.ts +89 -0
  86. package/dist/api-test/java-parser.d.ts.map +1 -0
  87. package/dist/api-test/java-parser.js +508 -0
  88. package/dist/api-test/java-parser.js.map +1 -0
  89. package/dist/api-test/md-writer.d.ts +49 -0
  90. package/dist/api-test/md-writer.d.ts.map +1 -0
  91. package/dist/api-test/md-writer.js +202 -0
  92. package/dist/api-test/md-writer.js.map +1 -0
  93. package/dist/api-test/parser-httpservice.d.ts +91 -0
  94. package/dist/api-test/parser-httpservice.d.ts.map +1 -0
  95. package/dist/api-test/parser-httpservice.js +271 -0
  96. package/dist/api-test/parser-httpservice.js.map +1 -0
  97. package/dist/api-test/report.d.ts +188 -0
  98. package/dist/api-test/report.d.ts.map +1 -0
  99. package/dist/api-test/report.js +522 -0
  100. package/dist/api-test/report.js.map +1 -0
  101. package/dist/api-test/snapshot.d.ts +26 -0
  102. package/dist/api-test/snapshot.d.ts.map +1 -0
  103. package/dist/api-test/snapshot.js +150 -0
  104. package/dist/api-test/snapshot.js.map +1 -0
  105. package/dist/api-test/test-history.d.ts +48 -0
  106. package/dist/api-test/test-history.d.ts.map +1 -0
  107. package/dist/api-test/test-history.js +122 -0
  108. package/dist/api-test/test-history.js.map +1 -0
  109. package/dist/api-test/types.d.ts +174 -0
  110. package/dist/api-test/types.d.ts.map +1 -0
  111. package/dist/api-test/types.js +13 -0
  112. package/dist/api-test/types.js.map +1 -0
  113. package/dist/api-test/verify-prepare.d.ts +30 -0
  114. package/dist/api-test/verify-prepare.d.ts.map +1 -0
  115. package/dist/api-test/verify-prepare.js +150 -0
  116. package/dist/api-test/verify-prepare.js.map +1 -0
  117. package/dist/api-test/verify-write.d.ts +31 -0
  118. package/dist/api-test/verify-write.d.ts.map +1 -0
  119. package/dist/api-test/verify-write.js +159 -0
  120. package/dist/api-test/verify-write.js.map +1 -0
  121. package/dist/dbquery/dump-schema.d.ts +46 -0
  122. package/dist/dbquery/dump-schema.d.ts.map +1 -0
  123. package/dist/dbquery/dump-schema.js +379 -0
  124. package/dist/dbquery/dump-schema.js.map +1 -0
  125. package/dist/installer/targets/claude.d.ts +15 -0
  126. package/dist/installer/targets/claude.d.ts.map +1 -1
  127. package/dist/installer/targets/claude.js +53 -0
  128. package/dist/installer/targets/claude.js.map +1 -1
  129. package/package.json +1 -1
  130. package/scripts/agent-eval/block-cgraphx-and-gitnexus-cli-hook.sh +0 -43
  131. package/scripts/agent-eval/block-cgraphx-cli-hook.sh +0 -32
  132. package/scripts/agent-eval/block-cgraphx-cli-settings.json +0 -16
  133. package/scripts/agent-eval/cli-vs-mcp-3arm.sh +0 -121
  134. package/scripts/agent-eval/multi-tool-eval.sh +0 -171
  135. package/scripts/agent-eval/parse-cli-vs-mcp.mjs +0 -232
  136. package/scripts/agent-eval/parse-multi-tool.mjs +0 -242
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Bruno CLI subprocess invoker — isolated in its own module so tests can
4
+ * `vi.spyOn` the `invokeBrunoCli` export and intercept calls from
5
+ * `bru-runner.ts`.
6
+ *
7
+ * Why a separate module: same reason as `db-query-cli.ts` — when the
8
+ * subprocess call lives in the same module as its caller, vitest's
9
+ * `vi.spyOn(module, 'fn')` cannot intercept the internal bare-local-binding
10
+ * call. Cross-module imports route through the namespace, which the spy CAN
11
+ * replace.
12
+ *
13
+ * Independent subsystem — does NOT import from `src/extraction/` /
14
+ * `src/resolution/` / `src/db/`. The Bruno CLI is invoked as a subprocess
15
+ * (spec §12 isolation).
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.__INTERNAL_BRU_CLI_INVOKER = void 0;
52
+ exports.invokeBrunoCli = invokeBrunoCli;
53
+ exports.detectBrunoCli = detectBrunoCli;
54
+ exports.resolveCollectionDir = resolveCollectionDir;
55
+ const node_child_process_1 = require("node:child_process");
56
+ const fs = __importStar(require("node:fs"));
57
+ const path = __importStar(require("node:path"));
58
+ /**
59
+ * Invoke `npx @usebruno/cli` with the given args. Returns the captured
60
+ * stdout/stderr/exitCode. The caller is responsible for arg construction
61
+ * (see `bru-runner.ts`).
62
+ *
63
+ * Exported so tests can `vi.spyOn(bruCliInvoker, 'invokeBrunoCli')` instead
64
+ * of spawning a real subprocess / real Bruno CLI.
65
+ */
66
+ function invokeBrunoCli(args, options) {
67
+ const maxBuffer = options.maxBuffer ?? 10 * 1024 * 1024;
68
+ try {
69
+ const result = (0, node_child_process_1.spawnSync)(process.execPath, args, {
70
+ cwd: options.cwd,
71
+ encoding: 'utf8',
72
+ timeout: options.timeoutMs,
73
+ maxBuffer,
74
+ stdio: ['ignore', 'pipe', 'pipe'],
75
+ });
76
+ return {
77
+ stdout: typeof result.stdout === 'string' ? result.stdout : '',
78
+ stderr: typeof result.stderr === 'string' ? result.stderr : '',
79
+ exitCode: result.status,
80
+ timedOut: result.signal === 'SIGTERM' || (result.signal != null && result.signal !== null),
81
+ };
82
+ }
83
+ catch (err) {
84
+ // spawnSync throws on ENOENT (node binary not found — shouldn't happen)
85
+ // or other spawn-level failures. Normalize to a non-zero exit.
86
+ const msg = err instanceof Error ? err.message : String(err);
87
+ return {
88
+ stdout: '',
89
+ stderr: `spawn failed: ${msg}`,
90
+ exitCode: 1,
91
+ timedOut: false,
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * Probe whether the Bruno CLI is available. Tries, in order:
97
+ * 1. `npx @usebruno/cli --version` (preferred — always works if npm cache
98
+ * has the package, even without global install).
99
+ * 2. Global `bru` command (`which bru`).
100
+ * 3. Global `bruno` command (`which bruno`).
101
+ *
102
+ * Returns the resolved command + base args for subsequent `invokeBrunoCli`
103
+ * calls, or `null` when no Bruno CLI is reachable.
104
+ *
105
+ * Exported so tests can spy on it to simulate "Bruno CLI unavailable".
106
+ */
107
+ function detectBrunoCli() {
108
+ // 1. npx @usebruno/cli --version (short timeout — npx may need to fetch).
109
+ const probe = (0, node_child_process_1.spawnSync)(process.execPath, ['@usebruno/cli', '--version'], {
110
+ encoding: 'utf8',
111
+ timeout: 30_000,
112
+ stdio: ['ignore', 'pipe', 'pipe'],
113
+ });
114
+ if (probe.status === 0 && probe.stdout.trim().length > 0) {
115
+ return { command: process.execPath, baseArgs: ['@usebruno/cli'] };
116
+ }
117
+ // npx wraps @usebruno/cli; the direct `node @usebruno/cli` form above only
118
+ // resolves when the package is installed locally. Use `npx` explicitly so
119
+ // the package is fetched on demand.
120
+ const npxProbe = (0, node_child_process_1.spawnSync)('npx', ['@usebruno/cli', '--version'], {
121
+ encoding: 'utf8',
122
+ timeout: 30_000,
123
+ stdio: ['ignore', 'pipe', 'pipe'],
124
+ shell: process.platform === 'win32',
125
+ });
126
+ if (npxProbe.status === 0 && npxProbe.stdout.trim().length > 0) {
127
+ return { command: 'npx', baseArgs: ['@usebruno/cli'] };
128
+ }
129
+ // 2. Global `bru` command.
130
+ const bruProbe = (0, node_child_process_1.spawnSync)('bru', ['--version'], {
131
+ encoding: 'utf8',
132
+ timeout: 5_000,
133
+ stdio: ['ignore', 'pipe', 'pipe'],
134
+ shell: process.platform === 'win32',
135
+ });
136
+ if (bruProbe.status === 0 && bruProbe.stdout.trim().length > 0) {
137
+ return { command: 'bru', baseArgs: [] };
138
+ }
139
+ // 3. Global `bruno` command.
140
+ const brunoProbe = (0, node_child_process_1.spawnSync)('bruno', ['--version'], {
141
+ encoding: 'utf8',
142
+ timeout: 5_000,
143
+ stdio: ['ignore', 'pipe', 'pipe'],
144
+ shell: process.platform === 'win32',
145
+ });
146
+ if (brunoProbe.status === 0 && brunoProbe.stdout.trim().length > 0) {
147
+ return { command: 'bruno', baseArgs: [] };
148
+ }
149
+ return null;
150
+ }
151
+ /**
152
+ * Resolve the collection directory. If `filter.service` is set, narrow to
153
+ * `<collectionDir>/<service>/` when it exists; otherwise fall back to the
154
+ * whole collection dir (Bruno CLI will just find no matching requests).
155
+ */
156
+ function resolveCollectionDir(collectionDir, filter) {
157
+ if (filter?.service) {
158
+ const sub = path.join(collectionDir, filter.service);
159
+ if (fs.existsSync(sub) && fs.statSync(sub).isDirectory()) {
160
+ return sub;
161
+ }
162
+ }
163
+ return collectionDir;
164
+ }
165
+ /** Internal helper re-exported for tests. */
166
+ exports.__INTERNAL_BRU_CLI_INVOKER = {
167
+ resolveCollectionDir,
168
+ };
169
+ //# sourceMappingURL=bru-cli-invoker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bru-cli-invoker.js","sourceRoot":"","sources":["../../src/api-test/bru-cli-invoker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * L-T-30: bru-report-parser — parse `bru run --output results.json --format json` output.
3
+ *
4
+ * Bruno CLI report schema (from L-T-00 exploration of bruno source code):
5
+ * { results: [ { name, suitename, path, runDuration, response: { status, body, ... },
6
+ * testResults, assertionResults, error, skipped } ] }
7
+ *
8
+ * Robust parser — supports field aliases across Bruno CLI versions.
9
+ */
10
+ export interface BruReportEntry {
11
+ endpoint: string;
12
+ httpStatus: number;
13
+ responseBody: string;
14
+ tests: unknown[];
15
+ durationMs: number;
16
+ error: string | null;
17
+ }
18
+ /**
19
+ * Parse a bru run JSON report and extract the entry matching `endpoint`.
20
+ * `endpoint` matches against `name` (preferred) or `path` stem.
21
+ * Returns null if no match found.
22
+ */
23
+ export declare function parseBruReport(reportJson: string, endpoint: string): BruReportEntry | null;
24
+ //# sourceMappingURL=bru-report-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bru-report-parser.d.ts","sourceRoot":"","sources":["../../src/api-test/bru-report-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAe1F"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * L-T-30: bru-report-parser — parse `bru run --output results.json --format json` output.
4
+ *
5
+ * Bruno CLI report schema (from L-T-00 exploration of bruno source code):
6
+ * { results: [ { name, suitename, path, runDuration, response: { status, body, ... },
7
+ * testResults, assertionResults, error, skipped } ] }
8
+ *
9
+ * Robust parser — supports field aliases across Bruno CLI versions.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.parseBruReport = parseBruReport;
13
+ /**
14
+ * Parse a bru run JSON report and extract the entry matching `endpoint`.
15
+ * `endpoint` matches against `name` (preferred) or `path` stem.
16
+ * Returns null if no match found.
17
+ */
18
+ function parseBruReport(reportJson, endpoint) {
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(reportJson);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ const results = extractResultsArray(parsed);
27
+ if (!results || results.length === 0)
28
+ return null;
29
+ const match = results.find((r) => matchesEndpoint(r, endpoint));
30
+ if (!match)
31
+ return null;
32
+ return extractEntry(match, endpoint);
33
+ }
34
+ function extractResultsArray(parsed) {
35
+ // Bruno CLI actual output: [{ iterationIndex: 0, results: [{ test, request, response, ... }] }]
36
+ // Unwrap iterations and flatten all `results` arrays.
37
+ if (Array.isArray(parsed)) {
38
+ const flat = [];
39
+ for (const item of parsed) {
40
+ if (item && typeof item === 'object') {
41
+ const obj = item;
42
+ if (Array.isArray(obj.results)) {
43
+ flat.push(...obj.results);
44
+ }
45
+ else if (Array.isArray(obj.tests)) {
46
+ flat.push(...obj.tests);
47
+ }
48
+ else {
49
+ // Already an entry (no wrapper)
50
+ flat.push(item);
51
+ }
52
+ }
53
+ }
54
+ return flat.length > 0 ? flat : parsed;
55
+ }
56
+ if (parsed && typeof parsed === 'object') {
57
+ const obj = parsed;
58
+ if (Array.isArray(obj.results))
59
+ return obj.results;
60
+ if (Array.isArray(obj.tests))
61
+ return obj.tests;
62
+ }
63
+ return null;
64
+ }
65
+ function matchesEndpoint(entry, endpoint) {
66
+ if (!entry || typeof entry !== 'object')
67
+ return false;
68
+ const obj = entry;
69
+ const name = obj.name ?? obj.request?.name;
70
+ if (typeof name === 'string' && name === endpoint)
71
+ return true;
72
+ const entryPath = obj.path ?? obj.test?.filename;
73
+ if (typeof entryPath === 'string') {
74
+ const stem = entryPath.replace(/\.bru$/, '').split('/').pop();
75
+ if (stem === endpoint)
76
+ return true;
77
+ }
78
+ return false;
79
+ }
80
+ function extractEntry(entry, endpoint) {
81
+ const obj = (entry && typeof entry === 'object' ? entry : {});
82
+ const response = (obj.response ?? {});
83
+ const httpStatus = (typeof response.status === 'number' ? response.status : null) ??
84
+ (typeof response.statusCode === 'number' ? response.statusCode : null) ??
85
+ (typeof obj.status === 'number' ? obj.status : 0);
86
+ // Bruno CLI stores response body in `response.data` (object or string), not `response.body`.
87
+ const responseData = response.data ?? response.body ?? obj.responseBody;
88
+ const responseBody = typeof responseData === 'string' ? responseData :
89
+ (responseData && typeof responseData === 'object' ? JSON.stringify(responseData) : '');
90
+ const tests = Array.isArray(obj.testResults) ? obj.testResults :
91
+ Array.isArray(obj.tests) ? obj.tests :
92
+ Array.isArray(obj.assertionResults) ? obj.assertionResults :
93
+ [];
94
+ const runDuration = (typeof obj.runDuration === 'number' ? obj.runDuration : null) ??
95
+ (typeof obj.duration === 'number' ? obj.duration : 0);
96
+ const durationMs = Math.round(runDuration * 1000);
97
+ const error = (typeof obj.error === 'string' ? obj.error : null) ??
98
+ (obj.error && typeof obj.error === 'object' && typeof obj.error.message === 'string'
99
+ ? obj.error.message
100
+ : null);
101
+ return {
102
+ endpoint,
103
+ httpStatus,
104
+ responseBody,
105
+ tests,
106
+ durationMs,
107
+ error,
108
+ };
109
+ }
110
+ //# sourceMappingURL=bru-report-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bru-report-parser.js","sourceRoot":"","sources":["../../src/api-test/bru-report-parser.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAgBH,wCAeC;AApBD;;;;GAIG;AACH,SAAgB,cAAc,CAAC,UAAkB,EAAE,QAAgB;IACjE,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAElD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAe;IAC1C,gGAAgG;IAChG,sDAAsD;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAc,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,GAAG,GAAG,IAA+B,CAAC;gBAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;qBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,gCAAgC;oBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,CAAC;IACD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAiC,CAAC;QAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,QAAgB;IACvD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAK,GAAG,CAAC,OAA+C,EAAE,IAAI,CAAC;IACpF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,IAAK,GAAG,CAAC,IAA4C,EAAE,QAAQ,CAAC;IAC1F,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9D,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,QAAgB;IACpD,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;IACzF,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAA4B,CAAC;IACjE,MAAM,UAAU,GACd,CAAC,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,CAAC,OAAO,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;QACtE,CAAC,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,6FAA6F;IAC7F,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,IAAI,GAAG,CAAC,YAAY,CAAC;IACxE,MAAM,YAAY,GAChB,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QACjD,CAAC,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzF,MAAM,KAAK,GACT,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAClD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACtC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,EAAE,CAAC;IACL,MAAM,WAAW,GACf,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,CAAC,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAClD,MAAM,KAAK,GACT,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAClD,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAQ,GAAG,CAAC,KAAiC,CAAC,OAAO,KAAK,QAAQ;YAC/G,CAAC,CAAG,GAAG,CAAC,KAAiC,CAAC,OAAkB;YAC5D,CAAC,CAAC,IAAI,CAAC,CAAC;IAEZ,OAAO;QACL,QAAQ;QACR,UAAU;QACV,YAAY;QACZ,KAAK;QACL,UAAU;QACV,KAAK;KACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Bruno runner — Phase 5 of the api-test pipeline.
3
+ *
4
+ * Spec contract (T-50):
5
+ * - Invoke `npx @usebruno/cli run <collection-dir>` to fire every assembled
6
+ * `.bru` request against the live target.
7
+ * - Pass `--env <profile.env>` and `--var key=value` for each
8
+ * `profile.variables` entry.
9
+ * - Single-request timeout 30s; failure does not retry; serial execution
10
+ * (MVP — no `--concurrent`).
11
+ * - Parse Bruno CLI's JSON output into one `BrunoRunResult` per request.
12
+ * - Bruno CLI unavailable → throw `BrunoCliError`; the CLI layer turns
13
+ * that into exit code 4 + an install hint on stderr.
14
+ *
15
+ * Independent subsystem — does NOT import from `src/extraction/` /
16
+ * `src/resolution/` / `src/db/`. The Bruno CLI is invoked as a subprocess
17
+ * via `./bru-cli-invoker.ts` (subsystem isolation per spec §12).
18
+ */
19
+ import type { ApiTestProfile } from './types';
20
+ import { type BrunoCliInvocation } from './bru-cli-invoker';
21
+ /** Result of running one endpoint through Bruno CLI. */
22
+ export interface BrunoRunResult {
23
+ /** Endpoint name — matches the `.bru` `meta.name` (i.e. `<svc_id>_<method>`). */
24
+ endpoint: string;
25
+ /** HTTP status code returned by the server. 0 when the request never completed. */
26
+ httpStatus: number;
27
+ /** Raw response body string (for biz-code extraction by the CLI layer). */
28
+ responseBody: string;
29
+ /** Request duration in milliseconds. */
30
+ durationMs: number;
31
+ /** Error tag when the request didn't succeed. `null` on a clean 2xx. */
32
+ error: string | null;
33
+ }
34
+ /**
35
+ * Run every `.bru` request in `collectionDir` against the live target.
36
+ *
37
+ * `filter.service` narrows the run to `<collectionDir>/<service>/` when that
38
+ * subdir exists.
39
+ *
40
+ * Throws `BrunoCliError` when the Bruno CLI cannot be reached — the CLI
41
+ * layer catches that and surfaces exit code 4 + an install hint.
42
+ */
43
+ export declare function runBrunoCollection(collectionDir: string, profile: ApiTestProfile, filter?: {
44
+ service?: string;
45
+ }): Promise<BrunoRunResult[]>;
46
+ /**
47
+ * Build the full argv for `npx @usebruno/cli run <dir> --env ... --var ...`.
48
+ *
49
+ * Uses `--output json` (Bruno CLI ≥1.x supports this; the flag was renamed
50
+ * to `--format json` in some versions — `parseBrunoOutput` handles both
51
+ * shapes, and we pass both flags defensively when Bruno CLI accepts them).
52
+ *
53
+ * `profile.variables` entries are passed as `--var key=value` so Bruno's
54
+ * `{{var}}` template syntax resolves them at request time.
55
+ */
56
+ declare function buildBrunoArgs(baseArgs: string[], collectionDir: string, profile: ApiTestProfile): string[];
57
+ /**
58
+ * Parse Bruno CLI's output into per-request `BrunoRunResult`s.
59
+ *
60
+ * Bruno CLI's JSON output shape varies across versions. This parser handles
61
+ * the known shapes:
62
+ * - JSON array: `[{ name, status, response, duration, error }, ...]`
63
+ * - JSON object with `results` array: `{ results: [...] }`
64
+ * - JSON object with `tests` array: `{ tests: [...] }`
65
+ *
66
+ * Field name aliases covered (best-effort):
67
+ * - name: `name` | `request` | `testName` | `suite`
68
+ * - status: `status` | `statusCode` | `responseStatus`
69
+ * - body: `response` | `data` | `body` | `responseBody`
70
+ * - duration: `duration` | `responseTime` | `elapsed`
71
+ * - error: `error` | `errorMessage` | `err`
72
+ *
73
+ * When the output cannot be parsed as JSON, falls back to a text-scan that
74
+ * extracts `(\\d+)\\s+ms` + status codes — best-effort, marks unparseable
75
+ * requests with `error: bruno_output_parse_failed`.
76
+ */
77
+ declare function parseBrunoOutput(invocation: BrunoCliInvocation): BrunoRunResult[];
78
+ /** Normalize one Bruno result record into a `BrunoRunResult`. */
79
+ declare function normalizeResult(record: unknown): BrunoRunResult;
80
+ /**
81
+ * Best-effort text fallback parser. Bruno CLI's text output looks like:
82
+ * ```
83
+ * Running request: qryOrderList
84
+ * Status: 200, Duration: 234ms
85
+ * Response: {"code":"0"}
86
+ * ```
87
+ * This parser extracts endpoint names + status + duration heuristically.
88
+ * Unparseable lines get `error: bruno_output_parse_failed`.
89
+ */
90
+ declare function parseTextOutput(stdout: string, timedOut: boolean): BrunoRunResult[];
91
+ /** Internal helpers re-exported for tests. */
92
+ export declare const __INTERNAL_BRU_RUNNER: {
93
+ buildBrunoArgs: typeof buildBrunoArgs;
94
+ parseBrunoOutput: typeof parseBrunoOutput;
95
+ parseTextOutput: typeof parseTextOutput;
96
+ normalizeResult: typeof normalizeResult;
97
+ PER_REQUEST_TIMEOUT_MS: number;
98
+ };
99
+ export { invokeBrunoCli, detectBrunoCli, resolveCollectionDir } from './bru-cli-invoker';
100
+ export type { BrunoCliInvocation, InvokeBrunoCliOptions } from './bru-cli-invoker';
101
+ //# sourceMappingURL=bru-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bru-runner.d.ts","sourceRoot":"","sources":["../../src/api-test/bru-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAO3B,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,cAAc,EACvB,MAAM,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,OAAO,CAAC,cAAc,EAAE,CAAC,CAsB3B;AAED;;;;;;;;;GASG;AACH,iBAAS,cAAc,CACrB,QAAQ,EAAE,MAAM,EAAE,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,cAAc,GACtB,MAAM,EAAE,CAgBV;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,iBAAS,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,GAAG,cAAc,EAAE,CA2D1E;AAeD,iEAAiE;AACjE,iBAAS,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CA6BxD;AAgCD;;;;;;;;;GASG;AACH,iBAAS,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,cAAc,EAAE,CAuD5E;AAED,8CAA8C;AAC9C,eAAO,MAAM,qBAAqB;;;;;;CAMjC,CAAC;AAGF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzF,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}