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.
Files changed (201) hide show
  1. package/README.md +0 -1
  2. package/dist/.claude-template/hooks/precommit-check/precommit-check.cjs +90 -0
  3. package/dist/.claude-template/skills/cgraphx/SKILL.md +3 -3
  4. package/dist/.claude-template/skills/cgraphx/agent-prompt.md +1 -1
  5. package/dist/.claude-template/skills/cgraphx-guide/SKILL.md +94 -0
  6. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +424 -0
  7. package/dist/.claude-template/skills/clarify-requirements/SKILL.md +19 -8
  8. package/dist/.claude-template/skills/code-impact-docgen/SKILL.md +186 -176
  9. package/dist/.claude-template/skills/code-impact-docgen/template-design-html.md +357 -0
  10. package/dist/.claude-template/skills/code-impact-docgen/template-design-md.md +164 -0
  11. package/dist/.claude-template/skills/code-impact-init/SKILL.md +47 -47
  12. package/dist/.claude-template/skills/developer-timeline/SKILL.md +9 -0
  13. package/dist/.claude-template/skills/precommit-review/SKILL.md +50 -0
  14. package/dist/.claude-template/skills/run-api-test/SKILL.md +187 -0
  15. package/dist/.claude-template/skills/run-api-test/assets/template-test-report.md +103 -0
  16. package/dist/.claude-template/skills/run-api-test/assets/template-test-verify.jsonl +5 -0
  17. package/dist/.claude-template/skills/run-api-test/references/bru-run.md +60 -0
  18. package/dist/.claude-template/skills/run-api-test/references/db-verification.md +81 -0
  19. package/dist/.claude-template/skills/run-api-test/references/report-format.md +104 -0
  20. package/dist/.claude-template/skills/run-api-test/references/service-readiness.md +61 -0
  21. package/dist/.claude-template/skills/run-api-test/references/test-scope.md +64 -0
  22. package/dist/.claude-template/skills/write-api/SKILL.md +150 -0
  23. package/dist/.claude-template/skills/write-api/assets/template-api-spec.md +112 -0
  24. package/dist/.claude-template/skills/write-api/assets/template-request.bru +75 -0
  25. package/dist/.claude-template/skills/write-api/references/ai-prompts.md +133 -0
  26. package/dist/.claude-template/skills/write-api/references/api-spec-format.md +108 -0
  27. package/dist/.claude-template/skills/write-api/references/bru-format.md +144 -0
  28. package/dist/.claude-template/skills/write-api/references/collection-layout.md +81 -0
  29. package/dist/.claude-template/skills/write-api/references/environment-setup.md +105 -0
  30. package/dist/.claude-template/skills/write-api/references/interface-scope.md +74 -0
  31. package/dist/.claude-template/skills/write-api-doc/SKILL.md +317 -0
  32. package/dist/.claude-template/skills/write-api-doc/template-api-html.md +422 -0
  33. package/dist/.claude-template/skills/write-plan/SKILL.md +38 -16
  34. package/dist/.claude-template/skills/write-prd/SKILL.md +32 -8
  35. package/dist/.claude-template/skills/write-spec/SKILL.md +34 -9
  36. package/dist/api-test/ai-fields.d.ts +37 -0
  37. package/dist/api-test/ai-fields.d.ts.map +1 -0
  38. package/dist/api-test/ai-fields.js +114 -0
  39. package/dist/api-test/ai-fields.js.map +1 -0
  40. package/dist/api-test/assemble.d.ts +76 -0
  41. package/dist/api-test/assemble.d.ts.map +1 -0
  42. package/dist/api-test/assemble.js +185 -0
  43. package/dist/api-test/assemble.js.map +1 -0
  44. package/dist/api-test/bru-cli-invoker.d.ts +72 -0
  45. package/dist/api-test/bru-cli-invoker.d.ts.map +1 -0
  46. package/dist/api-test/bru-cli-invoker.js +169 -0
  47. package/dist/api-test/bru-cli-invoker.js.map +1 -0
  48. package/dist/api-test/bru-report-parser.d.ts +24 -0
  49. package/dist/api-test/bru-report-parser.d.ts.map +1 -0
  50. package/dist/api-test/bru-report-parser.js +110 -0
  51. package/dist/api-test/bru-report-parser.js.map +1 -0
  52. package/dist/api-test/bru-runner.d.ts +101 -0
  53. package/dist/api-test/bru-runner.d.ts.map +1 -0
  54. package/dist/api-test/bru-runner.js +316 -0
  55. package/dist/api-test/bru-runner.js.map +1 -0
  56. package/dist/api-test/bru-writer.d.ts +52 -0
  57. package/dist/api-test/bru-writer.d.ts.map +1 -0
  58. package/dist/api-test/bru-writer.js +159 -0
  59. package/dist/api-test/bru-writer.js.map +1 -0
  60. package/dist/api-test/call-chain-extractor.d.ts +80 -0
  61. package/dist/api-test/call-chain-extractor.d.ts.map +1 -0
  62. package/dist/api-test/call-chain-extractor.js +179 -0
  63. package/dist/api-test/call-chain-extractor.js.map +1 -0
  64. package/dist/api-test/cli.d.ts +133 -0
  65. package/dist/api-test/cli.d.ts.map +1 -0
  66. package/dist/api-test/cli.js +1009 -0
  67. package/dist/api-test/cli.js.map +1 -0
  68. package/dist/api-test/config.d.ts +75 -0
  69. package/dist/api-test/config.d.ts.map +1 -0
  70. package/dist/api-test/config.js +406 -0
  71. package/dist/api-test/config.js.map +1 -0
  72. package/dist/api-test/db-query-cli.d.ts +51 -0
  73. package/dist/api-test/db-query-cli.d.ts.map +1 -0
  74. package/dist/api-test/db-query-cli.js +119 -0
  75. package/dist/api-test/db-query-cli.js.map +1 -0
  76. package/dist/api-test/enhance-prepare.d.ts +111 -0
  77. package/dist/api-test/enhance-prepare.d.ts.map +1 -0
  78. package/dist/api-test/enhance-prepare.js +425 -0
  79. package/dist/api-test/enhance-prepare.js.map +1 -0
  80. package/dist/api-test/enhance-write.d.ts +28 -0
  81. package/dist/api-test/enhance-write.d.ts.map +1 -0
  82. package/dist/api-test/enhance-write.js +145 -0
  83. package/dist/api-test/enhance-write.js.map +1 -0
  84. package/dist/api-test/errors.d.ts +48 -0
  85. package/dist/api-test/errors.d.ts.map +1 -0
  86. package/dist/api-test/errors.js +76 -0
  87. package/dist/api-test/errors.js.map +1 -0
  88. package/dist/api-test/field-extractor.d.ts +98 -0
  89. package/dist/api-test/field-extractor.d.ts.map +1 -0
  90. package/dist/api-test/field-extractor.js +327 -0
  91. package/dist/api-test/field-extractor.js.map +1 -0
  92. package/dist/api-test/impl-finder.d.ts +37 -0
  93. package/dist/api-test/impl-finder.d.ts.map +1 -0
  94. package/dist/api-test/impl-finder.js +54 -0
  95. package/dist/api-test/impl-finder.js.map +1 -0
  96. package/dist/api-test/index.d.ts +41 -0
  97. package/dist/api-test/index.d.ts.map +1 -0
  98. package/dist/api-test/index.js +124 -0
  99. package/dist/api-test/index.js.map +1 -0
  100. package/dist/api-test/java-parser.d.ts +89 -0
  101. package/dist/api-test/java-parser.d.ts.map +1 -0
  102. package/dist/api-test/java-parser.js +508 -0
  103. package/dist/api-test/java-parser.js.map +1 -0
  104. package/dist/api-test/md-writer.d.ts +49 -0
  105. package/dist/api-test/md-writer.d.ts.map +1 -0
  106. package/dist/api-test/md-writer.js +202 -0
  107. package/dist/api-test/md-writer.js.map +1 -0
  108. package/dist/api-test/parser-httpservice.d.ts +91 -0
  109. package/dist/api-test/parser-httpservice.d.ts.map +1 -0
  110. package/dist/api-test/parser-httpservice.js +271 -0
  111. package/dist/api-test/parser-httpservice.js.map +1 -0
  112. package/dist/api-test/report.d.ts +188 -0
  113. package/dist/api-test/report.d.ts.map +1 -0
  114. package/dist/api-test/report.js +522 -0
  115. package/dist/api-test/report.js.map +1 -0
  116. package/dist/api-test/snapshot.d.ts +26 -0
  117. package/dist/api-test/snapshot.d.ts.map +1 -0
  118. package/dist/api-test/snapshot.js +150 -0
  119. package/dist/api-test/snapshot.js.map +1 -0
  120. package/dist/api-test/test-history.d.ts +48 -0
  121. package/dist/api-test/test-history.d.ts.map +1 -0
  122. package/dist/api-test/test-history.js +122 -0
  123. package/dist/api-test/test-history.js.map +1 -0
  124. package/dist/api-test/types.d.ts +174 -0
  125. package/dist/api-test/types.d.ts.map +1 -0
  126. package/dist/api-test/types.js +13 -0
  127. package/dist/api-test/types.js.map +1 -0
  128. package/dist/api-test/verify-prepare.d.ts +30 -0
  129. package/dist/api-test/verify-prepare.d.ts.map +1 -0
  130. package/dist/api-test/verify-prepare.js +150 -0
  131. package/dist/api-test/verify-prepare.js.map +1 -0
  132. package/dist/api-test/verify-write.d.ts +31 -0
  133. package/dist/api-test/verify-write.d.ts.map +1 -0
  134. package/dist/api-test/verify-write.js +159 -0
  135. package/dist/api-test/verify-write.js.map +1 -0
  136. package/dist/bin/codegraph.js +0 -100
  137. package/dist/bin/codegraph.js.map +1 -1
  138. package/dist/dbquery/dump-schema.d.ts +46 -0
  139. package/dist/dbquery/dump-schema.d.ts.map +1 -0
  140. package/dist/dbquery/dump-schema.js +379 -0
  141. package/dist/dbquery/dump-schema.js.map +1 -0
  142. package/dist/installer/targets/claude.d.ts +15 -0
  143. package/dist/installer/targets/claude.d.ts.map +1 -1
  144. package/dist/installer/targets/claude.js +53 -0
  145. package/dist/installer/targets/claude.js.map +1 -1
  146. package/dist/resolution/index.d.ts.map +1 -1
  147. package/dist/resolution/index.js +13 -0
  148. package/dist/resolution/index.js.map +1 -1
  149. package/dist/resolution/scope-index.d.ts +86 -0
  150. package/dist/resolution/scope-index.d.ts.map +1 -0
  151. package/dist/resolution/scope-index.js +143 -0
  152. package/dist/resolution/scope-index.js.map +1 -0
  153. package/dist/resolution/stdlib-blocklist.d.ts +53 -0
  154. package/dist/resolution/stdlib-blocklist.d.ts.map +1 -0
  155. package/dist/resolution/stdlib-blocklist.js +143 -0
  156. package/dist/resolution/stdlib-blocklist.js.map +1 -0
  157. package/dist/search/ast-helpers.d.ts +42 -0
  158. package/dist/search/ast-helpers.d.ts.map +1 -0
  159. package/dist/search/ast-helpers.js +106 -0
  160. package/dist/search/ast-helpers.js.map +1 -0
  161. package/dist/search/call-sites.d.ts +398 -0
  162. package/dist/search/call-sites.d.ts.map +1 -0
  163. package/dist/search/call-sites.js +1433 -0
  164. package/dist/search/call-sites.js.map +1 -0
  165. package/dist/search/context.d.ts +134 -0
  166. package/dist/search/context.d.ts.map +1 -0
  167. package/dist/search/context.js +575 -0
  168. package/dist/search/context.js.map +1 -0
  169. package/dist/search/impact.d.ts +139 -0
  170. package/dist/search/impact.d.ts.map +1 -0
  171. package/dist/search/impact.js +646 -0
  172. package/dist/search/impact.js.map +1 -0
  173. package/dist/search/related.d.ts +178 -0
  174. package/dist/search/related.d.ts.map +1 -0
  175. package/dist/search/related.js +667 -0
  176. package/dist/search/related.js.map +1 -0
  177. package/dist/search/slice.d.ts +148 -0
  178. package/dist/search/slice.d.ts.map +1 -0
  179. package/dist/search/slice.js +460 -0
  180. package/dist/search/slice.js.map +1 -0
  181. package/dist/search/snr-constants.d.ts +41 -0
  182. package/dist/search/snr-constants.d.ts.map +1 -0
  183. package/dist/search/snr-constants.js +44 -0
  184. package/dist/search/snr-constants.js.map +1 -0
  185. package/dist/search/types.d.ts +28 -0
  186. package/dist/search/types.d.ts.map +1 -0
  187. package/dist/search/types.js +12 -0
  188. package/dist/search/types.js.map +1 -0
  189. package/dist/timeline/cli.d.ts.map +1 -1
  190. package/dist/timeline/cli.js +22 -3
  191. package/dist/timeline/cli.js.map +1 -1
  192. package/dist/timeline/store.d.ts +5 -0
  193. package/dist/timeline/store.d.ts.map +1 -1
  194. package/dist/timeline/store.js +23 -3
  195. package/dist/timeline/store.js.map +1 -1
  196. package/package.json +1 -1
  197. package/scripts/agent-eval/subagent-token-cost.py +188 -0
  198. package/dist/.claude-template/skills/code-impact-docgen/template-business-html.md +0 -242
  199. package/dist/.claude-template/skills/code-impact-docgen/template-business-md.md +0 -107
  200. package/dist/.claude-template/skills/code-impact-docgen/template-technical-html.md +0 -205
  201. 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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"}
@@ -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')