@agentbridge1/cli 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +4 -4
- package/dist/commands/start.js +1 -0
- package/dist/commands/watch.js +3 -2
- package/dist/contract-intelligence.js +597 -0
- package/dist/contract-verdict.js +79 -26
- package/dist/diff-reader.js +200 -0
- package/dist/intent-parser.js +178 -0
- package/dist/mcp/agentbridge-mcp.js +585 -27
- package/dist/mcp/agentbridge-mcp.js.map +4 -4
- package/dist/proof-parser.js +118 -0
- package/dist/session-state.js +15 -0
- package/dist/session.js +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Proof output parser — reads proofRun.stdoutExcerpt for structured test results.
|
|
4
|
+
* Supports vitest, jest, mocha. All logic is deterministic regex.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parseProofOutput = parseProofOutput;
|
|
8
|
+
exports.proofEvidenceString = proofEvidenceString;
|
|
9
|
+
const DOMAIN_TEST_KEYWORDS = {
|
|
10
|
+
auth: ["auth", "login", "logout", "session", "token", "password", "oauth", "signin", "signup"],
|
|
11
|
+
database: ["db", "database", "prisma", "migration", "schema", "query", "model"],
|
|
12
|
+
api: ["api", "route", "endpoint", "handler", "request", "response"],
|
|
13
|
+
payments: ["payment", "billing", "stripe", "invoice", "webhook", "subscription"],
|
|
14
|
+
mcp: ["mcp", "setup", "rules", "config", "agentbridge"],
|
|
15
|
+
ui: ["component", "render", "view", "style", "page", "layout"],
|
|
16
|
+
tests: ["test", "spec"],
|
|
17
|
+
};
|
|
18
|
+
// Vitest / Jest summary: "12 passed", "Tests: 5 passed", "5 failed"
|
|
19
|
+
const PASSED_RE = /(\d+)\s+passed/i;
|
|
20
|
+
const FAILED_RE = /(\d+)\s+failed/i;
|
|
21
|
+
const SKIPPED_RE = /(\d+)\s+skipped/i;
|
|
22
|
+
// Jest alternative: "Tests: 5 passed, 1 failed, 6 total"
|
|
23
|
+
const JEST_SUMMARY_RE = /Tests:\s+(?:(\d+)\s+skipped,\s*)?(?:(\d+)\s+passed)?(?:,\s*(\d+)\s+failed)?/i;
|
|
24
|
+
// Test name lines — vitest uses ✓/✗, jest uses ✓/×/✕, some use √
|
|
25
|
+
const PASS_NAME_RE = /^\s*[✓√]\s+(.+)/;
|
|
26
|
+
const FAIL_NAME_RE = /^\s*[✗×✕✘]\s+(.+)/;
|
|
27
|
+
// Vitest detection: output contains "Test Files" or "Duration" or vitest version header
|
|
28
|
+
const VITEST_DETECT_RE = /Test Files|vitest|v\d+\.\d+\.\d+.*vitest/i;
|
|
29
|
+
// Jest detection
|
|
30
|
+
const JEST_DETECT_RE = /PASS|FAIL|jest|Tests:/;
|
|
31
|
+
// Mocha
|
|
32
|
+
const MOCHA_DETECT_RE = /passing|failing|pending.*mocha/i;
|
|
33
|
+
function detectRunner(stdout) {
|
|
34
|
+
if (VITEST_DETECT_RE.test(stdout))
|
|
35
|
+
return "vitest";
|
|
36
|
+
if (JEST_DETECT_RE.test(stdout))
|
|
37
|
+
return "jest";
|
|
38
|
+
if (MOCHA_DETECT_RE.test(stdout))
|
|
39
|
+
return "mocha";
|
|
40
|
+
return "unknown";
|
|
41
|
+
}
|
|
42
|
+
function extractDomainKeywords(testNames) {
|
|
43
|
+
const found = new Set();
|
|
44
|
+
const lower = testNames.join(" ").toLowerCase();
|
|
45
|
+
for (const [domain, keywords] of Object.entries(DOMAIN_TEST_KEYWORDS)) {
|
|
46
|
+
if (keywords.some((kw) => lower.includes(kw)))
|
|
47
|
+
found.add(domain);
|
|
48
|
+
}
|
|
49
|
+
return [...found];
|
|
50
|
+
}
|
|
51
|
+
function hasDomainCoverage(domain, domainKeywordsInPassed) {
|
|
52
|
+
const aliases = {
|
|
53
|
+
auth: ["auth"],
|
|
54
|
+
database: ["database"],
|
|
55
|
+
api: ["api"],
|
|
56
|
+
payments: ["payments"],
|
|
57
|
+
mcp: ["mcp"],
|
|
58
|
+
ui: ["ui"],
|
|
59
|
+
};
|
|
60
|
+
const check = aliases[domain] ?? [domain];
|
|
61
|
+
return check.some((alias) => domainKeywordsInPassed.includes(alias));
|
|
62
|
+
}
|
|
63
|
+
function parseProofOutput(proofRun) {
|
|
64
|
+
const stdout = proofRun.stdoutExcerpt ?? "";
|
|
65
|
+
const lines = stdout.split("\n");
|
|
66
|
+
const runner = detectRunner(stdout);
|
|
67
|
+
let passed = 0;
|
|
68
|
+
let failed = 0;
|
|
69
|
+
let skipped = 0;
|
|
70
|
+
const test_names_passed = [];
|
|
71
|
+
const test_names_failed = [];
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
// Count summary
|
|
74
|
+
const pm = PASSED_RE.exec(line);
|
|
75
|
+
if (pm)
|
|
76
|
+
passed = Math.max(passed, parseInt(pm[1], 10));
|
|
77
|
+
const fm = FAILED_RE.exec(line);
|
|
78
|
+
if (fm)
|
|
79
|
+
failed = Math.max(failed, parseInt(fm[1], 10));
|
|
80
|
+
const sm = SKIPPED_RE.exec(line);
|
|
81
|
+
if (sm)
|
|
82
|
+
skipped = Math.max(skipped, parseInt(sm[1], 10));
|
|
83
|
+
// Named test lines
|
|
84
|
+
const passName = PASS_NAME_RE.exec(line);
|
|
85
|
+
if (passName)
|
|
86
|
+
test_names_passed.push(passName[1].trim());
|
|
87
|
+
const failName = FAIL_NAME_RE.exec(line);
|
|
88
|
+
if (failName)
|
|
89
|
+
test_names_failed.push(failName[1].trim());
|
|
90
|
+
}
|
|
91
|
+
const domain_keywords_in_passed = extractDomainKeywords(test_names_passed);
|
|
92
|
+
return {
|
|
93
|
+
runner,
|
|
94
|
+
passed,
|
|
95
|
+
failed,
|
|
96
|
+
skipped,
|
|
97
|
+
test_names_passed,
|
|
98
|
+
test_names_failed,
|
|
99
|
+
domain_keywords_in_passed,
|
|
100
|
+
has_domain_coverage: (domain) => hasDomainCoverage(domain, domain_keywords_in_passed),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Builds a human-readable evidence string from a parsed proof, for use in criterion evaluation.
|
|
105
|
+
*/
|
|
106
|
+
function proofEvidenceString(parsed, domain) {
|
|
107
|
+
const total = parsed.passed + parsed.failed + parsed.skipped;
|
|
108
|
+
const base = `Proof run ${parsed.failed > 0 ? "failed" : "passed"} (${parsed.passed}/${total} tests passed).`;
|
|
109
|
+
if (domain && parsed.passed > 0) {
|
|
110
|
+
if (parsed.has_domain_coverage(domain)) {
|
|
111
|
+
const covering = parsed.domain_keywords_in_passed.join(", ");
|
|
112
|
+
return `${base} Tests covering: ${covering}.`;
|
|
113
|
+
}
|
|
114
|
+
const keywords = DOMAIN_TEST_KEYWORDS[domain]?.slice(0, 3).join(", ") ?? domain;
|
|
115
|
+
return `${base} No passed tests mention ${keywords} — domain coverage unconfirmed.`;
|
|
116
|
+
}
|
|
117
|
+
return base;
|
|
118
|
+
}
|
package/dist/session-state.js
CHANGED
|
@@ -130,6 +130,21 @@ function isLocalSessionState(value) {
|
|
|
130
130
|
return false;
|
|
131
131
|
if (value.claimedPaths !== undefined && !isStringArray(value.claimedPaths))
|
|
132
132
|
return false;
|
|
133
|
+
if (value.createdBy !== undefined && value.createdBy !== "user_start" && value.createdBy !== "agent_hello") {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (value.contractProfiles !== undefined && !isStringArray(value.contractProfiles))
|
|
137
|
+
return false;
|
|
138
|
+
if (value.expectedSurfaces !== undefined && !isStringArray(value.expectedSurfaces))
|
|
139
|
+
return false;
|
|
140
|
+
if (value.expectedFileAreas !== undefined && !isStringArray(value.expectedFileAreas))
|
|
141
|
+
return false;
|
|
142
|
+
if (value.completionCriteria !== undefined && !isStringArray(value.completionCriteria))
|
|
143
|
+
return false;
|
|
144
|
+
if (value.proofNeeded !== undefined && !isStringArray(value.proofNeeded))
|
|
145
|
+
return false;
|
|
146
|
+
if (value.riskyOmissions !== undefined && !isStringArray(value.riskyOmissions))
|
|
147
|
+
return false;
|
|
133
148
|
if (value.lastLocalVerificationRun !== undefined &&
|
|
134
149
|
!(0, local_proof_1.isLocalVerificationRun)(value.lastLocalVerificationRun)) {
|
|
135
150
|
return false;
|
package/dist/session.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.openLocalSession = openLocalSession;
|
|
|
6
6
|
exports.closeLocalSession = closeLocalSession;
|
|
7
7
|
const node_child_process_1 = require("node:child_process");
|
|
8
8
|
const http_1 = require("./http");
|
|
9
|
+
const contract_intelligence_1 = require("./contract-intelligence");
|
|
9
10
|
const session_state_1 = require("./session-state");
|
|
10
11
|
const watch_core_1 = require("./watch-core");
|
|
11
12
|
const file_fingerprints_1 = require("./file-fingerprints");
|
|
@@ -54,11 +55,20 @@ function openLocalSession(input) {
|
|
|
54
55
|
const claimedPaths = [...new Set((input.claimedPaths ?? []).map((path) => path.trim()).filter(Boolean))];
|
|
55
56
|
const baseline = captureLocalSessionBaseline();
|
|
56
57
|
const now = baseline.startedAt;
|
|
58
|
+
const createdBy = input.createdBy ?? (input.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
59
|
+
const contract = (0, contract_intelligence_1.buildContractIntelligence)(input.intent?.trim(), createdBy);
|
|
57
60
|
const state = {
|
|
58
61
|
id: `local_${Date.now().toString(36)}`,
|
|
59
62
|
agentId: input.agentId?.trim() || "local",
|
|
60
63
|
laneDomain: input.laneDomain,
|
|
61
64
|
intent: input.intent?.trim() || undefined,
|
|
65
|
+
createdBy,
|
|
66
|
+
contractProfiles: contract.contractProfiles,
|
|
67
|
+
expectedSurfaces: contract.expectedSurfaces,
|
|
68
|
+
expectedFileAreas: contract.expectedFileAreas,
|
|
69
|
+
completionCriteria: contract.completionCriteria,
|
|
70
|
+
proofNeeded: contract.proofNeeded,
|
|
71
|
+
riskyOmissions: contract.riskyOmissions,
|
|
62
72
|
mode: input.mode,
|
|
63
73
|
changeRequestId: input.changeRequestId,
|
|
64
74
|
claimedPaths,
|