@praneeth_54/agentdoctor 2.0.0 → 2.0.1

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 (95) hide show
  1. package/CHANGELOG.md +73 -4
  2. package/README.md +283 -158
  3. package/dist/architecture/contract.d.ts +64 -0
  4. package/dist/architecture/contract.js +373 -0
  5. package/dist/assurance/change.d.ts +211 -0
  6. package/dist/assurance/change.js +624 -0
  7. package/dist/assurance/proof.d.ts +136 -0
  8. package/dist/assurance/proof.js +338 -0
  9. package/dist/auth/index.d.ts +81 -0
  10. package/dist/auth/index.js +130 -0
  11. package/dist/auth/rbac.d.ts +9 -0
  12. package/dist/auth/rbac.js +26 -0
  13. package/dist/cli/commands/architecture.d.ts +6 -0
  14. package/dist/cli/commands/architecture.js +109 -0
  15. package/dist/cli/commands/assurance.d.ts +67 -0
  16. package/dist/cli/commands/assurance.js +210 -0
  17. package/dist/cli/commands/complete.js +2 -2
  18. package/dist/cli/commands/platform.d.ts +2 -0
  19. package/dist/cli/commands/platform.js +5 -1
  20. package/dist/cli/commands/policy-graph-run.d.ts +40 -0
  21. package/dist/cli/commands/policy-graph-run.js +200 -0
  22. package/dist/cli/commands/workspace.d.ts +9 -0
  23. package/dist/cli/commands/workspace.js +82 -0
  24. package/dist/cli/program.js +535 -17
  25. package/dist/constants.d.ts +1 -1
  26. package/dist/constants.js +1 -1
  27. package/dist/contracts/index.d.ts +1 -1
  28. package/dist/contracts/index.js +2 -2
  29. package/dist/core/brain-product/init.js +5 -2
  30. package/dist/core/secrets/scan.d.ts +7 -1
  31. package/dist/core/secrets/scan.js +9 -9
  32. package/dist/coverage/cobertura.d.ts +6 -0
  33. package/dist/coverage/cobertura.js +52 -0
  34. package/dist/coverage/istanbul.d.ts +7 -0
  35. package/dist/coverage/istanbul.js +134 -0
  36. package/dist/coverage/lcov.d.ts +7 -0
  37. package/dist/coverage/lcov.js +59 -0
  38. package/dist/coverage/load.d.ts +9 -0
  39. package/dist/coverage/load.js +39 -0
  40. package/dist/coverage/types.d.ts +23 -0
  41. package/dist/coverage/types.js +5 -0
  42. package/dist/dashboard/server.d.ts +1 -1
  43. package/dist/dashboard/server.js +21 -5
  44. package/dist/enforcement/runner.d.ts +47 -3
  45. package/dist/enforcement/runner.js +420 -16
  46. package/dist/index.d.ts +23 -2
  47. package/dist/index.js +15 -2
  48. package/dist/intelligence/graph/build.d.ts +2 -0
  49. package/dist/intelligence/graph/build.js +49 -5
  50. package/dist/intelligence/graph/incremental.d.ts +68 -0
  51. package/dist/intelligence/graph/incremental.js +234 -0
  52. package/dist/intelligence/resolve/imports.d.ts +36 -0
  53. package/dist/intelligence/resolve/imports.js +245 -0
  54. package/dist/languages/go.d.ts +9 -0
  55. package/dist/languages/go.js +45 -0
  56. package/dist/languages/index.d.ts +11 -0
  57. package/dist/languages/index.js +76 -0
  58. package/dist/languages/php.d.ts +7 -0
  59. package/dist/languages/php.js +193 -0
  60. package/dist/languages/python.d.ts +7 -0
  61. package/dist/languages/python.js +150 -0
  62. package/dist/languages/types.d.ts +42 -0
  63. package/dist/languages/types.js +26 -0
  64. package/dist/languages/typescript.d.ts +3 -0
  65. package/dist/languages/typescript.js +95 -0
  66. package/dist/mcp/intelligence/handlers.d.ts +5 -0
  67. package/dist/mcp/intelligence/handlers.js +229 -40
  68. package/dist/mcp/intelligence/path-safety.d.ts +2 -4
  69. package/dist/mcp/intelligence/path-safety.js +25 -44
  70. package/dist/mcp/intelligence/registry.d.ts +1 -1
  71. package/dist/mcp/intelligence/registry.js +69 -1
  72. package/dist/platform/firewall/evaluate.d.ts +6 -3
  73. package/dist/platform/firewall/evaluate.js +66 -15
  74. package/dist/platform/graph/build.js +19 -23
  75. package/dist/platform/health/analyze.js +23 -17
  76. package/dist/platform/index.js +2 -0
  77. package/dist/platform/test-impact/analyze.d.ts +21 -3
  78. package/dist/platform/test-impact/analyze.js +214 -28
  79. package/dist/platform/tokens/plan.js +39 -20
  80. package/dist/platform/types.d.ts +9 -0
  81. package/dist/policy/compose.d.ts +34 -0
  82. package/dist/policy/compose.js +118 -0
  83. package/dist/policy/packs.js +33 -1
  84. package/dist/security/paths.d.ts +21 -0
  85. package/dist/security/paths.js +105 -0
  86. package/dist/storage/postgres.d.ts +26 -0
  87. package/dist/storage/postgres.js +90 -0
  88. package/dist/storage/provider.d.ts +2 -7
  89. package/dist/storage/provider.js +22 -16
  90. package/dist/storage/sqlite.d.ts +33 -0
  91. package/dist/storage/sqlite.js +77 -0
  92. package/dist/team/auth.js +1 -1
  93. package/dist/workspace/index.d.ts +69 -0
  94. package/dist/workspace/index.js +220 -0
  95. package/package.json +9 -3
