@agentbridge1/cli 0.0.8 → 0.0.10

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.
@@ -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
+ }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isActiveLocalSession = isActiveLocalSession;
4
+ exports.hasActiveContract = hasActiveContract;
4
5
  exports.resolveRepoRoot = resolveRepoRoot;
5
6
  exports.readSessionState = readSessionState;
6
7
  exports.writeSessionState = writeSessionState;
@@ -20,6 +21,10 @@ function isActiveLocalSession(state) {
20
21
  return false;
21
22
  return true;
22
23
  }
24
+ /** Active session with declared contract intent (local MVP scope). */
25
+ function hasActiveContract(state) {
26
+ return isActiveLocalSession(state) && Boolean(state.intent?.trim());
27
+ }
23
28
  function resolveRepoRoot() {
24
29
  return process.env.AGENTBRIDGE_REPO_ROOT?.trim() || process.cwd();
25
30
  }
@@ -130,6 +135,21 @@ function isLocalSessionState(value) {
130
135
  return false;
131
136
  if (value.claimedPaths !== undefined && !isStringArray(value.claimedPaths))
132
137
  return false;
138
+ if (value.createdBy !== undefined && value.createdBy !== "user_start" && value.createdBy !== "agent_hello") {
139
+ return false;
140
+ }
141
+ if (value.contractProfiles !== undefined && !isStringArray(value.contractProfiles))
142
+ return false;
143
+ if (value.expectedSurfaces !== undefined && !isStringArray(value.expectedSurfaces))
144
+ return false;
145
+ if (value.expectedFileAreas !== undefined && !isStringArray(value.expectedFileAreas))
146
+ return false;
147
+ if (value.completionCriteria !== undefined && !isStringArray(value.completionCriteria))
148
+ return false;
149
+ if (value.proofNeeded !== undefined && !isStringArray(value.proofNeeded))
150
+ return false;
151
+ if (value.riskyOmissions !== undefined && !isStringArray(value.riskyOmissions))
152
+ return false;
133
153
  if (value.lastLocalVerificationRun !== undefined &&
134
154
  !(0, local_proof_1.isLocalVerificationRun)(value.lastLocalVerificationRun)) {
135
155
  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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentbridge1/cli",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "CLI for AgentBridge — structured AI agent work sessions with domain authority and approval gates",
5
5
  "type": "commonjs",
6
6
  "bin": {