cgraphx 1.1.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/README.md +0 -1
- package/dist/.claude-template/hooks/precommit-check/precommit-check.cjs +90 -0
- package/dist/.claude-template/skills/cgraphx/SKILL.md +3 -3
- package/dist/.claude-template/skills/cgraphx/agent-prompt.md +1 -1
- package/dist/.claude-template/skills/cgraphx-guide/SKILL.md +94 -0
- package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +424 -0
- package/dist/.claude-template/skills/clarify-requirements/SKILL.md +19 -8
- package/dist/.claude-template/skills/code-impact-docgen/SKILL.md +186 -176
- package/dist/.claude-template/skills/code-impact-docgen/template-design-html.md +357 -0
- package/dist/.claude-template/skills/code-impact-docgen/template-design-md.md +164 -0
- package/dist/.claude-template/skills/code-impact-init/SKILL.md +47 -47
- package/dist/.claude-template/skills/developer-timeline/SKILL.md +9 -0
- 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/.claude-template/skills/write-api-doc/SKILL.md +317 -0
- package/dist/.claude-template/skills/write-api-doc/template-api-html.md +422 -0
- package/dist/.claude-template/skills/write-plan/SKILL.md +38 -16
- package/dist/.claude-template/skills/write-prd/SKILL.md +32 -8
- package/dist/.claude-template/skills/write-spec/SKILL.md +34 -9
- 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/bin/codegraph.js +0 -100
- package/dist/bin/codegraph.js.map +1 -1
- 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/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +13 -0
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/scope-index.d.ts +86 -0
- package/dist/resolution/scope-index.d.ts.map +1 -0
- package/dist/resolution/scope-index.js +143 -0
- package/dist/resolution/scope-index.js.map +1 -0
- package/dist/resolution/stdlib-blocklist.d.ts +53 -0
- package/dist/resolution/stdlib-blocklist.d.ts.map +1 -0
- package/dist/resolution/stdlib-blocklist.js +143 -0
- package/dist/resolution/stdlib-blocklist.js.map +1 -0
- package/dist/search/ast-helpers.d.ts +42 -0
- package/dist/search/ast-helpers.d.ts.map +1 -0
- package/dist/search/ast-helpers.js +106 -0
- package/dist/search/ast-helpers.js.map +1 -0
- package/dist/search/call-sites.d.ts +398 -0
- package/dist/search/call-sites.d.ts.map +1 -0
- package/dist/search/call-sites.js +1433 -0
- package/dist/search/call-sites.js.map +1 -0
- package/dist/search/context.d.ts +134 -0
- package/dist/search/context.d.ts.map +1 -0
- package/dist/search/context.js +575 -0
- package/dist/search/context.js.map +1 -0
- package/dist/search/impact.d.ts +139 -0
- package/dist/search/impact.d.ts.map +1 -0
- package/dist/search/impact.js +646 -0
- package/dist/search/impact.js.map +1 -0
- package/dist/search/related.d.ts +178 -0
- package/dist/search/related.d.ts.map +1 -0
- package/dist/search/related.js +667 -0
- package/dist/search/related.js.map +1 -0
- package/dist/search/slice.d.ts +148 -0
- package/dist/search/slice.d.ts.map +1 -0
- package/dist/search/slice.js +460 -0
- package/dist/search/slice.js.map +1 -0
- package/dist/search/snr-constants.d.ts +41 -0
- package/dist/search/snr-constants.d.ts.map +1 -0
- package/dist/search/snr-constants.js +44 -0
- package/dist/search/snr-constants.js.map +1 -0
- package/dist/search/types.d.ts +28 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +12 -0
- package/dist/search/types.js.map +1 -0
- package/dist/timeline/cli.d.ts.map +1 -1
- package/dist/timeline/cli.js +22 -3
- package/dist/timeline/cli.js.map +1 -1
- package/dist/timeline/store.d.ts +5 -0
- package/dist/timeline/store.d.ts.map +1 -1
- package/dist/timeline/store.js +23 -3
- package/dist/timeline/store.js.map +1 -1
- package/package.json +1 -1
- package/scripts/agent-eval/subagent-token-cost.py +188 -0
- package/dist/.claude-template/skills/code-impact-docgen/template-business-html.md +0 -242
- package/dist/.claude-template/skills/code-impact-docgen/template-business-md.md +0 -107
- package/dist/.claude-template/skills/code-impact-docgen/template-technical-html.md +0 -205
- package/dist/.claude-template/skills/code-impact-docgen/template-technical-md.md +0 -155
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* L-T-30: verify-prepare — read bru run report + before.json + post-run db snapshot,
|
|
4
|
+
* output structured JSON for AI to infer db_verify expectations.
|
|
5
|
+
*
|
|
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.3
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.__INTERNAL_VERIFY_PREPARE = void 0;
|
|
45
|
+
exports.verifyPrepare = verifyPrepare;
|
|
46
|
+
const fs = __importStar(require("node:fs"));
|
|
47
|
+
const path = __importStar(require("node:path"));
|
|
48
|
+
const report_1 = require("./report");
|
|
49
|
+
const bru_report_parser_1 = require("./bru-report-parser");
|
|
50
|
+
const db_query_cli_1 = require("./db-query-cli");
|
|
51
|
+
const DEFAULT_DOCS_DIR = 'docs';
|
|
52
|
+
const DEFAULT_API_TEST_DIR = 'api-test';
|
|
53
|
+
const DEFAULT_SERVICE = 'inst-service';
|
|
54
|
+
const RUNS_SUBDIR = 'runs';
|
|
55
|
+
const SNAPSHOT_LIMIT = 5;
|
|
56
|
+
async function verifyPrepare(projectRoot, endpoint, resultsFile, runId, service = DEFAULT_SERVICE) {
|
|
57
|
+
const resolvedRoot = path.resolve(projectRoot);
|
|
58
|
+
// 1. Read bru run report, extract this endpoint's entry
|
|
59
|
+
const reportJson = fs.readFileSync(resultsFile, 'utf8');
|
|
60
|
+
const bruEntry = (0, bru_report_parser_1.parseBruReport)(reportJson, endpoint);
|
|
61
|
+
// 2. Read .md frontmatter for dep_tables
|
|
62
|
+
const mdPath = path.join(resolvedRoot, DEFAULT_DOCS_DIR, DEFAULT_API_TEST_DIR, service, `${endpoint}.md`);
|
|
63
|
+
let depTables = [];
|
|
64
|
+
// implPath: not resolved here (AI already has it from enhance-prepare JSON).
|
|
65
|
+
// Set to null; consumers should read impl_path from enhance-prepare output.
|
|
66
|
+
let implPath = null;
|
|
67
|
+
if (fs.existsSync(mdPath)) {
|
|
68
|
+
const mdContent = fs.readFileSync(mdPath, 'utf8');
|
|
69
|
+
const fm = (0, report_1.parseFrontmatter)(mdContent);
|
|
70
|
+
depTables = parseDepTables(fm.dep_tables ?? null, mdContent);
|
|
71
|
+
}
|
|
72
|
+
// 3. Read before.json (from snapshot command)
|
|
73
|
+
const beforeJsonPath = path.join(resolvedRoot, '.cgraphx', DEFAULT_API_TEST_DIR, RUNS_SUBDIR, `${runId}-before.json`);
|
|
74
|
+
let dbBefore = null;
|
|
75
|
+
if (fs.existsSync(beforeJsonPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const beforeData = JSON.parse(fs.readFileSync(beforeJsonPath, 'utf8'));
|
|
78
|
+
if (beforeData && typeof beforeData.snapshots === 'object') {
|
|
79
|
+
dbBefore = beforeData.snapshots;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
dbBefore = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 4. Take post-run snapshot
|
|
87
|
+
const dbAfter = {};
|
|
88
|
+
for (const table of depTables) {
|
|
89
|
+
if (!table)
|
|
90
|
+
continue;
|
|
91
|
+
const sql = `SELECT * FROM ${table} LIMIT ${SNAPSHOT_LIMIT}`;
|
|
92
|
+
const result = await (0, db_query_cli_1.runDbQueryCli)(sql, resolvedRoot);
|
|
93
|
+
if (result.ok) {
|
|
94
|
+
dbAfter[table] = result.rows;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
dbAfter[table] = [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
endpoint,
|
|
102
|
+
service,
|
|
103
|
+
implPath,
|
|
104
|
+
response: {
|
|
105
|
+
httpStatus: bruEntry?.httpStatus ?? 0,
|
|
106
|
+
body: bruEntry?.responseBody ?? '',
|
|
107
|
+
tests: bruEntry?.tests ?? [],
|
|
108
|
+
durationMs: bruEntry?.durationMs ?? 0,
|
|
109
|
+
error: bruEntry ? (bruEntry.error ?? null) : 'bru report entry not found',
|
|
110
|
+
},
|
|
111
|
+
dbBefore,
|
|
112
|
+
dbAfter,
|
|
113
|
+
depTables,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function parseDepTables(rawValue, fullMdContent) {
|
|
117
|
+
if (rawValue && rawValue.trim() && !rawValue.includes('[')) {
|
|
118
|
+
return [rawValue.trim()];
|
|
119
|
+
}
|
|
120
|
+
if (rawValue && rawValue.includes('[')) {
|
|
121
|
+
const inner = rawValue.replace(/^\[/, '').replace(/\]$/, '');
|
|
122
|
+
return inner.split(',').map((s) => s.trim()).filter(Boolean);
|
|
123
|
+
}
|
|
124
|
+
const tables = [];
|
|
125
|
+
const lines = fullMdContent.split('\n');
|
|
126
|
+
let inDepTables = false;
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
if (/^dep_tables:/.test(line)) {
|
|
129
|
+
inDepTables = true;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (inDepTables) {
|
|
133
|
+
if (/^\s+-\s+/.test(line)) {
|
|
134
|
+
const t = line.replace(/^\s+-\s+/, '').trim().replace(/['"]/g, '');
|
|
135
|
+
if (t)
|
|
136
|
+
tables.push(t);
|
|
137
|
+
}
|
|
138
|
+
else if (/^\S/.test(line)) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return tables;
|
|
144
|
+
}
|
|
145
|
+
exports.__INTERNAL_VERIFY_PREPARE = {
|
|
146
|
+
DEFAULT_SERVICE,
|
|
147
|
+
RUNS_SUBDIR,
|
|
148
|
+
SNAPSHOT_LIMIT,
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=verify-prepare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-prepare.js","sourceRoot":"","sources":["../../src/api-test/verify-prepare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L-T-40: verify-write — read verify-prepare JSON + AI temp files, compute overall_passed,
|
|
3
|
+
* write ai JSONL (`runs/YYYY-MM-DD-ai.jsonl`).
|
|
4
|
+
*
|
|
5
|
+
* ai JSONL is a SEPARATE file from Layer 1's `runs/YYYY-MM-DD.jsonl` (per alignment decision #3).
|
|
6
|
+
* Schema per line:
|
|
7
|
+
* { endpoint, service, ran_at, http_status, biz_code, duration_ms,
|
|
8
|
+
* ai_assertions: { total, passed, failed, details },
|
|
9
|
+
* db_verify: { ran, passed, expected, actual, sql },
|
|
10
|
+
* overall_passed: boolean }
|
|
11
|
+
*
|
|
12
|
+
* overall_passed = http_passed && biz_code_passed && ai_assertions.passed && db_verify.passed
|
|
13
|
+
*
|
|
14
|
+
* Mechanical subcommand — no AI logic (AI temp files provide ai_assertions.passed / db_verify.passed).
|
|
15
|
+
*
|
|
16
|
+
* Spec: docs/features/2026-07-07-api-test-skill-bruno自动化接口测试/api-test-layer2-spec.md §7.1.4
|
|
17
|
+
*/
|
|
18
|
+
export interface VerifyWriteOptions {
|
|
19
|
+
projectRoot: string;
|
|
20
|
+
endpoint: string;
|
|
21
|
+
verifyPrepareJsonFile: string;
|
|
22
|
+
aiAssertionsFile: string;
|
|
23
|
+
dbVerifyFile: string;
|
|
24
|
+
ranAt: string;
|
|
25
|
+
service?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function verifyWrite(opts: VerifyWriteOptions): Promise<string>;
|
|
28
|
+
export declare const __INTERNAL_VERIFY_WRITE: {
|
|
29
|
+
RUNS_SUBDIR: string;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=verify-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-write.d.ts","sourceRoot":"","sources":["../../src/api-test/verify-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA2BD,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoF3E;AAkBD,eAAO,MAAM,uBAAuB;;CAEnC,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* L-T-40: verify-write — read verify-prepare JSON + AI temp files, compute overall_passed,
|
|
4
|
+
* write ai JSONL (`runs/YYYY-MM-DD-ai.jsonl`).
|
|
5
|
+
*
|
|
6
|
+
* ai JSONL is a SEPARATE file from Layer 1's `runs/YYYY-MM-DD.jsonl` (per alignment decision #3).
|
|
7
|
+
* Schema per line:
|
|
8
|
+
* { endpoint, service, ran_at, http_status, biz_code, duration_ms,
|
|
9
|
+
* ai_assertions: { total, passed, failed, details },
|
|
10
|
+
* db_verify: { ran, passed, expected, actual, sql },
|
|
11
|
+
* overall_passed: boolean }
|
|
12
|
+
*
|
|
13
|
+
* overall_passed = http_passed && biz_code_passed && ai_assertions.passed && db_verify.passed
|
|
14
|
+
*
|
|
15
|
+
* Mechanical subcommand — no AI logic (AI temp files provide ai_assertions.passed / db_verify.passed).
|
|
16
|
+
*
|
|
17
|
+
* Spec: docs/features/2026-07-07-api-test-skill-bruno自动化接口测试/api-test-layer2-spec.md §7.1.4
|
|
18
|
+
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.__INTERNAL_VERIFY_WRITE = void 0;
|
|
54
|
+
exports.verifyWrite = verifyWrite;
|
|
55
|
+
const fs = __importStar(require("node:fs"));
|
|
56
|
+
const path = __importStar(require("node:path"));
|
|
57
|
+
const config_1 = require("./config");
|
|
58
|
+
const RUNS_SUBDIR = 'runs';
|
|
59
|
+
async function verifyWrite(opts) {
|
|
60
|
+
const resolvedRoot = path.resolve(opts.projectRoot);
|
|
61
|
+
// 1. Read verify-prepare JSON
|
|
62
|
+
const vpContent = fs.readFileSync(opts.verifyPrepareJsonFile, 'utf8');
|
|
63
|
+
let vpData;
|
|
64
|
+
try {
|
|
65
|
+
vpData = JSON.parse(vpContent);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error(`[verify-write] verify-prepare JSON invalid: ${opts.verifyPrepareJsonFile}`);
|
|
69
|
+
}
|
|
70
|
+
// 2. Read AI temp files
|
|
71
|
+
const aiAssertions = readJsonFile(opts.aiAssertionsFile, 'ai-assertions');
|
|
72
|
+
const dbVerify = readJsonFile(opts.dbVerifyFile, 'db-verify');
|
|
73
|
+
// 3. Extract response fields from verify-prepare
|
|
74
|
+
const httpStatus = vpData.response?.httpStatus ?? 0;
|
|
75
|
+
const durationMs = vpData.response?.durationMs ?? 0;
|
|
76
|
+
const responseBody = vpData.response?.body ?? '';
|
|
77
|
+
// 4. Extract biz_code from response body using profile
|
|
78
|
+
let bizCode = null;
|
|
79
|
+
let bizCodePassed = false;
|
|
80
|
+
try {
|
|
81
|
+
const profile = (0, config_1.loadProfile)(resolvedRoot);
|
|
82
|
+
if (profile.bizCodeField && responseBody) {
|
|
83
|
+
try {
|
|
84
|
+
const bodyJson = JSON.parse(responseBody);
|
|
85
|
+
const codeValue = bodyJson[profile.bizCodeField];
|
|
86
|
+
if (codeValue !== undefined && codeValue !== null) {
|
|
87
|
+
bizCode = String(codeValue);
|
|
88
|
+
bizCodePassed = profile.bizCodeSuccessValues.includes(bizCode);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
bizCodePassed = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
bizCodePassed = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (!profile.bizCodeField) {
|
|
99
|
+
bizCodePassed = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
bizCodePassed = false;
|
|
104
|
+
}
|
|
105
|
+
// 5. Compute overall_passed
|
|
106
|
+
const httpPassed = httpStatus === 200;
|
|
107
|
+
const aiPassed = aiAssertions.passed === true;
|
|
108
|
+
const dbPassed = dbVerify.passed === true;
|
|
109
|
+
const overallPassed = httpPassed && bizCodePassed && aiPassed && dbPassed;
|
|
110
|
+
// 6. Build JSONL record
|
|
111
|
+
const record = {
|
|
112
|
+
endpoint: opts.endpoint,
|
|
113
|
+
service: opts.service ?? vpData.service ?? 'inst-service',
|
|
114
|
+
ran_at: opts.ranAt,
|
|
115
|
+
http_status: httpStatus,
|
|
116
|
+
biz_code: bizCode,
|
|
117
|
+
duration_ms: durationMs,
|
|
118
|
+
ai_assertions: {
|
|
119
|
+
total: aiAssertions.total ?? 0,
|
|
120
|
+
passed: aiAssertions.passed === true,
|
|
121
|
+
failed: aiAssertions.failed ?? 0,
|
|
122
|
+
details: aiAssertions.details ?? [],
|
|
123
|
+
},
|
|
124
|
+
db_verify: {
|
|
125
|
+
ran: dbVerify.ran ?? false,
|
|
126
|
+
passed: dbVerify.passed ?? false,
|
|
127
|
+
expected: dbVerify.expected ?? null,
|
|
128
|
+
actual: dbVerify.actual ?? null,
|
|
129
|
+
sql: dbVerify.sql ?? null,
|
|
130
|
+
},
|
|
131
|
+
overall_passed: overallPassed,
|
|
132
|
+
};
|
|
133
|
+
// 7. Append to ai JSONL
|
|
134
|
+
const date = extractDateFromIso(opts.ranAt);
|
|
135
|
+
const runsDir = path.join(resolvedRoot, '.cgraphx', 'api-test', RUNS_SUBDIR);
|
|
136
|
+
fs.mkdirSync(runsDir, { recursive: true });
|
|
137
|
+
const jsonlPath = path.join(runsDir, `${date}-ai.jsonl`);
|
|
138
|
+
fs.appendFileSync(jsonlPath, JSON.stringify(record) + '\n', 'utf8');
|
|
139
|
+
return jsonlPath;
|
|
140
|
+
}
|
|
141
|
+
function readJsonFile(filePath, label) {
|
|
142
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
143
|
+
throw new Error(`[verify-write] ${label} file required but not found: ${filePath}`);
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
throw new Error(`[verify-write] ${label} file is not valid JSON: ${filePath}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function extractDateFromIso(iso) {
|
|
153
|
+
const match = iso.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
154
|
+
return match && match[1] ? match[1] : new Date().toISOString().slice(0, 10);
|
|
155
|
+
}
|
|
156
|
+
exports.__INTERNAL_VERIFY_WRITE = {
|
|
157
|
+
RUNS_SUBDIR,
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=verify-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-write.js","sourceRoot":"","sources":["../../src/api-test/verify-write.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/codegraph.js
CHANGED
|
@@ -1601,106 +1601,6 @@ function main() {
|
|
|
1601
1601
|
process.exit(1);
|
|
1602
1602
|
}
|
|
1603
1603
|
});
|
|
1604
|
-
/**
|
|
1605
|
-
* cgraphx impact <symbol>
|
|
1606
|
-
*/
|
|
1607
|
-
program
|
|
1608
|
-
.command('impact <symbol>')
|
|
1609
|
-
.description('Analyze what code is affected by changing a symbol')
|
|
1610
|
-
.option('-p, --path <path>', 'Project path')
|
|
1611
|
-
.option('-d, --depth <number>', 'Traversal depth', '2')
|
|
1612
|
-
.option('-j, --json', 'Output as JSON')
|
|
1613
|
-
.action(async (symbol, options) => {
|
|
1614
|
-
const projectPath = resolveProjectPath(options.path);
|
|
1615
|
-
try {
|
|
1616
|
-
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
1617
|
-
error(`cgraphx not initialized in ${projectPath}`);
|
|
1618
|
-
process.exit(1);
|
|
1619
|
-
}
|
|
1620
|
-
const { default: CodeGraph } = await loadCodeGraph();
|
|
1621
|
-
const cg = await CodeGraph.open(projectPath);
|
|
1622
|
-
const depth = Math.min(Math.max(parseInt(options.depth || '2', 10), 1), 10);
|
|
1623
|
-
const matches = cg.searchNodes(symbol, { limit: 50 });
|
|
1624
|
-
if (matches.length === 0) {
|
|
1625
|
-
info(`Symbol "${symbol}" not found`);
|
|
1626
|
-
cg.destroy();
|
|
1627
|
-
return;
|
|
1628
|
-
}
|
|
1629
|
-
// Merge impact subgraphs across all exact-matching symbols
|
|
1630
|
-
const mergedNodes = new Map();
|
|
1631
|
-
const seenEdges = new Set();
|
|
1632
|
-
let edgeCount = 0;
|
|
1633
|
-
for (const match of matches) {
|
|
1634
|
-
const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
|
|
1635
|
-
if (!exactMatch && matches.length > 1)
|
|
1636
|
-
continue;
|
|
1637
|
-
const impact = cg.getImpactRadius(match.node.id, depth);
|
|
1638
|
-
for (const [id, n] of impact.nodes) {
|
|
1639
|
-
mergedNodes.set(id, { name: n.name, kind: n.kind, filePath: n.filePath, startLine: n.startLine });
|
|
1640
|
-
}
|
|
1641
|
-
for (const e of impact.edges) {
|
|
1642
|
-
const key = `${e.source}->${e.target}:${e.kind}`;
|
|
1643
|
-
if (!seenEdges.has(key)) {
|
|
1644
|
-
seenEdges.add(key);
|
|
1645
|
-
edgeCount++;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
// Fallback to top match if exact filter removed everything
|
|
1650
|
-
if (mergedNodes.size === 0 && matches[0]) {
|
|
1651
|
-
const impact = cg.getImpactRadius(matches[0].node.id, depth);
|
|
1652
|
-
for (const [id, n] of impact.nodes) {
|
|
1653
|
-
mergedNodes.set(id, { name: n.name, kind: n.kind, filePath: n.filePath, startLine: n.startLine });
|
|
1654
|
-
}
|
|
1655
|
-
edgeCount = impact.edges.length;
|
|
1656
|
-
}
|
|
1657
|
-
if (options.json) {
|
|
1658
|
-
console.log(JSON.stringify({
|
|
1659
|
-
symbol,
|
|
1660
|
-
depth,
|
|
1661
|
-
nodeCount: mergedNodes.size,
|
|
1662
|
-
edgeCount,
|
|
1663
|
-
affected: Array.from(mergedNodes.values()),
|
|
1664
|
-
}, null, 2));
|
|
1665
|
-
}
|
|
1666
|
-
else if (mergedNodes.size === 0) {
|
|
1667
|
-
info(`No affected symbols found for "${symbol}"`);
|
|
1668
|
-
}
|
|
1669
|
-
else {
|
|
1670
|
-
console.log(chalk.bold(`\nImpact of changing "${symbol}" — ${mergedNodes.size} affected symbols:\n`));
|
|
1671
|
-
// Group by file
|
|
1672
|
-
const byFile = new Map();
|
|
1673
|
-
for (const node of mergedNodes.values()) {
|
|
1674
|
-
const list = byFile.get(node.filePath) || [];
|
|
1675
|
-
list.push({ name: node.name, kind: node.kind, startLine: node.startLine });
|
|
1676
|
-
byFile.set(node.filePath, list);
|
|
1677
|
-
}
|
|
1678
|
-
for (const [file, nodes] of byFile) {
|
|
1679
|
-
console.log(chalk.cyan(file));
|
|
1680
|
-
for (const node of nodes) {
|
|
1681
|
-
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
1682
|
-
console.log(` ${chalk.dim(node.kind.padEnd(12))}${node.name}${chalk.dim(loc)}`);
|
|
1683
|
-
}
|
|
1684
|
-
console.log();
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
cg.destroy();
|
|
1688
|
-
}
|
|
1689
|
-
catch (err) {
|
|
1690
|
-
error(`impact failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1691
|
-
process.exit(1);
|
|
1692
|
-
}
|
|
1693
|
-
});
|
|
1694
|
-
/**
|
|
1695
|
-
* cgraphx affected [files...]
|
|
1696
|
-
*
|
|
1697
|
-
* Find test files affected by the given source files.
|
|
1698
|
-
* Traces dependency edges transitively to find test files that depend on changed code.
|
|
1699
|
-
*
|
|
1700
|
-
* Usage:
|
|
1701
|
-
* git diff --name-only | cgraphx affected --stdin
|
|
1702
|
-
* cgraphx affected src/lib/components/Editor.svelte src/routes/+page.svelte
|
|
1703
|
-
*/
|
|
1704
1604
|
program
|
|
1705
1605
|
.command('affected [files...]')
|
|
1706
1606
|
.description('Find test files affected by changed source files')
|