@@ -0,0 +1,373 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { resolveRepoRoot } from "../utils/path.js";
4
+ import { atomicWriteTextFile } from "../utils/fs.js";
5
+ const CONTRACT_JSON = ".agentdoctor/architecture.json";
6
+ const CONTRACT_YML = ".agentdoctor/architecture.yml";
7
+ export const DEFAULT_ARCHITECTURE_CONTRACT = {
8
+ version: "1",
9
+ layers: [
10
+ { id: "cli", paths: ["src/cli/"] },
11
+ { id: "platform", paths: ["src/platform/"] },
12
+ { id: "core", paths: ["src/core/"] },
13
+ { id: "tests", paths: ["tests/"] },
14
+ ],
15
+ forbidden: [
16
+ {
17
+ id: "core-must-not-import-cli",
18
+ fromLayer: "core",
19
+ toLayer: "cli",
20
+ description: "Core must not depend on CLI surfaces",
21
+ },
22
+ {
23
+ id: "src-must-not-import-tests",
24
+ fromLayer: "core",
25
+ toLayer: "tests",
26
+ description: "Production core must not import test files",
27
+ },
28
+ {
29
+ id: "platform-must-not-import-tests",
30
+ fromLayer: "platform",
31
+ toLayer: "tests",
32
+ description: "Platform must not import test files",
33
+ },
34
+ ],
35
+ allowed: [
36
+ { fromLayer: "cli", toLayer: "platform" },
37
+ { fromLayer: "cli", toLayer: "core" },
38
+ { fromLayer: "platform", toLayer: "core" },
39
+ { fromLayer: "tests", toLayer: "core" },
40
+ { fromLayer: "tests", toLayer: "platform" },
41
+ { fromLayer: "tests", toLayer: "cli" },
42
+ ],
43
+ };
44
+ function normalizeRel(p) {
45
+ return p.replace(/\\/g, "/").replace(/^\.\//, "");
46
+ }
47
+ export function layerForPath(filePath, layers) {
48
+ const rel = normalizeRel(filePath);
49
+ let best = null;
50
+ for (const layer of layers) {
51
+ for (const prefix of layer.paths) {
52
+ const p = normalizeRel(prefix);
53
+ if (rel === p.replace(/\/$/, "") ||
54
+ rel.startsWith(p) ||
55
+ rel.startsWith(p.replace(/\/$/, "") + "/")) {
56
+ if (!best || p.length > best.len)
57
+ best = { id: layer.id, len: p.length };
58
+ }
59
+ }
60
+ }
61
+ return best?.id ?? null;
62
+ }
63
+ /**
64
+ * Minimal YAML subset parser for architecture contracts.
65
+ * Also accepts JSON content inside .yml files.
66
+ */
67
+ export function parseArchitectureYamlSubset(text) {
68
+ const trimmed = text.trim();
69
+ if (trimmed.startsWith("{")) {
70
+ return parseArchitectureJson(trimmed);
71
+ }
72
+ // Line-oriented subset: version, layers/forbidden/allowed with indented keys
73
+ const lines = text.split(/\r?\n/);
74
+ let version = "1";
75
+ const layers = [];
76
+ const forbidden = [];
77
+ const allowed = [];
78
+ let section = "none";
79
+ let current = null;
80
+ const pushCurrent = () => {
81
+ if (!current)
82
+ return;
83
+ if (section === "layers" && typeof current.id === "string") {
84
+ const paths = Array.isArray(current.paths)
85
+ ? current.paths.filter((p) => typeof p === "string")
86
+ : [];
87
+ layers.push({ id: current.id, paths });
88
+ }
89
+ else if (section === "forbidden" && typeof current.id === "string") {
90
+ forbidden.push({
91
+ id: current.id,
92
+ fromLayer: String(current.fromLayer ?? ""),
93
+ toLayer: String(current.toLayer ?? ""),
94
+ description: String(current.description ?? ""),
95
+ });
96
+ }
97
+ else if (section === "allowed") {
98
+ allowed.push({
99
+ fromLayer: String(current.fromLayer ?? ""),
100
+ toLayer: String(current.toLayer ?? ""),
101
+ });
102
+ }
103
+ current = null;
104
+ };
105
+ for (const raw of lines) {
106
+ if (!raw.trim() || raw.trimStart().startsWith("#"))
107
+ continue;
108
+ const indent = raw.match(/^ */)?.[0].length ?? 0;
109
+ const line = raw.trim();
110
+ if (indent === 0 && line.startsWith("version:")) {
111
+ pushCurrent();
112
+ version = unquote(line.slice("version:".length).trim()) || "1";
113
+ section = "none";
114
+ continue;
115
+ }
116
+ if (indent === 0 && line === "layers:") {
117
+ pushCurrent();
118
+ section = "layers";
119
+ continue;
120
+ }
121
+ if (indent === 0 && line === "forbidden:") {
122
+ pushCurrent();
123
+ section = "forbidden";
124
+ continue;
125
+ }
126
+ if (indent === 0 && line === "allowed:") {
127
+ pushCurrent();
128
+ section = "allowed";
129
+ continue;
130
+ }
131
+ if (section !== "none" && line.startsWith("- ")) {
132
+ pushCurrent();
133
+ current = {};
134
+ const rest = line.slice(2).trim();
135
+ if (rest.includes(":")) {
136
+ const [k, ...restParts] = rest.split(":");
137
+ current[k.trim()] = parseYamlValue(restParts.join(":").trim());
138
+ }
139
+ continue;
140
+ }
141
+ if (current && indent >= 2 && line.includes(":")) {
142
+ const [k, ...restParts] = line.split(":");
143
+ const key = k.trim();
144
+ const val = restParts.join(":").trim();
145
+ if (val === "" || val === "|" || val === ">") {
146
+ // multi-line not supported; ignore
147
+ continue;
148
+ }
149
+ if (key === "paths" && val.startsWith("[")) {
150
+ try {
151
+ current.paths = JSON.parse(val.replace(/'/g, '"'));
152
+ }
153
+ catch {
154
+ current.paths = val
155
+ .replace(/^\[/, "")
156
+ .replace(/\]$/, "")
157
+ .split(",")
158
+ .map((s) => unquote(s.trim()))
159
+ .filter(Boolean);
160
+ }
161
+ }
162
+ else {
163
+ current[key] = parseYamlValue(val);
164
+ }
165
+ }
166
+ }
167
+ pushCurrent();
168
+ if (version !== "1") {
169
+ throw new Error(`Unsupported architecture contract version: ${version}`);
170
+ }
171
+ return { version: "1", layers, forbidden, allowed };
172
+ }
173
+ function parseYamlValue(val) {
174
+ if (val.startsWith("[") && val.endsWith("]")) {
175
+ try {
176
+ return JSON.parse(val.replace(/'/g, '"'));
177
+ }
178
+ catch {
179
+ return val
180
+ .slice(1, -1)
181
+ .split(",")
182
+ .map((s) => unquote(s.trim()))
183
+ .filter(Boolean);
184
+ }
185
+ }
186
+ return unquote(val);
187
+ }
188
+ function unquote(s) {
189
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
190
+ return s.slice(1, -1);
191
+ }
192
+ return s;
193
+ }
194
+ export function parseArchitectureJson(text) {
195
+ const parsed = JSON.parse(text);
196
+ if (parsed.version !== "1") {
197
+ throw new Error(`Unsupported architecture contract version: ${String(parsed.version)}`);
198
+ }
199
+ if (!Array.isArray(parsed.layers) || !Array.isArray(parsed.forbidden)) {
200
+ throw new Error("Architecture contract requires layers and forbidden arrays");
201
+ }
202
+ return {
203
+ version: "1",
204
+ layers: parsed.layers,
205
+ forbidden: parsed.forbidden,
206
+ allowed: Array.isArray(parsed.allowed) ? parsed.allowed : [],
207
+ };
208
+ }
209
+ export async function loadArchitectureContract(rootInput) {
210
+ const root = resolveRepoRoot(rootInput);
211
+ const jsonPath = path.join(root, CONTRACT_JSON);
212
+ const ymlPath = path.join(root, CONTRACT_YML);
213
+ try {
214
+ const text = await fs.readFile(jsonPath, "utf8");
215
+ return { contract: parseArchitectureJson(text), path: jsonPath };
216
+ }
217
+ catch {
218
+ // try yml
219
+ }
220
+ try {
221
+ const text = await fs.readFile(ymlPath, "utf8");
222
+ return { contract: parseArchitectureYamlSubset(text), path: ymlPath };
223
+ }
224
+ catch {
225
+ return null;
226
+ }
227
+ }
228
+ export async function initArchitecture(rootInput) {
229
+ const root = resolveRepoRoot(rootInput);
230
+ const out = path.join(root, CONTRACT_JSON);
231
+ await fs.mkdir(path.dirname(out), { recursive: true });
232
+ try {
233
+ await fs.access(out);
234
+ return out; // already exists — do not overwrite
235
+ }
236
+ catch {
237
+ // create
238
+ }
239
+ await atomicWriteTextFile(out, `${JSON.stringify(DEFAULT_ARCHITECTURE_CONTRACT, null, 2)}\n`);
240
+ return out;
241
+ }
242
+ function resolveNodePath(graph, nodeId) {
243
+ const node = graph.nodes.find((n) => n.id === nodeId);
244
+ if (node?.path)
245
+ return normalizeRel(node.path);
246
+ if (node?.label)
247
+ return normalizeRel(node.label);
248
+ return normalizeRel(nodeId.replace(/^file:/, ""));
249
+ }
250
+ /**
251
+ * Check import edges against the architecture contract.
252
+ * Forbidden rules always apply. When `allowed` is non-empty, cross-layer
253
+ * imports not listed in allowed (and not same-layer) are reported as not-allowed.
254
+ */
255
+ export function checkArchitecture(rootInput, graph, contract, contractPath) {
256
+ const root = resolveRepoRoot(rootInput);
257
+ const limitations = [
258
+ "Architecture check uses static import edges from the repository graph",
259
+ "Layer assignment is path-prefix based — not runtime topology",
260
+ ];
261
+ if (!contract) {
262
+ return {
263
+ root,
264
+ contractPath: contractPath ?? null,
265
+ contract: null,
266
+ violations: [],
267
+ importEdgesChecked: 0,
268
+ limitations: [
269
+ ...limitations,
270
+ "No architecture contract found — run: agentdoctor architecture init",
271
+ ],
272
+ };
273
+ }
274
+ const violations = [];
275
+ const importEdges = graph.edges.filter((e) => e.kind === "imports" || e.kind === "depends_on");
276
+ const allowSet = new Set(contract.allowed.map((a) => `${a.fromLayer}->${a.toLayer}`));
277
+ const enforceAllowList = contract.allowed.length > 0;
278
+ for (const edge of importEdges) {
279
+ const fromPath = resolveNodePath(graph, edge.from);
280
+ const toPath = resolveNodePath(graph, edge.to);
281
+ const fromLayer = layerForPath(fromPath, contract.layers);
282
+ const toLayer = layerForPath(toPath, contract.layers);
283
+ if (!fromLayer || !toLayer)
284
+ continue;
285
+ if (fromLayer === toLayer)
286
+ continue;
287
+ for (const rule of contract.forbidden) {
288
+ if (rule.fromLayer === fromLayer && rule.toLayer === toLayer) {
289
+ violations.push({
290
+ ruleId: rule.id,
291
+ kind: "forbidden",
292
+ description: rule.description,
293
+ fromPath,
294
+ toPath,
295
+ fromLayer,
296
+ toLayer,
297
+ evidence: {
298
+ edgeId: edge.id,
299
+ edgeKind: edge.kind,
300
+ evidenceKind: edge.evidence,
301
+ },
302
+ });
303
+ }
304
+ }
305
+ if (enforceAllowList && !allowSet.has(`${fromLayer}->${toLayer}`)) {
306
+ const alreadyForbidden = violations.some((v) => v.fromPath === fromPath &&
307
+ v.toPath === toPath &&
308
+ v.fromLayer === fromLayer &&
309
+ v.toLayer === toLayer &&
310
+ v.kind === "forbidden");
311
+ if (!alreadyForbidden) {
312
+ violations.push({
313
+ ruleId: `not-allowed:${fromLayer}->${toLayer}`,
314
+ kind: "not-allowed",
315
+ description: `Cross-layer import ${fromLayer} → ${toLayer} is not in the allowed list`,
316
+ fromPath,
317
+ toPath,
318
+ fromLayer,
319
+ toLayer,
320
+ evidence: {
321
+ edgeId: edge.id,
322
+ edgeKind: edge.kind,
323
+ evidenceKind: edge.evidence,
324
+ },
325
+ });
326
+ }
327
+ }
328
+ }
329
+ violations.sort((a, b) => `${a.ruleId}:${a.fromPath}:${a.toPath}`.localeCompare(`${b.ruleId}:${b.fromPath}:${b.toPath}`));
330
+ return {
331
+ root,
332
+ contractPath: contractPath ?? null,
333
+ contract,
334
+ violations,
335
+ importEdgesChecked: importEdges.length,
336
+ limitations,
337
+ };
338
+ }
339
+ export async function checkArchitectureAtRoot(rootInput, graph) {
340
+ const loaded = await loadArchitectureContract(rootInput);
341
+ return checkArchitecture(rootInput, graph, loaded?.contract ?? null, loaded?.path ?? null);
342
+ }
343
+ export function explainArchitecture(contract, check) {
344
+ const lines = ["AgentDoctor architecture contract"];
345
+ if (!contract) {
346
+ lines.push(" No contract loaded. Run: agentdoctor architecture init");
347
+ return `${lines.join("\n")}\n`;
348
+ }
349
+ lines.push(` version: ${contract.version}`);
350
+ lines.push(` layers: ${contract.layers.map((l) => l.id).join(", ") || "(none)"}`);
351
+ for (const layer of contract.layers) {
352
+ lines.push(` - ${layer.id}: ${layer.paths.join(", ")}`);
353
+ }
354
+ lines.push(` forbidden rules: ${contract.forbidden.length}`);
355
+ for (const rule of contract.forbidden) {
356
+ lines.push(` - [${rule.id}] ${rule.fromLayer} → ${rule.toLayer}: ${rule.description}`);
357
+ }
358
+ lines.push(` allowed pairs: ${contract.allowed.length}`);
359
+ for (const a of contract.allowed) {
360
+ lines.push(` - ${a.fromLayer} → ${a.toLayer}`);
361
+ }
362
+ if (check) {
363
+ lines.push(` import edges checked: ${check.importEdgesChecked}`);
364
+ lines.push(` violations: ${check.violations.length}`);
365
+ for (const v of check.violations.slice(0, 20)) {
366
+ lines.push(` - ${v.kind} ${v.ruleId}: ${v.fromPath} → ${v.toPath} (${v.fromLayer}→${v.toLayer})`);
367
+ }
368
+ for (const lim of check.limitations.slice(0, 5)) {
369
+ lines.push(` limitation: ${lim}`);
370
+ }
371
+ }
372
+ return `${lines.join("\n")}\n`;
373
+ }
@@ -0,0 +1,211 @@
1
+ export declare const EVIDENCE_SCHEMA_VERSION = "1.0.0";
2
+ export type VerificationStatus = "not-run" | "partial" | "evidence-produced" | "failed" | "verified";
3
+ export interface ChangeAssessment {
4
+ changeId: string;
5
+ schemaVersion: string;
6
+ agentDoctorVersion: string;
7
+ repository: {
8
+ root: string;
9
+ remote: string | null;
10
+ branch: string | null;
11
+ };
12
+ baseRevision: string | null;
13
+ targetRevision: string | null;
14
+ changedFiles: Array<{
15
+ path: string;
16
+ kind: string;
17
+ }>;
18
+ changedSymbols: string[];
19
+ /** Graph nodes / paths that call or import into changed symbols/files. */
20
+ callers: string[];
21
+ /** Graph targets called or imported from changed symbols/files. */
22
+ callees: string[];
23
+ /** Files that import changed files (reverse import deps). */
24
+ reverseDependencies: string[];
25
+ /** Workspace packages touched by changed files (from package.json workspaces when present). */
26
+ packageImpact: string[];
27
+ affectedComponents: string[];
28
+ dependencyImpact: {
29
+ status: "observed" | "unknown" | "heuristic";
30
+ relatedPaths: string[];
31
+ edgeCount: number;
32
+ limitations: string[];
33
+ };
34
+ architectureImpact: {
35
+ status: "inferred" | "unknown";
36
+ viewLevels: string[];
37
+ limitations: string[];
38
+ };
39
+ knowledgeReferences: Array<{
40
+ id: string;
41
+ title: string;
42
+ status: string;
43
+ authoritative: boolean;
44
+ }>;
45
+ securityFindings: {
46
+ secretFindingCount: number;
47
+ mode: "heuristic";
48
+ limitations: string[];
49
+ };
50
+ policyResults: Array<{
51
+ policyId: string;
52
+ decision: string;
53
+ reason: string;
54
+ subject: string;
55
+ action: string;
56
+ evidence: string;
57
+ }>;
58
+ testImpact: {
59
+ mode: "heuristic" | "coverage-backed";
60
+ recommendedTests: string[];
61
+ confidence: "low" | "medium" | "high";
62
+ limitations: string[];
63
+ };
64
+ evidence: {
65
+ directory: string | null;
66
+ files: string[];
67
+ };
68
+ verificationStatus: VerificationStatus;
69
+ limitations: string[];
70
+ createdAt: string;
71
+ }
72
+ export interface EvidenceManifest {
73
+ schemaVersion: string;
74
+ agentDoctorVersion: string;
75
+ changeId: string;
76
+ repositoryRoot: string;
77
+ baseRevision: string | null;
78
+ targetRevision: string | null;
79
+ createdAt: string;
80
+ files: Array<{
81
+ name: string;
82
+ sha256: string;
83
+ }>;
84
+ verificationStatus: VerificationStatus;
85
+ }
86
+ /**
87
+ * Derive callers / callees / reverse import deps from the intelligence graph
88
+ * for the given changed files and symbol ids. Honest: empty when graph lacks edges.
89
+ */
90
+ export declare function deriveGraphChangeImpact(graph: {
91
+ nodes: Array<{
92
+ id: string;
93
+ kind: string;
94
+ label: string;
95
+ path?: string;
96
+ }>;
97
+ edges: Array<{
98
+ from: string;
99
+ to: string;
100
+ kind: string;
101
+ }>;
102
+ }, changedFiles: Array<{
103
+ path: string;
104
+ kind: string;
105
+ }>, changedSymbols: string[]): {
106
+ callers: string[];
107
+ callees: string[];
108
+ reverseDependencies: string[];
109
+ };
110
+ /**
111
+ * Map changed files onto package.json workspaces (string globs or packages/*).
112
+ * Returns [] when workspaces are absent — does not invent packages.
113
+ */
114
+ export declare function derivePackageImpact(root: string, changedFiles: Array<{
115
+ path: string;
116
+ }>): Promise<string[]>;
117
+ /**
118
+ * Assemble a ChangeAssessment from existing AgentDoctor signals.
119
+ * Never sets verificationStatus to "verified" — that requires evidence verify.
120
+ */
121
+ export declare function analyzeChange(options: {
122
+ root: string;
123
+ since?: string;
124
+ changeId?: string;
125
+ coveragePath?: string;
126
+ }): Promise<ChangeAssessment>;
127
+ /**
128
+ * Persist evidence bundle. Status becomes evidence-produced (not "verified").
129
+ * "verified" is reserved for evidence verify when artifact hashes match.
130
+ */
131
+ export declare function verifyChange(options: {
132
+ root: string;
133
+ since?: string;
134
+ changeId?: string;
135
+ coveragePath?: string;
136
+ }): Promise<{
137
+ assessment: ChangeAssessment;
138
+ manifest: EvidenceManifest;
139
+ }>;
140
+ /**
141
+ * Human-readable explanation of a ChangeAssessment (does not claim correctness).
142
+ */
143
+ export declare function explainChange(assessment: ChangeAssessment): string;
144
+ /**
145
+ * Summarize base/target file diffs from git for a change.
146
+ */
147
+ export declare function diffChange(options: {
148
+ root: string;
149
+ since?: string;
150
+ changeId?: string;
151
+ }): Promise<{
152
+ changeId: string | null;
153
+ baseRevision: string | null;
154
+ targetRevision: string | null;
155
+ files: Array<{
156
+ path: string;
157
+ kind: string;
158
+ }>;
159
+ summary: {
160
+ added: number;
161
+ modified: number;
162
+ deleted: number;
163
+ renamed: number;
164
+ untracked: number;
165
+ };
166
+ stat: string | null;
167
+ limitations: string[];
168
+ }>;
169
+ /**
170
+ * Verification / evidence status for latest evidence or a specific change id.
171
+ */
172
+ export declare function changeStatus(options: {
173
+ root: string;
174
+ changeId?: string;
175
+ }): Promise<{
176
+ changeId: string | null;
177
+ evidenceDirectory: string | null;
178
+ verificationStatus: VerificationStatus;
179
+ evidencePresent: boolean;
180
+ proofPresent: boolean;
181
+ proofId: string | null;
182
+ integrityNote: string;
183
+ files: string[];
184
+ }>;
185
+ export declare function inspectEvidence(options: {
186
+ root: string;
187
+ changeId: string;
188
+ }): Promise<{
189
+ ok: boolean;
190
+ directory: string;
191
+ manifest: EvidenceManifest | null;
192
+ presentFiles: string[];
193
+ error?: string;
194
+ }>;
195
+ /**
196
+ * Hash-check evidence bundle. Returns "verified" only when all listed files match.
197
+ */
198
+ export declare function verifyEvidence(options: {
199
+ root: string;
200
+ changeId: string;
201
+ }): Promise<{
202
+ ok: boolean;
203
+ verificationStatus: VerificationStatus;
204
+ checked: Array<{
205
+ name: string;
206
+ match: boolean;
207
+ expected?: string;
208
+ actual?: string;
209
+ }>;
210
+ error?: string;
211
+ }>;