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.
- package/dist/.claude-template/hooks/precommit-check/precommit-check.cjs +90 -0
- package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +99 -78
- package/dist/.claude-template/skills/precommit-review/SKILL.md +50 -0
- package/dist/.claude-template/skills/run-api-test/SKILL.md +187 -0
- package/dist/.claude-template/skills/run-api-test/assets/template-test-report.md +103 -0
- package/dist/.claude-template/skills/run-api-test/assets/template-test-verify.jsonl +5 -0
- package/dist/.claude-template/skills/run-api-test/references/bru-run.md +60 -0
- package/dist/.claude-template/skills/run-api-test/references/db-verification.md +81 -0
- package/dist/.claude-template/skills/run-api-test/references/report-format.md +104 -0
- package/dist/.claude-template/skills/run-api-test/references/service-readiness.md +61 -0
- package/dist/.claude-template/skills/run-api-test/references/test-scope.md +64 -0
- package/dist/.claude-template/skills/write-api/SKILL.md +150 -0
- package/dist/.claude-template/skills/write-api/assets/template-api-spec.md +112 -0
- package/dist/.claude-template/skills/write-api/assets/template-request.bru +75 -0
- package/dist/.claude-template/skills/write-api/references/ai-prompts.md +133 -0
- package/dist/.claude-template/skills/write-api/references/api-spec-format.md +108 -0
- package/dist/.claude-template/skills/write-api/references/bru-format.md +144 -0
- package/dist/.claude-template/skills/write-api/references/collection-layout.md +81 -0
- package/dist/.claude-template/skills/write-api/references/environment-setup.md +105 -0
- package/dist/.claude-template/skills/write-api/references/interface-scope.md +74 -0
- package/dist/api-test/ai-fields.d.ts +37 -0
- package/dist/api-test/ai-fields.d.ts.map +1 -0
- package/dist/api-test/ai-fields.js +114 -0
- package/dist/api-test/ai-fields.js.map +1 -0
- package/dist/api-test/assemble.d.ts +76 -0
- package/dist/api-test/assemble.d.ts.map +1 -0
- package/dist/api-test/assemble.js +185 -0
- package/dist/api-test/assemble.js.map +1 -0
- package/dist/api-test/bru-cli-invoker.d.ts +72 -0
- package/dist/api-test/bru-cli-invoker.d.ts.map +1 -0
- package/dist/api-test/bru-cli-invoker.js +169 -0
- package/dist/api-test/bru-cli-invoker.js.map +1 -0
- package/dist/api-test/bru-report-parser.d.ts +24 -0
- package/dist/api-test/bru-report-parser.d.ts.map +1 -0
- package/dist/api-test/bru-report-parser.js +110 -0
- package/dist/api-test/bru-report-parser.js.map +1 -0
- package/dist/api-test/bru-runner.d.ts +101 -0
- package/dist/api-test/bru-runner.d.ts.map +1 -0
- package/dist/api-test/bru-runner.js +316 -0
- package/dist/api-test/bru-runner.js.map +1 -0
- package/dist/api-test/bru-writer.d.ts +52 -0
- package/dist/api-test/bru-writer.d.ts.map +1 -0
- package/dist/api-test/bru-writer.js +159 -0
- package/dist/api-test/bru-writer.js.map +1 -0
- package/dist/api-test/call-chain-extractor.d.ts +80 -0
- package/dist/api-test/call-chain-extractor.d.ts.map +1 -0
- package/dist/api-test/call-chain-extractor.js +179 -0
- package/dist/api-test/call-chain-extractor.js.map +1 -0
- package/dist/api-test/cli.d.ts +133 -0
- package/dist/api-test/cli.d.ts.map +1 -0
- package/dist/api-test/cli.js +1009 -0
- package/dist/api-test/cli.js.map +1 -0
- package/dist/api-test/config.d.ts +75 -0
- package/dist/api-test/config.d.ts.map +1 -0
- package/dist/api-test/config.js +406 -0
- package/dist/api-test/config.js.map +1 -0
- package/dist/api-test/db-query-cli.d.ts +51 -0
- package/dist/api-test/db-query-cli.d.ts.map +1 -0
- package/dist/api-test/db-query-cli.js +119 -0
- package/dist/api-test/db-query-cli.js.map +1 -0
- package/dist/api-test/enhance-prepare.d.ts +111 -0
- package/dist/api-test/enhance-prepare.d.ts.map +1 -0
- package/dist/api-test/enhance-prepare.js +425 -0
- package/dist/api-test/enhance-prepare.js.map +1 -0
- package/dist/api-test/enhance-write.d.ts +28 -0
- package/dist/api-test/enhance-write.d.ts.map +1 -0
- package/dist/api-test/enhance-write.js +145 -0
- package/dist/api-test/enhance-write.js.map +1 -0
- package/dist/api-test/errors.d.ts +48 -0
- package/dist/api-test/errors.d.ts.map +1 -0
- package/dist/api-test/errors.js +76 -0
- package/dist/api-test/errors.js.map +1 -0
- package/dist/api-test/field-extractor.d.ts +98 -0
- package/dist/api-test/field-extractor.d.ts.map +1 -0
- package/dist/api-test/field-extractor.js +327 -0
- package/dist/api-test/field-extractor.js.map +1 -0
- package/dist/api-test/impl-finder.d.ts +37 -0
- package/dist/api-test/impl-finder.d.ts.map +1 -0
- package/dist/api-test/impl-finder.js +54 -0
- package/dist/api-test/impl-finder.js.map +1 -0
- package/dist/api-test/index.d.ts +41 -0
- package/dist/api-test/index.d.ts.map +1 -0
- package/dist/api-test/index.js +124 -0
- package/dist/api-test/index.js.map +1 -0
- package/dist/api-test/java-parser.d.ts +89 -0
- package/dist/api-test/java-parser.d.ts.map +1 -0
- package/dist/api-test/java-parser.js +508 -0
- package/dist/api-test/java-parser.js.map +1 -0
- package/dist/api-test/md-writer.d.ts +49 -0
- package/dist/api-test/md-writer.d.ts.map +1 -0
- package/dist/api-test/md-writer.js +202 -0
- package/dist/api-test/md-writer.js.map +1 -0
- package/dist/api-test/parser-httpservice.d.ts +91 -0
- package/dist/api-test/parser-httpservice.d.ts.map +1 -0
- package/dist/api-test/parser-httpservice.js +271 -0
- package/dist/api-test/parser-httpservice.js.map +1 -0
- package/dist/api-test/report.d.ts +188 -0
- package/dist/api-test/report.d.ts.map +1 -0
- package/dist/api-test/report.js +522 -0
- package/dist/api-test/report.js.map +1 -0
- package/dist/api-test/snapshot.d.ts +26 -0
- package/dist/api-test/snapshot.d.ts.map +1 -0
- package/dist/api-test/snapshot.js +150 -0
- package/dist/api-test/snapshot.js.map +1 -0
- package/dist/api-test/test-history.d.ts +48 -0
- package/dist/api-test/test-history.d.ts.map +1 -0
- package/dist/api-test/test-history.js +122 -0
- package/dist/api-test/test-history.js.map +1 -0
- package/dist/api-test/types.d.ts +174 -0
- package/dist/api-test/types.d.ts.map +1 -0
- package/dist/api-test/types.js +13 -0
- package/dist/api-test/types.js.map +1 -0
- package/dist/api-test/verify-prepare.d.ts +30 -0
- package/dist/api-test/verify-prepare.d.ts.map +1 -0
- package/dist/api-test/verify-prepare.js +150 -0
- package/dist/api-test/verify-prepare.js.map +1 -0
- package/dist/api-test/verify-write.d.ts +31 -0
- package/dist/api-test/verify-write.d.ts.map +1 -0
- package/dist/api-test/verify-write.js +159 -0
- package/dist/api-test/verify-write.js.map +1 -0
- package/dist/dbquery/dump-schema.d.ts +46 -0
- package/dist/dbquery/dump-schema.d.ts.map +1 -0
- package/dist/dbquery/dump-schema.js +379 -0
- package/dist/dbquery/dump-schema.js.map +1 -0
- package/dist/installer/targets/claude.d.ts +15 -0
- package/dist/installer/targets/claude.d.ts.map +1 -1
- package/dist/installer/targets/claude.js +53 -0
- package/dist/installer/targets/claude.js.map +1 -1
- package/package.json +1 -1
- package/scripts/agent-eval/block-cgraphx-and-gitnexus-cli-hook.sh +0 -43
- package/scripts/agent-eval/block-cgraphx-cli-hook.sh +0 -32
- package/scripts/agent-eval/block-cgraphx-cli-settings.json +0 -16
- package/scripts/agent-eval/cli-vs-mcp-3arm.sh +0 -121
- package/scripts/agent-eval/multi-tool-eval.sh +0 -171
- package/scripts/agent-eval/parse-cli-vs-mcp.mjs +0 -232
- package/scripts/agent-eval/parse-multi-tool.mjs +0 -242
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Report + list phase — Phase 6 of the api-test pipeline (T-60).
|
|
4
|
+
*
|
|
5
|
+
* Spec contract:
|
|
6
|
+
* - `generateReport(projectRoot, date)` aggregates the day's JSONL run
|
|
7
|
+
* history + the static `.md` catalog into a Markdown report written to
|
|
8
|
+
* `docs/api-test/report-YYYY-MM-DD.md`.
|
|
9
|
+
* - `listEndpoints(projectRoot, filters)` renders a terminal table of every
|
|
10
|
+
* endpoint discovered from the `.md` catalog, with the most recent run
|
|
11
|
+
* result joined from JSONL history.
|
|
12
|
+
*
|
|
13
|
+
* Aggregation rules (spec §5.6):
|
|
14
|
+
* - total endpoints = number of `.md` files (the catalog is the source of
|
|
15
|
+
* truth for "what interfaces exist").
|
|
16
|
+
* - passed / failed = count of JSONL lines with `passed: true` / `false`.
|
|
17
|
+
* - skip count = number of `.md` files whose frontmatter `status` is
|
|
18
|
+
* `skip`.
|
|
19
|
+
* - per-service rate = group JSONL runs by `service`, passed/total.
|
|
20
|
+
* - failure list = JSONL lines with `passed: false` (endpoint + error).
|
|
21
|
+
* - skip list = `.md` files with `status: skip` (endpoint + skip_reason).
|
|
22
|
+
* - avg duration = mean of `duration_ms` across all JSONL lines for the date.
|
|
23
|
+
* - p99 duration = nearest-rank 99th percentile of `duration_ms` (degenerates
|
|
24
|
+
* to max for small N — that's expected, not a bug).
|
|
25
|
+
*
|
|
26
|
+
* JSONL missing for the requested date → `ReportError` (CLI exit code 2).
|
|
27
|
+
*
|
|
28
|
+
* Independent subsystem — only depends on `node:fs` / `node:path` and the
|
|
29
|
+
* subsystem's own `test-history.ts` / `errors.ts` / `types.ts`. No imports
|
|
30
|
+
* from `src/extraction/` / `src/resolution/` / `src/db/`, and no third-party
|
|
31
|
+
* YAML / table libraries (frontmatter is parsed with a hand-rolled scalar
|
|
32
|
+
* parser; the terminal table is rendered with manual padding).
|
|
33
|
+
*/
|
|
34
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
35
|
+
if (k2 === undefined) k2 = k;
|
|
36
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
37
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
38
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
39
|
+
}
|
|
40
|
+
Object.defineProperty(o, k2, desc);
|
|
41
|
+
}) : (function(o, m, k, k2) {
|
|
42
|
+
if (k2 === undefined) k2 = k;
|
|
43
|
+
o[k2] = m[k];
|
|
44
|
+
}));
|
|
45
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
46
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
47
|
+
}) : function(o, v) {
|
|
48
|
+
o["default"] = v;
|
|
49
|
+
});
|
|
50
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
51
|
+
var ownKeys = function(o) {
|
|
52
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
53
|
+
var ar = [];
|
|
54
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
55
|
+
return ar;
|
|
56
|
+
};
|
|
57
|
+
return ownKeys(o);
|
|
58
|
+
};
|
|
59
|
+
return function (mod) {
|
|
60
|
+
if (mod && mod.__esModule) return mod;
|
|
61
|
+
var result = {};
|
|
62
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
63
|
+
__setModuleDefault(result, mod);
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
})();
|
|
67
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
68
|
+
exports.__INTERNAL_REPORT = void 0;
|
|
69
|
+
exports.generateReport = generateReport;
|
|
70
|
+
exports.reportFilePath = reportFilePath;
|
|
71
|
+
exports.listEndpoints = listEndpoints;
|
|
72
|
+
exports.renderListTable = renderListTable;
|
|
73
|
+
exports.readRunsForDate = readRunsForDate;
|
|
74
|
+
exports.parseJsonl = parseJsonl;
|
|
75
|
+
exports.readLatestRunByEndpoint = readLatestRunByEndpoint;
|
|
76
|
+
exports.readAllEndpoints = readAllEndpoints;
|
|
77
|
+
exports.parseFrontmatter = parseFrontmatter;
|
|
78
|
+
exports.aggregateReport = aggregateReport;
|
|
79
|
+
exports.percentile = percentile;
|
|
80
|
+
exports.renderReport = renderReport;
|
|
81
|
+
exports.renderTable = renderTable;
|
|
82
|
+
const fs = __importStar(require("node:fs"));
|
|
83
|
+
const path = __importStar(require("node:path"));
|
|
84
|
+
const test_history_1 = require("./test-history");
|
|
85
|
+
const errors_1 = require("./errors");
|
|
86
|
+
/** Default output root (relative to project root) — mirrors `cli.ts`. */
|
|
87
|
+
const DEFAULT_OUTPUT_DIR = 'docs/api-test';
|
|
88
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* Generate the Markdown report for a single day.
|
|
91
|
+
*
|
|
92
|
+
* Reads `<projectRoot>/.cgraphx/api-test/runs/<date>.jsonl` and every
|
|
93
|
+
* `docs/api-test/<service>/*.md` catalog file, aggregates statistics, and
|
|
94
|
+
* returns the Markdown content. Throws `ReportError` when the JSONL file
|
|
95
|
+
* for the requested date doesn't exist (the report has no run data to
|
|
96
|
+
* summarize — that's a hard error, not an empty report).
|
|
97
|
+
*/
|
|
98
|
+
async function generateReport(projectRoot, date) {
|
|
99
|
+
const runs = readRunsForDate(projectRoot, date); // throws ReportError if missing
|
|
100
|
+
const endpoints = readAllEndpoints(projectRoot);
|
|
101
|
+
const data = aggregateReport(date, runs, endpoints);
|
|
102
|
+
return renderReport(data);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Resolve the report output path: `<projectRoot>/docs/api-test/report-<date>.md`.
|
|
106
|
+
*/
|
|
107
|
+
function reportFilePath(projectRoot, date) {
|
|
108
|
+
return path.join(projectRoot, DEFAULT_OUTPUT_DIR, `report-${date}.md`);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* List every catalog endpoint with its most recent run result, after filters.
|
|
112
|
+
*
|
|
113
|
+
* The "most recent run" is found by scanning every `*.jsonl` file in the runs
|
|
114
|
+
* directory and picking the entry with the largest `ran_at` for each endpoint.
|
|
115
|
+
* Endpoints with no run history get `lastRunResult = '—'`.
|
|
116
|
+
*/
|
|
117
|
+
function listEndpoints(projectRoot, filters = {}) {
|
|
118
|
+
const endpoints = readAllEndpoints(projectRoot);
|
|
119
|
+
const lastRunByEndpoint = readLatestRunByEndpoint(projectRoot);
|
|
120
|
+
const rows = [];
|
|
121
|
+
for (const ep of endpoints) {
|
|
122
|
+
if (filters.service && ep.service !== filters.service)
|
|
123
|
+
continue;
|
|
124
|
+
if (filters.status && ep.status !== filters.status)
|
|
125
|
+
continue;
|
|
126
|
+
if (filters.svcId && ep.svcId !== filters.svcId)
|
|
127
|
+
continue;
|
|
128
|
+
const last = lastRunByEndpoint.get(ep.endpoint);
|
|
129
|
+
const lastRunResult = last === undefined
|
|
130
|
+
? '—'
|
|
131
|
+
: (last.passed ? 'true' : 'false');
|
|
132
|
+
rows.push({
|
|
133
|
+
endpoint: ep.endpoint,
|
|
134
|
+
service: ep.service,
|
|
135
|
+
svcId: ep.svcId,
|
|
136
|
+
status: ep.status,
|
|
137
|
+
lastRunResult,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Stable sort: by service, then endpoint — so re-runs produce identical output.
|
|
141
|
+
rows.sort((a, b) => a.service === b.service
|
|
142
|
+
? a.endpoint.localeCompare(b.endpoint)
|
|
143
|
+
: a.service.localeCompare(b.service));
|
|
144
|
+
return rows;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Render `listEndpoints` output as a fixed-width terminal table with a header
|
|
148
|
+
* row and a separator line. Returns the empty string when there are no rows
|
|
149
|
+
* (the CLI prints a "no endpoints" notice instead).
|
|
150
|
+
*/
|
|
151
|
+
function renderListTable(rows) {
|
|
152
|
+
if (rows.length === 0)
|
|
153
|
+
return '';
|
|
154
|
+
const headers = ['ENDPOINT', 'SERVICE', 'SVC_ID', 'STATUS', 'LAST_RUN_RESULT'];
|
|
155
|
+
const table = rows.map((r) => [
|
|
156
|
+
r.endpoint,
|
|
157
|
+
r.service,
|
|
158
|
+
r.svcId,
|
|
159
|
+
r.status,
|
|
160
|
+
r.lastRunResult,
|
|
161
|
+
]);
|
|
162
|
+
return renderTable([headers, ...table]);
|
|
163
|
+
}
|
|
164
|
+
// ─── JSONL run history ─────────────────────────────────────────────────────
|
|
165
|
+
/**
|
|
166
|
+
* Read every `TestRun` from `<runsDir>/<date>.jsonl`. Throws `ReportError`
|
|
167
|
+
* when the file doesn't exist (the report cannot be summarized without run
|
|
168
|
+
* data — the spec says "选抛错,exit code 2").
|
|
169
|
+
*/
|
|
170
|
+
function readRunsForDate(projectRoot, date) {
|
|
171
|
+
const filePath = path.join((0, test_history_1.runsDirPath)(projectRoot), `${date}.jsonl`);
|
|
172
|
+
let content;
|
|
173
|
+
try {
|
|
174
|
+
content = fs.readFileSync(filePath, 'utf8');
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
if (err.code === 'ENOENT') {
|
|
178
|
+
throw new errors_1.ReportError(`No run history for ${date}: ${filePath}`);
|
|
179
|
+
}
|
|
180
|
+
throw err;
|
|
181
|
+
}
|
|
182
|
+
return parseJsonl(content);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Parse a JSONL string into `TestRun[]`. Blank lines are skipped; malformed
|
|
186
|
+
* lines throw `ReportError` (a corrupted history file shouldn't silently
|
|
187
|
+
* produce wrong stats).
|
|
188
|
+
*/
|
|
189
|
+
function parseJsonl(content) {
|
|
190
|
+
const runs = [];
|
|
191
|
+
const lines = content.split(/\r?\n/);
|
|
192
|
+
for (let i = 0; i < lines.length; i++) {
|
|
193
|
+
const line = lines[i].trim();
|
|
194
|
+
if (line.length === 0)
|
|
195
|
+
continue;
|
|
196
|
+
let obj;
|
|
197
|
+
try {
|
|
198
|
+
obj = JSON.parse(line);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
throw new errors_1.ReportError(`Failed to parse JSONL line ${i + 1}: ${err instanceof Error ? err.message : String(err)}`);
|
|
202
|
+
}
|
|
203
|
+
runs.push(deserializeRun(obj));
|
|
204
|
+
}
|
|
205
|
+
return runs;
|
|
206
|
+
}
|
|
207
|
+
/** Convert a parsed JSONL object (snake_case keys) back into a `TestRun`. */
|
|
208
|
+
function deserializeRun(obj) {
|
|
209
|
+
return {
|
|
210
|
+
endpoint: String(obj.endpoint ?? ''),
|
|
211
|
+
service: String(obj.service ?? ''),
|
|
212
|
+
ranAt: String(obj.ran_at ?? ''),
|
|
213
|
+
httpStatus: Number(obj.http_status ?? 0),
|
|
214
|
+
bizCode: obj.biz_code === null || obj.biz_code === undefined ? null : String(obj.biz_code),
|
|
215
|
+
durationMs: Number(obj.duration_ms ?? 0),
|
|
216
|
+
passed: Boolean(obj.passed),
|
|
217
|
+
error: obj.error === null || obj.error === undefined ? null : String(obj.error),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Build a map of `endpoint → most recent TestRun` by scanning every JSONL
|
|
222
|
+
* file in the runs directory. Returns an empty map when the runs directory
|
|
223
|
+
* doesn't exist (a fresh project with no run history — `list` still works,
|
|
224
|
+
* every endpoint just shows `—`).
|
|
225
|
+
*/
|
|
226
|
+
function readLatestRunByEndpoint(projectRoot) {
|
|
227
|
+
const dir = (0, test_history_1.runsDirPath)(projectRoot);
|
|
228
|
+
let files;
|
|
229
|
+
try {
|
|
230
|
+
files = fs.readdirSync(dir);
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
if (err.code === 'ENOENT')
|
|
234
|
+
return new Map();
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
const latest = new Map();
|
|
238
|
+
for (const file of files) {
|
|
239
|
+
if (!file.endsWith('.jsonl'))
|
|
240
|
+
continue;
|
|
241
|
+
const filePath = path.join(dir, file);
|
|
242
|
+
let content;
|
|
243
|
+
try {
|
|
244
|
+
content = fs.readFileSync(filePath, 'utf8');
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
for (const run of parseJsonl(content)) {
|
|
250
|
+
const prev = latest.get(run.endpoint);
|
|
251
|
+
if (prev === undefined || run.ranAt > prev.ranAt) {
|
|
252
|
+
latest.set(run.endpoint, run);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return latest;
|
|
257
|
+
}
|
|
258
|
+
// ─── .md catalog reading ───────────────────────────────────────────────────
|
|
259
|
+
/**
|
|
260
|
+
* Walk `docs/api-test/<service>/*.md` and parse each file's frontmatter into
|
|
261
|
+
* an `EndpointMd` record. Skips `report-*.md` files at the api-test root
|
|
262
|
+
* (those are this subsystem's own output, not catalog entries).
|
|
263
|
+
*/
|
|
264
|
+
function readAllEndpoints(projectRoot) {
|
|
265
|
+
const outputDir = path.join(projectRoot, DEFAULT_OUTPUT_DIR);
|
|
266
|
+
let serviceEntries;
|
|
267
|
+
try {
|
|
268
|
+
serviceEntries = fs.readdirSync(outputDir, { withFileTypes: true });
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
if (err.code === 'ENOENT')
|
|
272
|
+
return [];
|
|
273
|
+
throw err;
|
|
274
|
+
}
|
|
275
|
+
const endpoints = [];
|
|
276
|
+
for (const entry of serviceEntries) {
|
|
277
|
+
if (!entry.isDirectory())
|
|
278
|
+
continue;
|
|
279
|
+
const serviceDir = path.join(outputDir, entry.name);
|
|
280
|
+
let mdFiles;
|
|
281
|
+
try {
|
|
282
|
+
mdFiles = fs.readdirSync(serviceDir);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
for (const mdFile of mdFiles) {
|
|
288
|
+
if (!mdFile.endsWith('.md'))
|
|
289
|
+
continue;
|
|
290
|
+
const mdPath = path.join(serviceDir, mdFile);
|
|
291
|
+
const content = fs.readFileSync(mdPath, 'utf8');
|
|
292
|
+
const fm = parseFrontmatter(content);
|
|
293
|
+
const svcId = fm.svc_id ?? '';
|
|
294
|
+
const method = fm.method ?? '';
|
|
295
|
+
const service = fm.service ?? entry.name;
|
|
296
|
+
const status = fm.status === 'skip' ? 'skip' : 'active';
|
|
297
|
+
const skipReason = fm.skip_reason ?? null;
|
|
298
|
+
// The endpoint identifier in JSONL is `<svc_id>_<method>` (the .bru/.md
|
|
299
|
+
// filename stem, minus extension). Derive it from the filename for
|
|
300
|
+
// resilience — frontmatter `method` could in theory be missing.
|
|
301
|
+
const endpoint = mdFile.replace(/\.md$/, '');
|
|
302
|
+
endpoints.push({ endpoint, svcId, service, method, status, skipReason, mdPath });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return endpoints;
|
|
306
|
+
}
|
|
307
|
+
// ─── Frontmatter parsing (hand-rolled, scalars only) ───────────────────────
|
|
308
|
+
/**
|
|
309
|
+
* Parse the YAML frontmatter block (the text between `---` lines at the top
|
|
310
|
+
* of a `.md` file) into a string-keyed map.
|
|
311
|
+
*
|
|
312
|
+
* Scalar `key: value` pairs are extracted. Quoted scalars (`"..."` / `'...'`)
|
|
313
|
+
* are unquoted. The literal `null` becomes `null` in the map. Block scalars
|
|
314
|
+
* (`|-` followed by indented lines) and nested lists (`key:` + `- item`) are
|
|
315
|
+
* NOT parsed — the report/list phase only needs scalar fields (`svc_id`,
|
|
316
|
+
* `service`, `method`, `status`, `skip_reason`). Lines that look like list
|
|
317
|
+
* items or continuation lines (leading whitespace) are skipped.
|
|
318
|
+
*/
|
|
319
|
+
function parseFrontmatter(content) {
|
|
320
|
+
const result = {};
|
|
321
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
322
|
+
if (!m)
|
|
323
|
+
return result;
|
|
324
|
+
const fm = m[1] ?? '';
|
|
325
|
+
for (const line of fm.split(/\r?\n/)) {
|
|
326
|
+
// Skip indented lines (list items, block-scalar bodies, nested mappings).
|
|
327
|
+
if (/^\s/.test(line))
|
|
328
|
+
continue;
|
|
329
|
+
const kv = /^([a-z_]+):\s*(.*)$/.exec(line);
|
|
330
|
+
if (!kv)
|
|
331
|
+
continue;
|
|
332
|
+
const key = kv[1];
|
|
333
|
+
let value = kv[2] ?? '';
|
|
334
|
+
// An empty value means this key starts a block scalar or nested list
|
|
335
|
+
// (e.g. `dep_tables:` followed by ` - item` lines). The parser doesn't
|
|
336
|
+
// handle those — skip the key entirely so callers see `undefined`.
|
|
337
|
+
// YAML block-scalar indicators (`|`, `|-`, `|+`, `>`, `>-`, `>+`) are
|
|
338
|
+
// also skipped — the value lives on the following indented lines.
|
|
339
|
+
if (value === '' || /^[|>][+-]?$/.test(value))
|
|
340
|
+
continue;
|
|
341
|
+
// Strip surrounding quotes (single or double, with escape unescape for double).
|
|
342
|
+
if (value.length >= 2) {
|
|
343
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
344
|
+
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
345
|
+
}
|
|
346
|
+
else if (value.startsWith("'") && value.endsWith("'")) {
|
|
347
|
+
value = value.slice(1, -1).replace(/''/g, "'");
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (value === 'null') {
|
|
351
|
+
result[key] = null;
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
result[key] = value;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return result;
|
|
358
|
+
}
|
|
359
|
+
// ─── Aggregation ───────────────────────────────────────────────────────────
|
|
360
|
+
/** Aggregate JSONL runs + `.md` catalog into `ReportData` for rendering. */
|
|
361
|
+
function aggregateReport(date, runs, endpoints) {
|
|
362
|
+
const totalEndpoints = endpoints.length;
|
|
363
|
+
const passedCount = runs.filter((r) => r.passed).length;
|
|
364
|
+
const failedCount = runs.filter((r) => !r.passed).length;
|
|
365
|
+
const skipCount = endpoints.filter((e) => e.status === 'skip').length;
|
|
366
|
+
// Per-service grouping — based on JSONL runs (the run population). A service
|
|
367
|
+
// with catalog endpoints but zero runs still appears with total=0, passed=0,
|
|
368
|
+
// passRate=0 so the gap is visible in the report.
|
|
369
|
+
const servicesInCatalog = new Set(endpoints.map((e) => e.service));
|
|
370
|
+
const servicesInRuns = new Set(runs.map((r) => r.service));
|
|
371
|
+
const allServices = new Set([...servicesInCatalog, ...servicesInRuns]);
|
|
372
|
+
const perService = [];
|
|
373
|
+
for (const service of allServices) {
|
|
374
|
+
const serviceRuns = runs.filter((r) => r.service === service);
|
|
375
|
+
const total = serviceRuns.length;
|
|
376
|
+
const passed = serviceRuns.filter((r) => r.passed).length;
|
|
377
|
+
perService.push({
|
|
378
|
+
service,
|
|
379
|
+
total,
|
|
380
|
+
passed,
|
|
381
|
+
passRate: total === 0 ? 0 : passed / total,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
perService.sort((a, b) => a.service.localeCompare(b.service));
|
|
385
|
+
const failures = runs
|
|
386
|
+
.filter((r) => !r.passed)
|
|
387
|
+
.map((r) => ({ endpoint: r.endpoint, service: r.service, error: r.error }));
|
|
388
|
+
const skips = endpoints
|
|
389
|
+
.filter((e) => e.status === 'skip')
|
|
390
|
+
.map((e) => ({ endpoint: e.endpoint, service: e.service, skipReason: e.skipReason }));
|
|
391
|
+
const durations = runs.map((r) => r.durationMs);
|
|
392
|
+
const avgDurationMs = durations.length === 0
|
|
393
|
+
? 0
|
|
394
|
+
: durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
395
|
+
const p99DurationMs = percentile(durations, 0.99);
|
|
396
|
+
return {
|
|
397
|
+
date,
|
|
398
|
+
totalEndpoints,
|
|
399
|
+
passedCount,
|
|
400
|
+
failedCount,
|
|
401
|
+
skipCount,
|
|
402
|
+
perService,
|
|
403
|
+
failures,
|
|
404
|
+
skips,
|
|
405
|
+
avgDurationMs,
|
|
406
|
+
p99DurationMs,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Nearest-rank percentile. For a sample of size N, the P-th percentile (where
|
|
411
|
+
* `p` is a fraction in [0, 1]) is the value at the 1-indexed position
|
|
412
|
+
* `ceil(p * N)` of the sorted (ascending) sample. For N=0 returns 0. For
|
|
413
|
+
* small N this degenerates to the max — that's the documented behavior, not
|
|
414
|
+
* a bug.
|
|
415
|
+
*/
|
|
416
|
+
function percentile(values, p) {
|
|
417
|
+
if (values.length === 0)
|
|
418
|
+
return 0;
|
|
419
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
420
|
+
const rank = Math.ceil(p * sorted.length);
|
|
421
|
+
const idx = Math.min(Math.max(rank, 1), sorted.length) - 1;
|
|
422
|
+
return sorted[idx] ?? 0;
|
|
423
|
+
}
|
|
424
|
+
// ─── Markdown rendering ────────────────────────────────────────────────────
|
|
425
|
+
/** Render `ReportData` as a Markdown document. */
|
|
426
|
+
function renderReport(data) {
|
|
427
|
+
const lines = [];
|
|
428
|
+
const pct = (n) => `${(n * 100).toFixed(1)}%`;
|
|
429
|
+
lines.push(`# API Test Report — ${data.date}`);
|
|
430
|
+
lines.push('');
|
|
431
|
+
lines.push('## 概览');
|
|
432
|
+
lines.push('');
|
|
433
|
+
lines.push('| 指标 | 值 |');
|
|
434
|
+
lines.push('| --- | --- |');
|
|
435
|
+
lines.push(`| 总接口数 | ${data.totalEndpoints} |`);
|
|
436
|
+
lines.push(`| 通过数 | ${data.passedCount} |`);
|
|
437
|
+
lines.push(`| 失败数 | ${data.failedCount} |`);
|
|
438
|
+
lines.push(`| Skip 数 | ${data.skipCount} |`);
|
|
439
|
+
lines.push(`| 平均耗时 | ${data.avgDurationMs.toFixed(0)} ms |`);
|
|
440
|
+
lines.push(`| P99 耗时 | ${data.p99DurationMs.toFixed(0)} ms |`);
|
|
441
|
+
lines.push('');
|
|
442
|
+
lines.push('## 按微服务分组通过率');
|
|
443
|
+
lines.push('');
|
|
444
|
+
if (data.perService.length === 0) {
|
|
445
|
+
lines.push('_(无微服务数据)_');
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
lines.push('| 微服务 | 总数 | 通过 | 通过率 |');
|
|
449
|
+
lines.push('| --- | --- | --- | --- |');
|
|
450
|
+
for (const s of data.perService) {
|
|
451
|
+
lines.push(`| ${s.service} | ${s.total} | ${s.passed} | ${pct(s.passRate)} |`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
lines.push('');
|
|
455
|
+
lines.push('## 失败清单');
|
|
456
|
+
lines.push('');
|
|
457
|
+
if (data.failures.length === 0) {
|
|
458
|
+
lines.push('_(无失败用例)_');
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
lines.push('| Endpoint | Service | Error |');
|
|
462
|
+
lines.push('| --- | --- | --- |');
|
|
463
|
+
for (const f of data.failures) {
|
|
464
|
+
lines.push(`| ${f.endpoint} | ${f.service} | ${f.error ?? ''} |`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
lines.push('');
|
|
468
|
+
lines.push('## Skip 清单');
|
|
469
|
+
lines.push('');
|
|
470
|
+
if (data.skips.length === 0) {
|
|
471
|
+
lines.push('_(无 skip 用例)_');
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
lines.push('| Endpoint | Service | Skip Reason |');
|
|
475
|
+
lines.push('| --- | --- | --- |');
|
|
476
|
+
for (const s of data.skips) {
|
|
477
|
+
lines.push(`| ${s.endpoint} | ${s.service} | ${s.skipReason ?? ''} |`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
lines.push('');
|
|
481
|
+
return lines.join('\n');
|
|
482
|
+
}
|
|
483
|
+
// ─── Terminal table rendering (hand-rolled, no cli-table3) ─────────────────
|
|
484
|
+
/**
|
|
485
|
+
* Render a 2D string matrix as a fixed-width terminal table. The first row
|
|
486
|
+
* is treated as the header and separated from the body by a `---` divider
|
|
487
|
+
* line. Column widths are the max cell width in each column. Empty matrix
|
|
488
|
+
* returns the empty string.
|
|
489
|
+
*/
|
|
490
|
+
function renderTable(rows) {
|
|
491
|
+
if (rows.length === 0)
|
|
492
|
+
return '';
|
|
493
|
+
const cols = rows[0].length;
|
|
494
|
+
const widths = new Array(cols).fill(0);
|
|
495
|
+
for (const row of rows) {
|
|
496
|
+
for (let c = 0; c < cols; c++) {
|
|
497
|
+
const cell = row[c] ?? '';
|
|
498
|
+
widths[c] = Math.max(widths[c], cell.length);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
const pad = (cell, c) => (cell + ' '.repeat(widths[c])).slice(0, widths[c]);
|
|
502
|
+
const renderRow = (row) => row.map((cell, c) => pad(cell ?? '', c)).join(' ');
|
|
503
|
+
const header = renderRow(rows[0]);
|
|
504
|
+
const divider = widths.map((w) => '-'.repeat(w)).join(' ');
|
|
505
|
+
const body = rows.slice(1).map(renderRow).join('\n');
|
|
506
|
+
return [header, divider, body].filter((s) => s.length > 0).join('\n');
|
|
507
|
+
}
|
|
508
|
+
/** Internal helpers re-exported for tests. */
|
|
509
|
+
exports.__INTERNAL_REPORT = {
|
|
510
|
+
DEFAULT_OUTPUT_DIR,
|
|
511
|
+
reportFilePath,
|
|
512
|
+
parseJsonl,
|
|
513
|
+
deserializeRun,
|
|
514
|
+
readLatestRunByEndpoint,
|
|
515
|
+
readAllEndpoints,
|
|
516
|
+
parseFrontmatter,
|
|
517
|
+
aggregateReport,
|
|
518
|
+
percentile,
|
|
519
|
+
renderReport,
|
|
520
|
+
renderTable,
|
|
521
|
+
};
|
|
522
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/api-test/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L-T-50: snapshot — capture dep_tables row snapshots before `bru run`,
|
|
3
|
+
* stored as `.cgraphx/api-test/runs/<run-id>-before.json`.
|
|
4
|
+
*
|
|
5
|
+
* Part of the single-endpoint closed loop (enhance → snapshot → bru run → verify).
|
|
6
|
+
* Mechanical subcommand — no AI logic.
|
|
7
|
+
*
|
|
8
|
+
* Spec: docs/features/2026-07-07-api-test-skill-bruno自动化接口测试/api-test-layer2-spec.md §7.1 (snapshot is the
|
|
9
|
+
* realization of decision #2 option (d): skill calls snapshot before bru run, verify-prepare reads it)
|
|
10
|
+
*/
|
|
11
|
+
export interface SnapshotResult {
|
|
12
|
+
endpoint: string;
|
|
13
|
+
runId: string;
|
|
14
|
+
depTables: string[];
|
|
15
|
+
snapshots: Record<string, unknown[]>;
|
|
16
|
+
snapshotAt: string;
|
|
17
|
+
beforeJsonPath: string;
|
|
18
|
+
errors: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function snapshot(projectRoot: string, endpoint: string, runId: string, service?: string): Promise<SnapshotResult>;
|
|
21
|
+
export declare const __INTERNAL_SNAPSHOT: {
|
|
22
|
+
DEFAULT_SERVICE: string;
|
|
23
|
+
RUNS_SUBDIR: string;
|
|
24
|
+
SNAPSHOT_LIMIT: number;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/api-test/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAcH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAC5B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CAoDzB;AAuCD,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC"}
|