@praneeth_54/agentdoctor 1.1.1 → 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.
- package/CHANGELOG.md +164 -7
- package/README.md +263 -513
- package/dist/agents/aider/adapter.d.ts +1 -0
- package/dist/agents/aider/adapter.js +1 -0
- package/dist/agents/aider/detector.d.ts +14 -0
- package/dist/agents/aider/detector.js +120 -0
- package/dist/agents/copilot/adapter.d.ts +1 -0
- package/dist/agents/copilot/adapter.js +1 -0
- package/dist/agents/copilot/detector.d.ts +13 -0
- package/dist/agents/copilot/detector.js +113 -0
- package/dist/agents/gemini/adapter.d.ts +1 -0
- package/dist/agents/gemini/adapter.js +1 -0
- package/dist/agents/gemini/detector.d.ts +13 -0
- package/dist/agents/gemini/detector.js +151 -0
- package/dist/agents/registry.js +13 -1
- package/dist/agents/types.d.ts +1 -1
- package/dist/agents/windsurf/adapter.d.ts +1 -0
- package/dist/agents/windsurf/adapter.js +1 -0
- package/dist/agents/windsurf/detector.d.ts +14 -0
- package/dist/agents/windsurf/detector.js +119 -0
- package/dist/architecture/c4.d.ts +22 -0
- package/dist/architecture/c4.js +62 -0
- package/dist/architecture/contract.d.ts +64 -0
- package/dist/architecture/contract.js +373 -0
- package/dist/assurance/change.d.ts +211 -0
- package/dist/assurance/change.js +624 -0
- package/dist/assurance/proof.d.ts +136 -0
- package/dist/assurance/proof.js +338 -0
- package/dist/auth/index.d.ts +81 -0
- package/dist/auth/index.js +130 -0
- package/dist/auth/rbac.d.ts +9 -0
- package/dist/auth/rbac.js +26 -0
- package/dist/cli/commands/architecture.d.ts +6 -0
- package/dist/cli/commands/architecture.js +109 -0
- package/dist/cli/commands/assurance.d.ts +67 -0
- package/dist/cli/commands/assurance.js +210 -0
- package/dist/cli/commands/brain.d.ts +12 -0
- package/dist/cli/commands/brain.js +162 -0
- package/dist/cli/commands/complete.d.ts +23 -0
- package/dist/cli/commands/complete.js +232 -0
- package/dist/cli/commands/explain.js +1 -1
- package/dist/cli/commands/fix.js +22 -2
- package/dist/cli/commands/mcp.d.ts +8 -0
- package/dist/cli/commands/mcp.js +14 -0
- package/dist/cli/commands/platform.d.ts +17 -0
- package/dist/cli/commands/platform.js +195 -0
- package/dist/cli/commands/policy-graph-run.d.ts +40 -0
- package/dist/cli/commands/policy-graph-run.js +200 -0
- package/dist/cli/commands/v2.d.ts +55 -0
- package/dist/cli/commands/v2.js +278 -0
- package/dist/cli/commands/workspace.d.ts +9 -0
- package/dist/cli/commands/workspace.js +82 -0
- package/dist/cli/program.js +1328 -3
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +5 -1
- package/dist/contracts/adapters.d.ts +7 -0
- package/dist/contracts/adapters.js +60 -0
- package/dist/contracts/index.d.ts +162 -0
- package/dist/contracts/index.js +18 -0
- package/dist/core/baseline/store.d.ts +48 -0
- package/dist/core/baseline/store.js +163 -0
- package/dist/core/brain-cli/service.d.ts +26 -0
- package/dist/core/brain-cli/service.js +175 -0
- package/dist/core/brain-product/init.d.ts +45 -0
- package/dist/core/brain-product/init.js +235 -0
- package/dist/core/changes/analyze.d.ts +41 -0
- package/dist/core/changes/analyze.js +223 -0
- package/dist/core/context-health/analyze.d.ts +15 -0
- package/dist/core/context-health/analyze.js +234 -0
- package/dist/core/fix/apply.d.ts +21 -4
- package/dist/core/fix/apply.js +118 -18
- package/dist/core/fix/backup.d.ts +30 -0
- package/dist/core/fix/backup.js +193 -0
- package/dist/core/fix/plan.d.ts +6 -3
- package/dist/core/fix/plan.js +113 -9
- package/dist/core/fix/render.d.ts +2 -0
- package/dist/core/fix/render.js +36 -21
- package/dist/core/fix/run.js +5 -1
- package/dist/core/fix/safe-target.d.ts +14 -0
- package/dist/core/fix/safe-target.js +81 -0
- package/dist/core/fix/types.d.ts +12 -1
- package/dist/core/fix/types.js +2 -0
- package/dist/core/fix/writers/claude-settings.js +3 -1
- package/dist/core/fix/writers/codex-config.d.ts +3 -0
- package/dist/core/fix/writers/codex-config.js +24 -3
- package/dist/core/fix/writers/cursorignore.js +3 -1
- package/dist/core/fix/writers/simple-ignore.d.ts +16 -0
- package/dist/core/fix/writers/simple-ignore.js +68 -0
- package/dist/core/monorepo/detect.d.ts +13 -0
- package/dist/core/monorepo/detect.js +121 -0
- package/dist/core/rules/build-context.js +22 -3
- package/dist/core/rules/context/generated-directory.js +11 -1
- package/dist/core/rules/context/large-instruction-file.js +6 -0
- package/dist/core/rules/context/large-log-file.js +16 -1
- package/dist/core/rules/ignore.d.ts +11 -1
- package/dist/core/rules/ignore.js +22 -1
- package/dist/core/rules/instructions/empty-instructions.js +7 -0
- package/dist/core/rules/security/env-file-exposure.js +23 -2
- package/dist/core/rules/security/private-key-file.js +1 -1
- package/dist/core/scanner/scan.js +1 -1
- package/dist/core/schemas/validate.d.ts +6 -0
- package/dist/core/schemas/validate.js +62 -0
- package/dist/core/scoring/compute-scores.d.ts +1 -1
- package/dist/core/scoring/compute-scores.js +5 -1
- package/dist/core/scoring/placeholder.d.ts +1 -1
- package/dist/core/scoring/placeholder.js +5 -1
- package/dist/core/secrets/scan.d.ts +29 -0
- package/dist/core/secrets/scan.js +172 -0
- package/dist/coverage/cobertura.d.ts +6 -0
- package/dist/coverage/cobertura.js +52 -0
- package/dist/coverage/istanbul.d.ts +7 -0
- package/dist/coverage/istanbul.js +134 -0
- package/dist/coverage/lcov.d.ts +7 -0
- package/dist/coverage/lcov.js +59 -0
- package/dist/coverage/load.d.ts +9 -0
- package/dist/coverage/load.js +39 -0
- package/dist/coverage/types.d.ts +23 -0
- package/dist/coverage/types.js +5 -0
- package/dist/dashboard/server.d.ts +24 -0
- package/dist/dashboard/server.js +402 -0
- package/dist/enforcement/runner.d.ts +67 -0
- package/dist/enforcement/runner.js +460 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +25 -0
- package/dist/integrations/github/pr-analyze.d.ts +28 -0
- package/dist/integrations/github/pr-analyze.js +98 -0
- package/dist/integrations/local-ai/provider.d.ts +45 -0
- package/dist/integrations/local-ai/provider.js +104 -0
- package/dist/intelligence/git/analyze.d.ts +34 -0
- package/dist/intelligence/git/analyze.js +136 -0
- package/dist/intelligence/graph/build.d.ts +15 -0
- package/dist/intelligence/graph/build.js +259 -0
- package/dist/intelligence/graph/incremental.d.ts +68 -0
- package/dist/intelligence/graph/incremental.js +234 -0
- package/dist/intelligence/resolve/imports.d.ts +36 -0
- package/dist/intelligence/resolve/imports.js +245 -0
- package/dist/knowledge/store.d.ts +25 -0
- package/dist/knowledge/store.js +91 -0
- package/dist/languages/go.d.ts +9 -0
- package/dist/languages/go.js +45 -0
- package/dist/languages/index.d.ts +11 -0
- package/dist/languages/index.js +76 -0
- package/dist/languages/php.d.ts +7 -0
- package/dist/languages/php.js +193 -0
- package/dist/languages/python.d.ts +7 -0
- package/dist/languages/python.js +150 -0
- package/dist/languages/types.d.ts +42 -0
- package/dist/languages/types.js +26 -0
- package/dist/languages/typescript.d.ts +3 -0
- package/dist/languages/typescript.js +95 -0
- package/dist/mcp/agentdoctor/server.d.ts +16 -0
- package/dist/mcp/agentdoctor/server.js +67 -0
- package/dist/mcp/brain/session.js +7 -7
- package/dist/mcp/intelligence/handlers.d.ts +16 -0
- package/dist/mcp/intelligence/handlers.js +364 -0
- package/dist/mcp/intelligence/path-safety.d.ts +9 -0
- package/dist/mcp/intelligence/path-safety.js +63 -0
- package/dist/mcp/intelligence/registry.d.ts +8 -0
- package/dist/mcp/intelligence/registry.js +228 -0
- package/dist/ops/health.d.ts +18 -0
- package/dist/ops/health.js +51 -0
- package/dist/platform/ai-quality/analyze.d.ts +9 -0
- package/dist/platform/ai-quality/analyze.js +65 -0
- package/dist/platform/architecture/drift.d.ts +17 -0
- package/dist/platform/architecture/drift.js +74 -0
- package/dist/platform/auth/local.d.ts +15 -0
- package/dist/platform/auth/local.js +58 -0
- package/dist/platform/context-security/analyze.d.ts +6 -0
- package/dist/platform/context-security/analyze.js +97 -0
- package/dist/platform/firewall/evaluate.d.ts +57 -0
- package/dist/platform/firewall/evaluate.js +359 -0
- package/dist/platform/graph/build.d.ts +6 -0
- package/dist/platform/graph/build.js +189 -0
- package/dist/platform/health/analyze.d.ts +7 -0
- package/dist/platform/health/analyze.js +192 -0
- package/dist/platform/index.d.ts +27 -0
- package/dist/platform/index.js +89 -0
- package/dist/platform/knowledge/analyze.d.ts +20 -0
- package/dist/platform/knowledge/analyze.js +96 -0
- package/dist/platform/provenance/build.d.ts +44 -0
- package/dist/platform/provenance/build.js +65 -0
- package/dist/platform/readiness/scorecard.d.ts +5 -0
- package/dist/platform/readiness/scorecard.js +98 -0
- package/dist/platform/refactor/impact.d.ts +20 -0
- package/dist/platform/refactor/impact.js +60 -0
- package/dist/platform/reports/export.d.ts +12 -0
- package/dist/platform/reports/export.js +92 -0
- package/dist/platform/security/redact.d.ts +15 -0
- package/dist/platform/security/redact.js +87 -0
- package/dist/platform/sessions/store.d.ts +32 -0
- package/dist/platform/sessions/store.js +97 -0
- package/dist/platform/store.d.ts +6 -0
- package/dist/platform/store.js +57 -0
- package/dist/platform/test-impact/analyze.d.ts +50 -0
- package/dist/platform/test-impact/analyze.js +350 -0
- package/dist/platform/time-machine/compare.d.ts +17 -0
- package/dist/platform/time-machine/compare.js +62 -0
- package/dist/platform/tokens/plan.d.ts +28 -0
- package/dist/platform/tokens/plan.js +108 -0
- package/dist/platform/types.d.ts +120 -0
- package/dist/platform/types.js +5 -0
- package/dist/plugins/runtime.d.ts +36 -0
- package/dist/plugins/runtime.js +101 -0
- package/dist/plugins/sdk.d.ts +29 -0
- package/dist/plugins/sdk.js +114 -0
- package/dist/policy/compose.d.ts +34 -0
- package/dist/policy/compose.js +118 -0
- package/dist/policy/packs.d.ts +9 -0
- package/dist/policy/packs.js +91 -0
- package/dist/reporters/terminal/report.js +38 -5
- package/dist/security/paths.d.ts +21 -0
- package/dist/security/paths.js +105 -0
- package/dist/storage/postgres.d.ts +26 -0
- package/dist/storage/postgres.js +90 -0
- package/dist/storage/provider.d.ts +30 -0
- package/dist/storage/provider.js +109 -0
- package/dist/storage/sqlite.d.ts +33 -0
- package/dist/storage/sqlite.js +77 -0
- package/dist/team/auth.d.ts +35 -0
- package/dist/team/auth.js +70 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/workspace/index.d.ts +69 -0
- package/dist/workspace/index.js +220 -0
- package/package.json +15 -5
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role-based access control for AgentDoctor surfaces.
|
|
3
|
+
* Not enterprise SSO — roles are applied after a verified identity (local session or OIDC JWT).
|
|
4
|
+
*/
|
|
5
|
+
export const RBAC_ROLE_RANK = {
|
|
6
|
+
viewer: 1,
|
|
7
|
+
developer: 2,
|
|
8
|
+
reviewer: 3,
|
|
9
|
+
"policy-admin": 4,
|
|
10
|
+
admin: 5,
|
|
11
|
+
};
|
|
12
|
+
const PERMISSION_MIN_ROLE = {
|
|
13
|
+
"read-findings": "viewer",
|
|
14
|
+
"read-audit": "viewer",
|
|
15
|
+
"export-reports": "developer",
|
|
16
|
+
"approve-actions": "reviewer",
|
|
17
|
+
"manage-policies": "policy-admin",
|
|
18
|
+
"admin-settings": "admin",
|
|
19
|
+
};
|
|
20
|
+
export function hasRbacPermission(role, permission) {
|
|
21
|
+
const required = PERMISSION_MIN_ROLE[permission];
|
|
22
|
+
return (RBAC_ROLE_RANK[role] ?? 0) >= (RBAC_ROLE_RANK[required] ?? 99);
|
|
23
|
+
}
|
|
24
|
+
export function roleAtLeast(role, required) {
|
|
25
|
+
return (RBAC_ROLE_RANK[role] ?? 0) >= (RBAC_ROLE_RANK[required] ?? 99);
|
|
26
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
+
import { resolveRepoRoot } from "../../utils/path.js";
|
|
3
|
+
import { buildIntelligenceGraph } from "../../intelligence/graph/build.js";
|
|
4
|
+
import { buildC4Views } from "../../architecture/c4.js";
|
|
5
|
+
import { checkArchitectureAtRoot, explainArchitecture, initArchitecture, loadArchitectureContract, } from "../../architecture/contract.js";
|
|
6
|
+
function printJson(value) {
|
|
7
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
8
|
+
}
|
|
9
|
+
export async function runArchitectureCommand(options) {
|
|
10
|
+
const root = resolveRepoRoot(options.root ?? process.cwd());
|
|
11
|
+
try {
|
|
12
|
+
switch (options.action) {
|
|
13
|
+
case "init": {
|
|
14
|
+
const written = await initArchitecture(root);
|
|
15
|
+
if (options.json)
|
|
16
|
+
printJson({ path: written, createdOrExisting: true });
|
|
17
|
+
else
|
|
18
|
+
process.stdout.write(`Architecture contract at ${written}\n`);
|
|
19
|
+
return EXIT_CODES.SUCCESS;
|
|
20
|
+
}
|
|
21
|
+
case "analyze": {
|
|
22
|
+
const graph = await buildIntelligenceGraph({ root, mode: "auto" });
|
|
23
|
+
const views = buildC4Views(graph);
|
|
24
|
+
const loaded = await loadArchitectureContract(root);
|
|
25
|
+
const check = await checkArchitectureAtRoot(root, graph);
|
|
26
|
+
const payload = {
|
|
27
|
+
c4: {
|
|
28
|
+
levels: views.map((v) => v.level),
|
|
29
|
+
views,
|
|
30
|
+
label: "Inferred/proposed from graph evidence — not approved architecture facts",
|
|
31
|
+
},
|
|
32
|
+
contract: loaded
|
|
33
|
+
? {
|
|
34
|
+
path: loaded.path,
|
|
35
|
+
version: loaded.contract.version,
|
|
36
|
+
layerCount: loaded.contract.layers.length,
|
|
37
|
+
forbiddenCount: loaded.contract.forbidden.length,
|
|
38
|
+
allowedCount: loaded.contract.allowed.length,
|
|
39
|
+
}
|
|
40
|
+
: null,
|
|
41
|
+
check: {
|
|
42
|
+
violations: check.violations.length,
|
|
43
|
+
importEdgesChecked: check.importEdgesChecked,
|
|
44
|
+
limitations: check.limitations,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
if (options.json)
|
|
48
|
+
printJson(payload);
|
|
49
|
+
else {
|
|
50
|
+
process.stdout.write([
|
|
51
|
+
"AgentDoctor architecture analyze",
|
|
52
|
+
` C4 views: ${views.map((v) => v.level).join(", ")} (inferred)`,
|
|
53
|
+
loaded
|
|
54
|
+
? ` contract: ${loaded.path} (layers=${loaded.contract.layers.length}, forbidden=${loaded.contract.forbidden.length})`
|
|
55
|
+
: " contract: none (run architecture init)",
|
|
56
|
+
` check violations: ${check.violations.length} (edges=${check.importEdgesChecked})`,
|
|
57
|
+
].join("\n") + "\n");
|
|
58
|
+
}
|
|
59
|
+
return EXIT_CODES.SUCCESS;
|
|
60
|
+
}
|
|
61
|
+
case "check": {
|
|
62
|
+
const graph = await buildIntelligenceGraph({ root, mode: "auto" });
|
|
63
|
+
const check = await checkArchitectureAtRoot(root, graph);
|
|
64
|
+
if (options.json)
|
|
65
|
+
printJson(check);
|
|
66
|
+
else {
|
|
67
|
+
process.stdout.write([
|
|
68
|
+
"AgentDoctor architecture check",
|
|
69
|
+
` contract: ${check.contractPath ?? "none"}`,
|
|
70
|
+
` import edges checked: ${check.importEdgesChecked}`,
|
|
71
|
+
` violations: ${check.violations.length}`,
|
|
72
|
+
...check.violations
|
|
73
|
+
.slice(0, 30)
|
|
74
|
+
.map((v) => ` - [${v.kind}] ${v.ruleId}: ${v.fromPath} → ${v.toPath} (${v.fromLayer}→${v.toLayer})`),
|
|
75
|
+
...check.limitations.map((l) => ` limitation: ${l}`),
|
|
76
|
+
].join("\n") + "\n");
|
|
77
|
+
}
|
|
78
|
+
if (check.violations.some((v) => v.kind === "forbidden")) {
|
|
79
|
+
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
80
|
+
}
|
|
81
|
+
return EXIT_CODES.SUCCESS;
|
|
82
|
+
}
|
|
83
|
+
case "explain": {
|
|
84
|
+
const loaded = await loadArchitectureContract(root);
|
|
85
|
+
const graph = await buildIntelligenceGraph({ root, mode: "auto" });
|
|
86
|
+
const check = await checkArchitectureAtRoot(root, graph);
|
|
87
|
+
if (options.json) {
|
|
88
|
+
printJson({
|
|
89
|
+
contract: loaded?.contract ?? null,
|
|
90
|
+
path: loaded?.path ?? null,
|
|
91
|
+
check,
|
|
92
|
+
explanation: explainArchitecture(loaded?.contract ?? null, check),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
process.stdout.write(explainArchitecture(loaded?.contract ?? null, check));
|
|
97
|
+
}
|
|
98
|
+
return EXIT_CODES.SUCCESS;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
console.error(`Error: unknown architecture action`);
|
|
102
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
107
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare function runChangeAnalyzeCommand(options: {
|
|
2
|
+
root: string;
|
|
3
|
+
since?: string;
|
|
4
|
+
coverage?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): Promise<number>;
|
|
7
|
+
export declare function runChangeVerifyCommand(options: {
|
|
8
|
+
root: string;
|
|
9
|
+
since?: string;
|
|
10
|
+
changeId?: string;
|
|
11
|
+
coverage?: string;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}): Promise<number>;
|
|
14
|
+
export declare function runChangeExplainCommand(options: {
|
|
15
|
+
root: string;
|
|
16
|
+
since?: string;
|
|
17
|
+
changeId?: string;
|
|
18
|
+
coverage?: string;
|
|
19
|
+
json?: boolean;
|
|
20
|
+
}): Promise<number>;
|
|
21
|
+
export declare function runChangeDiffCommand(options: {
|
|
22
|
+
root: string;
|
|
23
|
+
since?: string;
|
|
24
|
+
changeId?: string;
|
|
25
|
+
json?: boolean;
|
|
26
|
+
}): Promise<number>;
|
|
27
|
+
export declare function runChangeStatusCommand(options: {
|
|
28
|
+
root: string;
|
|
29
|
+
changeId?: string;
|
|
30
|
+
json?: boolean;
|
|
31
|
+
}): Promise<number>;
|
|
32
|
+
export declare function runEvidenceInspectCommand(options: {
|
|
33
|
+
root: string;
|
|
34
|
+
changeId: string;
|
|
35
|
+
json?: boolean;
|
|
36
|
+
}): Promise<number>;
|
|
37
|
+
export declare function runEvidenceVerifyCommand(options: {
|
|
38
|
+
root: string;
|
|
39
|
+
changeId: string;
|
|
40
|
+
json?: boolean;
|
|
41
|
+
}): Promise<number>;
|
|
42
|
+
export declare function runProofBuildCommand(options: {
|
|
43
|
+
root: string;
|
|
44
|
+
changeId: string;
|
|
45
|
+
json?: boolean;
|
|
46
|
+
}): Promise<number>;
|
|
47
|
+
export declare function runProofInspectCommand(options: {
|
|
48
|
+
root: string;
|
|
49
|
+
id: string;
|
|
50
|
+
json?: boolean;
|
|
51
|
+
}): Promise<number>;
|
|
52
|
+
export declare function runProofExplainCommand(options: {
|
|
53
|
+
root: string;
|
|
54
|
+
id: string;
|
|
55
|
+
json?: boolean;
|
|
56
|
+
}): Promise<number>;
|
|
57
|
+
export declare function runProofVerifyCommand(options: {
|
|
58
|
+
root: string;
|
|
59
|
+
id: string;
|
|
60
|
+
json?: boolean;
|
|
61
|
+
}): Promise<number>;
|
|
62
|
+
export declare function runProofExportCommand(options: {
|
|
63
|
+
root: string;
|
|
64
|
+
id: string;
|
|
65
|
+
out: string;
|
|
66
|
+
json?: boolean;
|
|
67
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { analyzeChange, changeStatus, diffChange, explainChange, inspectEvidence, verifyChange, verifyEvidence, } from "../../assurance/change.js";
|
|
2
|
+
import { buildProofFromEvidence, explainProof, exportProof, inspectProof, verifyProof, } from "../../assurance/proof.js";
|
|
3
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
4
|
+
function emit(json, value, human) {
|
|
5
|
+
if (json) {
|
|
6
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
process.stdout.write(`${human}\n`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function runChangeAnalyzeCommand(options) {
|
|
13
|
+
try {
|
|
14
|
+
const assessment = await analyzeChange({
|
|
15
|
+
root: options.root,
|
|
16
|
+
...(options.since ? { since: options.since } : {}),
|
|
17
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
18
|
+
});
|
|
19
|
+
emit(Boolean(options.json), assessment, [
|
|
20
|
+
`Change assessment ${assessment.changeId}`,
|
|
21
|
+
` files: ${assessment.changedFiles.length}`,
|
|
22
|
+
` symbols: ${assessment.changedSymbols.length}`,
|
|
23
|
+
` testImpact: ${assessment.testImpact.mode} (${assessment.testImpact.confidence})`,
|
|
24
|
+
` verificationStatus: ${assessment.verificationStatus}`,
|
|
25
|
+
` Next: agentdoctor change verify${options.since ? ` --since ${options.since}` : ""}`,
|
|
26
|
+
].join("\n"));
|
|
27
|
+
return EXIT_CODES.SUCCESS;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
32
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function runChangeVerifyCommand(options) {
|
|
36
|
+
try {
|
|
37
|
+
const { assessment, manifest } = await verifyChange({
|
|
38
|
+
root: options.root,
|
|
39
|
+
...(options.since ? { since: options.since } : {}),
|
|
40
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
41
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
42
|
+
});
|
|
43
|
+
emit(Boolean(options.json), { assessment, manifest }, [
|
|
44
|
+
`Evidence produced for ${assessment.changeId}`,
|
|
45
|
+
` directory: ${assessment.evidence.directory}`,
|
|
46
|
+
` files: ${assessment.evidence.files?.join(", ") ?? ""}`,
|
|
47
|
+
` verificationStatus: ${assessment.verificationStatus}`,
|
|
48
|
+
` Next: agentdoctor evidence verify ${assessment.changeId}`,
|
|
49
|
+
].join("\n"));
|
|
50
|
+
return EXIT_CODES.SUCCESS;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
54
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
55
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function runChangeExplainCommand(options) {
|
|
59
|
+
try {
|
|
60
|
+
const assessment = await analyzeChange({
|
|
61
|
+
root: options.root,
|
|
62
|
+
...(options.since ? { since: options.since } : {}),
|
|
63
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
64
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
65
|
+
});
|
|
66
|
+
const text = explainChange(assessment);
|
|
67
|
+
emit(Boolean(options.json), { assessment, explanation: text }, text);
|
|
68
|
+
return EXIT_CODES.SUCCESS;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
73
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function runChangeDiffCommand(options) {
|
|
77
|
+
try {
|
|
78
|
+
const diff = await diffChange({
|
|
79
|
+
root: options.root,
|
|
80
|
+
...(options.since ? { since: options.since } : {}),
|
|
81
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
82
|
+
});
|
|
83
|
+
emit(Boolean(options.json), diff, [
|
|
84
|
+
`Change diff${diff.changeId ? ` (${diff.changeId})` : ""}`,
|
|
85
|
+
` base → target: ${diff.baseRevision ?? "(wt)"} → ${diff.targetRevision ?? "?"}`,
|
|
86
|
+
` files: +${diff.summary.added} ~${diff.summary.modified} -${diff.summary.deleted} ?${diff.summary.untracked}`,
|
|
87
|
+
diff.stat ? `\n${diff.stat}` : " (no git --stat output)",
|
|
88
|
+
].join("\n"));
|
|
89
|
+
return EXIT_CODES.SUCCESS;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
93
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
94
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export async function runChangeStatusCommand(options) {
|
|
98
|
+
try {
|
|
99
|
+
const status = await changeStatus({
|
|
100
|
+
root: options.root,
|
|
101
|
+
...(options.changeId ? { changeId: options.changeId } : {}),
|
|
102
|
+
});
|
|
103
|
+
emit(Boolean(options.json), status, [
|
|
104
|
+
`Change status${status.changeId ? `: ${status.changeId}` : " (no evidence)"}`,
|
|
105
|
+
` evidence: ${status.evidencePresent ? status.evidenceDirectory : "none"}`,
|
|
106
|
+
` verificationStatus: ${status.verificationStatus}`,
|
|
107
|
+
` proof: ${status.proofPresent ? status.proofId : "none"}`,
|
|
108
|
+
` note: ${status.integrityNote}`,
|
|
109
|
+
].join("\n"));
|
|
110
|
+
return EXIT_CODES.SUCCESS;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
114
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
115
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export async function runEvidenceInspectCommand(options) {
|
|
119
|
+
const result = await inspectEvidence({ root: options.root, changeId: options.changeId });
|
|
120
|
+
if (!result.ok) {
|
|
121
|
+
process.stderr.write(`Error: ${result.error ?? "evidence not found"}\n`);
|
|
122
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
123
|
+
}
|
|
124
|
+
emit(Boolean(options.json), result, [
|
|
125
|
+
`Evidence ${options.changeId}`,
|
|
126
|
+
` directory: ${result.directory}`,
|
|
127
|
+
` files: ${result.presentFiles.join(", ")}`,
|
|
128
|
+
` manifestStatus: ${result.manifest?.verificationStatus ?? "missing"}`,
|
|
129
|
+
].join("\n"));
|
|
130
|
+
return EXIT_CODES.SUCCESS;
|
|
131
|
+
}
|
|
132
|
+
export async function runEvidenceVerifyCommand(options) {
|
|
133
|
+
const result = await verifyEvidence({ root: options.root, changeId: options.changeId });
|
|
134
|
+
emit(Boolean(options.json), result, [
|
|
135
|
+
`Evidence verify ${options.changeId}`,
|
|
136
|
+
` status: ${result.verificationStatus}`,
|
|
137
|
+
...result.checked.map((c) => ` ${c.match ? "OK" : "FAIL"} ${c.name}`),
|
|
138
|
+
].join("\n"));
|
|
139
|
+
if (!result.ok) {
|
|
140
|
+
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
141
|
+
}
|
|
142
|
+
return EXIT_CODES.SUCCESS;
|
|
143
|
+
}
|
|
144
|
+
export async function runProofBuildCommand(options) {
|
|
145
|
+
try {
|
|
146
|
+
const proof = await buildProofFromEvidence(options.root, options.changeId);
|
|
147
|
+
emit(Boolean(options.json), proof, [
|
|
148
|
+
`ChangeProof ${proof.proofId}`,
|
|
149
|
+
` changeId: ${proof.changeId}`,
|
|
150
|
+
` integrityStatus: ${proof.integrityStatus}`,
|
|
151
|
+
` engineeringChecksStatus: ${proof.engineeringChecksStatus}`,
|
|
152
|
+
` verificationState: ${proof.verificationState}`,
|
|
153
|
+
` correctnessStatus: ${proof.correctnessStatus}`,
|
|
154
|
+
].join("\n"));
|
|
155
|
+
return EXIT_CODES.SUCCESS;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
159
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
160
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export async function runProofInspectCommand(options) {
|
|
164
|
+
const result = await inspectProof(options.root, options.id);
|
|
165
|
+
if (!result.ok || !result.proof) {
|
|
166
|
+
process.stderr.write(`Error: ${result.error ?? "proof not found"}\n`);
|
|
167
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
168
|
+
}
|
|
169
|
+
emit(Boolean(options.json), result, [
|
|
170
|
+
`Proof ${result.proof.proofId}`,
|
|
171
|
+
` changeId: ${result.proof.changeId}`,
|
|
172
|
+
` integrityStatus: ${result.proof.integrityStatus}`,
|
|
173
|
+
` engineeringChecksStatus: ${result.proof.engineeringChecksStatus}`,
|
|
174
|
+
` verificationState: ${result.proof.verificationState}`,
|
|
175
|
+
` correctnessStatus: ${result.proof.correctnessStatus}`,
|
|
176
|
+
` path: ${result.path}`,
|
|
177
|
+
].join("\n"));
|
|
178
|
+
return EXIT_CODES.SUCCESS;
|
|
179
|
+
}
|
|
180
|
+
export async function runProofExplainCommand(options) {
|
|
181
|
+
const result = await inspectProof(options.root, options.id);
|
|
182
|
+
if (!result.ok || !result.proof) {
|
|
183
|
+
process.stderr.write(`Error: ${result.error ?? "proof not found"}\n`);
|
|
184
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
185
|
+
}
|
|
186
|
+
const text = explainProof(result.proof);
|
|
187
|
+
emit(Boolean(options.json), { proof: result.proof, explanation: text }, text);
|
|
188
|
+
return EXIT_CODES.SUCCESS;
|
|
189
|
+
}
|
|
190
|
+
export async function runProofVerifyCommand(options) {
|
|
191
|
+
const result = await verifyProof(options.root, options.id);
|
|
192
|
+
emit(Boolean(options.json), result, [
|
|
193
|
+
`Proof verify ${options.id}`,
|
|
194
|
+
` integrityStatus: ${result.integrityStatus}`,
|
|
195
|
+
` engineeringChecksStatus: ${result.engineeringChecksStatus}`,
|
|
196
|
+
` verificationState: ${result.verificationState}`,
|
|
197
|
+
` correctnessStatus: ${result.correctnessStatus}`,
|
|
198
|
+
...result.checked.map((c) => ` ${c.match ? "OK" : "FAIL"} ${c.name}`),
|
|
199
|
+
].join("\n"));
|
|
200
|
+
return result.ok ? EXIT_CODES.SUCCESS : EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
201
|
+
}
|
|
202
|
+
export async function runProofExportCommand(options) {
|
|
203
|
+
const result = await exportProof(options.root, options.id, options.out);
|
|
204
|
+
if (!result.ok) {
|
|
205
|
+
process.stderr.write(`Error: ${result.error ?? "export failed"}\n`);
|
|
206
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
207
|
+
}
|
|
208
|
+
emit(Boolean(options.json), result, `Exported proof to ${result.path}`);
|
|
209
|
+
return EXIT_CODES.SUCCESS;
|
|
210
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ExitCode } from "../../types/index.js";
|
|
2
|
+
export declare function runBrainCommand(options: {
|
|
3
|
+
action: string;
|
|
4
|
+
root?: string;
|
|
5
|
+
query?: string;
|
|
6
|
+
snapshotId?: string;
|
|
7
|
+
file?: string;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
artifactId?: string;
|
|
10
|
+
decision?: "approved" | "rejected" | "pending-review" | "deprecated";
|
|
11
|
+
note?: string;
|
|
12
|
+
}): Promise<ExitCode>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
+
import { resolveRepoRoot } from "../../utils/path.js";
|
|
3
|
+
import { exportBrain, getBrainStatus, importBrain, initBrainStore, inspectBrainSummary, listBrainSnapshots, loadLatestBrain, rebuildBrain, searchBrain, showBrainSnapshot, } from "../../core/brain-cli/service.js";
|
|
4
|
+
import { listProposals, reviewProposal, writeBrainProductSnapshot, } from "../../core/brain-product/init.js";
|
|
5
|
+
function printJson(value) {
|
|
6
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
7
|
+
}
|
|
8
|
+
export async function runBrainCommand(options) {
|
|
9
|
+
const root = resolveRepoRoot(options.root ?? process.cwd());
|
|
10
|
+
const json = options.json === true;
|
|
11
|
+
try {
|
|
12
|
+
switch (options.action) {
|
|
13
|
+
case "init": {
|
|
14
|
+
const status = await initBrainStore(root);
|
|
15
|
+
if (json)
|
|
16
|
+
printJson(status);
|
|
17
|
+
else
|
|
18
|
+
process.stdout.write(`Project Brain store ready at ${status.storeRoot}\n`);
|
|
19
|
+
return EXIT_CODES.SUCCESS;
|
|
20
|
+
}
|
|
21
|
+
case "status": {
|
|
22
|
+
const status = await getBrainStatus(root);
|
|
23
|
+
if (json)
|
|
24
|
+
printJson(status);
|
|
25
|
+
else
|
|
26
|
+
process.stdout.write(`Brain status\n root: ${status.root}\n snapshots: ${status.snapshotCount}\n latest: ${status.latestSnapshotId ?? "(none)"}\n`);
|
|
27
|
+
return EXIT_CODES.SUCCESS;
|
|
28
|
+
}
|
|
29
|
+
case "inspect": {
|
|
30
|
+
const summary = await inspectBrainSummary(root);
|
|
31
|
+
if (json)
|
|
32
|
+
printJson(summary);
|
|
33
|
+
else
|
|
34
|
+
process.stdout.write(`Brain inspect\n project: ${String(summary.projectName)}\n snapshot: ${String(summary.snapshotId)}\n claims: ${String(summary.claimCount)}\n components: ${String(summary.componentCount)}\n risks: ${String(summary.riskCount)}\n`);
|
|
35
|
+
return EXIT_CODES.SUCCESS;
|
|
36
|
+
}
|
|
37
|
+
case "rebuild":
|
|
38
|
+
case "update": {
|
|
39
|
+
const brain = await rebuildBrain(root);
|
|
40
|
+
const productSnap = await writeBrainProductSnapshot(root);
|
|
41
|
+
if (json)
|
|
42
|
+
printJson({
|
|
43
|
+
snapshotId: brain.snapshot.id,
|
|
44
|
+
projectName: brain.metadata.projectName,
|
|
45
|
+
productSnapshot: productSnap,
|
|
46
|
+
});
|
|
47
|
+
else
|
|
48
|
+
process.stdout.write(`Rebuilt Project Brain snapshot ${brain.snapshot.id}\nRepository Brain product snapshot: ${productSnap}\n`);
|
|
49
|
+
return EXIT_CODES.SUCCESS;
|
|
50
|
+
}
|
|
51
|
+
case "snapshot": {
|
|
52
|
+
const brain = await rebuildBrain(root);
|
|
53
|
+
const productSnap = await writeBrainProductSnapshot(root);
|
|
54
|
+
if (json)
|
|
55
|
+
printJson({ brainSnapshotId: brain.snapshot.id, productSnapshot: productSnap });
|
|
56
|
+
else
|
|
57
|
+
process.stdout.write(`Brain snapshot ${brain.snapshot.id}\nProduct snapshot ${productSnap}\n`);
|
|
58
|
+
return EXIT_CODES.SUCCESS;
|
|
59
|
+
}
|
|
60
|
+
case "review": {
|
|
61
|
+
if (!options.artifactId || !options.decision) {
|
|
62
|
+
console.error("Error: --artifact <id> and --decision <approved|rejected|...> required");
|
|
63
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
64
|
+
}
|
|
65
|
+
const item = await reviewProposal({
|
|
66
|
+
root,
|
|
67
|
+
artifactId: options.artifactId,
|
|
68
|
+
decision: options.decision,
|
|
69
|
+
...(options.note ? { note: options.note } : {}),
|
|
70
|
+
});
|
|
71
|
+
if (json)
|
|
72
|
+
printJson(item);
|
|
73
|
+
else
|
|
74
|
+
process.stdout.write(`Reviewed ${item.artifactId} -> ${item.status}\n`);
|
|
75
|
+
return EXIT_CODES.SUCCESS;
|
|
76
|
+
}
|
|
77
|
+
case "proposals": {
|
|
78
|
+
const proposals = await listProposals(root);
|
|
79
|
+
if (json)
|
|
80
|
+
printJson({ proposals });
|
|
81
|
+
else {
|
|
82
|
+
for (const p of proposals) {
|
|
83
|
+
process.stdout.write(`${p.id} [${p.status}] ${p.kind} ${p.path}\n`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return EXIT_CODES.SUCCESS;
|
|
87
|
+
}
|
|
88
|
+
case "snapshot-list":
|
|
89
|
+
case "history": {
|
|
90
|
+
const snapshots = await listBrainSnapshots(root);
|
|
91
|
+
if (json)
|
|
92
|
+
printJson({ snapshots });
|
|
93
|
+
else if (snapshots.length === 0) {
|
|
94
|
+
process.stdout.write("No snapshots yet. Run: agentdoctor brain rebuild\n");
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
for (const snap of snapshots) {
|
|
98
|
+
process.stdout.write(`${snap.id} ${snap.createdAt} ${snap.projectName}\n`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return EXIT_CODES.SUCCESS;
|
|
102
|
+
}
|
|
103
|
+
case "snapshot-show": {
|
|
104
|
+
if (!options.snapshotId) {
|
|
105
|
+
console.error("Error: snapshot id required");
|
|
106
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
107
|
+
}
|
|
108
|
+
const brain = await showBrainSnapshot(root, options.snapshotId);
|
|
109
|
+
printJson({
|
|
110
|
+
snapshotId: brain.snapshot.id,
|
|
111
|
+
projectName: brain.metadata.projectName,
|
|
112
|
+
claimCount: brain.claims.length,
|
|
113
|
+
componentCount: brain.components.length,
|
|
114
|
+
});
|
|
115
|
+
return EXIT_CODES.SUCCESS;
|
|
116
|
+
}
|
|
117
|
+
case "search": {
|
|
118
|
+
if (!options.query) {
|
|
119
|
+
console.error("Error: search query required");
|
|
120
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
121
|
+
}
|
|
122
|
+
let brain = await loadLatestBrain(root);
|
|
123
|
+
if (!brain)
|
|
124
|
+
brain = await rebuildBrain(root);
|
|
125
|
+
const hits = searchBrain(brain, options.query);
|
|
126
|
+
if (json)
|
|
127
|
+
printJson({ query: options.query, hits });
|
|
128
|
+
else if (hits.length === 0)
|
|
129
|
+
process.stdout.write("No matches.\n");
|
|
130
|
+
else
|
|
131
|
+
for (const hit of hits)
|
|
132
|
+
process.stdout.write(`[${hit.kind}] ${hit.id}: ${hit.text}\n`);
|
|
133
|
+
return EXIT_CODES.SUCCESS;
|
|
134
|
+
}
|
|
135
|
+
case "export": {
|
|
136
|
+
if (!options.file) {
|
|
137
|
+
console.error("Error: --file <path> required for export");
|
|
138
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
139
|
+
}
|
|
140
|
+
const out = await exportBrain(root, options.file, options.snapshotId);
|
|
141
|
+
process.stdout.write(`Exported redacted brain to ${out}\n`);
|
|
142
|
+
return EXIT_CODES.SUCCESS;
|
|
143
|
+
}
|
|
144
|
+
case "import": {
|
|
145
|
+
if (!options.file) {
|
|
146
|
+
console.error("Error: --file <path> required for import");
|
|
147
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
148
|
+
}
|
|
149
|
+
const meta = await importBrain(root, options.file);
|
|
150
|
+
process.stdout.write(`Imported snapshot ${meta.id}\n`);
|
|
151
|
+
return EXIT_CODES.SUCCESS;
|
|
152
|
+
}
|
|
153
|
+
default:
|
|
154
|
+
console.error(`Error: unknown brain action: ${options.action}`);
|
|
155
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ExitCode } from "../../types/index.js";
|
|
2
|
+
export declare function runInitCommand(options: {
|
|
3
|
+
root?: string;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
name?: string;
|
|
6
|
+
domain?: string;
|
|
7
|
+
}): Promise<ExitCode>;
|
|
8
|
+
export declare function runV2SurfaceCommand(options: {
|
|
9
|
+
action: string;
|
|
10
|
+
root?: string;
|
|
11
|
+
json?: boolean;
|
|
12
|
+
query?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
content?: string;
|
|
15
|
+
id?: string;
|
|
16
|
+
decision?: string;
|
|
17
|
+
username?: string;
|
|
18
|
+
password?: string;
|
|
19
|
+
token?: string;
|
|
20
|
+
command?: string;
|
|
21
|
+
mode?: string;
|
|
22
|
+
symbol?: string;
|
|
23
|
+
}): Promise<ExitCode>;
|