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 @@
|
|
|
1
|
+
{"version":3,"file":"ai-fields.d.ts","sourceRoot":"","sources":["../../src/api-test/ai-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE/C,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA0BnF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAS1F;AAED,8CAA8C;AAC9C,eAAO,MAAM,oBAAoB;;CAEhC,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AI-inferred fields persistence (L-T-10).
|
|
4
|
+
*
|
|
5
|
+
* `enhance-prepare` reads any previously-written AI fields so a re-run keeps
|
|
6
|
+
* the AI's prior inference unless the human regenerates it. `enhance-write`
|
|
7
|
+
* (L-T-20) writes this file after the AI infers fields.
|
|
8
|
+
*
|
|
9
|
+
* Storage: `.cgraphx/api-test/ai-fields/<endpoint>.json` where `<endpoint>`
|
|
10
|
+
* is the .md filename stem (`<svc_id>_<method>`). One file per endpoint so
|
|
11
|
+
* partial reruns only touch their own file.
|
|
12
|
+
*
|
|
13
|
+
* Independent subsystem — only depends on `node:fs`/`node:path` and the
|
|
14
|
+
* `AiFields` / `Field` types.
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.__INTERNAL_AI_FIELDS = exports.AI_FIELDS_SUBDIR = void 0;
|
|
51
|
+
exports.aiFieldsFilePath = aiFieldsFilePath;
|
|
52
|
+
exports.readAiFields = readAiFields;
|
|
53
|
+
exports.writeAiFields = writeAiFields;
|
|
54
|
+
const fs = __importStar(require("node:fs"));
|
|
55
|
+
const path = __importStar(require("node:path"));
|
|
56
|
+
/** Subdir under `.cgraphx/api-test/` holding the per-endpoint JSON files. */
|
|
57
|
+
exports.AI_FIELDS_SUBDIR = 'ai-fields';
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the JSON path for an endpoint: `<projectRoot>/.cgraphx/api-test/
|
|
60
|
+
* ai-fields/<endpoint>.json`.
|
|
61
|
+
*/
|
|
62
|
+
function aiFieldsFilePath(projectRoot, endpoint) {
|
|
63
|
+
return path.join(projectRoot, '.cgraphx', 'api-test', exports.AI_FIELDS_SUBDIR, `${endpoint}.json`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Read previously-persisted AI fields for `endpoint`. Returns `null` when the
|
|
67
|
+
* file doesn't exist or can't be parsed (treat as "no prior inference").
|
|
68
|
+
*/
|
|
69
|
+
function readAiFields(projectRoot, endpoint) {
|
|
70
|
+
const file = aiFieldsFilePath(projectRoot, endpoint);
|
|
71
|
+
let content;
|
|
72
|
+
try {
|
|
73
|
+
content = fs.readFileSync(file, 'utf8');
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const parsed = JSON.parse(content);
|
|
80
|
+
if (typeof parsed !== 'object' ||
|
|
81
|
+
parsed === null ||
|
|
82
|
+
typeof parsed.endpoint !== 'string' ||
|
|
83
|
+
!Array.isArray(parsed.fields)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
endpoint: parsed.endpoint,
|
|
88
|
+
fields: parsed.fields,
|
|
89
|
+
updatedAt: typeof parsed.updatedAt === 'string' ? parsed.updatedAt : '',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Persist AI-inferred fields for `endpoint`. Creates the parent directory if
|
|
98
|
+
* needed. `updatedAt` is stamped with the current ISO timestamp.
|
|
99
|
+
*/
|
|
100
|
+
function writeAiFields(projectRoot, endpoint, fields) {
|
|
101
|
+
const file = aiFieldsFilePath(projectRoot, endpoint);
|
|
102
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
103
|
+
const payload = {
|
|
104
|
+
endpoint,
|
|
105
|
+
fields,
|
|
106
|
+
updatedAt: new Date().toISOString(),
|
|
107
|
+
};
|
|
108
|
+
fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n', 'utf8');
|
|
109
|
+
}
|
|
110
|
+
/** Internal helpers re-exported for tests. */
|
|
111
|
+
exports.__INTERNAL_AI_FIELDS = {
|
|
112
|
+
AI_FIELDS_SUBDIR: exports.AI_FIELDS_SUBDIR,
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=ai-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-fields.js","sourceRoot":"","sources":["../../src/api-test/ai-fields.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcH,4CAEC;AAMD,oCA0BC;AAMD,sCASC;AA7DD,4CAA8B;AAC9B,gDAAkC;AAIlC,6EAA6E;AAChE,QAAA,gBAAgB,GAAG,WAAW,CAAC;AAE5C;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,WAAmB,EAAE,QAAgB;IACpE,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,wBAAgB,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;AAC9F,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,WAAmB,EAAE,QAAgB;IAChE,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB,CAAC;QACxD,IACE,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;YACnC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAC7B,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAiB;YAChC,SAAS,EAAE,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;SACxE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,WAAmB,EAAE,QAAgB,EAAE,MAAe;IAClF,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,OAAO,GAAa;QACxB,QAAQ;QACR,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AAC1E,CAAC;AAED,8CAA8C;AACjC,QAAA,oBAAoB,GAAG;IAClC,gBAAgB,EAAhB,wBAAgB;CACjB,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assemble phase — source real parameter values for each endpoint and write
|
|
3
|
+
* them into the `.bru` `body:json` block.
|
|
4
|
+
*
|
|
5
|
+
* Spec contract (T-40): three-tier fallback per endpoint:
|
|
6
|
+
* 1. fixture hit → use `fixtures[<svc_id>_<methodName>]`.params verbatim.
|
|
7
|
+
* 2. db-query → for each Field with `sourceTable`, run
|
|
8
|
+
* `cgraphx db query --sql "SELECT ... LIMIT 1" --format json`
|
|
9
|
+
* via the dist binary (subprocess). `literal` fields are
|
|
10
|
+
* filled directly; `fixtureOnly` fields require a fixture
|
|
11
|
+
* (else the endpoint is skip).
|
|
12
|
+
* 3. skip → db-query CLI failure → `db_query_failed`;
|
|
13
|
+
* any field missing source/literal/fixture → `assemble_failed`.
|
|
14
|
+
*
|
|
15
|
+
* Independent subsystem — does NOT import from `src/dbquery/`. The db-query
|
|
16
|
+
* CLI is invoked as a subprocess (subsystem isolation per spec §12). The
|
|
17
|
+
* subprocess wrapper lives in `./db-query-cli.ts` so tests can `vi.spyOn`
|
|
18
|
+
* the export and intercept calls from this module.
|
|
19
|
+
*
|
|
20
|
+
* Public surface:
|
|
21
|
+
* - `assembleEndpoint(endpoint, config, fixtures, projectRoot)`
|
|
22
|
+
* → `{ body, skipped, reason }`
|
|
23
|
+
* - `writeBruBody(bruPath, body)` — patches a `.bru` file's `body:json` block.
|
|
24
|
+
* - `replaceBodyJsonBlock(bruContent, newBody)` — pure-string transform.
|
|
25
|
+
* - re-exports `runDbQueryCli` / `DbQueryResult` from `./db-query-cli` so
|
|
26
|
+
* callers can import everything from one place.
|
|
27
|
+
*/
|
|
28
|
+
import type { ApiTestConfig, Endpoint, Field, Fixtures } from './types';
|
|
29
|
+
import { runDbQueryCli, type DbQueryResult } from './db-query-cli';
|
|
30
|
+
export { runDbQueryCli, type DbQueryResult };
|
|
31
|
+
/** Outcome of assembling one endpoint. */
|
|
32
|
+
export interface AssembleResult {
|
|
33
|
+
/** JSON string ready to drop into a `.bru` `body:json` block. Empty when `skipped`. */
|
|
34
|
+
body: string;
|
|
35
|
+
skipped: boolean;
|
|
36
|
+
reason: string | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Assemble the request body for one endpoint following the three-tier
|
|
40
|
+
* fallback: fixture > db-query > skip.
|
|
41
|
+
*
|
|
42
|
+
* Fixture key: `<svc_id>_<methodName>` (matches the `.bru` filename stem).
|
|
43
|
+
* Fixture `params` is used verbatim as the body array (positional per
|
|
44
|
+
* method-declaration order).
|
|
45
|
+
*
|
|
46
|
+
* For db-query sourcing, fields are grouped by `paramIndex` and one object
|
|
47
|
+
* per param is emitted (in paramIndex order). The body is always a JSON
|
|
48
|
+
* array — `[{...param0}, {...param1}, ...]`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function assembleEndpoint(endpoint: Endpoint, _config: ApiTestConfig, fixtures: Fixtures, projectRoot: string): Promise<AssembleResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Build the `SELECT ... FROM ... WHERE ... LIMIT 1` SQL for a db-query-sourced
|
|
53
|
+
* field. `sourceFilter` is optional; `sourceColumn` and `sourceTable` are
|
|
54
|
+
* required (caller guards).
|
|
55
|
+
*/
|
|
56
|
+
declare function buildSourceSql(field: Field): string;
|
|
57
|
+
/**
|
|
58
|
+
* Patch a `.bru` file's `body:json` block content in place. Reads the file,
|
|
59
|
+
* replaces whatever is between `body:json {` and the matching closing `}`,
|
|
60
|
+
* and writes it back. Preserves the rest of the file verbatim.
|
|
61
|
+
*
|
|
62
|
+
* Returns the new content (also written to disk). Caller is responsible for
|
|
63
|
+
* the file existing.
|
|
64
|
+
*/
|
|
65
|
+
export declare function writeBruBody(bruPath: string, body: string): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Pure-string transform: replace the inner content of the `body:json { ... }`
|
|
68
|
+
* block in a `.bru` file. If the block can't be located, returns the input
|
|
69
|
+
* unchanged (defensive — scan phase always emits one).
|
|
70
|
+
*/
|
|
71
|
+
export declare function replaceBodyJsonBlock(bruContent: string, newBody: string): string;
|
|
72
|
+
/** Internal helpers re-exported for tests. */
|
|
73
|
+
export declare const __INTERNAL_ASSEMBLE: {
|
|
74
|
+
buildSourceSql: typeof buildSourceSql;
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=assemble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/api-test/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,KAAK,EACL,QAAQ,EACT,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,CAAC;AAE7C,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAyEzB;AAED;;;;GAIG;AACH,iBAAS,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAG5C;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKjF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIhF;AAED,8CAA8C;AAC9C,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Assemble phase — source real parameter values for each endpoint and write
|
|
4
|
+
* them into the `.bru` `body:json` block.
|
|
5
|
+
*
|
|
6
|
+
* Spec contract (T-40): three-tier fallback per endpoint:
|
|
7
|
+
* 1. fixture hit → use `fixtures[<svc_id>_<methodName>]`.params verbatim.
|
|
8
|
+
* 2. db-query → for each Field with `sourceTable`, run
|
|
9
|
+
* `cgraphx db query --sql "SELECT ... LIMIT 1" --format json`
|
|
10
|
+
* via the dist binary (subprocess). `literal` fields are
|
|
11
|
+
* filled directly; `fixtureOnly` fields require a fixture
|
|
12
|
+
* (else the endpoint is skip).
|
|
13
|
+
* 3. skip → db-query CLI failure → `db_query_failed`;
|
|
14
|
+
* any field missing source/literal/fixture → `assemble_failed`.
|
|
15
|
+
*
|
|
16
|
+
* Independent subsystem — does NOT import from `src/dbquery/`. The db-query
|
|
17
|
+
* CLI is invoked as a subprocess (subsystem isolation per spec §12). The
|
|
18
|
+
* subprocess wrapper lives in `./db-query-cli.ts` so tests can `vi.spyOn`
|
|
19
|
+
* the export and intercept calls from this module.
|
|
20
|
+
*
|
|
21
|
+
* Public surface:
|
|
22
|
+
* - `assembleEndpoint(endpoint, config, fixtures, projectRoot)`
|
|
23
|
+
* → `{ body, skipped, reason }`
|
|
24
|
+
* - `writeBruBody(bruPath, body)` — patches a `.bru` file's `body:json` block.
|
|
25
|
+
* - `replaceBodyJsonBlock(bruContent, newBody)` — pure-string transform.
|
|
26
|
+
* - re-exports `runDbQueryCli` / `DbQueryResult` from `./db-query-cli` so
|
|
27
|
+
* callers can import everything from one place.
|
|
28
|
+
*/
|
|
29
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
33
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(o, k2, desc);
|
|
36
|
+
}) : (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
o[k2] = m[k];
|
|
39
|
+
}));
|
|
40
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
41
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
42
|
+
}) : function(o, v) {
|
|
43
|
+
o["default"] = v;
|
|
44
|
+
});
|
|
45
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
46
|
+
var ownKeys = function(o) {
|
|
47
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
48
|
+
var ar = [];
|
|
49
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
50
|
+
return ar;
|
|
51
|
+
};
|
|
52
|
+
return ownKeys(o);
|
|
53
|
+
};
|
|
54
|
+
return function (mod) {
|
|
55
|
+
if (mod && mod.__esModule) return mod;
|
|
56
|
+
var result = {};
|
|
57
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
58
|
+
__setModuleDefault(result, mod);
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
})();
|
|
62
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
63
|
+
exports.__INTERNAL_ASSEMBLE = exports.runDbQueryCli = void 0;
|
|
64
|
+
exports.assembleEndpoint = assembleEndpoint;
|
|
65
|
+
exports.writeBruBody = writeBruBody;
|
|
66
|
+
exports.replaceBodyJsonBlock = replaceBodyJsonBlock;
|
|
67
|
+
const fs = __importStar(require("node:fs"));
|
|
68
|
+
const db_query_cli_1 = require("./db-query-cli");
|
|
69
|
+
Object.defineProperty(exports, "runDbQueryCli", { enumerable: true, get: function () { return db_query_cli_1.runDbQueryCli; } });
|
|
70
|
+
/**
|
|
71
|
+
* Assemble the request body for one endpoint following the three-tier
|
|
72
|
+
* fallback: fixture > db-query > skip.
|
|
73
|
+
*
|
|
74
|
+
* Fixture key: `<svc_id>_<methodName>` (matches the `.bru` filename stem).
|
|
75
|
+
* Fixture `params` is used verbatim as the body array (positional per
|
|
76
|
+
* method-declaration order).
|
|
77
|
+
*
|
|
78
|
+
* For db-query sourcing, fields are grouped by `paramIndex` and one object
|
|
79
|
+
* per param is emitted (in paramIndex order). The body is always a JSON
|
|
80
|
+
* array — `[{...param0}, {...param1}, ...]`.
|
|
81
|
+
*/
|
|
82
|
+
async function assembleEndpoint(endpoint, _config, fixtures, projectRoot) {
|
|
83
|
+
const fixtureKey = `${endpoint.svcId}_${endpoint.method}`;
|
|
84
|
+
const fixture = fixtures[fixtureKey];
|
|
85
|
+
// ─── Priority 1: fixture hit ────────────────────────────────────────────
|
|
86
|
+
if (fixture) {
|
|
87
|
+
const body = JSON.stringify(fixture.params);
|
|
88
|
+
return { body, skipped: false, reason: null };
|
|
89
|
+
}
|
|
90
|
+
// ─── Priority 2: db-query ───────────────────────────────────────────────
|
|
91
|
+
// No fields → can't assemble (the analyze phase either skipped or produced
|
|
92
|
+
// nothing). Mark `assemble_failed` so the .md reflects it.
|
|
93
|
+
if (endpoint.fields.length === 0) {
|
|
94
|
+
return { body: '', skipped: true, reason: 'assemble_failed' };
|
|
95
|
+
}
|
|
96
|
+
// fixtureOnly fields require a fixture (which we don't have here).
|
|
97
|
+
for (const f of endpoint.fields) {
|
|
98
|
+
if (f.fixtureOnly) {
|
|
99
|
+
return { body: '', skipped: true, reason: 'assemble_failed' };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Group fields by paramIndex (one body object per method parameter).
|
|
103
|
+
const paramGroups = new Map();
|
|
104
|
+
for (const f of endpoint.fields) {
|
|
105
|
+
const arr = paramGroups.get(f.paramIndex) ?? [];
|
|
106
|
+
arr.push(f);
|
|
107
|
+
paramGroups.set(f.paramIndex, arr);
|
|
108
|
+
}
|
|
109
|
+
const paramIndices = [...paramGroups.keys()].sort((a, b) => a - b);
|
|
110
|
+
const bodyArray = [];
|
|
111
|
+
for (const idx of paramIndices) {
|
|
112
|
+
const fields = paramGroups.get(idx);
|
|
113
|
+
const paramObj = {};
|
|
114
|
+
for (const f of fields) {
|
|
115
|
+
// literal — fill directly.
|
|
116
|
+
if (f.literal !== null) {
|
|
117
|
+
paramObj[f.name] = f.literal;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
// db-query sourced field.
|
|
121
|
+
if (f.sourceTable && f.sourceColumn) {
|
|
122
|
+
const sql = buildSourceSql(f);
|
|
123
|
+
const result = await (0, db_query_cli_1.runDbQueryCli)(sql, projectRoot);
|
|
124
|
+
if (!result.ok) {
|
|
125
|
+
return { body: '', skipped: true, reason: 'db_query_failed' };
|
|
126
|
+
}
|
|
127
|
+
const row = result.rows[0];
|
|
128
|
+
if (!row) {
|
|
129
|
+
// Query succeeded but returned no rows — field value can't be sourced.
|
|
130
|
+
return { body: '', skipped: true, reason: 'assemble_failed' };
|
|
131
|
+
}
|
|
132
|
+
const value = row[f.sourceColumn];
|
|
133
|
+
if (value === undefined || value === null) {
|
|
134
|
+
return { body: '', skipped: true, reason: 'assemble_failed' };
|
|
135
|
+
}
|
|
136
|
+
paramObj[f.name] = value;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// No source, no literal, no fixture → can't source this field.
|
|
140
|
+
return { body: '', skipped: true, reason: 'assemble_failed' };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
bodyArray.push(paramObj);
|
|
144
|
+
}
|
|
145
|
+
return { body: JSON.stringify(bodyArray), skipped: false, reason: null };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Build the `SELECT ... FROM ... WHERE ... LIMIT 1` SQL for a db-query-sourced
|
|
149
|
+
* field. `sourceFilter` is optional; `sourceColumn` and `sourceTable` are
|
|
150
|
+
* required (caller guards).
|
|
151
|
+
*/
|
|
152
|
+
function buildSourceSql(field) {
|
|
153
|
+
const filter = field.sourceFilter ? ` WHERE ${field.sourceFilter}` : '';
|
|
154
|
+
return `SELECT ${field.sourceColumn} FROM ${field.sourceTable}${filter} LIMIT 1`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Patch a `.bru` file's `body:json` block content in place. Reads the file,
|
|
158
|
+
* replaces whatever is between `body:json {` and the matching closing `}`,
|
|
159
|
+
* and writes it back. Preserves the rest of the file verbatim.
|
|
160
|
+
*
|
|
161
|
+
* Returns the new content (also written to disk). Caller is responsible for
|
|
162
|
+
* the file existing.
|
|
163
|
+
*/
|
|
164
|
+
async function writeBruBody(bruPath, body) {
|
|
165
|
+
const content = await fs.promises.readFile(bruPath, 'utf8');
|
|
166
|
+
const updated = replaceBodyJsonBlock(content, body);
|
|
167
|
+
await fs.promises.writeFile(bruPath, updated, 'utf8');
|
|
168
|
+
return updated;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Pure-string transform: replace the inner content of the `body:json { ... }`
|
|
172
|
+
* block in a `.bru` file. If the block can't be located, returns the input
|
|
173
|
+
* unchanged (defensive — scan phase always emits one).
|
|
174
|
+
*/
|
|
175
|
+
function replaceBodyJsonBlock(bruContent, newBody) {
|
|
176
|
+
const re = /(body:json\s*\{\n)([\s\S]*?)(\n\})/;
|
|
177
|
+
if (!re.test(bruContent))
|
|
178
|
+
return bruContent;
|
|
179
|
+
return bruContent.replace(re, `$1 ${newBody}$3`);
|
|
180
|
+
}
|
|
181
|
+
/** Internal helpers re-exported for tests. */
|
|
182
|
+
exports.__INTERNAL_ASSEMBLE = {
|
|
183
|
+
buildSourceSql,
|
|
184
|
+
};
|
|
185
|
+
//# sourceMappingURL=assemble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/api-test/assemble.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bruno CLI subprocess invoker — isolated in its own module so tests can
|
|
3
|
+
* `vi.spyOn` the `invokeBrunoCli` export and intercept calls from
|
|
4
|
+
* `bru-runner.ts`.
|
|
5
|
+
*
|
|
6
|
+
* Why a separate module: same reason as `db-query-cli.ts` — when the
|
|
7
|
+
* subprocess call lives in the same module as its caller, vitest's
|
|
8
|
+
* `vi.spyOn(module, 'fn')` cannot intercept the internal bare-local-binding
|
|
9
|
+
* call. Cross-module imports route through the namespace, which the spy CAN
|
|
10
|
+
* replace.
|
|
11
|
+
*
|
|
12
|
+
* Independent subsystem — does NOT import from `src/extraction/` /
|
|
13
|
+
* `src/resolution/` / `src/db/`. The Bruno CLI is invoked as a subprocess
|
|
14
|
+
* (spec §12 isolation).
|
|
15
|
+
*/
|
|
16
|
+
/** Result of one Bruno CLI invocation. */
|
|
17
|
+
export interface BrunoCliInvocation {
|
|
18
|
+
/** Combined stdout from the subprocess. */
|
|
19
|
+
stdout: string;
|
|
20
|
+
/** Combined stderr from the subprocess. */
|
|
21
|
+
stderr: string;
|
|
22
|
+
/** Process exit code (null if the process was killed by signal). */
|
|
23
|
+
exitCode: number | null;
|
|
24
|
+
/** True when the subprocess was killed by the timeout. */
|
|
25
|
+
timedOut: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface InvokeBrunoCliOptions {
|
|
28
|
+
/** Working directory for the subprocess. */
|
|
29
|
+
cwd: string;
|
|
30
|
+
/** Hard kill timeout in milliseconds. */
|
|
31
|
+
timeoutMs: number;
|
|
32
|
+
/** Max stdout/stderr buffer size in bytes (default 10 MB). */
|
|
33
|
+
maxBuffer?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Invoke `npx @usebruno/cli` with the given args. Returns the captured
|
|
37
|
+
* stdout/stderr/exitCode. The caller is responsible for arg construction
|
|
38
|
+
* (see `bru-runner.ts`).
|
|
39
|
+
*
|
|
40
|
+
* Exported so tests can `vi.spyOn(bruCliInvoker, 'invokeBrunoCli')` instead
|
|
41
|
+
* of spawning a real subprocess / real Bruno CLI.
|
|
42
|
+
*/
|
|
43
|
+
export declare function invokeBrunoCli(args: string[], options: InvokeBrunoCliOptions): BrunoCliInvocation;
|
|
44
|
+
/**
|
|
45
|
+
* Probe whether the Bruno CLI is available. Tries, in order:
|
|
46
|
+
* 1. `npx @usebruno/cli --version` (preferred — always works if npm cache
|
|
47
|
+
* has the package, even without global install).
|
|
48
|
+
* 2. Global `bru` command (`which bru`).
|
|
49
|
+
* 3. Global `bruno` command (`which bruno`).
|
|
50
|
+
*
|
|
51
|
+
* Returns the resolved command + base args for subsequent `invokeBrunoCli`
|
|
52
|
+
* calls, or `null` when no Bruno CLI is reachable.
|
|
53
|
+
*
|
|
54
|
+
* Exported so tests can spy on it to simulate "Bruno CLI unavailable".
|
|
55
|
+
*/
|
|
56
|
+
export declare function detectBrunoCli(): {
|
|
57
|
+
command: string;
|
|
58
|
+
baseArgs: string[];
|
|
59
|
+
} | null;
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the collection directory. If `filter.service` is set, narrow to
|
|
62
|
+
* `<collectionDir>/<service>/` when it exists; otherwise fall back to the
|
|
63
|
+
* whole collection dir (Bruno CLI will just find no matching requests).
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveCollectionDir(collectionDir: string, filter?: {
|
|
66
|
+
service?: string;
|
|
67
|
+
}): string;
|
|
68
|
+
/** Internal helper re-exported for tests. */
|
|
69
|
+
export declare const __INTERNAL_BRU_CLI_INVOKER: {
|
|
70
|
+
resolveCollectionDir: typeof resolveCollectionDir;
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=bru-cli-invoker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bru-cli-invoker.d.ts","sourceRoot":"","sources":["../../src/api-test/bru-cli-invoker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qBAAqB,GAC7B,kBAAkB,CA2BpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CA8C/E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,MAAM,CAQR;AAED,6CAA6C;AAC7C,eAAO,MAAM,0BAA0B;;CAEtC,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bruno CLI subprocess invoker — isolated in its own module so tests can
|
|
4
|
+
* `vi.spyOn` the `invokeBrunoCli` export and intercept calls from
|
|
5
|
+
* `bru-runner.ts`.
|
|
6
|
+
*
|
|
7
|
+
* Why a separate module: same reason as `db-query-cli.ts` — when the
|
|
8
|
+
* subprocess call lives in the same module as its caller, vitest's
|
|
9
|
+
* `vi.spyOn(module, 'fn')` cannot intercept the internal bare-local-binding
|
|
10
|
+
* call. Cross-module imports route through the namespace, which the spy CAN
|
|
11
|
+
* replace.
|
|
12
|
+
*
|
|
13
|
+
* Independent subsystem — does NOT import from `src/extraction/` /
|
|
14
|
+
* `src/resolution/` / `src/db/`. The Bruno CLI is invoked as a subprocess
|
|
15
|
+
* (spec §12 isolation).
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.__INTERNAL_BRU_CLI_INVOKER = void 0;
|
|
52
|
+
exports.invokeBrunoCli = invokeBrunoCli;
|
|
53
|
+
exports.detectBrunoCli = detectBrunoCli;
|
|
54
|
+
exports.resolveCollectionDir = resolveCollectionDir;
|
|
55
|
+
const node_child_process_1 = require("node:child_process");
|
|
56
|
+
const fs = __importStar(require("node:fs"));
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
58
|
+
/**
|
|
59
|
+
* Invoke `npx @usebruno/cli` with the given args. Returns the captured
|
|
60
|
+
* stdout/stderr/exitCode. The caller is responsible for arg construction
|
|
61
|
+
* (see `bru-runner.ts`).
|
|
62
|
+
*
|
|
63
|
+
* Exported so tests can `vi.spyOn(bruCliInvoker, 'invokeBrunoCli')` instead
|
|
64
|
+
* of spawning a real subprocess / real Bruno CLI.
|
|
65
|
+
*/
|
|
66
|
+
function invokeBrunoCli(args, options) {
|
|
67
|
+
const maxBuffer = options.maxBuffer ?? 10 * 1024 * 1024;
|
|
68
|
+
try {
|
|
69
|
+
const result = (0, node_child_process_1.spawnSync)(process.execPath, args, {
|
|
70
|
+
cwd: options.cwd,
|
|
71
|
+
encoding: 'utf8',
|
|
72
|
+
timeout: options.timeoutMs,
|
|
73
|
+
maxBuffer,
|
|
74
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
stdout: typeof result.stdout === 'string' ? result.stdout : '',
|
|
78
|
+
stderr: typeof result.stderr === 'string' ? result.stderr : '',
|
|
79
|
+
exitCode: result.status,
|
|
80
|
+
timedOut: result.signal === 'SIGTERM' || (result.signal != null && result.signal !== null),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
// spawnSync throws on ENOENT (node binary not found — shouldn't happen)
|
|
85
|
+
// or other spawn-level failures. Normalize to a non-zero exit.
|
|
86
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
87
|
+
return {
|
|
88
|
+
stdout: '',
|
|
89
|
+
stderr: `spawn failed: ${msg}`,
|
|
90
|
+
exitCode: 1,
|
|
91
|
+
timedOut: false,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Probe whether the Bruno CLI is available. Tries, in order:
|
|
97
|
+
* 1. `npx @usebruno/cli --version` (preferred — always works if npm cache
|
|
98
|
+
* has the package, even without global install).
|
|
99
|
+
* 2. Global `bru` command (`which bru`).
|
|
100
|
+
* 3. Global `bruno` command (`which bruno`).
|
|
101
|
+
*
|
|
102
|
+
* Returns the resolved command + base args for subsequent `invokeBrunoCli`
|
|
103
|
+
* calls, or `null` when no Bruno CLI is reachable.
|
|
104
|
+
*
|
|
105
|
+
* Exported so tests can spy on it to simulate "Bruno CLI unavailable".
|
|
106
|
+
*/
|
|
107
|
+
function detectBrunoCli() {
|
|
108
|
+
// 1. npx @usebruno/cli --version (short timeout — npx may need to fetch).
|
|
109
|
+
const probe = (0, node_child_process_1.spawnSync)(process.execPath, ['@usebruno/cli', '--version'], {
|
|
110
|
+
encoding: 'utf8',
|
|
111
|
+
timeout: 30_000,
|
|
112
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
113
|
+
});
|
|
114
|
+
if (probe.status === 0 && probe.stdout.trim().length > 0) {
|
|
115
|
+
return { command: process.execPath, baseArgs: ['@usebruno/cli'] };
|
|
116
|
+
}
|
|
117
|
+
// npx wraps @usebruno/cli; the direct `node @usebruno/cli` form above only
|
|
118
|
+
// resolves when the package is installed locally. Use `npx` explicitly so
|
|
119
|
+
// the package is fetched on demand.
|
|
120
|
+
const npxProbe = (0, node_child_process_1.spawnSync)('npx', ['@usebruno/cli', '--version'], {
|
|
121
|
+
encoding: 'utf8',
|
|
122
|
+
timeout: 30_000,
|
|
123
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
124
|
+
shell: process.platform === 'win32',
|
|
125
|
+
});
|
|
126
|
+
if (npxProbe.status === 0 && npxProbe.stdout.trim().length > 0) {
|
|
127
|
+
return { command: 'npx', baseArgs: ['@usebruno/cli'] };
|
|
128
|
+
}
|
|
129
|
+
// 2. Global `bru` command.
|
|
130
|
+
const bruProbe = (0, node_child_process_1.spawnSync)('bru', ['--version'], {
|
|
131
|
+
encoding: 'utf8',
|
|
132
|
+
timeout: 5_000,
|
|
133
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
134
|
+
shell: process.platform === 'win32',
|
|
135
|
+
});
|
|
136
|
+
if (bruProbe.status === 0 && bruProbe.stdout.trim().length > 0) {
|
|
137
|
+
return { command: 'bru', baseArgs: [] };
|
|
138
|
+
}
|
|
139
|
+
// 3. Global `bruno` command.
|
|
140
|
+
const brunoProbe = (0, node_child_process_1.spawnSync)('bruno', ['--version'], {
|
|
141
|
+
encoding: 'utf8',
|
|
142
|
+
timeout: 5_000,
|
|
143
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
144
|
+
shell: process.platform === 'win32',
|
|
145
|
+
});
|
|
146
|
+
if (brunoProbe.status === 0 && brunoProbe.stdout.trim().length > 0) {
|
|
147
|
+
return { command: 'bruno', baseArgs: [] };
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the collection directory. If `filter.service` is set, narrow to
|
|
153
|
+
* `<collectionDir>/<service>/` when it exists; otherwise fall back to the
|
|
154
|
+
* whole collection dir (Bruno CLI will just find no matching requests).
|
|
155
|
+
*/
|
|
156
|
+
function resolveCollectionDir(collectionDir, filter) {
|
|
157
|
+
if (filter?.service) {
|
|
158
|
+
const sub = path.join(collectionDir, filter.service);
|
|
159
|
+
if (fs.existsSync(sub) && fs.statSync(sub).isDirectory()) {
|
|
160
|
+
return sub;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return collectionDir;
|
|
164
|
+
}
|
|
165
|
+
/** Internal helper re-exported for tests. */
|
|
166
|
+
exports.__INTERNAL_BRU_CLI_INVOKER = {
|
|
167
|
+
resolveCollectionDir,
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=bru-cli-invoker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bru-cli-invoker.js","sourceRoot":"","sources":["../../src/api-test/bru-cli-invoker.ts"],"names":[],"mappings":"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"}
|